summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-15 00:27:11 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-02-15 00:27:11 +0100
commit253492406f04657fe71e6c0c6603496241280478 (patch)
tree5a9c1b785a5559025ff7d26bf9ed880ce98ff0ce /test
parent551b7be64f207845cb05b8ec593f9bf2d7f0c940 (diff)
parentb708dd4cce828c1089a18fefcc22804f7cdad908 (diff)
Merge branch 'master' into astoecke_parser_stack_new
Conflicts: application/CMakeLists.txt application/src/core/parser/stack/DocumentHandler.hpp application/src/core/parser/stack/DomainHandler.hpp application/src/core/parser/stack/ImportIncludeHandler.hpp
Diffstat (limited to 'test')
-rw-r--r--test/core/common/VariantReaderTest.cpp122
-rw-r--r--test/core/model/DocumentTest.cpp42
-rw-r--r--test/core/model/DomainTest.cpp236
-rw-r--r--test/core/model/TestAdvanced.hpp24
-rw-r--r--test/core/model/TestDomain.hpp18
-rw-r--r--test/formats/osxml/OsxmlParserTest.cpp100
-rw-r--r--test/plugins/html/DemoOutputTest.cpp23
7 files changed, 447 insertions, 118 deletions
diff --git a/test/core/common/VariantReaderTest.cpp b/test/core/common/VariantReaderTest.cpp
index f6a699b..a23af09 100644
--- a/test/core/common/VariantReaderTest.cpp
+++ b/test/core/common/VariantReaderTest.cpp
@@ -205,7 +205,7 @@ TEST(VariantReader, parseUnescapedString)
// Simple case with whitespace
{
- CharReader reader(" hello world ; ");
+ CharReader reader(" hello world ; aha");
auto res = VariantReader::parseUnescapedString(reader, logger, {';'});
ASSERT_TRUE(res.first);
ASSERT_EQ("hello world", res.second);
@@ -228,6 +228,54 @@ TEST(VariantReader, parseUnescapedString)
}
}
+TEST(VariantReader, parseBool)
+{
+ // Valid bools
+ {
+ CharReader reader(" true ");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_TRUE(res.second);
+ }
+ {
+ CharReader reader(" false ");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_FALSE(res.second);
+ }
+ {
+ CharReader reader(" true bla");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_TRUE(res.second);
+ reader.consumeWhitespace();
+ char c;
+ ASSERT_TRUE(reader.read(c));
+ ASSERT_EQ('b', c);
+ ASSERT_TRUE(reader.read(c));
+ ASSERT_EQ('l', c);
+ ASSERT_TRUE(reader.read(c));
+ ASSERT_EQ('a', c);
+ ASSERT_FALSE(reader.read(c));
+ }
+ // invalid bools.
+ {
+ CharReader reader(" bla ");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_FALSE(res.first);
+ }
+ {
+ CharReader reader(" TRUE ");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_FALSE(res.first);
+ }
+ {
+ CharReader reader(" tr ue ");
+ auto res = VariantReader::parseBool(reader, logger);
+ ASSERT_FALSE(res.first);
+ }
+}
+
static const std::unordered_set<char> noDelim;
TEST(VariantReader, parseInteger)
@@ -574,6 +622,13 @@ TEST(VariantReader, parseObject)
auto res = VariantReader::parseObject(reader, logger);
ASSERT_FALSE(res.first);
}
+
+ // Mutliple commas
+ {
+ CharReader reader("[r=50,,t=70, b=70,g=60]");
+ auto res = VariantReader::parseObject(reader, logger);
+ ASSERT_FALSE(res.first);
+ }
}
TEST(VariantReader, parseCardinality)
@@ -1134,5 +1189,70 @@ TEST(VariantReader, parseGenericComplex)
ASSERT_TRUE(reader.peek(c));
ASSERT_EQ(';', c);
}
+
+TEST(VariantReader, parseTyped)
+{
+ {
+ auto res = VariantReader::parseTyped(VariantType::BOOL, "true", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::BOOL, res.second.getType());
+ ASSERT_TRUE(res.second.asBool());
+ }
+ {
+ auto res =
+ VariantReader::parseTyped(VariantType::INT, " 1254", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::INT, res.second.getType());
+ ASSERT_EQ(1254, res.second.asInt());
+ }
+ {
+ auto res =
+ VariantReader::parseTyped(VariantType::DOUBLE, " 3.14", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::DOUBLE, res.second.getType());
+ ASSERT_EQ(3.14, res.second.asDouble());
+ }
+ {
+ auto res = VariantReader::parseTyped(VariantType::STRING,
+ "\'my string\'", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::STRING, res.second.getType());
+ ASSERT_EQ("my string", res.second.asString());
+ }
+ {
+ auto res =
+ VariantReader::parseTyped(VariantType::STRING, "my string", logger);
+ ASSERT_FALSE(res.first);
+ }
+ {
+ auto res =
+ VariantReader::parseTyped(VariantType::ARRAY, "[1, 4, 5]", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::ARRAY, res.second.getType());
+ Variant::arrayType actual = res.second.asArray();
+ Variant::arrayType expected{{1}, {4}, {5}};
+ ASSERT_EQ(expected, actual);
+ }
+ {
+ auto res = VariantReader::parseTyped(
+ VariantType::MAP, "[a=\"str\", b=true, i=4]", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::MAP, res.second.getType());
+ Variant::mapType actual = res.second.asMap();
+ Variant::mapType expected{{"a", {"str"}}, {"b", {true}}, {"i", {4}}};
+ ASSERT_EQ(expected, actual);
+ }
+ {
+ auto res = VariantReader::parseTyped(VariantType::CARDINALITY,
+ "{1-2, >18}", logger);
+ ASSERT_TRUE(res.first);
+ ASSERT_EQ(VariantType::CARDINALITY, res.second.getType());
+ Variant::cardinalityType actual = res.second.asCardinality();
+ Variant::cardinalityType expected;
+ expected.merge({1, 2});
+ expected.merge(Variant::rangeType::typeRangeFrom(19));
+ ASSERT_EQ(expected, actual);
+ }
+}
}
diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp
index 3164b7e..0c6eea6 100644
--- a/test/core/model/DocumentTest.cpp
+++ b/test/core/model/DocumentTest.cpp
@@ -67,11 +67,9 @@ TEST(Document, construct)
ASSERT_EQ("text", text->getDescriptor()->getName());
ASSERT_TRUE(text->getDescriptor()->hasField());
ASSERT_EQ(1U, text->getField().size());
- ASSERT_TRUE(
- text->getField()[0]->isa(typeOf<DocumentPrimitive>()));
- Variant content = text->getField()[0]
- .cast<DocumentPrimitive>()
- ->getContent();
+ ASSERT_TRUE(text->getField()[0]->isa(typeOf<DocumentPrimitive>()));
+ Variant content =
+ text->getField()[0].cast<DocumentPrimitive>()->getContent();
ASSERT_EQ("Some introductory text", content.asString());
}
}
@@ -101,11 +99,10 @@ TEST(Document, construct)
ASSERT_EQ("text", text->getDescriptor()->getName());
ASSERT_TRUE(text->getDescriptor()->hasField());
ASSERT_EQ(1U, text->getField().size());
- ASSERT_TRUE(text->getField()[0]->isa(
- typeOf<DocumentPrimitive>()));
- Variant content = text->getField()[0]
- .cast<DocumentPrimitive>()
- ->getContent();
+ ASSERT_TRUE(
+ text->getField()[0]->isa(typeOf<DocumentPrimitive>()));
+ Variant content =
+ text->getField()[0].cast<DocumentPrimitive>()->getContent();
ASSERT_EQ("Some actual text", content.asString());
}
}
@@ -149,7 +146,8 @@ TEST(Document, validate)
}
// now let's extend the rootClass with a default field.
- Rooted<FieldDescriptor> rootField{new FieldDescriptor(mgr, rootClass)};
+ Rooted<FieldDescriptor> rootField =
+ rootClass->createFieldDescriptor(logger);
// and add a child class for it.
Rooted<StructuredClass> childClass{
new StructuredClass(mgr, "child", domain, single)};
@@ -195,7 +193,8 @@ TEST(Document, validate)
* Make it even more complicated: child gets a field for further child
* instances now.
*/
- Rooted<FieldDescriptor> childField{new FieldDescriptor(mgr, childClass)};
+ Rooted<FieldDescriptor> childField =
+ childClass->createFieldDescriptor(logger);
childField->addChild(childClass);
{
/*
@@ -211,10 +210,13 @@ TEST(Document, validate)
ASSERT_FALSE(doc->validate(logger));
}
/*
- * Override the default field in childSubClass.
+ * Override the default field in childSubClass with an optional field.
*/
- Rooted<FieldDescriptor> childSubField{
- new FieldDescriptor(mgr, childSubClass)};
+ Rooted<FieldDescriptor> childSubField =
+ childSubClass->createFieldDescriptor(
+ logger, FieldDescriptor::FieldType::TREE, "dummy", true);
+ // add a child pro forma to make it valid.
+ childSubField->addChild(childSubClass);
{
/*
* Now a document with one instance of the Child subclass should be
@@ -229,8 +231,10 @@ TEST(Document, validate)
ASSERT_TRUE(doc->validate(logger));
}
// add a primitive field to the subclass with integer content.
- Rooted<FieldDescriptor> primitive_field{new FieldDescriptor(
- mgr, childSubClass, sys->getIntType(), "int", false)};
+ Rooted<FieldDescriptor> primitive_field =
+ childSubClass->createPrimitiveFieldDescriptor(
+ sys->getIntType(), logger, FieldDescriptor::FieldType::SUBTREE,
+ "int", false);
{
/*
* Now a document with one instance of the Child subclass should be
@@ -265,12 +269,12 @@ TEST(Document, validate)
doc->referenceDomain(domain);
Rooted<StructuredEntity> root =
buildRootStructuredEntity(doc, logger, {"root"});
- Rooted<Anchor> start{new Anchor(mgr, "start", root)};
+ Rooted<Anchor> start{new Anchor(mgr, root)};
Rooted<StructuredEntity> child =
buildStructuredEntity(doc, logger, root, {"childSub"});
Rooted<DocumentPrimitive> primitive{
new DocumentPrimitive(mgr, child, {2}, "int")};
- Rooted<Anchor> end{new Anchor(mgr, "end", root)};
+ Rooted<Anchor> end{new Anchor(mgr, root)};
ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState());
ASSERT_TRUE(doc->validate(logger));
// then add an AnnotationEntity without Anchors.
diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp
index 32ef7f0..8fcbdf2 100644
--- a/test/core/model/DomainTest.cpp
+++ b/test/core/model/DomainTest.cpp
@@ -91,7 +91,7 @@ Rooted<StructuredClass> getClass(const std::string name, Handle<Domain> dom)
TEST(Descriptor, pathTo)
{
// Start with some easy examples from the book domain.
- Logger logger;
+ TerminalLogger logger{std::cout};
Manager mgr{1};
Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
// Get the domain.
@@ -101,14 +101,14 @@ TEST(Descriptor, pathTo)
Rooted<StructuredClass> book = getClass("book", domain);
Rooted<StructuredClass> section = getClass("section", domain);
// get the path in between.
- std::vector<Rooted<Node>> path = book->pathTo(section);
+ NodeVector<Node> path = book->pathTo(section, logger);
ASSERT_EQ(1U, path.size());
ASSERT_TRUE(path[0]->isa(&RttiTypes::FieldDescriptor));
// get the text node.
Rooted<StructuredClass> text = getClass("text", domain);
// get the path between book and text via paragraph.
- path = book->pathTo(text);
+ path = book->pathTo(text, logger);
ASSERT_EQ(3U, path.size());
ASSERT_TRUE(path[0]->isa(&RttiTypes::FieldDescriptor));
ASSERT_TRUE(path[1]->isa(&RttiTypes::StructuredClass));
@@ -118,9 +118,21 @@ TEST(Descriptor, pathTo)
// get the subsection node.
Rooted<StructuredClass> subsection = getClass("subsection", domain);
// try to get the path between book and subsection.
- path = book->pathTo(subsection);
+ path = book->pathTo(subsection, logger);
// this should be impossible.
ASSERT_EQ(0U, path.size());
+
+ // try to construct the path between section and the text field.
+ auto res = section->pathTo(text->getFieldDescriptor(), logger);
+ ASSERT_TRUE(res.second);
+ path = res.first;
+ ASSERT_EQ(4U, path.size());
+ ASSERT_TRUE(path[0]->isa(&RttiTypes::FieldDescriptor));
+ ASSERT_TRUE(path[1]->isa(&RttiTypes::StructuredClass));
+ ASSERT_EQ("paragraph", path[1]->getName());
+ ASSERT_TRUE(path[2]->isa(&RttiTypes::FieldDescriptor));
+ ASSERT_TRUE(path[3]->isa(&RttiTypes::StructuredClass));
+ ASSERT_EQ("text", path[3]->getName());
}
TEST(Descriptor, pathToAdvanced)
@@ -134,20 +146,19 @@ TEST(Descriptor, pathToAdvanced)
*
* To achieve that we have the following structure:
* 1.) The start class inherits from A.
- * 2.) A has the target as child in the default field, but the default
- * field is overridden in the start class.
- * 3.) A has B as child in another field.
- * 4.) B is transparent and has no children (but C as subclass)
- * 5.) C is a subclass of B, transparent and has
+ * 2.) A has B as child in the default field.
+ * 3.) B is transparent and has no children (but C as subclass)
+ * 4.) C is a subclass of B, transparent and has
* the target as child (shortest path).
- * 6.) start has D as child in the default field.
- * 7.) D is transparent has E as child in the default field.
- * 8.) E is transparent and has target as child in the default field
+ * 5.) A has D as child in the default field.
+ * 6.) D is transparent has E as child in the default field.
+ * 7.) E is transparent and has target as child in the default field
* (longer path)
*
- * So the path start_field , E , E_field should be returned.
+ * So the path A_second_field, C, C_field should be returned.
*/
Manager mgr{1};
+ TerminalLogger logger{std::cout};
Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
// Construct the domain
Rooted<Domain> domain{new Domain(mgr, sys, "nasty")};
@@ -162,8 +173,8 @@ TEST(Descriptor, pathToAdvanced)
Rooted<StructuredClass> B{new StructuredClass(
mgr, "B", domain, Cardinality::any(), {nullptr}, true, false)};
- Rooted<StructuredClass> C{
- new StructuredClass(mgr, "C", domain, Cardinality::any(), B, true, false)};
+ Rooted<StructuredClass> C{new StructuredClass(
+ mgr, "C", domain, Cardinality::any(), B, true, false)};
Rooted<StructuredClass> D{new StructuredClass(
mgr, "D", domain, Cardinality::any(), {nullptr}, true, false)};
@@ -174,46 +185,157 @@ TEST(Descriptor, pathToAdvanced)
Rooted<StructuredClass> target{
new StructuredClass(mgr, "target", domain, Cardinality::any())};
- // We create two fields for A
- Rooted<FieldDescriptor> A_field{new FieldDescriptor(mgr, A)};
-
- A_field->addChild(target);
- Rooted<FieldDescriptor> A_field2{new FieldDescriptor(
- mgr, A, FieldDescriptor::FieldType::SUBTREE, "second")};
+ // We create a field for A
+ Rooted<FieldDescriptor> A_field = A->createFieldDescriptor(logger);
+ A_field->addChild(B);
+ A_field->addChild(D);
- A_field2->addChild(B);
// We create no field for B
// One for C
- Rooted<FieldDescriptor> C_field{new FieldDescriptor(mgr, C)};
-
+ Rooted<FieldDescriptor> C_field = C->createFieldDescriptor(logger);
C_field->addChild(target);
- // one for start
- Rooted<FieldDescriptor> start_field{new FieldDescriptor(mgr, start)};
- start_field->addChild(D);
// One for D
- Rooted<FieldDescriptor> D_field{new FieldDescriptor(mgr, D)};
-
+ Rooted<FieldDescriptor> D_field = D->createFieldDescriptor(logger);
D_field->addChild(E);
- // One for E
- Rooted<FieldDescriptor> E_field{new FieldDescriptor(mgr, E)};
+ // One for E
+ Rooted<FieldDescriptor> E_field = E->createFieldDescriptor(logger);
E_field->addChild(target);
+ ASSERT_TRUE(domain->validate(logger));
+
#ifdef MANAGER_GRAPHVIZ_EXPORT
// dump the manager state
mgr.exportGraphviz("nastyDomain.dot");
#endif
// and now we should be able to find the shortest path as suggested
- std::vector<Rooted<Node>> path = start->pathTo(target);
+ NodeVector<Node> path = start->pathTo(target, logger);
ASSERT_EQ(3U, path.size());
ASSERT_TRUE(path[0]->isa(&RttiTypes::FieldDescriptor));
- ASSERT_EQ("second", path[0]->getName());
+ ASSERT_EQ("", path[0]->getName());
ASSERT_TRUE(path[1]->isa(&RttiTypes::StructuredClass));
- ASSERT_EQ("B", path[1]->getName());
+ ASSERT_EQ("C", path[1]->getName());
ASSERT_TRUE(path[2]->isa(&RttiTypes::FieldDescriptor));
- ASSERT_EQ("$default", path[2]->getName());
+ ASSERT_EQ("", path[2]->getName());
+}
+
+TEST(Descriptor, getDefaultFields)
+{
+ // construct a domain with lots of default fields to test.
+ // start with a single structure class.
+ Manager mgr{1};
+ TerminalLogger logger{std::cout};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Construct the domain
+ Rooted<Domain> domain{new Domain(mgr, sys, "nasty")};
+
+ Rooted<StructuredClass> A{new StructuredClass(
+ mgr, "A", domain, Cardinality::any(), nullptr, false, true)};
+
+ // in this trivial case no field should be found.
+ ASSERT_TRUE(A->getDefaultFields().empty());
+
+ // create a field.
+ Rooted<FieldDescriptor> A_prim_field =
+ A->createPrimitiveFieldDescriptor(sys->getStringType(), logger);
+ // now we should find that.
+ auto fields = A->getDefaultFields();
+ ASSERT_EQ(1, fields.size());
+ ASSERT_EQ(A_prim_field, fields[0]);
+
+ // remove that field from A and add it to another class.
+
+ Rooted<StructuredClass> B{new StructuredClass(
+ mgr, "B", domain, Cardinality::any(), nullptr, false, true)};
+
+ B->moveFieldDescriptor(A_prim_field, logger);
+
+ // new we shouldn't find the field anymore.
+ ASSERT_TRUE(A->getDefaultFields().empty());
+
+ // but we should find it again if we set B as superclass of A.
+ A->setSuperclass(B, logger);
+ fields = A->getDefaultFields();
+ ASSERT_EQ(1, fields.size());
+ ASSERT_EQ(A_prim_field, fields[0]);
+
+ // and we should not be able to find it if we override the field.
+ Rooted<FieldDescriptor> A_field = A->createFieldDescriptor(logger);
+ ASSERT_TRUE(A->getDefaultFields().empty());
+
+ // add a transparent child class.
+
+ Rooted<StructuredClass> C{new StructuredClass(
+ mgr, "C", domain, Cardinality::any(), nullptr, true, false)};
+ A_field->addChild(C);
+
+ // add a primitive field for it.
+ Rooted<FieldDescriptor> C_field =
+ C->createPrimitiveFieldDescriptor(sys->getStringType(), logger);
+
+ // now we should find that.
+ fields = A->getDefaultFields();
+ ASSERT_EQ(1, fields.size());
+ ASSERT_EQ(C_field, fields[0]);
+
+ // add another transparent child class to A with a daughter class that has
+ // in turn a subclass with a primitive field.
+ Rooted<StructuredClass> D{new StructuredClass(
+ mgr, "D", domain, Cardinality::any(), nullptr, true, false)};
+ A_field->addChild(D);
+ Rooted<FieldDescriptor> D_field = D->createFieldDescriptor(logger);
+ Rooted<StructuredClass> E{new StructuredClass(
+ mgr, "E", domain, Cardinality::any(), nullptr, true, false)};
+ D_field->addChild(E);
+ Rooted<StructuredClass> F{new StructuredClass(
+ mgr, "E", domain, Cardinality::any(), E, true, false)};
+ Rooted<FieldDescriptor> F_field =
+ F->createPrimitiveFieldDescriptor(sys->getStringType(), logger);
+
+ // now we should find both primitive fields, but the C field first.
+ fields = A->getDefaultFields();
+ ASSERT_EQ(2, fields.size());
+ ASSERT_EQ(C_field, fields[0]);
+ ASSERT_EQ(F_field, fields[1]);
+}
+
+TEST(Descriptor, getPermittedChildren)
+{
+ // analyze the book domain.
+ TerminalLogger logger{std::cout};
+ Manager mgr{1};
+ Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
+ // Get the domain.
+ Rooted<Domain> domain = constructBookDomain(mgr, sys, logger);
+ // get the relevant classes.
+ Rooted<StructuredClass> book = getClass("book", domain);
+ Rooted<StructuredClass> section = getClass("section", domain);
+ Rooted<StructuredClass> paragraph = getClass("paragraph", domain);
+ Rooted<StructuredClass> text = getClass("text", domain);
+ /*
+ * as permitted children we expect section, paragraph and text in exactly
+ * that order. section should be before paragraph because of declaration
+ * order and text should be last because it needs a transparent paragraph
+ * in between.
+ */
+ NodeVector<StructuredClass> children = book->getPermittedChildren();
+ ASSERT_EQ(3, children.size());
+ ASSERT_EQ(section, children[0]);
+ ASSERT_EQ(paragraph, children[1]);
+ ASSERT_EQ(text, children[2]);
+
+ // Now we add a subclass to text.
+ Rooted<StructuredClass> sub{new StructuredClass(
+ mgr, "Subclass", domain, Cardinality::any(), text, true, false)};
+ // And that should be in the result list as well now.
+ children = book->getPermittedChildren();
+ ASSERT_EQ(4, children.size());
+ ASSERT_EQ(section, children[0]);
+ ASSERT_EQ(paragraph, children[1]);
+ ASSERT_EQ(text, children[2]);
+ ASSERT_EQ(sub, children[3]);
}
TEST(StructuredClass, isSubclassOf)
@@ -313,8 +435,8 @@ TEST(Domain, validate)
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
// Let's add a primitive field (without a primitive type at first)
- Rooted<FieldDescriptor> base_field{
- new FieldDescriptor(mgr, base, nullptr)};
+ Rooted<FieldDescriptor> base_field =
+ base->createPrimitiveFieldDescriptor(nullptr, logger);
// this should not be valid.
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_FALSE(domain->validate(logger));
@@ -322,13 +444,6 @@ TEST(Domain, validate)
base_field->setPrimitiveType(sys->getStringType());
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
- // not anymore, however, if we tamper with the FieldType.
- base_field->setFieldType(FieldDescriptor::FieldType::TREE);
- ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
- ASSERT_FALSE(domain->validate(logger));
- base_field->setFieldType(FieldDescriptor::FieldType::PRIMITIVE);
- ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
- ASSERT_TRUE(domain->validate(logger));
// add a subclass for our base class.
Rooted<StructuredClass> sub{new StructuredClass(mgr, "sub", domain)};
// this should be valid in itself.
@@ -338,7 +453,7 @@ TEST(Domain, validate)
sub->setSuperclass(base, logger);
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
- // and still we we remove the subclass from the base class.
+ // and still if we remove the subclass from the base class.
base->removeSubclass(sub, logger);
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
@@ -349,19 +464,11 @@ TEST(Domain, validate)
ASSERT_TRUE(domain->validate(logger));
ASSERT_EQ(base, sub->getSuperclass());
// add a non-primitive field to the child class.
- Rooted<FieldDescriptor> sub_field{new FieldDescriptor(mgr, sub)};
- // this should be valid
- ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
- ASSERT_TRUE(domain->validate(logger));
- // .. until we set a primitive type.
- sub_field->setPrimitiveType(sys->getStringType());
+ Rooted<FieldDescriptor> sub_field = sub->createFieldDescriptor(logger);
+ // this should not be valid because we allow no children.
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_FALSE(domain->validate(logger));
- // and valid again if we unset it.
- sub_field->setPrimitiveType(nullptr);
- ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
- ASSERT_TRUE(domain->validate(logger));
- // we should also be able to add a child and have it still be valid.
+ // we should also be able to add a child and make it valid.
sub_field->addChild(base);
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
@@ -373,6 +480,23 @@ TEST(Domain, validate)
sub_field->removeChild(base);
ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
ASSERT_TRUE(domain->validate(logger));
+ // if we set a primitive type it should be invalid
+ sub_field->setPrimitiveType(sys->getStringType());
+ ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
+ ASSERT_FALSE(domain->validate(logger));
+ // and valid again if we unset it.
+ sub_field->setPrimitiveType(nullptr);
+ ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
+ ASSERT_TRUE(domain->validate(logger));
+ // It should be invalid if we set another TREE field.
+ Rooted<FieldDescriptor> sub_field2 = sub->createFieldDescriptor(
+ logger, FieldDescriptor::FieldType::TREE, "test", false);
+ ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
+ ASSERT_FALSE(domain->validate(logger));
+ // but valid again if we remove it
+ sub->removeFieldDescriptor(sub_field2);
+ ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState());
+ ASSERT_TRUE(domain->validate(logger));
}
}
}
diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp
index 915d973..27f33cc 100644
--- a/test/core/model/TestAdvanced.hpp
+++ b/test/core/model/TestAdvanced.hpp
@@ -55,18 +55,18 @@ static Rooted<Domain> constructHeadingDomain(Manager &mgr,
Cardinality card;
card.merge({0, 1});
// set up heading StructuredClass.
- Rooted<StructuredClass> heading{new StructuredClass(
- mgr, "heading", domain, card, {nullptr}, true)};
- // as field want to copy the field of paragraph.
+ Rooted<StructuredClass> heading{
+ new StructuredClass(mgr, "heading", domain, card, {nullptr}, true)};
+ // as field want to reference the field of paragraph.
Rooted<StructuredClass> p = resolveDescriptor(bookDomain, "paragraph");
- heading->copyFieldDescriptor(p->getFieldDescriptors()[0]);
+ heading->addFieldDescriptor(p->getFieldDescriptor(), logger);
// create a new field for headings in each section type.
std::vector<std::string> secclasses{"book", "section", "subsection",
"paragraph"};
for (auto &s : secclasses) {
Rooted<StructuredClass> desc = resolveDescriptor(bookDomain, s);
- Rooted<FieldDescriptor> heading_field{new FieldDescriptor(
- mgr, desc, FieldDescriptor::FieldType::SUBTREE, "heading")};
+ Rooted<FieldDescriptor> heading_field = desc->createFieldDescriptor(
+ logger, FieldDescriptor::FieldType::SUBTREE, "heading", true);
heading_field->addChild(heading);
}
return domain;
@@ -88,8 +88,8 @@ static Rooted<Domain> constructListDomain(Manager &mgr,
Rooted<StructuredClass> item{new StructuredClass(
mgr, "item", domain, Cardinality::any(), {nullptr}, false)};
- // as field we want to copy the field of paragraph.
- item->copyFieldDescriptor(p->getFieldDescriptors()[0]);
+ // as field we want to reference the field of paragraph.
+ item->addFieldDescriptor(p->getFieldDescriptor(), logger);
// set up list StructuredClasses.
std::vector<std::string> listTypes{"ol", "ul"};
for (auto &listType : listTypes) {
@@ -150,19 +150,17 @@ static bool addHeading(Logger &logger, Handle<Document> doc,
return true;
}
-static int annoIdx = 1;
-
// Only works for non-overlapping annotations!
static bool addAnnotation(Logger &logger, Handle<Document> doc,
Handle<StructuredEntity> parent,
const std::string &text, const std::string &annoClass)
{
- Manager& mgr = parent->getManager();
- Rooted<Anchor> start{new Anchor(mgr, std::to_string(annoIdx++), parent)};
+ Manager &mgr = parent->getManager();
+ Rooted<Anchor> start{new Anchor(mgr, parent)};
if (!addText(logger, doc, parent, text)) {
return false;
}
- Rooted<Anchor> end{new Anchor(mgr, std::to_string(annoIdx++), parent)};
+ Rooted<Anchor> end{new Anchor(mgr, parent)};
Rooted<AnnotationEntity> anno =
buildAnnotationEntity(doc, logger, {annoClass}, start, end);
if (anno.isNull()) {
diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp
index 5ac510c..c107a0d 100644
--- a/test/core/model/TestDomain.hpp
+++ b/test/core/model/TestDomain.hpp
@@ -42,7 +42,7 @@ static Rooted<Domain> constructBookDomain(Manager &mgr,
mgr, "book", domain, single, {nullptr}, false, true)};
// The structure field of it.
- Rooted<FieldDescriptor> book_field{new FieldDescriptor(mgr, book)};
+ Rooted<FieldDescriptor> book_field = book->createFieldDescriptor(logger);
// From there on the "section".
Rooted<StructuredClass> section{
@@ -50,7 +50,8 @@ static Rooted<Domain> constructBookDomain(Manager &mgr,
book_field->addChild(section);
// And the field of it.
- Rooted<FieldDescriptor> section_field{new FieldDescriptor(mgr, section)};
+ Rooted<FieldDescriptor> section_field =
+ section->createFieldDescriptor(logger);
// We also add the "paragraph", which is transparent.
Rooted<StructuredClass> paragraph{new StructuredClass(
@@ -59,8 +60,8 @@ static Rooted<Domain> constructBookDomain(Manager &mgr,
book_field->addChild(paragraph);
// And the field of it.
- Rooted<FieldDescriptor> paragraph_field{
- new FieldDescriptor(mgr, paragraph)};
+ Rooted<FieldDescriptor> paragraph_field =
+ paragraph->createFieldDescriptor(logger);
// We append "subsection" to section.
Rooted<StructuredClass> subsection{
@@ -68,8 +69,8 @@ static Rooted<Domain> constructBookDomain(Manager &mgr,
section_field->addChild(subsection);
// And the field of it.
- Rooted<FieldDescriptor> subsection_field{
- new FieldDescriptor(mgr, subsection)};
+ Rooted<FieldDescriptor> subsection_field =
+ subsection->createFieldDescriptor(logger);
// and we add the paragraph to subsections fields
subsection_field->addChild(paragraph);
@@ -80,9 +81,8 @@ static Rooted<Domain> constructBookDomain(Manager &mgr,
paragraph_field->addChild(text);
// ... and has a primitive field.
- Rooted<FieldDescriptor> text_field{new FieldDescriptor(
- mgr, text, domain->getTypesystems()[0]->getTypes()[0],
- DEFAULT_FIELD_NAME, false)};
+ Rooted<FieldDescriptor> text_field =
+ text->createPrimitiveFieldDescriptor(sys->getStringType(), logger);
return domain;
}
diff --git a/test/formats/osxml/OsxmlParserTest.cpp b/test/formats/osxml/OsxmlParserTest.cpp
index c0fb50d..269a3f6 100644
--- a/test/formats/osxml/OsxmlParserTest.cpp
+++ b/test/formats/osxml/OsxmlParserTest.cpp
@@ -22,6 +22,7 @@
#include <core/common/CharReader.hpp>
#include <core/common/SourceContextReader.hpp>
+#include <core/model/Document.hpp>
#include <core/model/Domain.hpp>
#include <core/model/Node.hpp>
#include <core/model/Project.hpp>
@@ -168,6 +169,7 @@ static void checkFieldDescriptor(
ASSERT_EQ(parent, field->getParent());
ASSERT_EQ(type, field->getFieldType());
ASSERT_EQ(primitiveType, field->getPrimitiveType());
+ ASSERT_EQ(primitiveType != nullptr, field->isPrimitive());
ASSERT_EQ(optional, field->isOptional());
// check the children.
ASSERT_EQ(children.size(), field->getChildren().size());
@@ -179,7 +181,7 @@ static void checkFieldDescriptor(
static void checkFieldDescriptor(
Handle<Descriptor> desc, Handle<Descriptor> parent,
NodeVector<StructuredClass> children,
- const std::string &name = DEFAULT_FIELD_NAME,
+ const std::string &name = "",
FieldDescriptor::FieldType type = FieldDescriptor::FieldType::TREE,
Handle<Type> primitiveType = nullptr, bool optional = false)
{
@@ -191,7 +193,7 @@ static void checkFieldDescriptor(
static void checkFieldDescriptor(
Handle<Descriptor> desc, NodeVector<StructuredClass> children,
- const std::string &name = DEFAULT_FIELD_NAME,
+ const std::string &name = "",
FieldDescriptor::FieldType type = FieldDescriptor::FieldType::TREE,
Handle<Type> primitiveType = nullptr, bool optional = false)
{
@@ -242,7 +244,7 @@ TEST(XmlParser, domainParsing)
checkFieldDescriptor(subsection, {paragraph});
checkFieldDescriptor(paragraph, {text});
checkFieldDescriptor(
- text, {}, DEFAULT_FIELD_NAME, FieldDescriptor::FieldType::PRIMITIVE,
+ text, {}, "", FieldDescriptor::FieldType::TREE,
env.project->getSystemTypesystem()->getStringType(), false);
// check parent handling using the headings domain.
@@ -290,7 +292,7 @@ TEST(XmlParser, domainParsing)
std::vector<Rooted<Descriptor>> descs{comment_anno, comment, reply};
for (auto &d : descs) {
checkFieldDescriptor(d, {paragraph}, "content",
- FieldDescriptor::FieldType::SUBTREE, nullptr,
+ FieldDescriptor::FieldType::TREE, nullptr,
false);
checkFieldDescriptor(d, {reply}, "replies",
FieldDescriptor::FieldType::SUBTREE, nullptr,
@@ -303,12 +305,98 @@ TEST(XmlParser, domainParsing)
checkFieldDescriptor(heading, paragraph, {text, comment});
}
+static void checkStructuredEntity(
+ Handle<Node> s, Handle<Node> expectedParent, Handle<StructuredClass> strct,
+ const Variant::mapType &expectedAttributes = Variant::mapType{},
+ const std::string &expectedName = "")
+{
+ ASSERT_FALSE(s == nullptr);
+ ASSERT_TRUE(s->isa(&RttiTypes::StructuredEntity));
+ Rooted<StructuredEntity> entity = s.cast<StructuredEntity>();
+ ASSERT_EQ(expectedParent, entity->getParent());
+ ASSERT_EQ(strct, entity->getDescriptor());
+ ASSERT_EQ(expectedAttributes, entity->getAttributes());
+ ASSERT_EQ(expectedName, entity->getName());
+}
+
+static void checkStructuredEntity(
+ Handle<Node> s, Handle<Node> expectedParent, Handle<Document> doc,
+ const std::string &className,
+ const Variant::mapType &expectedAttributes = Variant::mapType{},
+ const std::string &expectedName = "")
+{
+ auto res = doc->resolve(&RttiTypes::StructuredClass, className);
+ if (res.size() != 1) {
+ throw OusiaException("resolution error!");
+ }
+ Handle<StructuredClass> sc = res[0].node.cast<StructuredClass>();
+ checkStructuredEntity(s, expectedParent, sc, expectedAttributes,
+ expectedName);
+}
+
+static void checkText(Handle<Node> p, Handle<Node> expectedParent,
+ Handle<Document> doc, Variant expected)
+{
+ checkStructuredEntity(p, expectedParent, doc, "paragraph");
+ Rooted<StructuredEntity> par = p.cast<StructuredEntity>();
+ ASSERT_EQ(1, par->getField().size());
+ checkStructuredEntity(par->getField()[0], par, doc, "text");
+ Rooted<StructuredEntity> text = par->getField()[0].cast<StructuredEntity>();
+ ASSERT_EQ(1, text->getField().size());
+
+ Handle<StructureNode> d = text->getField()[0];
+ ASSERT_FALSE(d == nullptr);
+ ASSERT_TRUE(d->isa(&RttiTypes::DocumentPrimitive));
+ Rooted<DocumentPrimitive> prim = d.cast<DocumentPrimitive>();
+ ASSERT_EQ(text, prim->getParent());
+ ASSERT_EQ(expected, prim->getContent());
+}
+
TEST(XmlParser, documentParsing)
{
XmlStandaloneEnvironment env(logger);
- Rooted<Node> book_domain_node =
+ Rooted<Node> book_document_node =
env.parse("simple_book.oxd", "", "", RttiSet{&RttiTypes::Document});
- //TODO: Check result
+ ASSERT_FALSE(book_document_node == nullptr);
+ ASSERT_TRUE(book_document_node->isa(&RttiTypes::Document));
+ Rooted<Document> doc = book_document_node.cast<Document>();
+ ASSERT_TRUE(doc->validate(logger));
+ checkStructuredEntity(doc->getRoot(), doc, doc, "book");
+ {
+ Rooted<StructuredEntity> book = doc->getRoot();
+ ASSERT_EQ(2, book->getField().size());
+ checkText(book->getField()[0], book, doc,
+ "This might be some introductory text or a dedication.");
+ checkStructuredEntity(book->getField()[1], book, doc, "chapter",
+ Variant::mapType{}, "myFirstChapter");
+ {
+ Rooted<StructuredEntity> chapter =
+ book->getField()[1].cast<StructuredEntity>();
+ ASSERT_EQ(3, chapter->getField().size());
+ checkText(chapter->getField()[0], chapter, doc,
+ "Here we might have an introduction to the chapter.");
+ checkStructuredEntity(chapter->getField()[1], chapter, doc,
+ "section", Variant::mapType{},
+ "myFirstSection");
+ {
+ Rooted<StructuredEntity> section =
+ chapter->getField()[1].cast<StructuredEntity>();
+ ASSERT_EQ(1, section->getField().size());
+ checkText(section->getField()[0], section, doc,
+ "Here we might find the actual section content.");
+ }
+ checkStructuredEntity(chapter->getField()[2], chapter, doc,
+ "section", Variant::mapType{},
+ "mySndSection");
+ {
+ Rooted<StructuredEntity> section =
+ chapter->getField()[2].cast<StructuredEntity>();
+ ASSERT_EQ(1, section->getField().size());
+ checkText(section->getField()[0], section, doc,
+ "Here we might find the actual section content.");
+ }
+ }
+ }
}
}
diff --git a/test/plugins/html/DemoOutputTest.cpp b/test/plugins/html/DemoOutputTest.cpp
index 5006655..2f56e40 100644
--- a/test/plugins/html/DemoOutputTest.cpp
+++ b/test/plugins/html/DemoOutputTest.cpp
@@ -41,14 +41,11 @@ TEST(DemoHTMLTransformer, writeHTML)
Manager mgr{1};
Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
// Get the domains.
- Rooted<Domain> bookDom =
- constructBookDomain(mgr, sys, logger);
+ Rooted<Domain> bookDom = constructBookDomain(mgr, sys, logger);
Rooted<Domain> headingDom =
constructHeadingDomain(mgr, sys, bookDom, logger);
- Rooted<Domain> listDom =
- constructListDomain(mgr, sys, bookDom, logger);
- Rooted<Domain> emDom =
- constructEmphasisDomain(mgr, sys, logger);
+ Rooted<Domain> listDom = constructListDomain(mgr, sys, bookDom, logger);
+ Rooted<Domain> emDom = constructEmphasisDomain(mgr, sys, logger);
// Construct the document.
Rooted<Document> doc = constructAdvancedDocument(
mgr, logger, bookDom, headingDom, listDom, emDom);
@@ -79,10 +76,8 @@ TEST(DemoHTMLTransformer, AnnotationProcessing)
Manager mgr{1};
Rooted<SystemTypesystem> sys{new SystemTypesystem(mgr)};
// Get the domains.
- Rooted<Domain> bookDom =
- constructBookDomain(mgr, sys, logger);
- Rooted<Domain> emDom =
- constructEmphasisDomain(mgr, sys, logger);
+ Rooted<Domain> bookDom = constructBookDomain(mgr, sys, logger);
+ Rooted<Domain> emDom = constructEmphasisDomain(mgr, sys, logger);
// Construct a document only containing overlapping annotations.
// it has the form: <em>bla<strong>blub</em>bla</strong>
Rooted<Document> doc{new Document(mgr, "annotations.oxd")};
@@ -93,13 +88,13 @@ TEST(DemoHTMLTransformer, AnnotationProcessing)
Rooted<StructuredEntity> p =
buildStructuredEntity(doc, logger, book, {"paragraph"});
ASSERT_TRUE(p != nullptr);
- Rooted<Anchor> em_start{new Anchor(mgr, "1", p)};
+ Rooted<Anchor> em_start{new Anchor(mgr, p)};
ASSERT_TRUE(addText(logger, doc, p, "bla"));
- Rooted<Anchor> strong_start{new Anchor(mgr, "2", p)};
+ Rooted<Anchor> strong_start{new Anchor(mgr, p)};
ASSERT_TRUE(addText(logger, doc, p, "blub"));
- Rooted<Anchor> em_end{new Anchor(mgr, "3", p)};
+ Rooted<Anchor> em_end{new Anchor(mgr, p)};
ASSERT_TRUE(addText(logger, doc, p, "bla"));
- Rooted<Anchor> strong_end{new Anchor(mgr, "4", p)};
+ Rooted<Anchor> strong_end{new Anchor(mgr, p)};
buildAnnotationEntity(doc, logger, {"emphasized"}, em_start, em_end);
buildAnnotationEntity(doc, logger, {"strong"}, strong_start, strong_end);