diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-22 02:47:36 +0100 |
---|---|---|
committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-01-22 02:47:36 +0100 |
commit | 4df98e9ae04dd077e47f0a5539aeb68b96c710c4 (patch) | |
tree | 918950c16bbb6f112309f7c3c8a1e6aca12d3650 | |
parent | f90a9bf51f300dd277071b1461d00411d7c21b89 (diff) | |
parent | 33008f1110523ae9c9b9e1d2ca24ed642637c40d (diff) |
Merge branch 'master' of somweyr.de:ousia
-rw-r--r-- | src/core/model/Document.cpp | 114 | ||||
-rw-r--r-- | src/core/model/Document.hpp | 93 | ||||
-rw-r--r-- | src/core/model/Domain.cpp | 101 | ||||
-rw-r--r-- | src/core/model/Domain.hpp | 70 | ||||
-rw-r--r-- | src/core/model/Node.hpp | 21 | ||||
-rw-r--r-- | src/core/model/Typesystem.hpp | 4 | ||||
-rw-r--r-- | test/core/model/DocumentTest.cpp | 40 | ||||
-rw-r--r-- | test/core/model/DomainTest.cpp | 28 |
8 files changed, 388 insertions, 83 deletions
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 7552bd3..2ae9107 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -147,10 +147,14 @@ bool DocumentEntity::doValidate(Logger &logger) const // a constructor we can not check anything else. return false; } - // TODO: check the validated form of Attributes - // TODO: Check if descriptor is registered at the Document? - - bool valid = true; + // check the attribute primitive content. + bool valid; + if (descriptor->getAttributesDescriptor() == nullptr) { + valid = getAttributes() == nullptr; + } else { + valid = descriptor->getAttributesDescriptor()->isValid(getAttributes(), + logger); + } /* * generate the set of effective fields. This is trivial for * AnnotationEntities, but in the case of StructuredEntities we have to @@ -188,7 +192,18 @@ bool DocumentEntity::doValidate(Logger &logger) const continue; } // if we are here we know that exactly one child exists. - // TODO: Check the primitive type of the child. + if (!fields[f][0]->isa(RttiTypes::DocumentPrimitive)) { + logger.error(std::string("Primitive Field \"") + + fieldDescs[f]->getName() + + "\" has non primitive content!"); + valid = false; + } else { + Handle<DocumentPrimitive> primitive = + fields[f][0].cast<DocumentPrimitive>(); + valid = valid & + fieldDescs[f]->getPrimitiveType()->isValid( + primitive->getContent(), logger); + } continue; } @@ -320,13 +335,39 @@ void DocumentEntity::setAttributes(const Variant &a) void DocumentEntity::addStructureNode(Handle<StructureNode> s, const int &i) { - invalidateSubInstance(); - fields[i].push_back(s); - if (s->getParent() != subInst) { + // only add the new node if we don't have it already. + auto it = fields[i].find(s); + if (it == fields[i].end()) { + invalidateSubInstance(); + fields[i].push_back(s); + } + Handle<Managed> par = s->getParent(); + if (par != subInst) { + // if a previous parent existed, remove the StructureNode from it + if (par != nullptr) { + if (par->isa(RttiTypes::StructuredEntity)) { + par.cast<StructuredEntity>()->removeStructureNode(s); + } else { + par.cast<AnnotationEntity>()->removeStructureNode(s); + } + } s->setParent(subInst); } } +bool DocumentEntity::removeStructureNodeFromField(Handle<StructureNode> s, + const int &i) +{ + auto it = fields[i].find(s); + if (it != fields[i].end()) { + invalidateSubInstance(); + fields[i].erase(it); + s->setParent(nullptr); + return true; + } + return false; +} + void DocumentEntity::addStructureNode(Handle<StructureNode> s, const std::string &fieldName) { @@ -342,6 +383,13 @@ void DocumentEntity::addStructureNodes( } } +bool DocumentEntity::removeStructureNodeFromField( + Handle<StructureNode> s, const std::string &fieldName) +{ + return removeStructureNodeFromField( + s, getFieldDescriptorIndex(fieldName, true)); +} + void DocumentEntity::addStructureNode(Handle<StructureNode> s, Handle<FieldDescriptor> fieldDescriptor) { @@ -358,6 +406,28 @@ void DocumentEntity::addStructureNodes( } } +bool DocumentEntity::removeStructureNodeFromField( + Handle<StructureNode> s, Handle<FieldDescriptor> fieldDescriptor) +{ + return removeStructureNodeFromField( + s, getFieldDescriptorIndex(fieldDescriptor, true)); +} + +bool DocumentEntity::removeStructureNode(Handle<StructureNode> s) +{ + for (auto field : fields) { + auto it = field.find(s); + if (it != field.end()) { + invalidateSubInstance(); + field.erase(it); + s->setParent(nullptr); + return true; + } + } + + return false; +} + /* Class StructureNode */ bool StructureNode::doValidate(Logger &logger) const @@ -543,9 +613,17 @@ bool Document::doValidate(Logger &logger) const void Document::addAnnotation(Handle<AnnotationEntity> a) { - invalidate(); - annotations.push_back(a); - if (a->getParent() != this) { + // only add it if we need to. + if (annotations.find(a) == annotations.end()) { + invalidate(); + annotations.push_back(a); + } + Handle<Managed> par = a->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the StructuredClass from the old parent. + par.cast<Document>()->removeAnnotation(a); + } a->setParent(this); } } @@ -557,6 +635,20 @@ void Document::addAnnotations(const std::vector<Handle<AnnotationEntity>> &as) } } + + +bool Document::removeAnnotation(Handle<AnnotationEntity> a) +{ + auto it = annotations.find(a); + if (it != annotations.end()) { + invalidate(); + annotations.erase(it); + a->setParent(nullptr); + return true; + } + return false; +} + bool Document::hasChild(Handle<StructureNode> s) const { Rooted<Managed> parent = s->getParent(); diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index a7dee25..7357dd2 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -162,6 +162,8 @@ private: void addStructureNode(Handle<StructureNode> s, const int &i); + bool removeStructureNodeFromField(Handle<StructureNode> s, const int &i); + protected: bool doValidate(Logger &logger) const; @@ -278,8 +280,8 @@ public: * If the name is unknown an exception is thrown. * * This method also changes the parent of the newly added StructureNode if - * it is not set to this DocumentEntity already. - * TODO: This could get move semantics. + * it is not set to this DocumentEntity already and removes it from the + * old parent. * * @param s is the StructureNode that shall be added. * @param fieldName is the name of a field as specified in the @@ -287,6 +289,7 @@ public: */ void addStructureNode(Handle<StructureNode> s, const std::string &fieldName = ""); + /** * This adds multiple StructureNodes to the field with the given name. * If an empty name is given it is assumed that the 'default' @@ -297,7 +300,8 @@ public: * If the name is unknown an exception is thrown. * * This method also changes the parent of each newly added StructureNode if - * it is not set to this DocumentEntity already. + * it is not set to this DocumentEntity already and removes it from the + * old parent. * * @param ss are the StructureNodes that shall be added. * @param fieldName is the name of a field as specified in the @@ -307,13 +311,34 @@ public: const std::string &fieldName = ""); /** + * This removes a StructureNode from the field with the given name. If an + * empty name is given it is assumed that the 'default' FieldDescriptor is + * referenced, where 'default' means either: + * 1.) The only TREE typed FieldDescriptor (if present) or + * 2.) the only FieldDescriptor (if only one is specified). + * + * If the name is unknown an exception is thrown. + * + * This method also changes the parent of the removed StructureNode to null. + * + * @param s is the StructureNode that shall be removed. + * @param fieldName is the name of a field as specified in the + * FieldDescriptor in the Domain description. + * @return true if this StructureNode was a child here and false if + * if was not found. + */ + bool removeStructureNodeFromField(Handle<StructureNode> s, + const std::string &fieldName = ""); + + /** * This adds a StructureNode to the field with the given FieldDescriptor. * * If the FieldDescriptor does not belong to the Descriptor of this node * an exception is thrown. * * This method also changes the parent of the newly added StructureNode if - * it is not set to this DocumentEntity already. + * it is not set to this DocumentEntity already and removes it from the + * old parent. * * @param s is the StructureNode that shall be added. * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for @@ -330,7 +355,8 @@ public: * an exception is thrown. * * This method also changes the parent of each newly added StructureNode if - * it is not set to this DocumentEntity already. + * it is not set to this DocumentEntity already and removes it from the + * old parent. * * @param ss are the StructureNodes that shall be added. * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for @@ -338,6 +364,35 @@ public: */ void addStructureNodes(const std::vector<Handle<StructureNode>> &ss, Handle<FieldDescriptor> fieldDescriptor); + + /** + * This removes a StructureNode from the field with the given + * FieldDescriptor. + * + * This method also changes the parent of the removed StructureNode to null. + * + * @param s is the StructureNode that shall be removed. + * @param fieldDescriptor is a FieldDescriptor defined in the Descriptor for + * this DocumentEntity. + + * @return true if this StructureNode was a child here and false if + * if was not found. + */ + bool removeStructureNodeFromField(Handle<StructureNode> s, + Handle<FieldDescriptor> fieldDescriptor); + + /** + * This removes a StructureNode from this DocumentEntity. It iterates + * through all fields to find it. + * + * This method also changes the parent of the removed StructureNode to null. + * + * @param s is the StructureNode that shall be removed. + + * @return true if this StructureNode was a child here and false if if was + * not found. + */ + bool removeStructureNode(Handle<StructureNode> s); }; /** @@ -372,6 +427,8 @@ public: * information please refer to the header documentation above. */ class StructuredEntity : public StructureNode, public DocumentEntity { + friend Document; + protected: bool doValidate(Logger &logger) const override; @@ -497,7 +554,7 @@ public: class Anchor : public StructureNode { protected: bool doValidate(Logger &logger) const override; - + public: /** * Constructor for Anchor. @@ -545,6 +602,7 @@ public: */ class AnnotationEntity : public Node, public DocumentEntity { friend DocumentEntity; + friend Document; private: Owned<Anchor> start; @@ -677,21 +735,32 @@ public: } /** - * Adds an AnnotationEntity to this document. This also sets the parent - * of the given AnnotationEntity if it is not set to this document already. + * Adds an AnnotationEntity to this Document. This also sets the parent + * of the given AnnotationEntity if it is not set to this Document already + * and removes it from the old Document. * * @param a is some AnnotationEntity */ void addAnnotation(Handle<AnnotationEntity> a); /** - * Adds multiple AnnotationEntities to this document. This also sets the - * parent of each given AnnotationEntity if it is not set to this document - * already. + * Adds multiple AnnotationEntities to this Document. This also sets the + * parent of each given AnnotationEntity if it is not set to this Document + * already and removes it from the old Document. * * @param as is a vector of AnnotationEntities. */ - void addAnnotations(const std::vector<Handle<AnnotationEntity>>& as); + void addAnnotations(const std::vector<Handle<AnnotationEntity>> &as); + + /** + * Removes an AnnotationEntity from this Document. This also sets the parent + * of the given AnnotationEntity to null. + * + * @param a is some AnnotationEntity. + * @return true if the given AnnotationEntity was removed and false if this + * Document did not have the given AnnotationEntity as child. + */ + bool removeAnnotation(Handle<AnnotationEntity> a); /** * Returns a const reference to the NodeVector of Domains that are used diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index 50bde9c..b425174 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -59,7 +59,7 @@ bool FieldDescriptor::doValidate(Logger &logger) const { bool valid = true; // check parent type - if(getParent() == nullptr){ + if (getParent() == nullptr) { logger.error("This field has no parent!"); valid = false; } else if (!getParent()->isa(RttiTypes::Descriptor)) { @@ -110,10 +110,10 @@ bool FieldDescriptor::doValidate(Logger &logger) const return valid; } - -bool FieldDescriptor::removeChild(Handle<StructuredClass> c){ +bool FieldDescriptor::removeChild(Handle<StructuredClass> c) +{ auto it = children.find(c); - if(it != children.end()){ + if (it != children.end()) { invalidate(); children.erase(it); return true; @@ -138,7 +138,7 @@ bool Descriptor::doValidate(Logger &logger) const { bool valid = true; // check parent type - if(getParent() == nullptr){ + if (getParent() == nullptr) { logger.error("This Descriptor has no parent!"); valid = false; } else if (!getParent()->isa(RttiTypes::Domain)) { @@ -149,7 +149,7 @@ bool Descriptor::doValidate(Logger &logger) const if (getName().empty()) { logger.error("The name of this Descriptor is empty!"); valid = false; - } else{ + } else { valid = valid & validateName(logger); } // check if all FieldDescriptors have this Descriptor as parent. @@ -244,9 +244,25 @@ bool Descriptor::continuePath(Handle<StructuredClass> target, return found; } +void Descriptor::addFieldDescriptor(Handle<FieldDescriptor> fd) +{ + // only add it if we need to. + if (fieldDescriptors.find(fd) == fieldDescriptors.end()) { + invalidate(); + fieldDescriptors.push_back(fd); + } + Handle<Managed> par = fd->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the FieldDescriptor from the old parent. + par.cast<Descriptor>()->removeFieldDescriptor(fd); + } + fd->setParent(this); + } +} + void Descriptor::copyFieldDescriptor(Handle<FieldDescriptor> fd) { - invalidate(); if (fd->getFieldType() == FieldDescriptor::FieldType::PRIMITIVE) { /* * To call the "new" operation is enough here, because the @@ -261,6 +277,18 @@ void Descriptor::copyFieldDescriptor(Handle<FieldDescriptor> fd) } } +bool Descriptor::removeFieldDescriptor(Handle<FieldDescriptor> fd) +{ + auto it = fieldDescriptors.find(fd); + if (it != fieldDescriptors.end()) { + invalidate(); + fieldDescriptors.erase(it); + fd->setParent(nullptr); + return true; + } + return false; +} + /* Class StructuredClass */ StructuredClass::StructuredClass(Manager &mgr, std::string name, @@ -341,11 +369,10 @@ bool StructuredClass::isSubclassOf(Handle<StructuredClass> c) const void StructuredClass::addSubclass(Handle<StructuredClass> sc) { // check if we already have that class. - if (subclasses.find(sc) != subclasses.end()) { - return; + if (subclasses.find(sc) == subclasses.end()) { + invalidate(); + subclasses.push_back(sc); } - invalidate(); - subclasses.push_back(sc); sc->setSuperclass(this); } @@ -427,21 +454,61 @@ bool Domain::doValidate(Logger &logger) const void Domain::addStructuredClass(Handle<StructuredClass> s) { - invalidate(); - structuredClasses.push_back(s); - if (s->getParent() != this) { + // only add it if we need to. + if (structuredClasses.find(s) == structuredClasses.end()) { + invalidate(); + structuredClasses.push_back(s); + } + Handle<Managed> par = s->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the StructuredClass from the old parent. + par.cast<Domain>()->removeStructuredClass(s); + } s->setParent(this); } } +bool Domain::removeStructuredClass(Handle<StructuredClass> s) +{ + auto it = structuredClasses.find(s); + if (it != structuredClasses.end()) { + invalidate(); + structuredClasses.erase(it); + s->setParent(nullptr); + return true; + } + return false; +} + void Domain::addAnnotationClass(Handle<AnnotationClass> a) { - invalidate(); - annotationClasses.push_back(a); - if (a->getParent() != this) { + // only add it if we need to. + if (annotationClasses.find(a) == annotationClasses.end()) { + invalidate(); + annotationClasses.push_back(a); + } + Handle<Managed> par = a->getParent(); + if (par != this) { + if (par != nullptr) { + // remove the StructuredClass from the old parent. + par.cast<Domain>()->removeAnnotationClass(a); + } a->setParent(this); } } + +bool Domain::removeAnnotationClass(Handle<AnnotationClass> a) +{ + auto it = annotationClasses.find(a); + if (it != annotationClasses.end()) { + invalidate(); + annotationClasses.erase(it); + a->setParent(nullptr); + return true; + } + return false; +} } /* Type registrations */ diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index e485171..12cb9b3 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -249,6 +249,8 @@ class Domain; * undefined state. */ class FieldDescriptor : public Node { + friend Descriptor; + public: /** * This enum class contains all possible FieldTypes, meaning either the @@ -508,33 +510,21 @@ public: /** * Adds the given FieldDescriptor to this Descriptor. This also sets the * parent of the given FieldDescriptor if it is not set to this Descriptor - * already. - * - * This should not be used if the given FieldDescriptor is a field of - * another Descriptor already. Use copyFieldDescriptor in that case. - * TODO: But this could get move semantics. + * already and removes it from the old parent Descriptor. * * @param fd is a FieldDescriptor. */ - void addFieldDescriptor(Handle<FieldDescriptor> fd) - { - invalidate(); - fieldDescriptors.push_back(fd); - if (fd->getParent() != this) { - fd->setParent(this); - } - } + void addFieldDescriptor(Handle<FieldDescriptor> fd); /** * Adds the given FieldDescriptors to this Descriptor. This also sets the * parent of each given FieldDescriptor if it is not set to this Descriptor - * already. + * already and removes it from the old parent Descriptor. * * @param fds are FieldDescriptors. */ void addFieldDescriptors(const std::vector<Handle<FieldDescriptor>> &fds) { - invalidate(); for (Handle<FieldDescriptor> fd : fds) { addFieldDescriptor(fd); } @@ -549,6 +539,16 @@ public: void copyFieldDescriptor(Handle<FieldDescriptor> fd); /** + * Removes the given FieldDescriptor from this Descriptor. This also sets + * the parent of the given FieldDescriptor to null. + * + * @param fd is a FieldDescriptor. + * @return true if the FieldDescriptor was removed and false if this + * Descriptor did not have the given FieldDescriptor as child. + */ + bool removeFieldDescriptor(Handle<FieldDescriptor> fd); + + /** * This tries to construct the shortest possible path of this Descriptor * to the given child Descriptor. As an example consider the book domain * from above. @@ -672,6 +672,8 @@ static const Cardinality AnyCardinality = createAny(); * What about the cardinality? */ class StructuredClass : public Descriptor { + friend Domain; + private: const Cardinality cardinality; Owned<StructuredClass> superclass; @@ -833,6 +835,8 @@ public: * This class has no special properties and is in essence just a Descriptor. */ class AnnotationClass : public Descriptor { + friend Domain; + public: /** * The constructor for a new AnnotationClass. Note that you have to add @@ -871,13 +875,7 @@ private: protected: void doResolve(ResolutionState &state) override; - /* - * TODO: doValidate with: - * # namecheck - * # are all structureclasses valid and have a unique name? - * # are all annotationclasses valid and have a unique name? - * # are all typesystems valid? - */ + bool doValidate(Logger &logger) const override; public: @@ -925,14 +923,24 @@ public: } /** * Adds a StructuredClass to this domain. This also sets the parent of the - * given StructuredClass if it is not set to this Domain already. - * TODO: This could have move semantics. + * given StructuredClass if it is not set to this Domain already and removes + * it from the old Domain. * * @param s is some StructuredClass. */ void addStructuredClass(Handle<StructuredClass> s); /** + * Removes a StructuredClass from this domain. This also sets the parent of + * the given StructuredClass to null. + * + * @param s is some StructuredClass. + * @return true if the given StructuredClass was removed and false if this + * Domain did not have the given StructuredClass as child. + */ + bool removeStructuredClass(Handle<StructuredClass> s); + + /** * Returns a const reference to the NodeVector of AnnotationClasses that are * part of this Domain. * @@ -945,14 +953,24 @@ public: } /** * Adds an AnnotationClass to this domain. This also sets the parent of the - * given AnnotationClass if it is not set to this Domain already. - * TODO: This could have move semantics. + * given AnnotationClass if it is not set to this Domain already and removes + * it from the old Domain. * * @param a is some AnnotationClass. */ void addAnnotationClass(Handle<AnnotationClass> a); /** + * Removes a AnnotationClass from this domain. This also sets the parent of + * the given AnnotationClass to null. + * + * @param a is some AnnotationClass. + * @return true if the given AnnotationClass was removed and false if this + * Domain did not have the given AnnotationClass as child. + */ + bool removeAnnotationClass(Handle<AnnotationClass> a); + + /** * Returns a const reference to the NodeVector of TypeSystems that are * references in this Domain. * diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp index 6b13c30..c5761a8 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -210,6 +210,13 @@ private: protected: /** + * Sets the parent node. + * + * @param parent is a Handle to the parent node. + */ + void setParent(Handle<Node> parent); + + /** * Function which should be overwritten by derived classes in order to * resolve node names to a list of possible nodes. The implementations of * this function do not need to do anything but call the @@ -451,13 +458,6 @@ public: Rooted<Managed> getParent() const { return parent; } /** - * Sets the parent node. - * - * @param parent is a Handle to the parent node. - */ - void setParent(Handle<Node> parent); - - /** * Returns true, if the node does not have a parent. Root nodes may either * be the root element of the complete DOM tree * @@ -512,6 +512,13 @@ public: * @return true if this Node is valid. */ bool validate(Logger &logger) const; + + /** + * Returns the current ValidationState of this Node. + * + * @return the current ValidationState of this Node. + */ + ValidationState getValidationState() const { return validationState; } }; /** diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index f4182fc..e0aa81e 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -660,7 +660,7 @@ protected: public: /** - * Private constructor of the StructType class, creates a new instance + * Constructor of the StructType class, creates a new instance * without performing any validity checks. * * @param mgr is the underlying Manager instance. @@ -680,7 +680,7 @@ public: * parameters for validity. * * @param mgr is the underlying Manager instance. - * @param name is the name of the EnumType instance. Should be a valid + * @param name is the name of the StructType instance. Should be a valid * identifier. * @param system is a reference to the parent Typesystem instance. * @param parentStructure is a reference to the StructType this type is diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index 874fba7..a9c0dcc 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -128,10 +128,12 @@ TEST(Document, validate) // first an invalid one, which is empty. Rooted<Document> doc{new Document(mgr, "myDoc.oxd")}; doc->addDomain(domain); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); // then add a root, which should make it valid. Rooted<StructuredEntity> root = buildRootStructuredEntity(doc, logger, {"root"}); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } { @@ -140,6 +142,7 @@ TEST(Document, validate) doc->addDomain(domain); Rooted<StructuredEntity> root = buildRootStructuredEntity( doc, logger, {"root"}, {}, "my invalid root"); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); } @@ -158,12 +161,15 @@ TEST(Document, validate) doc->addDomain(domain); Rooted<StructuredEntity> 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)); } /* @@ -180,6 +186,7 @@ TEST(Document, validate) Rooted<StructuredEntity> root = buildRootStructuredEntity(doc, logger, {"root"}); buildStructuredEntity(doc, logger, root, {"childSub"}); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } /* @@ -198,6 +205,7 @@ TEST(Document, validate) Rooted<StructuredEntity> root = buildRootStructuredEntity(doc, logger, {"root"}); buildStructuredEntity(doc, logger, root, {"childSub"}); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_FALSE(doc->validate(logger)); } /* @@ -215,6 +223,7 @@ TEST(Document, validate) Rooted<StructuredEntity> 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. @@ -231,14 +240,16 @@ TEST(Document, validate) buildRootStructuredEntity(doc, logger, {"root"}); Rooted<StructuredEntity> 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<DocumentPrimitive> primitive{ new DocumentPrimitive(mgr, child, {"ololol"}, "int")}; - //TODO: ASSERT_FALSE(doc->validate(logger)); + 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)); } @@ -258,14 +269,41 @@ TEST(Document, validate) Rooted<DocumentPrimitive> primitive{ new DocumentPrimitive(mgr, child, {2}, "int")}; Rooted<Anchor> end{new Anchor(mgr, "end", root)}; + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); // then add an AnnotationEntity without Anchors. Rooted<AnnotationEntity> 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{StructType::createValidated( + mgr, "attributes", nullptr, nullptr, + NodeVector<Attribute>{ + new Attribute{mgr, "myAttr", sys->getStringType(), "default"}}, + logger)}; + childSubClass->setAttributesDescriptor(structType); + // the right map content should be valid now. + child->setAttributes( + std::map<std::string, Variant>{{"myAttr", "content"}}); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); + ASSERT_TRUE(doc->validate(logger)); + // but an empty map as well + child->setAttributes(std::map<std::string, Variant>()); + ASSERT_EQ(ValidationState::UNKNOWN, doc->getValidationState()); ASSERT_TRUE(doc->validate(logger)); } } diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp index 8ece2c9..2b63aeb 100644 --- a/test/core/model/DomainTest.cpp +++ b/test/core/model/DomainTest.cpp @@ -293,77 +293,91 @@ TEST(Domain, validate) // start with an easy example: Our book domain should be valid. { Rooted<Domain> domain = constructBookDomain(mgr, sys, logger); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); } { // Even easier: An empty domain should be valid. Rooted<Domain> domain{new Domain(mgr, sys, "domain")}; + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); // if we add a StructureClass it should be valid still. Rooted<StructuredClass> base{ new StructuredClass(mgr, "myClass", domain)}; + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); - // if we tamper with the parent reference, however, it shouldn't be - // valid anymore. - base->setParent(nullptr); - ASSERT_FALSE(base->validate(logger)); - base->setParent(domain); - ASSERT_TRUE(domain->validate(logger)); - // the same goes for the name. + // if we tamper with the name, however, it shouldn't be valid anymore. base->setName(""); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); base->setName("my class"); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); base->setName("myClass"); + 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)}; // this should not be valid. + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); // but it should be if we set the type. 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. + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); // and still if we add a superclass. sub->setSuperclass(base); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); // and still we we remove the subclass from the base class. base->removeSubclass(sub); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); ASSERT_EQ(nullptr, sub->getSuperclass()); // and still if we re-add it. base->addSubclass(sub); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); 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()); + 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. sub_field->addChild(base); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); // it should be invalid if we add it twice. sub_field->addChild(base); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); // and valid again if we remove it once. sub_field->removeChild(base); + ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); } } |