/* 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, ANNOTATION_START, ANNOTATION_END, FIELD_END, DATA }; class TestOsxmlEventListener : public OsxmlEvents { public: std::vector> events; void command(const Variant &name, const Variant::mapType &args) override { events.emplace_back(OsxmlEvent::COMMAND, Variant::arrayType{name, args}); } void annotationStart(const Variant &className, const Variant::mapType &args) override { events.emplace_back(OsxmlEvent::ANNOTATION_START, Variant::arrayType{className, args}); } void annotationEnd(const Variant &className, const Variant &elementName) override { events.emplace_back(OsxmlEvent::ANNOTATION_END, Variant::arrayType{className, elementName}); } void fieldEnd() override { events.emplace_back(OsxmlEvent::FIELD_END, Variant::arrayType{}); } void data(const 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, 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, Variant::arrayType{{"a", Variant::mapType{}}}}, {OsxmlEvent::FIELD_END, Variant::arrayType{}}, {OsxmlEvent::COMMAND, 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, Variant::arrayType{{"a", Variant::mapType{}}}}, {OsxmlEvent::COMMAND, 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, 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, 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, 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()); } }