From 2659b4595d809cbd69a77e5ff7e2fc08d225f065 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 00:02:54 +0100 Subject: Tidied OsxmlEventParser up, implemented correct whitespace handling, started to write unit tests for the osxml parser --- test/formats/osxml/OsxmlEventParserTest.cpp | 222 ++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 test/formats/osxml/OsxmlEventParserTest.cpp (limited to 'test/formats/osxml/OsxmlEventParserTest.cpp') diff --git a/test/formats/osxml/OsxmlEventParserTest.cpp b/test/formats/osxml/OsxmlEventParserTest.cpp new file mode 100644 index 0000000..06c800f --- /dev/null +++ b/test/formats/osxml/OsxmlEventParserTest.cpp @@ -0,0 +1,222 @@ +/* + Ousía + Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include +#include +#include + +#include + +namespace ousia { + +static TerminalLogger logger(std::cerr, true); +// static ConcreteLogger logger; + +namespace { +enum class OsxmlEvent { + COMMAND_START, + ANNOTATION_START, + ANNOTATION_END, + FIELD_END, + DATA +}; + +class TestOsxmlEventListener : public OsxmlEvents { +public: + std::vector> events; + + void commandStart(Variant name, Variant args) override + { + events.emplace_back(OsxmlEvent::COMMAND_START, + Variant::arrayType{name, args}); + } + + void annotationStart(Variant name, Variant args) override + { + events.emplace_back(OsxmlEvent::ANNOTATION_START, + Variant::arrayType{name, args}); + } + + void annotationEnd(Variant name, Variant elementName) override + { + events.emplace_back(OsxmlEvent::ANNOTATION_END, + Variant::arrayType{name, elementName}); + } + + void fieldEnd() override + { + events.emplace_back(OsxmlEvent::FIELD_END, Variant::arrayType{}); + } + + void data(Variant data) override + { + events.emplace_back(OsxmlEvent::DATA, Variant::arrayType{data}); + } +}; + +static std::vector> parseXml( + const char *testString, + WhitespaceMode whitespaceMode = WhitespaceMode::TRIM) +{ + TestOsxmlEventListener listener; + CharReader reader(testString); + OsxmlEventParser parser(reader, listener, logger); + parser.setWhitespaceMode(whitespaceMode); + parser.parse(); + return listener.events; +} +} + +TEST(OsxmlEventParser, simpleCommandWithArgs) +{ + const char *testString = ""; + // 01234567 89012 3456 78 9012 34 5678 90123 456 + // 0 1 2 3 + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{ + "a", Variant::mapType{ + {"name", "test"}, {"a", 1}, {"b", 2}, {"c", "blub"}}}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString); + ASSERT_EQ(expectedEvents, events); + + // Check the locations (I'll do this one time and then just assume it works) + ASSERT_EQ(1U, events[0].second.asArray()[0].getLocation().getStart()); + ASSERT_EQ(2U, events[0].second.asArray()[0].getLocation().getEnd()); + ASSERT_EQ( + 9U, + events[0].second.asArray()[1].asMap()["name"].getLocation().getStart()); + ASSERT_EQ( + 13U, + events[0].second.asArray()[1].asMap()["name"].getLocation().getEnd()); + ASSERT_EQ( + 18U, + events[0].second.asArray()[1].asMap()["a"].getLocation().getStart()); + ASSERT_EQ( + 19U, events[0].second.asArray()[1].asMap()["a"].getLocation().getEnd()); + ASSERT_EQ( + 24U, + events[0].second.asArray()[1].asMap()["b"].getLocation().getStart()); + ASSERT_EQ( + 25U, events[0].second.asArray()[1].asMap()["b"].getLocation().getEnd()); + ASSERT_EQ( + 30U, + events[0].second.asArray()[1].asMap()["c"].getLocation().getStart()); + ASSERT_EQ( + 34U, events[0].second.asArray()[1].asMap()["c"].getLocation().getEnd()); +} + +TEST(OsxmlEventParser, magicTopLevelTag) +{ + const char *testString = ""; + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{{"a", Variant::mapType{}}}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}, + {OsxmlEvent::COMMAND_START, + Variant::arrayType{{"b", Variant::mapType{}}}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString); + ASSERT_EQ(expectedEvents, events); +} + +TEST(OsxmlEventParser, magicTopLevelTagInside) +{ + const char *testString = ""; + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{{"a", Variant::mapType{}}}}, + {OsxmlEvent::COMMAND_START, + Variant::arrayType{{"ousia", Variant::mapType{}}}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString); + ASSERT_EQ(expectedEvents, events); +} + +TEST(OsxmlEventParser, commandWithDataPreserveWhitespace) +{ + const char *testString = " hello \n world "; + // 012345678901 234567890123 + // 0 1 2 + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::DATA, Variant::arrayType{" hello \n world "}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString, WhitespaceMode::PRESERVE); + ASSERT_EQ(expectedEvents, events); + + // Check the location of the text + ASSERT_EQ(3U, events[1].second.asArray()[0].getLocation().getStart()); + ASSERT_EQ(20U, events[1].second.asArray()[0].getLocation().getEnd()); +} + +TEST(OsxmlEventParser, commandWithDataTrimWhitespace) +{ + const char *testString = " hello \n world "; + // 012345678901 234567890123 + // 0 1 2 + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::DATA, Variant::arrayType{"hello \n world"}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString, WhitespaceMode::TRIM); + ASSERT_EQ(expectedEvents, events); + + // Check the location of the text + ASSERT_EQ(5U, events[1].second.asArray()[0].getLocation().getStart()); + ASSERT_EQ(19U, events[1].second.asArray()[0].getLocation().getEnd()); +} + +TEST(OsxmlEventParser, commandWithDataCollapseWhitespace) +{ + const char *testString = " hello \n world "; + // 012345678901 234567890123 + // 0 1 2 + + std::vector> expectedEvents{ + {OsxmlEvent::COMMAND_START, + Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::DATA, Variant::arrayType{"hello world"}}, + {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; + + auto events = parseXml(testString, WhitespaceMode::COLLAPSE); + ASSERT_EQ(expectedEvents, events); + + // Check the location of the text + ASSERT_EQ(5U, events[1].second.asArray()[0].getLocation().getStart()); + ASSERT_EQ(19U, events[1].second.asArray()[0].getLocation().getEnd()); +} + +} + -- cgit v1.2.3 From b7ffeb3dca889aee1c878e2ef0f07644f910dba2 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Sun, 15 Feb 2015 20:58:05 +0100 Subject: Made OsxmlEvents interface consistent with Stack commands --- src/formats/osxml/OsxmlEventParser.cpp | 2 +- src/formats/osxml/OsxmlEventParser.hpp | 24 +++++++++-------- test/formats/osxml/OsxmlEventParserTest.cpp | 41 +++++++++++++---------------- 3 files changed, 32 insertions(+), 35 deletions(-) (limited to 'test/formats/osxml/OsxmlEventParserTest.cpp') diff --git a/src/formats/osxml/OsxmlEventParser.cpp b/src/formats/osxml/OsxmlEventParser.cpp index b4aff77..7404960 100644 --- a/src/formats/osxml/OsxmlEventParser.cpp +++ b/src/formats/osxml/OsxmlEventParser.cpp @@ -329,7 +329,7 @@ static void xmlStartElementHandler(void *ref, const XML_Char *name, // Just issue a "commandStart" event in any other case Variant nameVar = Variant::fromString(nameStr); nameVar.setLocation(nameLoc); - parser->getEvents().commandStart(nameVar, args); + parser->getEvents().command(nameVar, args); } } diff --git a/src/formats/osxml/OsxmlEventParser.hpp b/src/formats/osxml/OsxmlEventParser.hpp index aa20ea9..e39245f 100644 --- a/src/formats/osxml/OsxmlEventParser.hpp +++ b/src/formats/osxml/OsxmlEventParser.hpp @@ -58,34 +58,36 @@ public: * * @param name is a string variant containing name and location of the * command. - * @param args is a map variant containing the arguments that were given - * to the command. + * @param args is a map containing the arguments that were given to the + * command. */ - virtual void commandStart(Variant name, Variant args) = 0; + virtual void command(const Variant &name, const Variant::mapType &args) = 0; /** * Called whenever an annotation starts. Note that this implicitly always * starts the default field of the annotation. * - * @param name is a string variant containing the name of the annotation - * class and the location of the annotation definition. + * @param className is a string variant containing the name of the + * annotation class and the location of the annotation definition. * @param args is a map variant containing the arguments that were given * to the annotation definition. */ - virtual void annotationStart(Variant name, Variant args) = 0; + virtual void annotationStart(const Variant &className, + const Variant::mapType &args) = 0; /** * Called whenever the range of an annotation ends. The callee must * disambiguate the actual annotation that is finished here. * - * @param name is a string variant containing the name of the annotation - * class that should end here. May be empty (or nullptr), if no elementName - * has been specified at the end of the annotation. + * @param className is a string variant containing the name of the + * annotation class that should end here. May be empty (or nullptr), if no + * elementName has been specified at the end of the annotation. * @param elementName is the name of the annotation element that should be * ended here. May be empty (or nullptr), if no elementName has been * specified at the end of the annotation. */ - virtual void annotationEnd(Variant name, Variant elementName) = 0; + virtual void annotationEnd(const Variant &className, + const Variant &elementName) = 0; /** * Called whenever the default field which was implicitly started by @@ -105,7 +107,7 @@ public: * @param data is the already parsed data that should be passed to the * handler. */ - virtual void data(Variant data) = 0; + virtual void data(const Variant &data) = 0; }; /** diff --git a/test/formats/osxml/OsxmlEventParserTest.cpp b/test/formats/osxml/OsxmlEventParserTest.cpp index 06c800f..3293370 100644 --- a/test/formats/osxml/OsxmlEventParserTest.cpp +++ b/test/formats/osxml/OsxmlEventParserTest.cpp @@ -31,7 +31,7 @@ static TerminalLogger logger(std::cerr, true); namespace { enum class OsxmlEvent { - COMMAND_START, + COMMAND, ANNOTATION_START, ANNOTATION_END, FIELD_END, @@ -42,22 +42,24 @@ class TestOsxmlEventListener : public OsxmlEvents { public: std::vector> events; - void commandStart(Variant name, Variant args) override + void command(const Variant &name, const Variant::mapType &args) override { - events.emplace_back(OsxmlEvent::COMMAND_START, + events.emplace_back(OsxmlEvent::COMMAND, Variant::arrayType{name, args}); } - void annotationStart(Variant name, Variant args) override + void annotationStart(const Variant &className, + const Variant::mapType &args) override { events.emplace_back(OsxmlEvent::ANNOTATION_START, - Variant::arrayType{name, args}); + Variant::arrayType{className, args}); } - void annotationEnd(Variant name, Variant elementName) override + void annotationEnd(const Variant &className, + const Variant &elementName) override { events.emplace_back(OsxmlEvent::ANNOTATION_END, - Variant::arrayType{name, elementName}); + Variant::arrayType{className, elementName}); } void fieldEnd() override @@ -65,7 +67,7 @@ public: events.emplace_back(OsxmlEvent::FIELD_END, Variant::arrayType{}); } - void data(Variant data) override + void data(const Variant &data) override { events.emplace_back(OsxmlEvent::DATA, Variant::arrayType{data}); } @@ -91,7 +93,7 @@ TEST(OsxmlEventParser, simpleCommandWithArgs) // 0 1 2 3 std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, + {OsxmlEvent::COMMAND, Variant::arrayType{ "a", Variant::mapType{ {"name", "test"}, {"a", 1}, {"b", 2}, {"c", "blub"}}}}, @@ -131,11 +133,9 @@ TEST(OsxmlEventParser, magicTopLevelTag) const char *testString = ""; std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, - Variant::arrayType{{"a", Variant::mapType{}}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{{"a", Variant::mapType{}}}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}, - {OsxmlEvent::COMMAND_START, - Variant::arrayType{{"b", Variant::mapType{}}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{{"b", Variant::mapType{}}}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; auto events = parseXml(testString); @@ -147,9 +147,8 @@ TEST(OsxmlEventParser, magicTopLevelTagInside) const char *testString = ""; std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, - Variant::arrayType{{"a", Variant::mapType{}}}}, - {OsxmlEvent::COMMAND_START, + {OsxmlEvent::COMMAND, Variant::arrayType{{"a", Variant::mapType{}}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{{"ousia", Variant::mapType{}}}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; @@ -165,8 +164,7 @@ TEST(OsxmlEventParser, commandWithDataPreserveWhitespace) // 0 1 2 std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, - Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{"a", Variant::mapType{}}}, {OsxmlEvent::DATA, Variant::arrayType{" hello \n world "}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; @@ -185,8 +183,7 @@ TEST(OsxmlEventParser, commandWithDataTrimWhitespace) // 0 1 2 std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, - Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{"a", Variant::mapType{}}}, {OsxmlEvent::DATA, Variant::arrayType{"hello \n world"}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; @@ -205,8 +202,7 @@ TEST(OsxmlEventParser, commandWithDataCollapseWhitespace) // 0 1 2 std::vector> expectedEvents{ - {OsxmlEvent::COMMAND_START, - Variant::arrayType{"a", Variant::mapType{}}}, + {OsxmlEvent::COMMAND, Variant::arrayType{"a", Variant::mapType{}}}, {OsxmlEvent::DATA, Variant::arrayType{"hello world"}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}}; @@ -217,6 +213,5 @@ TEST(OsxmlEventParser, commandWithDataCollapseWhitespace) ASSERT_EQ(5U, events[1].second.asArray()[0].getLocation().getStart()); ASSERT_EQ(19U, events[1].second.asArray()[0].getLocation().getEnd()); } - } -- cgit v1.2.3