diff options
Diffstat (limited to 'test/core/model/DomainTest.cpp')
-rw-r--r-- | test/core/model/DomainTest.cpp | 236 |
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)); } } } |