/* 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 . */ #include #include #include #include #include #include #include "TestDocument.hpp" #include "TestDomain.hpp" namespace ousia { TEST(Document, construct) { // Construct Manager TerminalLogger logger{std::cerr, true}; Manager mgr{1}; Rooted sys{new SystemTypesystem(mgr)}; // Get the domain. Rooted domain = constructBookDomain(mgr, sys, logger); // Construct the document. Rooted doc = constructBookDocument(mgr, logger, domain); // Check the document content. ASSERT_FALSE(doc.isNull()); // get root node. Rooted root = doc->getRoot(); ASSERT_FALSE(root.isNull()); ASSERT_EQ("book", root->getDescriptor()->getName()); ASSERT_TRUE(root->hasField()); ASSERT_EQ(2U, root->getField().size()); // get foreword (paragraph) { Rooted foreword = root->getField()[0].cast(); ASSERT_FALSE(foreword.isNull()); ASSERT_EQ("paragraph", foreword->getDescriptor()->getName()); // it should contain one text node ASSERT_TRUE(foreword->hasField()); ASSERT_EQ(1U, foreword->getField().size()); // which in turn should have a primitive content field containing the // right text. { Rooted text = foreword->getField()[0].cast(); ASSERT_FALSE(text.isNull()); ASSERT_EQ("text", text->getDescriptor()->getName()); ASSERT_TRUE(text->hasField()); ASSERT_EQ(1U, text->getField().size()); ASSERT_TRUE(text->getField()[0]->isa(typeOf())); Variant content = text->getField()[0].cast()->getContent(); ASSERT_EQ("Some introductory text", content.asString()); } } // get section { Rooted section = root->getField()[1].cast(); ASSERT_FALSE(section.isNull()); ASSERT_EQ("section", section->getDescriptor()->getName()); // it should contain one paragraph ASSERT_TRUE(section->hasField()); ASSERT_EQ(1U, section->getField().size()); { Rooted par = section->getField()[0].cast(); ASSERT_FALSE(par.isNull()); ASSERT_EQ("paragraph", par->getDescriptor()->getName()); // it should contain one text node ASSERT_TRUE(par->hasField()); ASSERT_EQ(1U, par->getField().size()); // which in turn should have a primitive content field containing // the right text. { Rooted text = par->getField()[0].cast(); ASSERT_FALSE(text.isNull()); ASSERT_EQ("text", text->getDescriptor()->getName()); ASSERT_TRUE(text->hasField()); ASSERT_EQ(1U, text->getField().size()); ASSERT_TRUE( text->getField()[0]->isa(typeOf())); Variant content = text->getField()[0].cast()->getContent(); ASSERT_EQ("Some actual text", content.asString()); } } } } TEST(Document, validate) { // Let's start with a trivial domain and a trivial document. TerminalLogger logger{std::cerr, true}; Manager mgr{1}; Rooted sys{new SystemTypesystem(mgr)}; Rooted domain{new Domain(mgr, sys, "trivial")}; Cardinality single; single.merge({1}); // Set up the "root" StructuredClass. Rooted rootClass{new StructuredClass( mgr, "root", domain, single, {nullptr}, {nullptr}, false, true)}; // set up a document for it. { // first an invalid one, which is empty. Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // then add a root, which should make it valid. Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } { // A root with an invalid name, however, should make it invalid Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity( doc, logger, {"root"}, {}, "my invalid root"); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); } // now let's extend the rootClass with a default field. Rooted rootField{new FieldDescriptor(mgr, rootClass)}; // and add a child class for it. Rooted childClass{ new StructuredClass(mgr, "child", domain, single)}; rootField->addChild(childClass); { /* * now check again: Because the child has the cardinality {1} our * document should be invalid again. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // but it should get valid if we add a proper child. buildStructuredEntity(doc, logger, root, {"child"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // and it should get invalid again if we add one more child. buildStructuredEntity(doc, logger, root, {"child"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); } /* * Add a further extension to the domain: We add a subclass to child. */ Rooted childSubClass{new StructuredClass( mgr, "childSub", domain, single, {nullptr}, childClass)}; { /* * A document with one instance of the Child subclass should be valid. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); buildStructuredEntity(doc, logger, root, {"childSub"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } /* * Make it even more complicated: child gets a field for further child * instances now. */ Rooted childField{new FieldDescriptor(mgr, childClass)}; childField->addChild(childClass); { /* * Now a document with one instance of the Child subclass should be * invalid, because it has no children of itself. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); buildStructuredEntity(doc, logger, root, {"childSub"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); } /* * Override the default field in childSubClass. */ Rooted childSubField{ new FieldDescriptor(mgr, childSubClass)}; { /* * Now a document with one instance of the Child subclass should be * valid, because of the override. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); buildStructuredEntity(doc, logger, root, {"childSub"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } // add a primitive field to the subclass with integer content. Rooted primitive_field{new FieldDescriptor( mgr, childSubClass, sys->getIntType(), "int", false)}; { /* * Now a document with one instance of the Child subclass should be * invalid again, because we are missing the primitive content. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); Rooted child = buildStructuredEntity(doc, logger, root, {"childSub"}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // if we add a DocumentPrimitive with the wrong content it should not // work either. Rooted primitive{ new DocumentPrimitive(mgr, child, {"ololol"}, "int")}; ASSERT_FALSE(doc->validate(logger)); // but if we set the content right, it should work. primitive->setContent({2}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } // Now add an Annotation class to the domain. Rooted annoClass{new AnnotationClass(mgr, "anno", domain)}; { /* * Create a valid document in itself. */ Rooted doc{new Document(mgr, "myDoc.oxd")}; doc->referenceDomain(domain); Rooted root = buildRootStructuredEntity(doc, logger, {"root"}); Rooted start{new Anchor(mgr, "start", root)}; Rooted child = buildStructuredEntity(doc, logger, root, {"childSub"}); Rooted primitive{ new DocumentPrimitive(mgr, child, {2}, "int")}; Rooted end{new Anchor(mgr, "end", root)}; ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // then add an AnnotationEntity without Anchors. Rooted anno = buildAnnotationEntity(doc, logger, {"anno"}, nullptr, nullptr); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // but it should be valid again if we set the start end and Anchor. anno->setStart(start); anno->setEnd(end); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // add an attribute to the root, which should make it invalid. root->setAttributes({2}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // if we reset it to null it should be valid again root->setAttributes({}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // let's set an attribute descriptor. Rooted structType{StructType::createValidated( mgr, "attributes", nullptr, nullptr, NodeVector{ new Attribute{mgr, "myAttr", sys->getStringType(), "default"}}, logger)}; childSubClass->setAttributesDescriptor(structType); // the right map content should be valid now. child->setAttributes( std::map{{"myAttr", "content"}}); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // but an empty map as well child->setAttributes(std::map()); ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } } }