summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt177
-rw-r--r--test/formats/osml/OsmlStreamParserTest.cpp973
-rw-r--r--test/formats/osxml/OsxmlParserTest.cpp314
3 files changed, 1377 insertions, 87 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4458d1b..6e3b90f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -134,7 +134,6 @@ ADD_LIBRARY(ousia_core
src/core/common/VariantConverter
src/core/common/VariantReader
src/core/common/VariantWriter
- src/core/common/Whitespace
src/core/frontend/Terminal
src/core/frontend/TerminalLogger
src/core/managed/Events
@@ -148,11 +147,15 @@ ADD_LIBRARY(ousia_core
src/core/model/RootNode
src/core/model/Style
src/core/model/Typesystem
- src/core/parser/Parser
- src/core/parser/ParserContext
- src/core/parser/ParserScope
- src/core/parser/generic/ParserStateStack
- src/core/parser/generic/ParserState
+# src/core/parser/Parser
+# src/core/parser/ParserContext
+# src/core/parser/ParserScope
+# src/core/parser/generic/ParserState
+# src/core/parser/generic/ParserStateCallbacks
+# src/core/parser/generic/ParserStateHandler
+# src/core/parser/generic/ParserStateStack
+ src/core/parser/utils/Tokenizer
+ src/core/parser/utils/TokenTrie
src/core/resource/Resource
src/core/resource/ResourceLocator
src/core/resource/ResourceManager
@@ -160,6 +163,8 @@ ADD_LIBRARY(ousia_core
# src/core/script/ScriptEngine
)
+# Format libraries
+
#ADD_LIBRARY(ousia_css
# src/plugins/css/CodeTokenizer
# src/plugins/css/Tokenizer
@@ -170,43 +175,44 @@ ADD_LIBRARY(ousia_core
# ousia_core
#)
-ADD_LIBRARY(ousia_filesystem
- src/plugins/filesystem/FileLocator
- src/plugins/filesystem/SpecialPaths
+ADD_LIBRARY(ousia_osml
+ src/formats/osml/OsmlStreamParser
)
-TARGET_LINK_LIBRARIES(ousia_filesystem
+TARGET_LINK_LIBRARIES(ousia_osml
ousia_core
- ${Boost_LIBRARIES}
)
-ADD_LIBRARY(ousia_html
- src/plugins/html/DemoOutput
-)
+#ADD_LIBRARY(ousia_osxml
+# src/formats/osxml/osxmlParser
+#)
-TARGET_LINK_LIBRARIES(ousia_html
- ousia_core
-)
+#TARGET_LINK_LIBRARIES(ousia_osxml
+# ousia_core
+# ${EXPAT_LIBRARIES}
+#)
-ADD_LIBRARY(ousia_xml
- src/plugins/xml/XmlParser
-)
+# Resource locators
-TARGET_LINK_LIBRARIES(ousia_xml
- ousia_core
- ${EXPAT_LIBRARIES}
-)
+#ADD_LIBRARY(ousia_filesystem
+# src/plugins/filesystem/FileLocator
+# src/plugins/filesystem/SpecialPaths
+#)
-ADD_LIBRARY(ousia_osdm
- src/formats/osdm/DynamicTokenizer
- src/formats/osdm/TokenTrie
- src/formats/osdm/OsdmStreamParser
-)
+#TARGET_LINK_LIBRARIES(ousia_filesystem
+# ousia_core
+# ${Boost_LIBRARIES}
+#)
-TARGET_LINK_LIBRARIES(ousia_osdm
- ousia_core
-)
+# Output libraries
+#ADD_LIBRARY(ousia_html
+# src/plugins/html/DemoOutput
+#)
+
+#TARGET_LINK_LIBRARIES(ousia_html
+# ousia_core
+#)
#ADD_LIBRARY(ousia_mozjs
# src/plugins/mozjs/MozJsScriptEngine
@@ -219,17 +225,17 @@ TARGET_LINK_LIBRARIES(ousia_osdm
# Command line interface
-ADD_EXECUTABLE(ousia
- src/cli/Main
-)
+#ADD_EXECUTABLE(ousia
+# src/cli/Main
+#)
-TARGET_LINK_LIBRARIES(ousia
- ousia_core
- ousia_filesystem
- ousia_html
- ousia_xml
- ${Boost_LIBRARIES}
-)
+#TARGET_LINK_LIBRARIES(ousia
+# ousia_core
+# ousia_filesystem
+# ousia_html
+# ousia_xml
+# ${Boost_LIBRARIES}
+#)
# If testing is enabled, build the unit tests
IF(TEST)
@@ -240,10 +246,8 @@ IF(TEST)
)
ADD_EXECUTABLE(ousia_test_core
- test/core/CodeTokenizerTest
test/core/RangeSetTest
- test/core/RegistryTest
- test/core/TokenizerTest
+# test/core/RegistryTest
test/core/XMLTest
test/core/common/ArgumentTest
test/core/common/CharReaderTest
@@ -257,7 +261,6 @@ IF(TEST)
test/core/common/VariantWriterTest
test/core/common/VariantTest
test/core/common/UtilsTest
- test/core/common/WhitespaceTest
test/core/frontend/TerminalLoggerTest
test/core/managed/ManagedContainerTest
test/core/managed/ManagedTest
@@ -269,9 +272,11 @@ IF(TEST)
test/core/model/NodeTest
test/core/model/StyleTest
test/core/model/TypesystemTest
- test/core/parser/ParserScopeTest
- test/core/parser/ParserStackTest
- test/core/parser/ParserStateTest
+# test/core/parser/ParserScopeTest
+# test/core/parser/ParserStackTest
+# test/core/parser/ParserStateTest
+ test/core/parser/utils/TokenizerTest
+ test/core/parser/utils/TokenTrieTest
test/core/resource/ResourceLocatorTest
test/core/resource/ResourceRequestTest
# test/core/script/FunctionTest
@@ -284,15 +289,15 @@ IF(TEST)
ousia_core
)
- ADD_EXECUTABLE(ousia_test_filesystem
- test/plugins/filesystem/FileLocatorTest
- )
+# ADD_EXECUTABLE(ousia_test_filesystem
+# test/plugins/filesystem/FileLocatorTest
+# )
- TARGET_LINK_LIBRARIES(ousia_test_filesystem
- ${GTEST_LIBRARIES}
- ousia_core
- ousia_filesystem
- )
+# TARGET_LINK_LIBRARIES(ousia_test_filesystem
+# ${GTEST_LIBRARIES}
+# ousia_core
+# ousia_filesystem
+# )
# ADD_EXECUTABLE(ousia_test_css
# test/plugins/css/Tokenizer
@@ -306,38 +311,36 @@ IF(TEST)
# ousia_css
# )
- ADD_EXECUTABLE(ousia_test_html
- test/plugins/html/DemoOutputTest
- )
+# ADD_EXECUTABLE(ousia_test_html
+# test/plugins/html/DemoOutputTest
+# )
- TARGET_LINK_LIBRARIES(ousia_test_html
- ${GTEST_LIBRARIES}
- ousia_core
- ousia_html
- )
+# TARGET_LINK_LIBRARIES(ousia_test_html
+# ${GTEST_LIBRARIES}
+# ousia_core
+# ousia_html
+# )
- ADD_EXECUTABLE(ousia_test_xml
- test/plugins/xml/XmlParserTest
+ ADD_EXECUTABLE(ousia_test_osml
+ test/formats/osml/OsmlStreamParserTest
)
- TARGET_LINK_LIBRARIES(ousia_test_xml
+ TARGET_LINK_LIBRARIES(ousia_test_osml
${GTEST_LIBRARIES}
ousia_core
- ousia_xml
- ousia_filesystem
+ ousia_osml
)
- ADD_EXECUTABLE(ousia_test_osdm
- test/formats/osdm/TokenTrieTest
- test/formats/osdm/DynamicTokenizerTest
- test/formats/osdm/OsdmStreamParserTest
- )
+# ADD_EXECUTABLE(ousia_test_osxml
+# test/plugins/xml/XmlParserTest
+# )
- TARGET_LINK_LIBRARIES(ousia_test_osdm
- ${GTEST_LIBRARIES}
- ousia_core
- ousia_osdm
- )
+# TARGET_LINK_LIBRARIES(ousia_test_osxml
+# ${GTEST_LIBRARIES}
+# ousia_core
+# ousia_osml
+# ousia_filesystem
+# )
# ADD_EXECUTABLE(ousia_test_mozjs
# test/plugins/mozjs/MozJsScriptEngineTest
@@ -351,11 +354,11 @@ IF(TEST)
# Register the unit tests
ADD_TEST(ousia_test_core ousia_test_core)
- ADD_TEST(ousia_test_filesystem ousia_test_filesystem)
+# ADD_TEST(ousia_test_filesystem ousia_test_filesystem)
# ADD_TEST(ousia_test_css ousia_test_css)
- ADD_TEST(ousia_test_html ousia_test_html)
- ADD_TEST(ousia_test_xml ousia_test_xml)
- ADD_TEST(ousia_test_osdm ousia_test_osdm)
+# ADD_TEST(ousia_test_html ousia_test_html)
+ ADD_TEST(ousia_test_osml ousia_test_osml)
+# ADD_TEST(ousia_test_osxml ousia_test_osxml)
# ADD_TEST(ousia_test_mozjs ousia_test_mozjs)
ENDIF()
@@ -373,6 +376,6 @@ INSTALL(DIRECTORY data/ DESTINATION share/ousia
OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE
)
-INSTALL(TARGETS ousia
- RUNTIME DESTINATION bin
-)
+#INSTALL(TARGETS ousia
+# RUNTIME DESTINATION bin
+#)
diff --git a/test/formats/osml/OsmlStreamParserTest.cpp b/test/formats/osml/OsmlStreamParserTest.cpp
new file mode 100644
index 0000000..e5eff05
--- /dev/null
+++ b/test/formats/osml/OsmlStreamParserTest.cpp
@@ -0,0 +1,973 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include <core/common/CharReader.hpp>
+#include <core/frontend/TerminalLogger.hpp>
+
+#include <formats/osml/OsmlStreamParser.hpp>
+
+namespace ousia {
+
+static TerminalLogger logger(std::cerr, true);
+
+TEST(OsmlStreamParser, empty)
+{
+ const char *testString = "";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, oneCharacter)
+{
+ const char *testString = "a";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("a", reader.getData().asString());
+
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(1U, loc.getEnd());
+}
+
+TEST(OsmlStreamParser, whitespaceElimination)
+{
+ const char *testString = " hello \t world ";
+ // 0123456 78901234
+ // 0 1
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("hello world", reader.getData().asString());
+
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(1U, loc.getStart());
+ ASSERT_EQ(14U, loc.getEnd());
+}
+
+TEST(OsmlStreamParser, whitespaceEliminationWithLinebreak)
+{
+ const char *testString = " hello \n world ";
+ // 0123456 78901234
+ // 0 1
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("hello world", reader.getData().asString());
+
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(1U, loc.getStart());
+ ASSERT_EQ(14U, loc.getEnd());
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, escapeWhitespace)
+{
+ const char *testString = " hello\\ \\ world ";
+ // 012345 67 89012345
+ // 0 1
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("hello world", reader.getData().asString());
+
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(1U, loc.getStart());
+ ASSERT_EQ(15U, loc.getEnd());
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+static void testEscapeSpecialCharacter(const std::string &c)
+{
+ CharReader charReader(std::string("\\") + c);
+ OsmlStreamParser reader(charReader, logger);
+ EXPECT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ EXPECT_EQ(c, reader.getData().asString());
+
+ SourceLocation loc = reader.getData().getLocation();
+ EXPECT_EQ(0U, loc.getStart());
+ EXPECT_EQ(1U + c.size(), loc.getEnd());
+}
+
+TEST(OsmlStreamParser, escapeSpecialCharacters)
+{
+ testEscapeSpecialCharacter("\\");
+ testEscapeSpecialCharacter("{");
+ testEscapeSpecialCharacter("}");
+ testEscapeSpecialCharacter("<");
+ testEscapeSpecialCharacter(">");
+}
+
+TEST(OsmlStreamParser, simpleSingleLineComment)
+{
+ const char *testString = "% This is a single line comment";
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, singleLineComment)
+{
+ const char *testString = "a% This is a single line comment\nb";
+ // 01234567890123456789012345678901 23
+ // 0 1 2 3
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("a", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(1U, loc.getEnd());
+ }
+
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("b", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(33U, loc.getStart());
+ ASSERT_EQ(34U, loc.getEnd());
+ }
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+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 reader(charReader, logger);
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("a", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(1U, loc.getEnd());
+ }
+
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("b", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(40U, loc.getStart());
+ ASSERT_EQ(41U, loc.getEnd());
+ }
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+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 reader(charReader, logger);
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("a", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(1U, loc.getEnd());
+ }
+
+ {
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ ASSERT_EQ("b", reader.getData().asString());
+ SourceLocation loc = reader.getData().getLocation();
+ ASSERT_EQ(40U, loc.getStart());
+ ASSERT_EQ(41U, loc.getEnd());
+ }
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, simpleCommand)
+{
+ const char *testString = "\\test";
+ // 0 12345
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+ ASSERT_EQ(OsmlStreamParser::State::COMMAND, reader.parse());
+
+ Variant commandName = reader.getCommandName();
+ ASSERT_EQ("test", commandName.asString());
+
+ SourceLocation loc = commandName.getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(5U, loc.getEnd());
+
+ ASSERT_EQ(0U, reader.getCommandArguments().asMap().size());
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, simpleCommandWithName)
+{
+ const char *testString = "\\test#bla";
+ // 0 12345678
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+ ASSERT_EQ(OsmlStreamParser::State::COMMAND, reader.parse());
+
+ Variant commandName = reader.getCommandName();
+ ASSERT_EQ("test", commandName.asString());
+ SourceLocation loc = commandName.getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(5U, loc.getEnd());
+
+ Variant commandArguments = reader.getCommandArguments();
+ ASSERT_TRUE(commandArguments.isMap());
+ ASSERT_EQ(1U, commandArguments.asMap().size());
+ ASSERT_EQ(1U, commandArguments.asMap().count("name"));
+ ASSERT_EQ("bla", commandArguments.asMap()["name"].asString());
+
+ loc = commandArguments.asMap()["name"].getLocation();
+ ASSERT_EQ(5U, loc.getStart());
+ ASSERT_EQ(9U, loc.getEnd());
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+TEST(OsmlStreamParser, simpleCommandWithArguments)
+{
+ const char *testString = "\\test[a=1,b=2,c=\"test\"]";
+ // 0 123456789012345 678901 2
+ // 0 1 2
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+ ASSERT_EQ(OsmlStreamParser::State::COMMAND, reader.parse());
+
+ Variant commandName = reader.getCommandName();
+ ASSERT_EQ("test", commandName.asString());
+ SourceLocation loc = commandName.getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(5U, loc.getEnd());
+
+ Variant commandArguments = reader.getCommandArguments();
+ ASSERT_TRUE(commandArguments.isMap());
+ ASSERT_EQ(3U, commandArguments.asMap().size());
+ ASSERT_EQ(1U, commandArguments.asMap().count("a"));
+ ASSERT_EQ(1U, commandArguments.asMap().count("b"));
+ ASSERT_EQ(1U, commandArguments.asMap().count("c"));
+ ASSERT_EQ(1, commandArguments.asMap()["a"].asInt());
+ ASSERT_EQ(2, commandArguments.asMap()["b"].asInt());
+ ASSERT_EQ("test", commandArguments.asMap()["c"].asString());
+
+ loc = commandArguments.asMap()["a"].getLocation();
+ ASSERT_EQ(8U, loc.getStart());
+ ASSERT_EQ(9U, loc.getEnd());
+
+ loc = commandArguments.asMap()["b"].getLocation();
+ ASSERT_EQ(12U, loc.getStart());
+ ASSERT_EQ(13U, loc.getEnd());
+
+ loc = commandArguments.asMap()["c"].getLocation();
+ ASSERT_EQ(16U, loc.getStart());
+ ASSERT_EQ(22U, loc.getEnd());
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+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 reader(charReader, logger);
+ ASSERT_EQ(OsmlStreamParser::State::COMMAND, reader.parse());
+
+ Variant commandName = reader.getCommandName();
+ ASSERT_EQ("test", commandName.asString());
+ SourceLocation loc = commandName.getLocation();
+ ASSERT_EQ(0U, loc.getStart());
+ ASSERT_EQ(5U, loc.getEnd());
+
+ Variant commandArguments = reader.getCommandArguments();
+ ASSERT_TRUE(commandArguments.isMap());
+ ASSERT_EQ(4U, commandArguments.asMap().size());
+ ASSERT_EQ(1U, commandArguments.asMap().count("a"));
+ ASSERT_EQ(1U, commandArguments.asMap().count("b"));
+ ASSERT_EQ(1U, commandArguments.asMap().count("c"));
+ ASSERT_EQ(1U, commandArguments.asMap().count("name"));
+ ASSERT_EQ(1, commandArguments.asMap()["a"].asInt());
+ ASSERT_EQ(2, commandArguments.asMap()["b"].asInt());
+ ASSERT_EQ("test", commandArguments.asMap()["c"].asString());
+ ASSERT_EQ("bla", commandArguments.asMap()["name"].asString());
+
+ loc = commandArguments.asMap()["a"].getLocation();
+ ASSERT_EQ(12U, loc.getStart());
+ ASSERT_EQ(13U, loc.getEnd());
+
+ loc = commandArguments.asMap()["b"].getLocation();
+ ASSERT_EQ(16U, loc.getStart());
+ ASSERT_EQ(17U, loc.getEnd());
+
+ loc = commandArguments.asMap()["c"].getLocation();
+ ASSERT_EQ(20U, loc.getStart());
+ ASSERT_EQ(26U, loc.getEnd());
+
+ loc = commandArguments.asMap()["name"].getLocation();
+ ASSERT_EQ(5U, loc.getStart());
+ ASSERT_EQ(9U, loc.getEnd());
+
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+}
+
+static void assertCommand(OsmlStreamParser &reader, const std::string &name,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ ASSERT_EQ(OsmlStreamParser::State::COMMAND, reader.parse());
+ EXPECT_EQ(name, reader.getCommandName().asString());
+ if (start != InvalidSourceOffset) {
+ EXPECT_EQ(start, reader.getCommandName().getLocation().getStart());
+ EXPECT_EQ(start, reader.getLocation().getStart());
+ }
+ if (end != InvalidSourceOffset) {
+ EXPECT_EQ(end, reader.getCommandName().getLocation().getEnd());
+ EXPECT_EQ(end, reader.getLocation().getEnd());
+ }
+}
+
+static void assertCommand(OsmlStreamParser &reader, const std::string &name,
+ const Variant::mapType &args,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ assertCommand(reader, name, start, end);
+ EXPECT_EQ(args, reader.getCommandArguments());
+}
+
+static void assertData(OsmlStreamParser &reader, const std::string &data,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ ASSERT_EQ(OsmlStreamParser::State::DATA, reader.parse());
+ EXPECT_EQ(data, reader.getData().asString());
+ if (start != InvalidSourceOffset) {
+ EXPECT_EQ(start, reader.getData().getLocation().getStart());
+ EXPECT_EQ(start, reader.getLocation().getStart());
+ }
+ if (end != InvalidSourceOffset) {
+ EXPECT_EQ(end, reader.getData().getLocation().getEnd());
+ EXPECT_EQ(end, reader.getLocation().getEnd());
+ }
+}
+
+static void assertFieldStart(OsmlStreamParser &reader,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ ASSERT_EQ(OsmlStreamParser::State::FIELD_START, reader.parse());
+ if (start != InvalidSourceOffset) {
+ EXPECT_EQ(start, reader.getLocation().getStart());
+ }
+ if (end != InvalidSourceOffset) {
+ EXPECT_EQ(end, reader.getLocation().getEnd());
+ }
+}
+
+static void assertFieldEnd(OsmlStreamParser &reader,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ ASSERT_EQ(OsmlStreamParser::State::FIELD_END, reader.parse());
+ if (start != InvalidSourceOffset) {
+ EXPECT_EQ(start, reader.getLocation().getStart());
+ }
+ if (end != InvalidSourceOffset) {
+ EXPECT_EQ(end, reader.getLocation().getEnd());
+ }
+}
+
+static void assertEnd(OsmlStreamParser &reader,
+ SourceOffset start = InvalidSourceOffset,
+ SourceOffset end = InvalidSourceOffset)
+{
+ ASSERT_EQ(OsmlStreamParser::State::END, reader.parse());
+ if (start != InvalidSourceOffset) {
+ EXPECT_EQ(start, reader.getLocation().getStart());
+ }
+ if (end != InvalidSourceOffset) {
+ EXPECT_EQ(end, reader.getLocation().getEnd());
+ }
+}
+
+TEST(OsmlStreamParser, fields)
+{
+ const char *testString = "\\test{a}{b}{c}";
+ // 01234567890123
+ // 0 1
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ assertData(reader, "a", 6, 7);
+ assertFieldEnd(reader, 7, 8);
+
+ assertFieldStart(reader, 8, 9);
+ assertData(reader, "b", 9, 10);
+ assertFieldEnd(reader, 10, 11);
+
+ assertFieldStart(reader, 11, 12);
+ assertData(reader, "c", 12, 13);
+ assertFieldEnd(reader, 13, 14);
+ assertEnd(reader, 14, 14);
+}
+
+TEST(OsmlStreamParser, dataOutsideField)
+{
+ const char *testString = "\\test{a}{b} c";
+ // 0123456789012
+ // 0 1
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ assertData(reader, "a", 6, 7);
+ assertFieldEnd(reader, 7, 8);
+
+ assertFieldStart(reader, 8, 9);
+ assertData(reader, "b", 9, 10);
+ assertFieldEnd(reader, 10, 11);
+
+ assertData(reader, "c", 12, 13);
+ assertEnd(reader, 13, 13);
+}
+
+TEST(OsmlStreamParser, nestedCommand)
+{
+ const char *testString = "\\test{a}{\\test2{b} c} d";
+ // 012345678 90123456789012
+ // 0 1 2
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test", 0, 5);
+
+ assertFieldStart(reader, 5, 6);
+ assertData(reader, "a", 6, 7);
+ assertFieldEnd(reader, 7, 8);
+
+ assertFieldStart(reader, 8, 9);
+ {
+ assertCommand(reader, "test2", 9, 15);
+ assertFieldStart(reader, 15, 16);
+ assertData(reader, "b", 16, 17);
+ assertFieldEnd(reader, 17, 18);
+ }
+ assertData(reader, "c", 19, 20);
+ assertFieldEnd(reader, 20, 21);
+ assertData(reader, "d", 22, 23);
+ assertEnd(reader, 23, 23);
+}
+
+TEST(OsmlStreamParser, nestedCommandImmediateEnd)
+{
+ const char *testString = "\\test{\\test2{b}} d";
+ // 012345 678901234567
+ // 0 1
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ {
+ assertCommand(reader, "test2", 6, 12);
+ assertFieldStart(reader, 12, 13);
+ assertData(reader, "b", 13, 14);
+ assertFieldEnd(reader, 14, 15);
+ }
+ assertFieldEnd(reader, 15, 16);
+ assertData(reader, "d", 17, 18);
+ assertEnd(reader, 18, 18);
+}
+
+TEST(OsmlStreamParser, nestedCommandNoData)
+{
+ const char *testString = "\\test{\\test2}";
+ // 012345 6789012
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ assertCommand(reader, "test2", 6, 12);
+ assertFieldEnd(reader, 12, 13);
+ assertEnd(reader, 13, 13);
+}
+
+TEST(OsmlStreamParser, multipleCommands)
+{
+ const char *testString = "\\a \\b \\c \\d";
+ // 012 345 678 90
+ // 0 1
+ CharReader charReader(testString);
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "a", 0, 2);
+ assertCommand(reader, "b", 3, 5);
+ assertCommand(reader, "c", 6, 8);
+ assertCommand(reader, "d", 9, 11);
+ assertEnd(reader, 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 reader(charReader, logger);
+
+ assertCommand(reader, "a", 0, 2);
+ assertFieldStart(reader, 3, 4);
+ assertCommand(reader, "b", 4, 6);
+ assertCommand(reader, "c", 7, 9);
+ assertFieldEnd(reader, 9, 10);
+ assertFieldStart(reader, 16, 17);
+ assertCommand(reader, "d", 17, 19);
+ assertFieldEnd(reader, 19, 20);
+ assertEnd(reader, 20, 20);
+}
+
+TEST(OsmlStreamParser, errorNoFieldToStart)
+{
+ const char *testString = "\\a b {";
+ // 012345
+ // 0
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "a", 0, 2);
+ assertData(reader, "b", 3, 4);
+ ASSERT_FALSE(logger.hasError());
+ assertEnd(reader, 6, 6);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorNoFieldToEnd)
+{
+ const char *testString = "\\a b }";
+ // 012345
+ // 0
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "a", 0, 2);
+ assertData(reader, "b", 3, 4);
+ ASSERT_FALSE(logger.hasError());
+ assertEnd(reader, 6, 6);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorNoFieldEndNested)
+{
+ const char *testString = "\\test{\\test2{}}}";
+ // 012345 6789012345
+ // 0 1
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ assertCommand(reader, "test2", 6, 12);
+ assertFieldStart(reader, 12, 13);
+ assertFieldEnd(reader, 13, 14);
+ assertFieldEnd(reader, 14, 15);
+ ASSERT_FALSE(logger.hasError());
+ assertEnd(reader, 16, 16);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorNoFieldEndNestedData)
+{
+ const char *testString = "\\test{\\test2{}}a}";
+ // 012345 67890123456
+ // 0 1
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "test", 0, 5);
+ assertFieldStart(reader, 5, 6);
+ assertCommand(reader, "test2", 6, 12);
+ assertFieldStart(reader, 12, 13);
+ assertFieldEnd(reader, 13, 14);
+ assertFieldEnd(reader, 14, 15);
+ assertData(reader, "a", 15, 16);
+ ASSERT_FALSE(logger.hasError());
+ assertEnd(reader, 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 reader(charReader, logger);
+
+ assertCommand(reader, "book", 7, 11);
+ assertFieldStart(reader, 12, 13);
+ assertFieldEnd(reader, 17, 21);
+ assertEnd(reader, 22, 22);
+}
+
+TEST(OsmlStreamParser, beginEndWithName)
+{
+ const char *testString = "\\begin{book#a}\\end{book}";
+ // 01234567890123 4567890123
+ // 0 1 2
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "book", {{"name", "a"}}, 7, 11);
+ assertFieldStart(reader, 14, 15);
+ assertFieldEnd(reader, 19, 23);
+ assertEnd(reader, 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 reader(charReader, logger);
+
+ assertCommand(reader, "book",
+ {{"name", "a"}, {"a", 1}, {"b", 2}, {"c", "test"}}, 7, 11);
+ assertFieldStart(reader, 32, 33);
+ assertFieldEnd(reader, 37, 41);
+ assertEnd(reader, 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 reader(charReader, logger);
+
+ assertCommand(reader, "book",
+ {{"name", "a"}, {"a", 1}, {"b", 2}, {"c", "test"}}, 7, 11);
+ assertFieldStart(reader, 32, 33);
+ assertData(reader, "a", 33, 34);
+ assertCommand(reader, "test", Variant::mapType{}, 35, 40);
+ assertFieldEnd(reader, 40, 41);
+ assertFieldStart(reader, 41, 42);
+ assertData(reader, "b", 42, 43);
+ assertCommand(reader, "test", Variant::mapType{}, 44, 49);
+ assertFieldStart(reader, 49, 50);
+ assertFieldEnd(reader, 50, 51);
+ assertFieldEnd(reader, 51, 52);
+ assertFieldStart(reader, 52, 53);
+ assertFieldEnd(reader, 57, 61);
+ assertEnd(reader, 62, 62);
+}
+
+TEST(OsmlStreamParser, beginEndWithData)
+{
+ const char *testString = "\\begin{book}a\\end{book}";
+ // 0123456789012 3456789012
+ // 0 1 2
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "book", 7, 11);
+ assertFieldStart(reader, 12, 13);
+ assertData(reader, "a", 12, 13);
+ assertFieldEnd(reader, 18, 22);
+ assertEnd(reader, 23, 23);
+}
+
+TEST(OsmlStreamParser, beginEndWithCommand)
+{
+ const char *testString = "\\begin{book}\\a{test}\\end{book}";
+ // 012345678901 23456789 0123456789
+ // 0 1 2
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "book", 7, 11);
+ assertFieldStart(reader, 12, 13);
+ assertCommand(reader, "a", 12, 14);
+ assertFieldStart(reader, 14, 15);
+ assertData(reader, "test", 15, 19);
+ assertFieldEnd(reader, 19, 20);
+ assertFieldEnd(reader, 25, 29);
+ assertEnd(reader, 30, 30);
+}
+
+TEST(OsmlStreamParser, errorBeginNoBraceOpen)
+{
+ const char *testString = "\\begin a";
+ // 01234567
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertData(reader, "a", 7, 8);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorBeginNoIdentifier)
+{
+ const char *testString = "\\begin{!";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.parse(), LoggableException);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorBeginNoBraceClose)
+{
+ const char *testString = "\\begin{a";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.parse(), LoggableException);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorBeginNoName)
+{
+ const char *testString = "\\begin{a#}";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertCommand(reader, "a");
+ ASSERT_TRUE(logger.hasError());
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertEnd(reader);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorEndNoBraceOpen)
+{
+ const char *testString = "\\end a";
+ // 012345
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertData(reader, "a", 5, 6);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorEndNoIdentifier)
+{
+ const char *testString = "\\end{!";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.parse(), LoggableException);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorEndNoBraceClose)
+{
+ const char *testString = "\\end{a";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.parse(), LoggableException);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, errorEndNoBegin)
+{
+ const char *testString = "\\end{a}";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.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 reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "a", 7, 8);
+ assertFieldStart(reader, 10, 11);
+ assertCommand(reader, "b", 17, 18);
+ assertFieldStart(reader, 20, 24);
+ assertData(reader, "test", 20, 24);
+ ASSERT_FALSE(logger.hasError());
+ ASSERT_THROW(reader.parse(), LoggableException);
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(OsmlStreamParser, commandWithNSSep)
+{
+ const char *testString = "\\test1:test2";
+ // 012345678901
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test1:test2", 0, 12);
+ assertEnd(reader, 12, 12);
+}
+
+TEST(OsmlStreamParser, beginEndWithNSSep)
+{
+ const char *testString = "\\begin{test1:test2}\\end{test1:test2}";
+ // 0123456789012345678 90123456789012345
+ // 0 1 2 3
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ assertCommand(reader, "test1:test2", 7, 18);
+ assertFieldStart(reader, 19, 20);
+ assertFieldEnd(reader, 24, 35);
+ assertEnd(reader, 36, 36);
+}
+
+TEST(OsmlStreamParser, errorBeginNSSep)
+{
+ const char *testString = "\\begin:test{blub}\\end{blub}";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertCommand(reader, "blub");
+ ASSERT_TRUE(logger.hasError());
+ assertFieldStart(reader);
+ assertFieldEnd(reader);
+ assertEnd(reader);
+}
+
+TEST(OsmlStreamParser, errorEndNSSep)
+{
+ const char *testString = "\\begin{blub}\\end:test{blub}";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ assertCommand(reader, "blub");
+ assertFieldStart(reader);
+ ASSERT_FALSE(logger.hasError());
+ assertFieldEnd(reader);
+ ASSERT_TRUE(logger.hasError());
+ assertEnd(reader);
+}
+
+TEST(OsmlStreamParser, errorEmptyNs)
+{
+ const char *testString = "\\test:";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertCommand(reader, "test");
+ ASSERT_TRUE(logger.hasError());
+ assertData(reader, ":");
+ assertEnd(reader);
+}
+
+TEST(OsmlStreamParser, errorRepeatedNs)
+{
+ const char *testString = "\\test::";
+ CharReader charReader(testString);
+
+ OsmlStreamParser reader(charReader, logger);
+
+ logger.reset();
+ ASSERT_FALSE(logger.hasError());
+ assertCommand(reader, "test");
+ ASSERT_TRUE(logger.hasError());
+ assertData(reader, "::");
+ assertEnd(reader);
+}
+}
+
diff --git a/test/formats/osxml/OsxmlParserTest.cpp b/test/formats/osxml/OsxmlParserTest.cpp
new file mode 100644
index 0000000..c0fb50d
--- /dev/null
+++ b/test/formats/osxml/OsxmlParserTest.cpp
@@ -0,0 +1,314 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <core/common/CharReader.hpp>
+#include <core/common/SourceContextReader.hpp>
+#include <core/model/Domain.hpp>
+#include <core/model/Node.hpp>
+#include <core/model/Project.hpp>
+#include <core/frontend/TerminalLogger.hpp>
+#include <core/StandaloneEnvironment.hpp>
+
+#include <plugins/filesystem/FileLocator.hpp>
+#include <formats/osdmx/OsdmxParser.hpp>
+
+namespace ousia {
+
+namespace RttiTypes {
+extern const Rtti Document;
+extern const Rtti Domain;
+extern const Rtti Typesystem;
+}
+
+struct XmlStandaloneEnvironment : public StandaloneEnvironment {
+ XmlParser xmlParser;
+ FileLocator fileLocator;
+
+ XmlStandaloneEnvironment(ConcreteLogger &logger)
+ : StandaloneEnvironment(logger)
+ {
+ fileLocator.addDefaultSearchPaths();
+ fileLocator.addUnittestSearchPath("xmlparser");
+
+ registry.registerDefaultExtensions();
+ registry.registerParser({"text/vnd.ousia.oxm", "text/vnd.ousia.oxd"},
+ {&RttiTypes::Node}, &xmlParser);
+ registry.registerResourceLocator(&fileLocator);
+ }
+};
+
+static TerminalLogger logger(std::cerr, true);
+
+TEST(XmlParser, mismatchedTag)
+{
+ XmlStandaloneEnvironment env(logger);
+ env.parse("mismatchedTag.oxm", "", "", RttiSet{&RttiTypes::Document});
+ ASSERT_TRUE(logger.hasError());
+}
+
+TEST(XmlParser, generic)
+{
+ XmlStandaloneEnvironment env(logger);
+ env.parse("generic.oxm", "", "", RttiSet{&RttiTypes::Node});
+#ifdef MANAGER_GRAPHVIZ_EXPORT
+ env.manager.exportGraphviz("xmlDocument.dot");
+#endif
+}
+
+static void checkAttributes(Handle<StructType> expected,
+ Handle<Descriptor> desc)
+{
+ if (expected == nullptr) {
+ ASSERT_TRUE(desc->getAttributesDescriptor()->getAttributes().empty());
+ } else {
+ ASSERT_EQ(expected->getName(),
+ desc->getAttributesDescriptor()->getName());
+ auto &attrs_exp = expected->getAttributes();
+ auto &attrs = desc->getAttributesDescriptor()->getAttributes();
+ ASSERT_EQ(attrs_exp.size(), attrs.size());
+ for (size_t i = 0; i < attrs_exp.size(); i++) {
+ ASSERT_EQ(attrs_exp[i]->getName(), attrs[i]->getName());
+ ASSERT_EQ(attrs_exp[i]->getType(), attrs[i]->getType());
+ ASSERT_EQ(attrs_exp[i]->isOptional(), attrs[i]->isOptional());
+ ASSERT_EQ(attrs_exp[i]->getDefaultValue(),
+ attrs[i]->getDefaultValue());
+ }
+ }
+}
+
+static void checkStructuredClass(
+ Handle<Node> n, const std::string &name, Handle<Domain> domain,
+ Variant cardinality = Cardinality::any(),
+ Handle<StructType> attributesDescriptor = nullptr,
+ Handle<StructuredClass> superclass = nullptr, bool transparent = false,
+ bool root = false)
+{
+ ASSERT_FALSE(n == nullptr);
+ Handle<StructuredClass> sc = n.cast<StructuredClass>();
+ ASSERT_FALSE(sc == nullptr);
+ ASSERT_EQ(name, sc->getName());
+ ASSERT_EQ(domain, sc->getParent());
+ ASSERT_EQ(cardinality, sc->getCardinality());
+ ASSERT_EQ(transparent, sc->isTransparent());
+ ASSERT_EQ(root, sc->hasRootPermission());
+ checkAttributes(attributesDescriptor, sc);
+}
+
+static Rooted<StructuredClass> checkStructuredClass(
+ const std::string &resolve, const std::string &name, Handle<Domain> domain,
+ Variant cardinality = Cardinality::any(),
+ Handle<StructType> attributesDescriptor = nullptr,
+ Handle<StructuredClass> superclass = nullptr, bool transparent = false,
+ bool root = false)
+{
+ auto res = domain->resolve(&RttiTypes::StructuredClass, resolve);
+ if (res.size() != 1) {
+ throw OusiaException("resolution error!");
+ }
+ Handle<StructuredClass> sc = res[0].node.cast<StructuredClass>();
+ checkStructuredClass(sc, name, domain, cardinality, attributesDescriptor,
+ superclass, transparent, root);
+ return sc;
+}
+
+static void checkAnnotationClass(
+ Handle<Node> n, const std::string &name, Handle<Domain> domain,
+ Handle<StructType> attributesDescriptor = nullptr)
+{
+ ASSERT_FALSE(n == nullptr);
+ Handle<AnnotationClass> ac = n.cast<AnnotationClass>();
+ ASSERT_FALSE(ac == nullptr);
+ ASSERT_EQ(name, ac->getName());
+ ASSERT_EQ(domain, ac->getParent());
+ checkAttributes(attributesDescriptor, ac);
+}
+
+static Rooted<AnnotationClass> checkAnnotationClass(
+ const std::string &resolve, const std::string &name, Handle<Domain> domain,
+ Handle<StructType> attributesDescriptor = nullptr)
+{
+ auto res = domain->resolve(&RttiTypes::AnnotationClass, resolve);
+ if (res.size() != 1) {
+ throw OusiaException("resolution error!");
+ }
+ Handle<AnnotationClass> ac = res[0].node.cast<AnnotationClass>();
+ checkAnnotationClass(ac, name, domain, attributesDescriptor);
+ return ac;
+}
+
+static void checkFieldDescriptor(
+ Handle<Node> n, const std::string &name, Handle<Descriptor> parent,
+ NodeVector<StructuredClass> children,
+ FieldDescriptor::FieldType type = FieldDescriptor::FieldType::TREE,
+ Handle<Type> primitiveType = nullptr, bool optional = false)
+{
+ ASSERT_FALSE(n == nullptr);
+ Handle<FieldDescriptor> field = n.cast<FieldDescriptor>();
+ ASSERT_FALSE(field.isNull());
+ ASSERT_EQ(name, field->getName());
+ ASSERT_EQ(parent, field->getParent());
+ ASSERT_EQ(type, field->getFieldType());
+ ASSERT_EQ(primitiveType, field->getPrimitiveType());
+ ASSERT_EQ(optional, field->isOptional());
+ // check the children.
+ ASSERT_EQ(children.size(), field->getChildren().size());
+ for (unsigned int c = 0; c < children.size(); c++) {
+ ASSERT_EQ(children[c], field->getChildren()[c]);
+ }
+}
+
+static void checkFieldDescriptor(
+ Handle<Descriptor> desc, Handle<Descriptor> parent,
+ NodeVector<StructuredClass> children,
+ const std::string &name = DEFAULT_FIELD_NAME,
+ FieldDescriptor::FieldType type = FieldDescriptor::FieldType::TREE,
+ Handle<Type> primitiveType = nullptr, bool optional = false)
+{
+ auto res = desc->resolve(&RttiTypes::FieldDescriptor, name);
+ ASSERT_EQ(1, res.size());
+ checkFieldDescriptor(res[0].node, name, parent, children, type,
+ primitiveType, optional);
+}
+
+static void checkFieldDescriptor(
+ Handle<Descriptor> desc, NodeVector<StructuredClass> children,
+ const std::string &name = DEFAULT_FIELD_NAME,
+ FieldDescriptor::FieldType type = FieldDescriptor::FieldType::TREE,
+ Handle<Type> primitiveType = nullptr, bool optional = false)
+{
+ checkFieldDescriptor(desc, desc, children, name, type, primitiveType,
+ optional);
+}
+
+TEST(XmlParser, domainParsing)
+{
+ XmlStandaloneEnvironment env(logger);
+ Rooted<Node> book_domain_node =
+ env.parse("book_domain.oxm", "", "", RttiSet{&RttiTypes::Domain});
+ ASSERT_FALSE(book_domain_node == nullptr);
+ ASSERT_FALSE(logger.hasError());
+ // check the domain node.
+ Rooted<Domain> book_domain = book_domain_node.cast<Domain>();
+ ASSERT_EQ("book", book_domain->getName());
+ // get the book struct node.
+ Cardinality single;
+ single.merge({1});
+ Rooted<StructType> bookAuthor{
+ new StructType(book_domain->getManager(), "", nullptr)};
+ bookAuthor->addAttribute(
+ {new Attribute(book_domain->getManager(), "author",
+ env.project->getSystemTypesystem()->getStringType(),
+ "")},
+ logger);
+ Rooted<StructuredClass> book = checkStructuredClass(
+ "book", "book", book_domain, single, bookAuthor, nullptr, false, true);
+ // get the chapter struct node.
+ Rooted<StructuredClass> chapter =
+ checkStructuredClass("chapter", "chapter", book_domain);
+ Rooted<StructuredClass> section =
+ checkStructuredClass("section", "section", book_domain);
+ Rooted<StructuredClass> subsection =
+ checkStructuredClass("subsection", "subsection", book_domain);
+ Rooted<StructuredClass> paragraph =
+ checkStructuredClass("paragraph", "paragraph", book_domain,
+ Cardinality::any(), nullptr, nullptr, true, false);
+ Rooted<StructuredClass> text =
+ checkStructuredClass("text", "text", book_domain, Cardinality::any(),
+ nullptr, nullptr, true, false);
+
+ // check the FieldDescriptors.
+ checkFieldDescriptor(book, {chapter, paragraph});
+ checkFieldDescriptor(chapter, {section, paragraph});
+ checkFieldDescriptor(section, {subsection, paragraph});
+ checkFieldDescriptor(subsection, {paragraph});
+ checkFieldDescriptor(paragraph, {text});
+ checkFieldDescriptor(
+ text, {}, DEFAULT_FIELD_NAME, FieldDescriptor::FieldType::PRIMITIVE,
+ env.project->getSystemTypesystem()->getStringType(), false);
+
+ // check parent handling using the headings domain.
+ Rooted<Node> headings_domain_node =
+ env.parse("headings_domain.oxm", "", "", RttiSet{&RttiTypes::Domain});
+ ASSERT_FALSE(headings_domain_node == nullptr);
+ ASSERT_FALSE(logger.hasError());
+ Rooted<Domain> headings_domain = headings_domain_node.cast<Domain>();
+ // now there should be a heading struct.
+ Rooted<StructuredClass> heading =
+ checkStructuredClass("heading", "heading", headings_domain, single,
+ nullptr, nullptr, true, false);
+ // which should be a reference to the paragraph descriptor.
+ checkFieldDescriptor(heading, paragraph, {text});
+ // and each struct in the book domain (except for text) should have a
+ // heading field now.
+ checkFieldDescriptor(book, {heading}, "heading",
+ FieldDescriptor::FieldType::SUBTREE, nullptr, true);
+ checkFieldDescriptor(chapter, {heading}, "heading",
+ FieldDescriptor::FieldType::SUBTREE, nullptr, true);
+ checkFieldDescriptor(section, {heading}, "heading",
+ FieldDescriptor::FieldType::SUBTREE, nullptr, true);
+ checkFieldDescriptor(subsection, {heading}, "heading",
+ FieldDescriptor::FieldType::SUBTREE, nullptr, true);
+ checkFieldDescriptor(paragraph, {heading}, "heading",
+ FieldDescriptor::FieldType::SUBTREE, nullptr, true);
+
+ // check annotation handling using the comments domain.
+ Rooted<Node> comments_domain_node =
+ env.parse("comments_domain.oxm", "", "", RttiSet{&RttiTypes::Domain});
+ ASSERT_FALSE(comments_domain_node == nullptr);
+ ASSERT_FALSE(logger.hasError());
+ Rooted<Domain> comments_domain = comments_domain_node.cast<Domain>();
+ // now we should be able to find a comment annotation.
+ Rooted<AnnotationClass> comment_anno =
+ checkAnnotationClass("comment", "comment", comments_domain);
+ // as well as a comment struct
+ Rooted<StructuredClass> comment =
+ checkStructuredClass("comment", "comment", comments_domain);
+ // and a reply struct
+ Rooted<StructuredClass> reply =
+ checkStructuredClass("reply", "reply", comments_domain);
+ // check the fields for each of them.
+ {
+ std::vector<Rooted<Descriptor>> descs{comment_anno, comment, reply};
+ for (auto &d : descs) {
+ checkFieldDescriptor(d, {paragraph}, "content",
+ FieldDescriptor::FieldType::SUBTREE, nullptr,
+ false);
+ checkFieldDescriptor(d, {reply}, "replies",
+ FieldDescriptor::FieldType::SUBTREE, nullptr,
+ false);
+ }
+ }
+ // paragraph should have comment as child now as well.
+ checkFieldDescriptor(paragraph, {text, comment});
+ // as should heading, because it references the paragraph default field.
+ checkFieldDescriptor(heading, paragraph, {text, comment});
+}
+
+TEST(XmlParser, documentParsing)
+{
+ XmlStandaloneEnvironment env(logger);
+ Rooted<Node> book_domain_node =
+ env.parse("simple_book.oxd", "", "", RttiSet{&RttiTypes::Document});
+ //TODO: Check result
+}
+}
+