summaryrefslogtreecommitdiff
path: root/test/core/model/DomainTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/core/model/DomainTest.cpp')
-rw-r--r--test/core/model/DomainTest.cpp236
1 files changed, 180 insertions, 56 deletions
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));
}
}
}