/* Ousía Copyright (C) 2014 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 #include #include #include namespace ousia { static TerminalLogger logger(std::cerr, true); // static ConcreteLogger logger; static void assertCommandStart(OsmlStreamParser &parser, const std::string &name, bool rangeCommand, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::COMMAND_START, parser.parse()); EXPECT_EQ(name, parser.getCommandName().asString()); EXPECT_EQ(rangeCommand, parser.inRangeCommand()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getCommandName().getLocation().getStart()); EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getCommandName().getLocation().getEnd()); EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertCommandStart(OsmlStreamParser &parser, const std::string &name, bool rangeCommand, const Variant::mapType &args, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { assertCommandStart(parser, name, rangeCommand, start, end); EXPECT_EQ(args, parser.getCommandArguments()); } static void assertCommand(OsmlStreamParser &parser, const std::string &name, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { assertCommandStart(parser, name, false, Variant::mapType{}, start, end); } static void assertRangeEnd(OsmlStreamParser &parser, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::RANGE_END, parser.parse()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertTextData(OsmlStreamParser &parser, const std::string &text, SourceOffset dataStart = InvalidSourceOffset, SourceOffset dataEnd = InvalidSourceOffset, SourceOffset textStart = InvalidSourceOffset, SourceOffset textEnd = InvalidSourceOffset, WhitespaceMode mode = WhitespaceMode::COLLAPSE) { ASSERT_EQ(OsmlStreamParser::State::DATA, parser.parse()); const TokenizedData &data = parser.getData(); TokenizedDataReader dataReader = data.reader(); Token token; ASSERT_TRUE(dataReader.read(token, TokenSet{}, mode)); EXPECT_EQ(Tokens::Data, token.id); EXPECT_EQ(text, token.content); if (dataStart != InvalidSourceOffset) { EXPECT_EQ(dataStart, data.getLocation().getStart()); EXPECT_EQ(dataStart, parser.getLocation().getStart()); } if (dataEnd != InvalidSourceOffset) { EXPECT_EQ(dataEnd, data.getLocation().getEnd()); EXPECT_EQ(dataEnd, parser.getLocation().getEnd()); } if (textStart != InvalidSourceOffset) { EXPECT_EQ(textStart, token.getLocation().getStart()); } if (textEnd != InvalidSourceOffset) { EXPECT_EQ(textEnd, token.getLocation().getEnd()); } } static void assertData(OsmlStreamParser &parser, const std::string &text, SourceOffset textStart = InvalidSourceOffset, SourceOffset textEnd = InvalidSourceOffset, WhitespaceMode mode = WhitespaceMode::COLLAPSE) { assertTextData(parser, text, InvalidSourceOffset, InvalidSourceOffset, textStart, textEnd, mode); } static void assertEmptyData(OsmlStreamParser &parser) { ASSERT_EQ(OsmlStreamParser::State::DATA, parser.parse()); const TokenizedData &data = parser.getData(); TokenizedDataReader dataReader = data.reader(); Token token; EXPECT_FALSE(dataReader.read(token, TokenSet{}, WhitespaceMode::TRIM)); } static void assertFieldStart(OsmlStreamParser &parser, bool defaultField, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::FIELD_START, parser.parse()); EXPECT_EQ(defaultField, parser.inDefaultField()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertFieldEnd(OsmlStreamParser &parser, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::FIELD_END, parser.parse()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertAnnotationStart(OsmlStreamParser &parser, const std::string &name, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::ANNOTATION_START, parser.parse()); EXPECT_EQ(name, parser.getCommandName().asString()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getCommandName().getLocation().getStart()); EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getCommandName().getLocation().getEnd()); EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertAnnotationStart(OsmlStreamParser &parser, const std::string &name, const Variant::mapType &args, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { assertAnnotationStart(parser, name, start, end); EXPECT_EQ(args, parser.getCommandArguments()); } static void assertAnnotationEnd(OsmlStreamParser &parser, const std::string &name, const std::string &elementName, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::ANNOTATION_END, parser.parse()); ASSERT_EQ(name, parser.getCommandName().asString()); if (!elementName.empty()) { ASSERT_EQ(1U, parser.getCommandArguments().asMap().size()); ASSERT_EQ(1U, parser.getCommandArguments().asMap().count("name")); auto it = parser.getCommandArguments().asMap().find("name"); ASSERT_EQ(elementName, it->second.asString()); } if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getLocation().getEnd()); } } static void assertEnd(OsmlStreamParser &parser, SourceOffset start = InvalidSourceOffset, SourceOffset end = InvalidSourceOffset) { ASSERT_EQ(OsmlStreamParser::State::END, parser.parse()); if (start != InvalidSourceOffset) { EXPECT_EQ(start, parser.getLocation().getStart()); } if (end != InvalidSourceOffset) { EXPECT_EQ(end, parser.getLocation().getEnd()); } } TEST(OsmlStreamParser, empty) { const char *testString = ""; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertEnd(parser, 0, 0); } TEST(OsmlStreamParser, oneCharacter) { const char *testString = "a"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "a", 0, 1, 0, 1, WhitespaceMode::COLLAPSE); assertEnd(parser, 1, 1); } TEST(OsmlStreamParser, whitespacePreserve) { const char *testString = " hello \t world "; // 0123456 78901234 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, " hello \t world ", 0, 15, 0, 15, WhitespaceMode::PRESERVE); assertEnd(parser, 15, 15); } TEST(OsmlStreamParser, whitespaceTrim) { const char *testString = " hello \t world "; // 0123456 78901234 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "hello \t world", 0, 15, 1, 14, WhitespaceMode::TRIM); assertEnd(parser, 15, 15); } TEST(OsmlStreamParser, whitespaceCollapse) { const char *testString = " hello \t world "; // 0123456 78901234 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "hello world", 0, 15, 1, 14, WhitespaceMode::COLLAPSE); assertEnd(parser, 15, 15); } TEST(OsmlStreamParser, whitespaceCollapseLinebreak) { const char *testString = " hello \n world "; // 0123456 78901234 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "hello world", 0, 15, 1, 14, WhitespaceMode::COLLAPSE); assertEnd(parser, 15, 15); } TEST(OsmlStreamParser, whitespaceCollapseProtected) { const char *testString = " hello\\ \\ world "; // 012345 67 89012345 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "hello world", 0, 16, 1, 15, WhitespaceMode::COLLAPSE); assertEnd(parser, 16, 16); } TEST(OsmlStreamParser, whitespaceCollapseProtected2) { const char *testString = " hello \\ \\ world "; // 012345 67 89012345 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "hello world", 0, 17, 1, 16, WhitespaceMode::COLLAPSE); assertEnd(parser, 17, 17); } static void testEscapeSpecialCharacter(const std::string &c) { CharReader charReader(std::string("\\") + c); OsmlStreamParser parser(charReader, logger); assertTextData(parser, c, 0, 2, 0, 2, WhitespaceMode::PRESERVE); assertEnd(parser, 2, 2); } TEST(OsmlStreamParser, escapeSpecialCharacters) { testEscapeSpecialCharacter("\\"); testEscapeSpecialCharacter("{"); testEscapeSpecialCharacter("}"); } TEST(OsmlStreamParser, simpleSingleLineComment) { const char *testString = "% This is a single line comment"; // 0123456789012345678901234567890 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertEnd(parser, 31, 31); } TEST(OsmlStreamParser, singleLineComment) { const char *testString = "a% This is a single line comment\nb"; // 01234567890123456789012345678901 23 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "ab", 0, 34, 0, 34, WhitespaceMode::PRESERVE); assertEnd(parser, 34, 34); } TEST(OsmlStreamParser, multilineComment) { const char *testString = "a%{ This is a\n\n multiline line comment}%b"; // 0123456789012 3 456789012345678901234567890 // 0 1 2 3 4 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "ab", 0, 41, 0, 41, WhitespaceMode::PRESERVE); assertEnd(parser, 41, 41); } TEST(OsmlStreamParser, unfinishedMultilineComment) { const char *testString = "a%{ This is a\n\n multiline line comment"; // 0123456789012 3 456789012345678901234567 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertTextData(parser, "a", 0, 1, 0, 1, WhitespaceMode::PRESERVE); ASSERT_TRUE(logger.hasError()); assertEnd(parser, 38, 38); } TEST(OsmlStreamParser, nestedMultilineComment) { const char *testString = "a%{%{Another\n\n}%multiline line comment}%b"; // 0123456789012 3 456789012345678901234567890 // 0 1 2 3 4 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertTextData(parser, "ab", 0, 41, 0, 41, WhitespaceMode::PRESERVE); assertEnd(parser, 41, 41); } TEST(OsmlStreamParser, simpleCommand) { const char *testString = "\\test"; // 0 12345 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertEnd(parser); } TEST(OsmlStreamParser, simpleCommandWithName) { const char *testString = "\\test#foo"; // 012345678 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "test", false, Variant::mapType{{"name", "foo"}}, 0, 5); Variant::mapType args = parser.getCommandArguments().asMap(); ASSERT_EQ(5U, args["name"].getLocation().getStart()); ASSERT_EQ(9U, args["name"].getLocation().getEnd()); assertEnd(parser); } TEST(OsmlStreamParser, simpleCommandWithArguments) { const char *testString = "\\test[a=1,b=2,c=\"test\"]"; // 0 123456789012345 678901 2 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "test", false, Variant::mapType{{"a", 1}, {"b", 2}, {"c", "test"}}, 0, 5); Variant::mapType args = parser.getCommandArguments().asMap(); ASSERT_EQ(8U, args["a"].getLocation().getStart()); ASSERT_EQ(9U, args["a"].getLocation().getEnd()); ASSERT_EQ(12U, args["b"].getLocation().getStart()); ASSERT_EQ(13U, args["b"].getLocation().getEnd()); ASSERT_EQ(16U, args["c"].getLocation().getStart()); ASSERT_EQ(22U, args["c"].getLocation().getEnd()); assertEnd(parser); } TEST(OsmlStreamParser, simpleCommandWithArgumentsAndName) { const char *testString = "\\test#bla[a=1,b=2,c=\"test\"]"; // 0 1234567890123456789 01234 56 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart( parser, "test", false, Variant::mapType{{"name", "bla"}, {"a", 1}, {"b", 2}, {"c", "test"}}, 0, 5); Variant::mapType args = parser.getCommandArguments().asMap(); ASSERT_EQ(5U, args["name"].getLocation().getStart()); ASSERT_EQ(9U, args["name"].getLocation().getEnd()); ASSERT_EQ(12U, args["a"].getLocation().getStart()); ASSERT_EQ(13U, args["a"].getLocation().getEnd()); ASSERT_EQ(16U, args["b"].getLocation().getStart()); ASSERT_EQ(17U, args["b"].getLocation().getEnd()); ASSERT_EQ(20U, args["c"].getLocation().getStart()); ASSERT_EQ(26U, args["c"].getLocation().getEnd()); assertEnd(parser); } TEST(OsmlStreamParser, fields) { const char *testString = "\\test{a}{b}{c}"; // 01234567890123 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertTextData(parser, "a", 6, 7, 6, 7, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 7, 8); assertFieldStart(parser, false, 8, 9); assertTextData(parser, "b", 9, 10, 9, 10, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 10, 11); assertFieldStart(parser, false, 11, 12); assertTextData(parser, "c", 12, 13, 12, 13, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 13, 14); assertEnd(parser, 14, 14); } TEST(OsmlStreamParser, fieldsWithoutCommand) { const char *testString = "{a}{b}{c}"; // 012345678 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertFieldStart(parser, false, 0, 1); assertTextData(parser, "a", 1, 2, 1, 2, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 2, 3); assertFieldStart(parser, false, 3, 4); assertTextData(parser, "b", 4, 5, 4, 5, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 5, 6); assertFieldStart(parser, false, 6, 7); assertTextData(parser, "c", 7, 8, 7, 8, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 8, 9); assertEnd(parser, 9, 9); } TEST(OsmlStreamParser, nestedField) { const char *testString = "{{a{b}}}"; // 01234567 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertFieldStart(parser, false, 0, 1); assertFieldStart(parser, false, 1, 2); assertTextData(parser, "a", 2, 3, 2, 3, WhitespaceMode::PRESERVE); assertFieldStart(parser, false, 3, 4); assertTextData(parser, "b", 4, 5, 4, 5, WhitespaceMode::PRESERVE); assertFieldEnd(parser, 5, 6); assertFieldEnd(parser, 6, 7); assertFieldEnd(parser, 7, 8); assertEnd(parser, 8, 8); } TEST(OsmlStreamParser, errorUnbalancedField) { const char *testString = "{a"; // 01 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertFieldStart(parser, false, 0, 1); assertTextData(parser, "a", 1, 2, 1, 2, WhitespaceMode::PRESERVE); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 2, 2); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, dataOutsideField) { const char *testString = "\\test{a}{b} c"; // 0123456789012 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertTextData(parser, "a", 6, 7, 6, 7, WhitespaceMode::COLLAPSE); assertFieldEnd(parser, 7, 8); assertFieldStart(parser, false, 8, 9); assertTextData(parser, "b", 9, 10, 9, 10, WhitespaceMode::COLLAPSE); assertFieldEnd(parser, 10, 11); assertTextData(parser, "c", 11, 13, 12, 13, WhitespaceMode::COLLAPSE); assertEnd(parser, 13, 13); } TEST(OsmlStreamParser, nestedCommand) { const char *testString = "\\test{a}{\\test2{b} c} d"; // 012345678 90123456789012 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertData(parser, "a", 6, 7); assertFieldEnd(parser, 7, 8); assertFieldStart(parser, false, 8, 9); assertCommand(parser, "test2", 9, 15); assertFieldStart(parser, false, 15, 16); assertData(parser, "b", 16, 17); assertFieldEnd(parser, 17, 18); assertData(parser, "c", 19, 20); assertFieldEnd(parser, 20, 21); assertData(parser, "d", 22, 23); assertEnd(parser, 23, 23); } TEST(OsmlStreamParser, nestedCommandImmediateEnd) { const char *testString = "\\test{\\test2{b}} d"; // 012345 678901234567 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); { assertCommand(parser, "test2", 6, 12); assertFieldStart(parser, false, 12, 13); assertData(parser, "b", 13, 14); assertFieldEnd(parser, 14, 15); } assertFieldEnd(parser, 15, 16); assertData(parser, "d", 17, 18); assertEnd(parser, 18, 18); } TEST(OsmlStreamParser, nestedCommandNoData) { const char *testString = "\\test{\\test2}"; // 012345 6789012 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertCommand(parser, "test2", 6, 12); assertFieldEnd(parser, 12, 13); assertEnd(parser, 13, 13); } TEST(OsmlStreamParser, multipleCommands) { const char *testString = "\\a \\b \\c \\d"; // 012 345 678 90 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "a", 0, 2); assertEmptyData(parser); assertCommand(parser, "b", 3, 5); assertEmptyData(parser); assertCommand(parser, "c", 6, 8); assertEmptyData(parser); assertCommand(parser, "d", 9, 11); assertEnd(parser, 11, 11); } TEST(OsmlStreamParser, fieldsWithSpaces) { const char *testString = "\\a {\\b \\c} \n\n {\\d}"; // 0123 456 789012 3 456 789 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "a", 0, 2); assertEmptyData(parser); assertFieldStart(parser, false, 3, 4); assertCommand(parser, "b", 4, 6); assertEmptyData(parser); assertCommand(parser, "c", 7, 9); assertFieldEnd(parser, 9, 10); assertEmptyData(parser); assertFieldStart(parser, false, 16, 17); assertCommand(parser, "d", 17, 19); assertFieldEnd(parser, 19, 20); assertEnd(parser, 20, 20); } TEST(OsmlStreamParser, errorEndButOpenField) { const char *testString = "\\a b {"; // 012345 // 0 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommand(parser, "a", 0, 2); assertData(parser, "b", 3, 4); assertFieldStart(parser, false, 5, 6); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 6, 6); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorNoFieldToEnd) { const char *testString = "\\a b }"; // 012345 // 0 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommand(parser, "a", 0, 2); assertData(parser, "b", 3, 4); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 6, 6); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorNoFieldEndNested) { const char *testString = "\\test{\\test2{}}}"; // 012345 6789012345 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertCommand(parser, "test2", 6, 12); assertFieldStart(parser, false, 12, 13); assertFieldEnd(parser, 13, 14); assertFieldEnd(parser, 14, 15); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 16, 16); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorNoFieldEndNestedData) { const char *testString = "\\test{\\test2{}}a}"; // 012345 67890123456 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommand(parser, "test", 0, 5); assertFieldStart(parser, false, 5, 6); assertCommand(parser, "test2", 6, 12); assertFieldStart(parser, false, 12, 13); assertFieldEnd(parser, 13, 14); assertFieldEnd(parser, 14, 15); assertData(parser, "a", 15, 16); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 17, 17); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, beginEnd) { const char *testString = "\\begin{book}\\end{book}"; // 012345678901 2345678901 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, Variant::mapType{}, 7, 11); assertRangeEnd(parser, 17, 21); assertEnd(parser, 22, 22); } TEST(OsmlStreamParser, beginEndWithName) { const char *testString = "\\begin{book#a}\\end{book}"; // 01234567890123 4567890123 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, {{"name", "a"}}, 7, 11); assertRangeEnd(parser, 19, 23); assertEnd(parser, 24, 24); } TEST(OsmlStreamParser, beginEndWithNameAndArgs) { const char *testString = "\\begin{book#a}[a=1,b=2,c=\"test\"]\\end{book}"; // 0123456789012345678901234 56789 01 2345678901 // 0 1 2 3 4 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, {{"name", "a"}, {"a", 1}, {"b", 2}, {"c", "test"}}, 7, 11); assertRangeEnd(parser, 37, 41); assertEnd(parser, 42, 42); } TEST(OsmlStreamParser, beginEndWithNameAndArgsMultipleFields) { const char *testString = "\\begin{book#a}[a=1,b=2,c=\"test\"]{a \\test}{b \\test{}}\\end{book}"; // 0123456789012345678901234 56789 01234 567890123 45678901 2345678901 // 0 1 2 3 4 5 6 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, {{"name", "a"}, {"a", 1}, {"b", 2}, {"c", "test"}}, 7, 11); assertFieldStart(parser, false, 32, 33); assertData(parser, "a", 33, 34); assertCommand(parser, "test", 35, 40); assertFieldEnd(parser, 40, 41); assertFieldStart(parser, false, 41, 42); assertData(parser, "b", 42, 43); assertCommand(parser, "test", 44, 49); assertFieldStart(parser, false, 49, 50); assertFieldEnd(parser, 50, 51); assertFieldEnd(parser, 51, 52); assertRangeEnd(parser, 57, 61); assertEnd(parser, 62, 62); } TEST(OsmlStreamParser, beginEndWithData) { const char *testString = "\\begin{book}a\\end{book}"; // 0123456789012 3456789012 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, Variant::mapType{}, 7, 11); assertData(parser, "a", 12, 13); assertRangeEnd(parser, 18, 22); assertEnd(parser, 23, 23); } TEST(OsmlStreamParser, beginEndNested) { const char *testString = "\\begin{a}{b} c \\begin{d}{e}{f} \\g{h} \\end{d}\\end{a}"; // 012345678901234 5678901234567890 123456 7890123 4567890 // 0 1 2 3 4 5 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "a", true, Variant::mapType{}, 7, 8); assertFieldStart(parser, false, 9, 10); assertData(parser, "b", 10, 11); assertFieldEnd(parser, 11, 12); assertData(parser, "c", 13, 14); assertCommandStart(parser, "d", true, Variant::mapType{}, 22, 23); assertFieldStart(parser, false, 24, 25); assertData(parser, "e", 25, 26); assertFieldEnd(parser, 26, 27); assertFieldStart(parser, false, 27, 28); assertData(parser, "f", 28, 29); assertFieldEnd(parser, 29, 30); assertEmptyData(parser); assertCommand(parser, "g", 31, 33); assertFieldStart(parser, false, 33, 34); assertData(parser, "h", 34, 35); assertFieldEnd(parser, 35, 36); assertEmptyData(parser); assertRangeEnd(parser, 42, 43); assertRangeEnd(parser, 49, 50); assertEnd(parser, 51, 51); } TEST(OsmlStreamParser, beginEndWithCommand) { const char *testString = "\\begin{book}\\a{test}\\end{book}"; // 012345678901 23456789 0123456789 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "book", true, Variant::mapType{}, 7, 11); assertCommand(parser, "a", 12, 14); assertFieldStart(parser, false, 14, 15); assertData(parser, "test", 15, 19); assertFieldEnd(parser, 19, 20); assertRangeEnd(parser, 25, 29); assertEnd(parser, 30, 30); } TEST(OsmlStreamParser, beginEndNestedFields) { const char *testString = "\\begin{book}a{{b{c}}}\\end{book}"; // 012345678901234567890 1234567890 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommandStart(parser, "book", true, Variant::mapType{}, 7, 11); assertData(parser, "a", 12, 13); assertFieldStart(parser, false, 13, 14); assertFieldStart(parser, false, 14, 15); assertData(parser, "b", 15, 16); assertFieldStart(parser, false, 16, 17); assertData(parser, "c", 17, 18); assertFieldEnd(parser, 18, 19); assertFieldEnd(parser, 19, 20); assertFieldEnd(parser, 20, 21); assertRangeEnd(parser, 26, 30); assertEnd(parser, 31, 31); } TEST(OsmlStreamParser, errorBeginEndUnbalancedNestedFields) { const char *testString = "\\begin{book}a{{b{c}}\\end{book}"; // 012345678901234567890 123456789 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommandStart(parser, "book", true, Variant::mapType{}, 7, 11); assertData(parser, "a", 12, 13); assertFieldStart(parser, false, 13, 14); assertFieldStart(parser, false, 14, 15); assertData(parser, "b", 15, 16); assertFieldStart(parser, false, 16, 17); assertData(parser, "c", 17, 18); assertFieldEnd(parser, 18, 19); assertFieldEnd(parser, 19, 20); ASSERT_THROW(assertRangeEnd(parser, 25, 29), LoggableException); } TEST(OsmlStreamParser, errorBeginEndUnbalancedFields) { const char *testString = "{a"; // 01 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertFieldStart(parser, false, 0, 1); assertTextData(parser, "a", 1, 2, 1, 2, WhitespaceMode::PRESERVE); ASSERT_FALSE(logger.hasError()); assertEnd(parser, 2, 2); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorBeginNoBraceOpen) { const char *testString = "\\begin a"; // 01234567 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertData(parser, "a", 7, 8); ASSERT_TRUE(logger.hasError()); assertEnd(parser, 8, 8); } TEST(OsmlStreamParser, errorBeginNoIdentifier) { const char *testString = "\\begin{!"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorBeginNoBraceClose) { const char *testString = "\\begin{a"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorBeginNoName) { const char *testString = "\\begin{a#}"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertCommandStart(parser, "a", true); ASSERT_TRUE(logger.hasError()); logger.reset(); ASSERT_FALSE(logger.hasError()); assertEnd(parser); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorEndNoBraceOpen) { const char *testString = "\\end a"; // 012345 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertData(parser, "a", 5, 6); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorEndNoIdentifier) { const char *testString = "\\end{!"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorEndNoBraceClose) { const char *testString = "\\end{a"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorEndNoBegin) { const char *testString = "\\end{a}"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, errorBeginEndMismatch) { const char *testString = "\\begin{a} \\begin{b} test \\end{a}"; // 0123456789 012345678901234 5678901 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommandStart(parser, "a", true, Variant::mapType{}, 7, 8); assertEmptyData(parser); assertCommandStart(parser, "b", true, Variant::mapType{}, 17, 18); assertData(parser, "test", 20, 24); ASSERT_FALSE(logger.hasError()); ASSERT_THROW(parser.parse(), LoggableException); ASSERT_TRUE(logger.hasError()); } TEST(OsmlStreamParser, commandWithNSSep) { const char *testString = "\\test1:test2"; // 012345678901 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "test1:test2", 0, 12); assertEnd(parser, 12, 12); } TEST(OsmlStreamParser, beginEndWithNSSep) { const char *testString = "\\begin{test1:test2}\\end{test1:test2}"; // 0123456789012345678 90123456789012345 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "test1:test2", true, Variant::mapType{}, 7, 18); assertRangeEnd(parser, 24, 35); assertEnd(parser, 36, 36); } TEST(OsmlStreamParser, errorBeginNSSep) { const char *testString = "\\begin:test{blub}\\end{blub}"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertCommandStart(parser, "blub", true, Variant::mapType{}); ASSERT_TRUE(logger.hasError()); assertRangeEnd(parser); assertEnd(parser); } TEST(OsmlStreamParser, errorEndNSSep) { const char *testString = "\\begin{blub}\\end:test{blub}"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommandStart(parser, "blub", true, Variant::mapType{}); ASSERT_FALSE(logger.hasError()); assertRangeEnd(parser); ASSERT_TRUE(logger.hasError()); assertEnd(parser); } TEST(OsmlStreamParser, errorEmptyNs) { const char *testString = "\\test:"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertCommand(parser, "test"); ASSERT_TRUE(logger.hasError()); assertData(parser, ":"); assertEnd(parser); } TEST(OsmlStreamParser, errorRepeatedNs) { const char *testString = "\\test::"; CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertCommand(parser, "test"); ASSERT_TRUE(logger.hasError()); assertData(parser, "::"); assertEnd(parser); } TEST(OsmlStreamParser, explicitDefaultField) { const char *testString = "\\a{!b}c"; // 01234567 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "a", 0, 2); assertFieldStart(parser, true, 2, 4); assertData(parser, "b", 4, 5); assertFieldEnd(parser, 5, 6); assertData(parser, "c", 6, 7); assertEnd(parser, 7, 7); } TEST(OsmlStreamParser, explicitDefaultFieldWithCommand) { const char *testString = "\\a{!\\b}c"; // 0123 4567 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommand(parser, "a", 0, 2); assertFieldStart(parser, true, 2, 4); assertCommand(parser, "b", 4, 6); assertFieldEnd(parser, 6, 7); assertData(parser, "c", 7, 8); assertEnd(parser, 8, 8); } TEST(OsmlStreamParser, fieldAfterExplicitDefaultField) { const char *testString = "\\a{!\\b}{c}"; // 0123 456789 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); assertCommand(parser, "a", 0, 2); assertFieldStart(parser, true, 2, 4); assertCommand(parser, "b", 4, 6); assertFieldEnd(parser, 6, 7); assertFieldStart(parser, false, 7, 8); assertData(parser, "c", 8, 9); assertFieldEnd(parser, 9, 10); assertEnd(parser, 10, 10); } TEST(OsmlStreamParser, annotationStart) { const char *testString = "<\\a"; // 0 12 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationStart(parser, "a", Variant::mapType{}, 0, 3); assertEnd(parser, 3, 3); } TEST(OsmlStreamParser, annotationStartWithName) { const char *testString = "<\\annotationWithName#aName"; // 0 1234567890123456789012345 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationStart(parser, "annotationWithName", Variant::mapType{{"name", "aName"}}, 0, 20); assertEnd(parser, 26, 26); } TEST(OsmlStreamParser, annotationStartWithArguments) { const char *testString = "<\\annotationWithName#aName[a=1,b=2]"; // 0 1234567890123456789012345678901234 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationStart( parser, "annotationWithName", Variant::mapType{{"name", "aName"}, {"a", 1}, {"b", 2}}, 0, 20); assertEnd(parser, 35, 35); } TEST(OsmlStreamParser, simpleAnnotationStartBeginEnd) { const char *testString = "<\\begin{ab#name}[a=1,b=2] a \\end{ab}\\>"; // 0 123456789012345678901234567 89012345 67 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationStart( parser, "ab", Variant::mapType{{"name", "name"}, {"a", 1}, {"b", 2}}, 8, 10); ASSERT_TRUE(parser.inRangeCommand()); assertData(parser, "a", 26, 27); assertRangeEnd(parser, 33, 35); assertAnnotationEnd(parser, "", "", 36, 38); assertEnd(parser, 38, 38); } TEST(OsmlStreamParser, annotationEnd) { const char *testString = "\\a>"; // 012 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationEnd(parser, "a", "", 0, 2); assertEnd(parser, 3, 3); } TEST(OsmlStreamParser, annotationEndWithName) { const char *testString = "\\a#name>"; // 01234567 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationEnd(parser, "a", "name", 0, 2); assertEnd(parser, 8, 8); } TEST(OsmlStreamParser, annotationEndWithNameAsArgs) { const char *testString = "\\a[name=name]>"; // 01234567890123 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationEnd(parser, "a", "name", 0, 2); assertEnd(parser, 14, 14); } TEST(OsmlStreamParser, errorAnnotationEndWithArguments) { const char *testString = "\\a[foo=bar]>"; // 012345678901 // 0 1 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); logger.reset(); ASSERT_FALSE(logger.hasError()); assertCommandStart(parser, "a", false, Variant::mapType{{"foo", "bar"}}, 0, 2); ASSERT_TRUE(logger.hasError()); assertData(parser, ">", 11, 12); assertEnd(parser, 12, 12); } TEST(OsmlStreamParser, closingAnnotation) { const char *testString = "<\\a>"; // 0 123 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertAnnotationStart(parser, "a", Variant::mapType{}, 0, 3); assertData(parser, ">", 3, 4); assertEnd(parser, 4, 4); } TEST(OsmlStreamParser, annotationWithFields) { const char *testString = "a <\\b{c}{d}{!e} f \\> g"; // 012 345678901234567 8901 // 0 1 2 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertData(parser, "a ", 0, 2); assertAnnotationStart(parser, "b", Variant::mapType{}, 2, 5); assertFieldStart(parser, false, 5, 6); assertData(parser, "c", 6, 7); assertFieldEnd(parser, 7, 8); assertFieldStart(parser, false, 8, 9); assertData(parser, "d", 9, 10); assertFieldEnd(parser, 10, 11); assertFieldStart(parser, true, 11, 13); assertData(parser, "e", 13, 14); assertFieldEnd(parser, 14, 15); assertData(parser, "f", 16, 17); assertAnnotationEnd(parser, "", "", 18, 20); assertData(parser, "g", 21, 22); assertEnd(parser, 22, 22); } TEST(OsmlStreamParser, annotationStartEscape) { const char *testString = "<\\%test"; // 0 123456 // 0 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertData(parser, "<%test", 0, 7); assertEnd(parser, 7, 7); } TEST(OsmlStreamParser, userDefinedTokens) { const char *testString = "<>, the *old man* said."; // 0123456789012345678901234567890123456789 // 0 1 2 3 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); TokenId tSpeechStart = parser.registerToken("<<"); TokenId tSpeechEnd = parser.registerToken(">>"); TokenId tStar = parser.registerToken("*"); ASSERT_TRUE(tSpeechStart != Tokens::Empty); ASSERT_TRUE(tSpeechEnd != Tokens::Empty); ASSERT_TRUE(tStar != Tokens::Empty); TokenSet tokens{tSpeechStart, tSpeechEnd, tStar}; ASSERT_EQ(OsmlStreamParser::State::DATA, parser.parse()); TokenizedDataReader reader = parser.getData().reader(); assertToken(reader, tSpeechStart, "<<", tokens, WhitespaceMode::PRESERVE, 0, 2); assertText(reader, "My dear fellows", tokens, WhitespaceMode::PRESERVE, 2, 17); assertToken(reader, tSpeechEnd, ">>", tokens, WhitespaceMode::PRESERVE, 17, 19); assertText(reader, ", the ", tokens, WhitespaceMode::PRESERVE, 19, 25); assertToken(reader, tStar, "*", tokens, WhitespaceMode::PRESERVE, 25, 26); assertText(reader, "old man", tokens, WhitespaceMode::PRESERVE, 26, 33); assertToken(reader, tStar, "*", tokens, WhitespaceMode::PRESERVE, 33, 34); assertText(reader, " said.", tokens, WhitespaceMode::PRESERVE, 34, 40); assertEnd(reader); } TEST(OsmlStreamParser, commandWithUnderscoreAndEnd) { const char *testString = "\\sum_"; // 01234 // 0 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "sum", false, Variant::mapType{}, 0, 4); assertData(parser, "_", 4, 5); assertEnd(parser); } TEST(OsmlStreamParser, commandWithUnderscore) { const char *testString = "\\sum_ a"; // 0123456 // 0 CharReader charReader(testString); OsmlStreamParser parser(charReader, logger); assertCommandStart(parser, "sum", false, Variant::mapType{}, 0, 4); assertData(parser, "_ a", 4, 7); assertEnd(parser); } }