summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-12-19 15:36:41 +0100
committerAndreas Stöckel <andreas@somweyr.de>2014-12-19 15:36:41 +0100
commit2eda4f5ba1e3ed0577e3804110debf102abc9d43 (patch)
treef7f823e10d32ebc96aba8d9014a148bd6a6d3a9b
parent6fa81636f088654f154534fd939421a5b25d9c5c (diff)
parent3654efa59547d23b3c27715483999570daedc0b3 (diff)
Merge branch 'master' of somweyr.de:ousia
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/core/Node.hpp5
-rw-r--r--src/core/managed/ManagedContainer.hpp11
-rw-r--r--src/core/model/Document.cpp104
-rw-r--r--src/core/model/Document.hpp108
-rw-r--r--src/core/model/Domain.cpp54
-rw-r--r--src/core/model/Domain.hpp112
-rw-r--r--src/core/model/Typesystem.hpp80
-rw-r--r--test/core/managed/ManagedContainerTest.cpp41
-rw-r--r--test/core/model/DocumentTest.cpp44
-rw-r--r--test/core/model/DomainTest.cpp100
-rw-r--r--test/core/model/TestDocument.hpp84
-rw-r--r--test/core/model/TestDomain.hpp94
13 files changed, 767 insertions, 72 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 285abca..077ac47 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -184,6 +184,8 @@ IF(TEST)
test/core/managed/ManagedContainerTest
test/core/managed/ManagedTest
test/core/managed/ManagerTest
+ test/core/model/DomainTest
+ test/core/model/DocumentTest
test/core/parser/ParserStackTest
# test/core/script/FunctionTest
# test/core/script/ObjectTest
diff --git a/src/core/Node.hpp b/src/core/Node.hpp
index 4bc95be..516da03 100644
--- a/src/core/Node.hpp
+++ b/src/core/Node.hpp
@@ -350,6 +350,11 @@ public:
* Returns the name of the node.
*/
std::string getName() const { return name; }
+
+ /**
+ * Returns a reference to the name of the node.
+ */
+ const std::string& getNameRef() const { return name; }
/**
* Specifies whether the node has a name, e.g. whether the current name is
diff --git a/src/core/managed/ManagedContainer.hpp b/src/core/managed/ManagedContainer.hpp
index 19bff3f..6bf1915 100644
--- a/src/core/managed/ManagedContainer.hpp
+++ b/src/core/managed/ManagedContainer.hpp
@@ -32,6 +32,7 @@
#include <unordered_set>
#include <vector>
#include <map>
+#include <stdexcept>
#include <type_traits>
#include "Manager.hpp"
@@ -496,6 +497,16 @@ public:
}
Base::c.pop_back();
}
+
+ Rooted<T> operator[](int i) const {
+ for (const_iterator it = Base::cbegin(); it != Base::cend(); it++) {
+ if (i == 0) {
+ return Rooted<T>(*it);
+ }
+ i--;
+ }
+ throw std::out_of_range(std::to_string(i) + " is out of range!");
+ }
};
/**
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index 31b22e3..709981b 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -58,7 +58,7 @@ int DocumentEntity::getFieldDescriptorIndex(const std::string &fieldName)
}
void DocumentEntity::getField(ManagedVector<StructuredEntity> &res,
- const std::string &fieldName)
+ const std::string &fieldName)
{
int f = getFieldDescriptorIndex(fieldName);
if (f < 0) {
@@ -85,6 +85,108 @@ ManagedVector<StructuredEntity> &DocumentEntity::getField(
"The given FieldDescriptor is not specified in the Descriptor of this "
"node.");
}
+
+static Rooted<StructuredClass> resolveDescriptor(
+ std::vector<Handle<Domain>> domains, const std::string &className)
+{
+ // iterate over all domains.
+ for (auto &d : domains) {
+ // use the actual resolve method.
+ std::vector<Rooted<Managed>> resolved = d->resolve(className);
+ // if we don't find anything, continue.
+ if (resolved.size() == 0) {
+ continue;
+ }
+ // Otherwise take the first valid result.
+ for (auto &r : resolved) {
+ Managed *m = &(*r);
+ StructuredClass *c = dynamic_cast<StructuredClass *>(m);
+ if (c != nullptr) {
+ return Rooted<StructuredClass>(c);
+ }
+ }
+ }
+ return {nullptr};
+}
+
+Rooted<StructuredEntity> StructuredEntity::buildRootEntity(
+ Handle<Document> document, std::vector<Handle<Domain>> domains,
+ const std::string &className, Variant attributes, std::string name)
+{
+ // If the parent is not set, we can not build the entity.
+ if (document == nullptr) {
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the entity
+ // either.
+ Rooted<StructuredClass> descriptor = resolveDescriptor(domains, className);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<StructuredEntity> root{
+ new StructuredEntity(document->getManager(), document, descriptor,
+ attributes, std::move(name))};
+ // append it to the document.
+ document->setRoot(root);
+ // and return it.
+ return root;
+}
+
+Rooted<StructuredEntity> StructuredEntity::buildEntity(
+ Handle<DocumentEntity> parent, std::vector<Handle<Domain>> domains,
+ const std::string &className, const std::string &fieldName,
+ Variant attributes, std::string name)
+{
+ // If the parent is not set, we can not build the entity.
+ if (parent == nullptr) {
+ return {nullptr};
+ }
+ // If we can not find the correct descriptor, we can not build the entity
+ // either.
+ Rooted<StructuredClass> descriptor = resolveDescriptor(domains, className);
+ if (descriptor == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<StructuredEntity> entity{new StructuredEntity(
+ parent->getManager(), parent, descriptor, attributes, std::move(name))};
+ // if the field does not exist, return null handle as well.
+ if (!parent->hasField(fieldName)) {
+ return {nullptr};
+ }
+ // append the new entity to the right field.
+ ManagedVector<StructuredEntity> field{parent};
+ parent->getField(field, fieldName);
+ field.push_back(entity);
+
+ // and return it.
+ return entity;
+}
+
+Rooted<DocumentPrimitive> DocumentPrimitive::buildEntity(
+ Handle<DocumentEntity> parent, Variant content,
+ const std::string &fieldName)
+{
+ // If the parent is not set, we can not build the entity.
+ if (parent == nullptr) {
+ return {nullptr};
+ }
+ // Then construct the StructuredEntity itself.
+ Rooted<DocumentPrimitive> entity{
+ new DocumentPrimitive(parent->getManager(), parent, content)};
+ // if the field does not exist, return null handle as well.
+ if (!parent->hasField(fieldName)) {
+ return {nullptr};
+ }
+ // append the new entity to the right field.
+ ManagedVector<StructuredEntity> field{parent};
+ parent->getField(field, fieldName);
+ field.push_back(entity);
+
+ // and return it.
+ return entity;
+}
}
}
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 3114480..15a4599 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -26,9 +26,11 @@
*
* A Document, from top to bottom, consists of "Document" instance,
* which "owns" the structural root node of the in-document graph. This might
- * for example be a "book" node, if the respective document implements the
- * "book" domain. That root node in turn has structure nodes as children as well
- * as annotations that refer to the content of that structure node.
+ * for example be a "book" node of the "book" domain. That root node in turn has
+ * structure nodes as children, which in turn may have children. This
+ * constitutes a Structure Tree. Additionally annotations may be attached to
+ * Structure Nodes, effectively resulting in a Document Graph instead of a
+ * Document Tree (other references may introduce cycles as well).
*
* Consider this simplified XML representation of a document (TODO: Use
* non-simplified XML as soon as possible):
@@ -78,6 +80,7 @@ namespace model {
class StructuredEntity;
class AnnotationEntity;
+class Document;
/**
* A DocumentEntity is the common superclass for StructuredEntities and
@@ -108,8 +111,11 @@ public:
{
// TODO: Validation at construction time?
// insert empty vectors for each field.
- for (size_t f = 0; f < descriptor->getFieldDescriptors().size(); f++) {
- fields.push_back(ManagedVector<StructuredEntity>(this));
+ if (!descriptor.isNull()) {
+ for (size_t f = 0; f < descriptor->getFieldDescriptors().size();
+ f++) {
+ fields.push_back(ManagedVector<StructuredEntity>(this));
+ }
}
}
@@ -200,6 +206,57 @@ public:
}
ManagedVector<AnnotationEntity> &getAnnotations() { return annotations; }
+
+ /**
+ * This builds the root StructuredEntity for the given document. It
+ * automatically appends the newly build entity to the given document.
+ *
+ * @param document is the document this entity shall be build for. The
+ * resulting entity will automatically be appended to that
+ * document. Also the manager of that document will be
+ * used to register the new node.
+ * @param domains are the domains that are used to find the
+ * StructuredClass for the new node. The domains will be
+ * searched in the given order.
+ * @param className is the name of the StructuredClass.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this StructuredEntity (empty per
+ * default).
+ * @return the newly created StructuredEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a StructuredClass with the given name.
+ */
+ static Rooted<StructuredEntity> buildRootEntity(
+ Handle<Document> document, std::vector<Handle<Domain>> domains,
+ const std::string &className, Variant attributes = Variant(),
+ std::string name = "");
+
+ /**
+ * This builds a StructuredEntity as child of the given DocumentEntity. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * StructuredEntity will automatically be appended to it.
+ * @param domains are the domains that are used to find the
+ * StructuredClass for the new node. The domains will be
+ * searched in the given order.
+ * @param className is the name of the StructuredClass.
+ * @param fieldName is the name of the field where the newly constructed
+ * StructuredEntity shall be appended.
+ * @param attributes are the attributes of the new node in terms of a Struct
+ * variant (empty per default).
+ * @param name is the name of this StructuredEntity (empty per
+ * default).
+ *
+ * @return the newly created StructuredEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a StructuredClass with the given name.
+ */
+ static Rooted<StructuredEntity> buildEntity(
+ Handle<DocumentEntity> parent, std::vector<Handle<Domain>> domains,
+ const std::string &className, const std::string &fieldName = "",
+ Variant attributes = Variant(), std::string name = "");
};
/**
@@ -209,7 +266,7 @@ public:
*/
class DocumentPrimitive : public StructuredEntity {
public:
- DocumentPrimitive(Manager &mgr, Handle<StructuredEntity> parent,
+ DocumentPrimitive(Manager &mgr, Handle<DocumentEntity> parent,
Variant content)
: StructuredEntity(mgr, parent, nullptr, std::move(content))
{
@@ -218,6 +275,25 @@ public:
Variant getContent() const { return getAttributes(); }
// TODO: Override such methods like "getField" to disable them?
+
+ /**
+ * This builds a DocumentPrimitive as child of the given DocumentEntity. It
+ * automatically appends the newly build entity to its parent.
+ *
+ * @param parent is the parent DocumentEntity. The newly constructed
+ * DocumentPrimitive will automatically be appended to it.
+ * @param content is the primitive content of the new node in terms of a
+ * Struct variant.
+ * @param fieldName is the name of the field where the newly constructed
+ * StructuredEntity shall be appended.
+ *
+ * @return the newly created StructuredEntity or a nullptr if some
+ * input handle was empty or the given domains did not
+ * contain a StructuredClass with the given name.
+ */
+ static Rooted<DocumentPrimitive> buildEntity(
+ Handle<DocumentEntity> parent,
+ Variant content, const std::string &fieldName = "");
};
/**
@@ -282,6 +358,26 @@ public:
Rooted<Anchor> getEnd() { return end; }
};
+
+/**
+ * A Document is mainly a wrapper for the Root structure node of the Document
+ * Graph.
+ */
+class Document : public Node {
+private:
+ Owned<StructuredEntity> root;
+
+public:
+ Document(Manager &mgr, std::string name)
+ // TODO: Can a document have a parent?
+ : Node(mgr, std::move(name), nullptr)
+ {
+ }
+
+ void setRoot(Handle<StructuredEntity> root) { root = acquire(root); };
+
+ Rooted<StructuredEntity> getRoot() const { return root; }
+};
}
}
diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp
index bafd205..8eee86a 100644
--- a/src/core/model/Domain.cpp
+++ b/src/core/model/Domain.cpp
@@ -21,6 +21,60 @@
namespace ousia {
namespace model {
+void FieldDescriptor::doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path,
+ Filter filter, void *filterData, unsigned idx,
+ VisitorSet &visited)
+{
+ // We call resolve for the children, but give them the field name as
+ // alias.
+ for (auto &c : children) {
+ c->resolve(res, path, filter, filterData, idx, visited, &getNameRef());
+ }
+}
+
+// TODO: better alias?
+static std::string DESCRIPTOR_ATTRIBUTES_ALIAS {"attributes"};
+
+void Descriptor::doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited)
+{
+ // TODO: This could be a problem, because the name of the field might be
+ // needed in the path.
+ for (auto &fd : fieldDescriptors) {
+ fd->resolve(res, path, filter, filterData, idx, visited, nullptr);
+ }
+ // TODO: This throws a SEGFAULT for some reason.
+// attributesDescriptor->resolve(res, path, filter, filterData, idx, visited,
+// &DESCRIPTOR_ATTRIBUTES_ALIAS);
+}
+
+void StructuredClass::doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path,
+ Filter filter, void *filterData, unsigned idx,
+ VisitorSet &visited)
+{
+ Descriptor::doResolve(res, path, filter, filterData, idx, visited);
+ if(!isa.isNull()){
+ isa->doResolve(res, path, filter, filterData, idx, visited);
+ }
+}
+
+void Domain::doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx, VisitorSet &visited)
+{
+ for (auto &s : rootStructures) {
+ s->resolve(res, path, filter, filterData, idx, visited, nullptr);
+ }
+ for (auto &a : annotationClasses) {
+ a->resolve(res, path, filter, filterData, idx, visited, nullptr);
+ }
+ for (auto &t : typesystems) {
+ t->resolve(res, path, filter, filterData, idx, visited, nullptr);
+ }
+}
}
}
diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp
index 50c0bb1..112f2fa 100644
--- a/src/core/model/Domain.hpp
+++ b/src/core/model/Domain.hpp
@@ -84,14 +84,16 @@
#include <core/managed/ManagedContainer.hpp>
#include <core/Node.hpp>
+#include <core/RangeSet.hpp>
#include "Typesystem.hpp"
namespace ousia {
namespace model {
-class StructuredClass;
class Descriptor;
+class StructuredClass;
+class Domain;
/**
* As mentioned in the description above a FieldDescriptor specifies the
@@ -137,6 +139,12 @@ private:
FieldType fieldType;
Owned<Type> primitiveType;
+protected:
+ void doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx,
+ VisitorSet &visited) override;
+
public:
const bool optional;
@@ -146,17 +154,18 @@ public:
* set to "PRIMITIVE".
*
* @param mgr is the global Manager instance.
- * @param name is the name of this field.
* @param parent is a handle of the Descriptor node that has this
* FieldDescriptor.
* @param primitiveType is a handle to some Type in some Typesystem of which
* one instance is allowed to fill this field.
+ * @param name is the name of this field.
* @param optional should be set to 'false' is this field needs to be
* filled in order for an instance of the parent
* Descriptor to be valid.
*/
- FieldDescriptor(Manager &mgr, std::string name, Handle<Descriptor> parent,
- Handle<Type> primitiveType, bool optional)
+ FieldDescriptor(Manager &mgr, Handle<Descriptor> parent,
+ Handle<Type> primitiveType, std::string name = "",
+ bool optional = false)
: Node(mgr, std::move(name), parent),
children(this),
fieldType(FieldType::PRIMITIVE),
@@ -170,21 +179,21 @@ public:
* children here.
*
* @param mgr is the global Manager instance.
- * @param name is the name of this field.
* @param parent is a handle of the Descriptor node that has this
* FieldDescriptor.
* @param fieldType is the FieldType of this FieldDescriptor, either
* TREE for the main or default structure or SUBTREE
* for supporting structures.
+ * @param name is the name of this field.
* @param optional should be set to 'false' is this field needs to be
* filled in order for an instance of the parent
* Descriptor to be valid.
*/
- FieldDescriptor(Manager &mgr, std::string name, Handle<Descriptor> parent,
- FieldType fieldType,
- ManagedVector<StructuredClass> children, bool optional)
+ FieldDescriptor(Manager &mgr, Handle<Descriptor> parent,
+ FieldType fieldType = FieldType::TREE,
+ std::string name = "", bool optional = false)
: Node(mgr, std::move(name), parent),
- children(children),
+ children(this),
fieldType(fieldType),
// TODO: What would be a wise initialization of the primitiveType?
optional(optional)
@@ -194,6 +203,11 @@ public:
// TODO: Is returning a ManagedVector alright?
ManagedVector<StructuredClass> &getChildren() { return children; }
+ const ManagedVector<StructuredClass> &getChildren() const
+ {
+ return children;
+ }
+
FieldType getFieldType() const { return fieldType; }
bool isPrimitive() const { return fieldType == FieldType::PRIMITIVE; }
@@ -212,7 +226,7 @@ public:
* the attribute specification of a descriptor is done by referencing an
* appropriate StructType that contains all permitted keys and value types.
*
- * TODO: What aout optional attributes?
+ * TODO: What about optional attributes?
*
* In XML terms the difference between primitive fields and attributes can be
* explained as the difference between node attributes and node children.
@@ -233,14 +247,19 @@ private:
Owned<StructType> attributesDescriptor;
ManagedVector<FieldDescriptor> fieldDescriptors;
+protected:
+ void doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx,
+ VisitorSet &visited) override;
+
public:
- Descriptor(Manager &mgr, std::string name, Handle<Node> parent,
+ Descriptor(Manager &mgr, std::string name, Handle<Domain> domain,
// TODO: What would be a wise default value for attributes?
- Handle<StructType> attributesDescriptor,
- ManagedVector<FieldDescriptor> fieldDescriptors)
- : Node(mgr, std::move(name), parent),
+ Handle<StructType> attributesDescriptor)
+ : Node(mgr, std::move(name), domain),
attributesDescriptor(acquire(attributesDescriptor)),
- fieldDescriptors(fieldDescriptors)
+ fieldDescriptors(this)
{
}
@@ -261,9 +280,7 @@ public:
}
};
-// TODO: Implement
-class Cardinality {
-};
+typedef RangeSet<size_t> Cardinality;
/**
* A StructuredClass specifies nodes in the StructureTree of a document that
@@ -346,21 +363,25 @@ private:
Owned<StructuredClass> isa;
ManagedVector<FieldDescriptor> parents;
+protected:
+ void doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx,
+ VisitorSet &visited) override;
+
public:
const bool transparent;
- StructuredClass(Manager &mgr, std::string name, Handle<Node> parent,
- Handle<StructType> attributesDescriptor,
- ManagedVector<FieldDescriptor> fieldDescriptors,
+ StructuredClass(Manager &mgr, std::string name, Handle<Domain> domain,
const Cardinality &cardinality,
+ Handle<StructType> attributesDescriptor = {nullptr},
// TODO: What would be a wise default value for isa?
- Handle<StructuredClass> isa,
- ManagedVector<FieldDescriptor> parents, bool transparent)
- : Descriptor(mgr, std::move(name), parent, attributesDescriptor,
- fieldDescriptors),
+ Handle<StructuredClass> isa = {nullptr},
+ bool transparent = false)
+ : Descriptor(mgr, std::move(name), domain, attributesDescriptor),
cardinality(cardinality),
isa(acquire(isa)),
- parents(parents),
+ parents(this),
transparent(transparent)
{
}
@@ -370,7 +391,7 @@ public:
Rooted<StructuredClass> getIsA() const { return isa; }
// TODO: Is returning a ManagedVector alright?
- ManagedVector<FieldDescriptor>& getParents() { return parents; }
+ ManagedVector<FieldDescriptor> &getParents() { return parents; }
const ManagedVector<FieldDescriptor> &getParents() const { return parents; }
};
@@ -394,28 +415,51 @@ class Domain : public Node {
private:
ManagedVector<StructuredClass> rootStructures;
ManagedVector<AnnotationClass> annotationClasses;
+ ManagedVector<Typesystem> typesystems;
+
+protected:
+ void doResolve(std::vector<Rooted<Managed>> &res,
+ const std::vector<std::string> &path, Filter filter,
+ void *filterData, unsigned idx,
+ VisitorSet &visited) override;
public:
- Domain(Manager &mgr, std::string name,
- ManagedVector<StructuredClass> rootStructures,
- ManagedVector<AnnotationClass> annotationClasses)
+ Domain(Manager &mgr, std::string name)
// TODO: Can a domain have a parent?
: Node(mgr, std::move(name), nullptr),
- rootStructures(rootStructures),
- annotationClasses(annotationClasses)
+ rootStructures(this),
+ annotationClasses(this),
+ typesystems(this)
{
}
// TODO: Is returning a ManagedVector alright?
- ManagedVector<StructuredClass> getRootStructures()
+ ManagedVector<StructuredClass> &getRootStructures()
{
return rootStructures;
}
- ManagedVector<AnnotationClass> getAnnotationClasses()
+ const ManagedVector<StructuredClass> &getRootStructures() const
+ {
+ return rootStructures;
+ }
+
+ ManagedVector<AnnotationClass> &getAnnotationClasses()
+ {
+ return annotationClasses;
+ }
+
+ const ManagedVector<AnnotationClass> &getAnnotationClasses() const
{
return annotationClasses;
}
+
+ ManagedVector<Typesystem> &getTypesystems() { return typesystems; }
+
+ const ManagedVector<Typesystem> &getTypesystems() const
+ {
+ return typesystems;
+ }
};
}
}
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 347adb8..20c6e8b 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -50,7 +50,7 @@ protected:
{
}
- virtual bool doPrepare(Variant &var, Logger &log) = 0;
+ virtual bool doPrepare(Variant &var, Logger &log) const = 0;
public:
/**
@@ -65,12 +65,12 @@ public:
/**
* TODO: DOC
*/
- virtual Variant create() = 0;
+ virtual Variant create() const = 0;
/**
* TODO: DOC
*/
- bool prepare(Variant &var, Logger &log)
+ bool prepare(Variant &var, Logger &log) const
{
try {
return doPrepare(var, log);
@@ -88,7 +88,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (!var.isPrimitive()) {
throw LoggableException{"Expected a string or primitive input."};
@@ -114,7 +114,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{""}; }
+ Variant create() const override { return Variant{""}; }
};
class IntType : public Type {
@@ -122,7 +122,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (!var.isInt()) {
throw LoggableException{"Expected an integer value."};
@@ -142,7 +142,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{0}; }
+ Variant create() const override { return Variant{0}; }
};
class DoubleType : public Type {
@@ -150,7 +150,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (!var.isInt() && !var.isDouble()) {
throw LoggableException{"Expected a double value."};
@@ -171,7 +171,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{0.}; }
+ Variant create() const override { return Variant{0.}; }
};
class UnknownType : public Type {
@@ -179,7 +179,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override { return true; }
+ bool doPrepare(Variant &var, Logger &log) const override { return true; }
public:
/**
@@ -193,7 +193,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{nullptr}; }
+ Variant create() const override { return Variant{nullptr}; }
};
class BoolType : public Type {
@@ -201,7 +201,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (!var.isBool()) {
throw LoggableException("Expected boolean value!");
@@ -221,7 +221,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{false}; }
+ Variant create() const override { return Variant{false}; }
};
class EnumerationType : public Type {
@@ -232,7 +232,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (var.isInt()) {
int i = var.asInt();
@@ -275,7 +275,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{0}; }
+ Variant create() const override { return Variant{0}; }
};
class StructType : public Type {
@@ -296,7 +296,45 @@ public:
}
};
-private:
+protected:
+ /**
+ * TODO: DOC
+ */
+ bool doPrepare(Variant &var, Logger &log) const override
+ {
+ // If we already have an array, we just check that.
+ if(var.isArray()){
+ auto arr = var.asArray();
+ for(size_t a = 0; a < attrs.size(); a++){
+ if(!attrs[a].type->prepare(arr[a], log)){
+ return false;
+ }
+ }
+ return true;
+ }
+ // Otherwise we expect a map.
+ if (!var.isMap()) {
+ throw LoggableException("Expected map!");
+ }
+ auto &map = var.asMap();
+ // We transform the map into an array with the correct values at the
+ // correct places.
+ std::vector<Variant> vec;
+ for (auto &a : attrs) {
+ auto it = map.find(a.name);
+ // we use the default if nothing is set.
+ if (it == map.end() || !a.type->prepare(it->second, log)) {
+ log.note(std::string("Using default value for ") + a.name);
+ vec.push_back(a.defaultValue);
+ } else{
+ vec.push_back(it->second);
+ }
+ }
+ var = Variant(vec);
+ return true;
+ }
+
+public:
std::vector<AttributeDescriptor> attrs;
StructType(Manager &mgr, std::string name, Handle<Typesystem> system,
@@ -305,15 +343,13 @@ private:
attrs(std::move(attrs))
{
}
-
-public:
// TODO
// static StructType createValidated(
// Manager &mgr, std::string name, Handle<Typesystem> system,
// Handle<StructType> parent,
// const std::vector<AttributeDescriptor> &attrs, Logger &logger);
- Variant create() override { return Variant{Variant::arrayType{}}; }
+ Variant create() const override { return Variant{Variant::arrayType{}}; }
};
class ArrayType : public Type {
@@ -324,7 +360,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) override
+ bool doPrepare(Variant &var, Logger &log) const override
{
if (!var.isArray()) {
throw LoggableException("Expected array!");
@@ -353,7 +389,7 @@ public:
/**
* TODO: DOC
*/
- Variant create() override { return Variant{Variant::arrayType{}}; }
+ Variant create() const override { return Variant{Variant::arrayType{}}; }
Rooted<Type> getType() { return innerType; }
};
@@ -372,6 +408,8 @@ public:
* TODO: DOC
*/
void addType(Handle<Type> type) { types.push_back(type); }
+
+ const NodeVector<Type> &getTypes() const { return types; }
};
}
}
diff --git a/test/core/managed/ManagedContainerTest.cpp b/test/core/managed/ManagedContainerTest.cpp
index c34541a..7ff819f 100644
--- a/test/core/managed/ManagedContainerTest.cpp
+++ b/test/core/managed/ManagedContainerTest.cpp
@@ -38,7 +38,7 @@ TEST(ManagedVector, managedVector)
{
Rooted<Managed> root{new Managed{mgr}};
- std::vector<TestManaged*> elems;
+ std::vector<TestManaged *> elems;
for (int i = 0; i < nElem; i++) {
elems.push_back(new TestManaged{mgr, a[i]});
}
@@ -49,7 +49,8 @@ TEST(ManagedVector, managedVector)
ManagedVector<TestManaged> v(root, elems.begin(), elems.end());
- // Remove the last element from the list. It should be garbage collected.
+ // Remove the last element from the list. It should be garbage
+ // collected.
v.pop_back();
ASSERT_FALSE(a[nElem - 1]);
@@ -85,7 +86,6 @@ TEST(ManagedVector, managedVector)
}
}
-
TEST(ManagedVector, moveAssignment)
{
constexpr int nElem = 16;
@@ -220,16 +220,39 @@ TEST(ManagedVector, moveWithNewOwner)
}
}
-class TestManagedWithContainer : public Managed {
+TEST(ManagedVector, accessOperator)
+{
+ Manager mgr{1};
+ Rooted<Managed> root{new Managed{mgr}};
+ ManagedVector<Managed> instance{root};
+ Rooted<Managed> elem{new Managed{mgr}};
+ instance.push_back(elem);
+
+ ASSERT_EQ(elem, instance[0]);
+
+ // Test out of bounds.
+ bool caught = false;
+ try {
+ instance[1];
+ }
+ catch (std::out_of_range ex) {
+ caught = true;
+ }
+ ASSERT_TRUE(caught);
+
+ instance.push_back(elem);
+ ASSERT_EQ(elem, instance[1]);
+}
+class TestManagedWithContainer : public Managed {
public:
ManagedVector<TestManaged> elems;
- TestManagedWithContainer(Manager &mgr) : Managed(mgr), elems(this) {};
-
+ TestManagedWithContainer(Manager &mgr) : Managed(mgr), elems(this){};
};
-TEST(ManagedVector, embedded) {
+TEST(ManagedVector, embedded)
+{
// Note: This test depends on the correct deletion order -- otherwise
// valgrind shows an error
bool a;
@@ -248,7 +271,6 @@ TEST(ManagedVector, embedded) {
ASSERT_FALSE(a);
}
-
TEST(ManagedMap, managedMap)
{
// TODO: This test is highly incomplete
@@ -260,7 +282,7 @@ TEST(ManagedMap, managedMap)
{
Rooted<Managed> root{new Managed{mgr}};
- std::map<int, TestManaged*> elems;
+ std::map<int, TestManaged *> elems;
for (int i = 0; i < nElem; i++) {
elems.insert(std::make_pair(i, new TestManaged{mgr, a[i]}));
}
@@ -298,6 +320,5 @@ TEST(ManagedMap, managedMap)
ASSERT_FALSE(v);
}
}
-
}
diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp
new file mode 100644
index 0000000..26553dd
--- /dev/null
+++ b/test/core/model/DocumentTest.cpp
@@ -0,0 +1,44 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtest/gtest.h>
+
+#include <core/model/Document.hpp>
+#include <core/model/Domain.hpp>
+
+#include "TestDocument.hpp"
+#include "TestDomain.hpp"
+
+namespace ousia {
+namespace model {
+
+
+TEST(Document, testDocumentConstruction)
+{
+ // Construct Manager
+ Manager mgr{1};
+ // Get the domain.
+ Rooted<Domain> domain = constructBookDomain(mgr);
+ // Construct the document.
+ Rooted<Document> doc = constructBookDocument(mgr, domain);
+
+ // If that works we are happy already.
+ ASSERT_FALSE(doc.isNull());
+}
+}
+}
diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp
new file mode 100644
index 0000000..f6dff3c
--- /dev/null
+++ b/test/core/model/DomainTest.cpp
@@ -0,0 +1,100 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#include <core/model/Domain.hpp>
+
+#include "TestDomain.hpp"
+
+namespace ousia {
+namespace model {
+
+void assert_path(std::vector<Rooted<Managed>> &result, size_t idx,
+ const std::type_info &expected_type,
+ std::vector<std::string> expected_path)
+{
+ ASSERT_TRUE(result.size() > idx);
+ // check class/type
+ ASSERT_EQ(expected_type, typeid(*result[idx]));
+ // transform to node
+ Managed *m = &(*result[idx]);
+ Node *n = dynamic_cast<Node *>(m);
+ ASSERT_TRUE(n);
+ // extract actual path
+ std::vector<std::string> actual_path = n->path();
+ // check path
+ ASSERT_EQ(expected_path, actual_path);
+}
+
+TEST(Document, testDomainResolving)
+{
+ // Construct Manager
+ Manager mgr{1};
+ // Get the domain.
+ Rooted<Domain> domain = constructBookDomain(mgr);
+
+ /*
+ * Start with the "book" search keyword. This should resolve to the domain
+ * itself (because it is called "book"), as well as the structure "book"
+ * node.
+ */
+ std::vector<Rooted<Managed>> res =
+ domain->resolve(std::vector<std::string>{"book"});
+ // First we expect the book domain.
+ assert_path(res, 0, typeid(Domain), {"book"});
+ // Then the book structure.
+ assert_path(res, 1, typeid(StructuredClass), {"book", "book"});
+ ASSERT_EQ(2, res.size());
+
+ /*
+ * If we explicitly ask for the "book, book" path, then only the
+ * StructuredClass should be returned.
+ */
+ res = domain->resolve(std::vector<std::string>{"book", "book"});
+ assert_path(res, 0, typeid(StructuredClass), {"book", "book"});
+ ASSERT_EQ(1, res.size());
+
+ /*
+ * If we ask for "section" the result should be unique as well.
+ */
+ res = domain->resolve(std::vector<std::string>{"section"});
+ // TODO: Is that the path result we want?
+ assert_path(res, 0, typeid(StructuredClass), {"book", "section"});
+ ASSERT_EQ(1, res.size());
+
+ /*
+ * If we ask for the path "book", "book", "" we reference the
+ * FieldDescriptor of the StructuredClass "book".
+ */
+ res = domain->resolve(std::vector<std::string>{"book", "book", ""});
+ assert_path(res, 0, typeid(FieldDescriptor), {"book", "book", ""});
+ ASSERT_EQ(1, res.size());
+
+ /*
+ * If we ask for "paragraph" it is references two times in the Domain graph,
+ * but should be returned only once.
+ */
+ res = domain->resolve("paragraph");
+ assert_path(res, 0, typeid(StructuredClass), {"book", "paragraph"});
+ ASSERT_EQ(1, res.size());
+}
+}
+}
diff --git a/test/core/model/TestDocument.hpp b/test/core/model/TestDocument.hpp
new file mode 100644
index 0000000..a1a3434
--- /dev/null
+++ b/test/core/model/TestDocument.hpp
@@ -0,0 +1,84 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MODEL_TEST_DOCUMENT_HPP_
+#define _MODEL_TEST_DOCUMENT_HPP_
+
+#include <core/model/Document.hpp>
+#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
+
+namespace ousia {
+namespace model {
+
+/**
+ * This constructs a fairly simple test document for the "book" domain. The
+ * structure of the document can be seen in the Code below.
+ */
+static Rooted<Document> constructBookDocument(Manager &mgr,
+ Rooted<Domain> bookDomain)
+{
+ // Start with the (empty) document.
+ Rooted<Document> doc{new Document(mgr, "myDoc.oxd")};
+
+ // Add the root.
+ Rooted<StructuredEntity> root =
+ StructuredEntity::buildRootEntity(doc, {bookDomain}, "book");
+ if (root.isNull()) {
+ return {nullptr};
+ }
+
+ // Add a paragraph.
+ Rooted<StructuredEntity> foreword =
+ StructuredEntity::buildEntity(root, {bookDomain}, "paragraph");
+ if (foreword.isNull()) {
+ return {nullptr};
+ }
+ // Add its text.
+ Variant text{std::map<std::string, Variant>{
+ {"content", Variant("Some introductory text")}}};
+ Rooted<DocumentPrimitive> foreword_text =
+ DocumentPrimitive::buildEntity(foreword, text, "text");
+ if (foreword_text.isNull()) {
+ return {nullptr};
+ }
+ // Add a section.
+ Rooted<StructuredEntity> section =
+ StructuredEntity::buildEntity(root, {bookDomain}, "section");
+ // Add a paragraph for it.
+ Rooted<StructuredEntity> main =
+ StructuredEntity::buildEntity(section, {bookDomain}, "paragraph");
+ if (main.isNull()) {
+ return {nullptr};
+ }
+ // Add its text.
+ text = Variant{std::map<std::string, Variant>{
+ {"content", Variant("Some introductory text")}}};
+ Rooted<DocumentPrimitive> main_text =
+ DocumentPrimitive::buildEntity(foreword, text, "text");
+ if (main_text.isNull()) {
+ return {nullptr};
+ }
+
+ return doc;
+}
+}
+}
+
+#endif /* _TEST_DOCUMENT_HPP_ */
+
diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp
new file mode 100644
index 0000000..41fcdef
--- /dev/null
+++ b/test/core/model/TestDomain.hpp
@@ -0,0 +1,94 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MODEL_TEST_DOMAIN_HPP_
+#define _MODEL_TEST_DOMAIN_HPP_
+
+#include <core/model/Domain.hpp>
+#include <core/model/Typesystem.hpp>
+
+namespace ousia {
+namespace model {
+
+/**
+ * This constructs a somewhat trivial system of standard types.
+ *
+ * Currently contained: string, text (struct wrapper for string)
+ */
+static Rooted<Typesystem> constructTypeSystem(Manager &mgr)
+{
+ Rooted<Typesystem> sys{new Typesystem(mgr, "std")};
+ Rooted<StringType> string{new StringType(mgr, sys)};
+ sys->addType(string);
+ Rooted<StructType> string_struct{new StructType(
+ mgr, "text", sys, {{"content", "", false, sys->acquire(string)}})};
+ sys->addType(string_struct);
+
+ return sys;
+}
+
+/**
+ * This constructs the "book" domain for test purposes. The structure of the
+ * domain is fairly simple and can be seen from the construction itself.
+ */
+static Rooted<Domain> constructBookDomain(Manager &mgr)
+{
+ // Start with the Domain itself.
+ Rooted<Domain> domain{new Domain(mgr, "book")};
+ // The standard type system.
+ domain->getTypesystems().push_back(constructTypeSystem(mgr));
+ // Set up the cardinalities we'll need.
+ Cardinality single;
+ single.merge({1});
+ Cardinality any;
+ any.merge(Range<size_t>::typeRangeFrom(0));
+
+ // Set up the "book" node.
+ Rooted<StructuredClass> book{
+ new StructuredClass(mgr, "book", domain, single)};
+ domain->getRootStructures().push_back(book);
+ // The structure field of it.
+ Rooted<FieldDescriptor> book_field{new FieldDescriptor(mgr, book)};
+ book->getFieldDescriptors().push_back(book_field);
+
+ // From there on the "section".
+ Rooted<StructuredClass> section{
+ new StructuredClass(mgr, "section", domain, any)};
+ book_field->getChildren().push_back(section);
+ // And the field of it.
+ Rooted<FieldDescriptor> section_field{new FieldDescriptor(mgr, section)};
+ section->getFieldDescriptors().push_back(section_field);
+
+ // We also add the "paragraph", which is transparent.
+ Rooted<StructuredClass> paragraph{new StructuredClass(
+ mgr, "paragraph", domain, any, {nullptr}, {nullptr}, true)};
+ section_field->getChildren().push_back(paragraph);
+ book_field->getChildren().push_back(paragraph);
+ // ... and has a primitive field.
+ Rooted<FieldDescriptor> paragraph_field{new FieldDescriptor(
+ mgr, paragraph, domain->getTypesystems()[0]->getTypes()[1], "text",
+ false)};
+ paragraph->getFieldDescriptors().push_back(paragraph_field);
+
+ return domain;
+}
+}
+}
+
+#endif /* _TEST_DOMAIN_HPP_ */
+