From 6f1954eb9eed34aa1b5836bd1a2d153470cf3d59 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Wed, 21 Jan 2015 00:30:28 +0100 Subject: introduced Domain validation functionality and a Unit test for it. --- src/core/model/Domain.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++++-- src/core/model/Domain.hpp | 47 +++++++-------- 2 files changed, 164 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index 0fc078f..50bde9c 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -55,6 +55,72 @@ FieldDescriptor::FieldDescriptor(Manager &mgr, Handle parent, } } +bool FieldDescriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if(getParent() == nullptr){ + logger.error("This field has no parent!"); + valid = false; + } else if (!getParent()->isa(RttiTypes::Descriptor)) { + logger.error("The parent of this field is not a descriptor!"); + valid = false; + } + // check name + if (!getName().empty()) { + valid = valid & validateName(logger); + } + // check consistency of FieldType with the rest of the FieldDescriptor. + if (fieldType == FieldType::PRIMITIVE) { + if (children.size() > 0) { + logger.error( + "This field is supposed to be primitive but has " + "registered child classes!"); + valid = false; + } + if (primitiveType == nullptr) { + logger.error( + "This field is supposed to be primitive but has " + "no primitive type!"); + valid = false; + } + } else { + if (primitiveType != nullptr) { + logger.error( + "This field is supposed to be non-primitive but has " + "a primitive type!"); + valid = false; + } + } + /* + * we are not allowed to call the validation functions of each child because + * this might lead to cycles. What we should do, however, is to check if + * there are no duplicates. + */ + std::set names; + for (Handle c : children) { + if (!names.insert(c->getName()).second) { + logger.error(std::string("Field \"") + getName() + + "\" had multiple children with the name \"" + + c->getName() + "\""); + valid = false; + } + } + + return valid; +} + + +bool FieldDescriptor::removeChild(Handle c){ + auto it = children.find(c); + if(it != children.end()){ + invalidate(); + children.erase(it); + return true; + } + return false; +} + /* Class Descriptor */ void Descriptor::doResolve(ResolutionState &state) @@ -68,6 +134,40 @@ void Descriptor::doResolve(ResolutionState &state) state); } +bool Descriptor::doValidate(Logger &logger) const +{ + bool valid = true; + // check parent type + if(getParent() == nullptr){ + logger.error("This Descriptor has no parent!"); + valid = false; + } else if (!getParent()->isa(RttiTypes::Domain)) { + logger.error("The parent of this Descriptor is not a Domain!"); + valid = false; + } + // check name + if (getName().empty()) { + logger.error("The name of this Descriptor is empty!"); + valid = false; + } else{ + valid = valid & validateName(logger); + } + // check if all FieldDescriptors have this Descriptor as parent. + for (Handle fd : fieldDescriptors) { + if (fd->getParent() != this) { + logger.error(std::string("Descriptor \"") + getName() + + "\" has " + "field \"" + + fd->getName() + + "\" as child but the field does not " + "have the Descriptor as parent."); + valid = false; + } + } + // check the FieldDescriptors themselves. + return valid & continueValidationCheckDuplicates(fieldDescriptors, logger); +} + std::vector> Descriptor::pathTo( Handle target) const { @@ -184,19 +284,47 @@ StructuredClass::StructuredClass(Manager &mgr, std::string name, } } +bool StructuredClass::doValidate(Logger &logger) const +{ + bool valid = true; + // check if all registered subclasses have this StructuredClass as parent. + for (Handle sub : subclasses) { + if (sub->getSuperclass() != this) { + logger.error(std::string("Struct \"") + sub->getName() + + "\" is registered as subclass of \"" + getName() + + "\" but does not have it as superclass!"); + valid = false; + } + } + // check the validity of this superclass. + if (superclass != nullptr) { + valid = valid & superclass->validate(logger); + } + // check the validity as a Descriptor. + /* + * Note that we do not check the validity of all subclasses. This is because + * it will lead to cycles as the subclasses would call validate on their + * superclass, which is this one. + */ + return valid & Descriptor::doValidate(logger); +} + void StructuredClass::setSuperclass(Handle sup) { if (superclass == sup) { return; } - invalidate(); - if (sup != nullptr) { - sup->addSubclass(this); - } + // remove this subclass from the old superclass. if (superclass != nullptr) { superclass->removeSubclass(this); } + // set the new superclass superclass = acquire(sup); + invalidate(); + // add this class as new subclass of the new superclass. + if (sup != nullptr) { + sup->addSubclass(this); + } } bool StructuredClass::isSubclassOf(Handle c) const @@ -287,6 +415,16 @@ void Domain::doResolve(ResolutionState &state) } } +bool Domain::doValidate(Logger &logger) const +{ + // check validity of name, of StructuredClasses, of AnnotationClasses and + // TypeSystems. + return validateName(logger) & + continueValidationCheckDuplicates(structuredClasses, logger) & + continueValidationCheckDuplicates(annotationClasses, logger) & + continueValidationCheckDuplicates(typesystems, logger); +} + void Domain::addStructuredClass(Handle s) { invalidate(); @@ -323,4 +461,3 @@ const Rtti Domain = RttiBuilder("Domain") .composedOf({&StructuredClass, &AnnotationClass}); } } - diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index e4a6967..e485171 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -271,13 +271,9 @@ private: Owned primitiveType; bool optional; - /* - * TODO: doValidate with: - * # primitive and primitiveType set and no children XOR other FieldType and - * no primitive type set - * # namecheck - * # parent typecheck - */ +protected: + bool doValidate(Logger &logger) const override; + public: /** * This is the constructor for primitive fields. The type is automatically @@ -347,6 +343,17 @@ public: children.insert(children.end(), cs.begin(), cs.end()); } + /** + * Removes the given StructuredClass from the list of children of this + * FieldDescriptor. + * + * @param c some StructuredClass that shan't be a child of this + * FieldDescriptor anymore. + * @return true if the FieldDescriptor contained this child and false if it + * did not. + */ + bool removeChild(Handle c); + /** * Returns the type of this field (not to be confused with the primitive * type of this field). @@ -451,14 +458,8 @@ private: protected: void doResolve(ResolutionState &state) override; - /* - * TODO: doValidate with: - * # namecheck - * # FieldDescriptor name uniqueness - * # do all FieldDescriptors have this Descriptor as parent? - * # is the parent a domain? - * # is the attributes descriptor either not set or a StructType? - */ + + bool doValidate(Logger &logger) const override; public: Descriptor(Manager &mgr, std::string name, Handle domain, @@ -584,12 +585,12 @@ public: */ typedef RangeSet Cardinality; - /** * This is the default cardinality. */ -static Cardinality createAny(){ +static Cardinality createAny() +{ Cardinality any; any.merge(Range::typeRangeFrom(0)); return std::move(any); @@ -685,14 +686,8 @@ private: NodeVector ¤t, std::set &overriddenFields) const; - - - /* - * TODO: doValidate with - * # does the subclasses have this class as superclass? - * # are the subclasses and the superclass valid? - * # is this a valid descriptor? - */ +protected: + bool doValidate(Logger &logger) const override; public: /** @@ -883,6 +878,8 @@ protected: * # are all annotationclasses valid and have a unique name? * # are all typesystems valid? */ + bool doValidate(Logger &logger) const override; + public: /** * The constructor for a new domain. Note that this is an empty Domain and -- cgit v1.2.3