summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-12 19:47:43 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-12 19:47:43 +0100
commitfa387f9bef0d1a70a4b40c28c5cf9d661c421f73 (patch)
treec1857d0d7fc0a8db8c1f3a841913b1f496d8e661
parent2b15fcab4b81fa8a854e724c48ee9c771fb126f8 (diff)
parent55f943ba1b31542157b984b5955b91261c280f46 (diff)
Merge branch 'master' of somweyr.de:ousia
Conflicts: application/src/core/model/Document.hpp
-rw-r--r--src/core/common/Argument.cpp4
-rw-r--r--src/core/common/Function.hpp23
-rw-r--r--src/core/common/Variant.cpp6
-rw-r--r--src/core/common/Variant.hpp15
-rw-r--r--src/core/common/VariantConverter.cpp28
-rw-r--r--src/core/model/Document.cpp12
-rw-r--r--src/core/model/Document.hpp72
-rw-r--r--test/core/common/ArgumentTest.cpp441
-rw-r--r--test/core/model/TestDocumentBuilder.hpp6
9 files changed, 533 insertions, 74 deletions
diff --git a/src/core/common/Argument.cpp b/src/core/common/Argument.cpp
index 78dd4b4..3461868 100644
--- a/src/core/common/Argument.cpp
+++ b/src/core/common/Argument.cpp
@@ -91,13 +91,13 @@ Argument Argument::String(std::string name,
Argument Argument::Object(std::string name, const RttiType &type)
{
- return Argument(std::move(name), type, RttiTypes::None, nullptr, false);
+ return Argument(std::move(name), type, RttiTypes::None, Variant::fromObject(nullptr), false);
}
Argument Argument::Object(std::string name, const RttiType &type,
std::nullptr_t)
{
- return Argument(std::move(name), type, RttiTypes::None, nullptr, true);
+ return Argument(std::move(name), type, RttiTypes::None, Variant::fromObject(nullptr), true);
}
Argument Argument::Function(std::string name)
diff --git a/src/core/common/Function.hpp b/src/core/common/Function.hpp
index 04030c8..79ee6b9 100644
--- a/src/core/common/Function.hpp
+++ b/src/core/common/Function.hpp
@@ -42,7 +42,7 @@ namespace ousia {
*/
class Function {
protected:
- Function() {};
+ Function(){};
public:
Function(const Function &) = delete;
@@ -62,6 +62,23 @@ public:
};
/**
+ * Function doing nothing. Instances of this class are used as default values
+ * for instances of the Function class.
+ */
+class FunctionStub : public Function {
+public:
+ /**
+ * Constructor of the FunctionStub class.
+ */
+ FunctionStub() {}
+
+ Variant call(const Variant::arrayType &, void *) const override
+ {
+ return nullptr;
+ }
+};
+
+/**
* The Method class refers to a method in the C++ code, belonging to an object
* of a certain type T.
*
@@ -93,7 +110,7 @@ public:
*
* @param method is a pointer at the C++ function that should be called.
*/
- Method(Callback method) : method(method) {};
+ Method(Callback method) : method(method){};
/**
* Calls the underlying method.
@@ -106,7 +123,7 @@ public:
void *thisRef = nullptr) const override
{
// Call the method
- return method(args, static_cast<T*>(thisRef));
+ return method(args, static_cast<T *>(thisRef));
}
};
}
diff --git a/src/core/common/Variant.cpp b/src/core/common/Variant.cpp
index e199bc7..81e6339 100644
--- a/src/core/common/Variant.cpp
+++ b/src/core/common/Variant.cpp
@@ -158,8 +158,10 @@ const RttiType& Variant::getRttiType() const
return RttiTypes::Map;
case VariantType::FUNCTION:
return RttiTypes::Function;
- case VariantType::OBJECT:
- return asObject()->type();
+ case VariantType::OBJECT: {
+ Variant::objectType o = asObject();
+ return (o == nullptr) ? RttiTypes::Nullptr : o->type();
+ }
}
return RttiTypes::None;
}
diff --git a/src/core/common/Variant.hpp b/src/core/common/Variant.hpp
index 27dfda8..e5bca4d 100644
--- a/src/core/common/Variant.hpp
+++ b/src/core/common/Variant.hpp
@@ -342,6 +342,19 @@ public:
Variant(mapType m) : ptrVal(nullptr) { setMap(std::move(m)); }
/**
+ * Named constructor for object values.
+ *
+ * @param o is an object that can be converted to a Rooted handle.
+ */
+ template<class T>
+ static Variant fromObject(T o)
+ {
+ Variant res;
+ res.setObject(o);
+ return res;
+ }
+
+ /**
* Named constructor for function values.
*
* @param f is a shared pointer pointing at the Function instance.
@@ -900,7 +913,7 @@ public:
* to a Rooted handle.
*/
template <class T>
- void setObject(Handle<T> o)
+ void setObject(T o)
{
destroy();
type = VariantType::OBJECT;
diff --git a/src/core/common/VariantConverter.cpp b/src/core/common/VariantConverter.cpp
index 1f5f514..1c23c43 100644
--- a/src/core/common/VariantConverter.cpp
+++ b/src/core/common/VariantConverter.cpp
@@ -243,8 +243,11 @@ bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode)
// Print object address and type
Variant::objectType obj = var.asObject();
std::stringstream ss;
- ss << "<object " << obj.get() << " (" << obj->type().name << ")"
- << ">";
+ ss << "<object " << obj.get();
+ if (obj.get() != nullptr) {
+ ss << " (" << obj->type().name << ")";
+ }
+ ss << ">";
var = ss.str().c_str();
return true;
}
@@ -290,11 +293,7 @@ bool VariantConverter::toArray(Variant &var, const RttiType &innerType,
for (Variant &v : var.asArray()) {
res = convert(v, innerType, RttiTypes::None, logger, mode) & res;
}
-
- // Return on successful conversion, otherwise output the default value
- if (res) {
- return true;
- }
+ return res;
}
// No conversion possible, assign the default value and log an error
@@ -321,11 +320,7 @@ bool VariantConverter::toMap(Variant &var, const RttiType &innerType,
res = convert(e.second, innerType, RttiTypes::None, logger, mode) &
res;
}
-
- // Return on successful conversion, otherwise output the default value
- if (res) {
- return true;
- }
+ return res;
}
// No conversion possible, assign the default value and log an error
@@ -341,9 +336,8 @@ bool VariantConverter::toFunction(Variant &var, Logger &logger)
}
// No conversion possible, assign the default value and log an error
- logger.error(msgUnexpectedType(var, VariantType::MAP));
- var.setFunction(std::shared_ptr<Function>{new Method<void>([](
- const Variant::arrayType &args, void *thisRef) { return Variant{}; })});
+ logger.error(msgUnexpectedType(var, VariantType::FUNCTION));
+ var.setFunction(std::shared_ptr<Function>{new FunctionStub()});
return false;
}
@@ -383,7 +377,7 @@ bool VariantConverter::convert(Variant &var, const RttiType &type,
// obviously asked for a managed object.
if (!var.isObject()) {
logger.error(msgUnexpectedType(var, VariantType::OBJECT));
- var.setNull();
+ var.setObject(nullptr);
return false;
}
@@ -391,7 +385,7 @@ bool VariantConverter::convert(Variant &var, const RttiType &type,
if (!var.getRttiType().isa(type)) {
logger.error(std::string("Expected object of type ") + type.name +
" but got object of type " + var.getRttiType().name);
- var.setNull();
+ var.setObject(nullptr);
return false;
}
return true;
diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp
index 723aafd..022b91c 100644
--- a/src/core/model/Document.cpp
+++ b/src/core/model/Document.cpp
@@ -103,19 +103,17 @@ void Document::continueResolve(ResolutionState &state)
/* Type registrations */
namespace RttiTypes {
-const Rtti<model::DocumentEntity> DocumentEntity =
- RttiBuilder("DocumentEntity").parent(&Node);
const Rtti<model::Document> Document =
RttiBuilder("Document").parent(&Node).composedOf(
{&AnnotationEntity, &StructuredEntity});
-const Rtti<model::AnnotationEntity> AnnotationEntity =
- RttiBuilder("AnnotationEntity").parent(&DocumentEntity).composedOf(
- &StructuredEntity);
const Rtti<model::StructureNode> StructureNode =
RttiBuilder("StructureNode").parent(&Node);
+const Rtti<model::AnnotationEntity> AnnotationEntity =
+ RttiBuilder("AnnotationEntity").parent(&Node).composedOf(
+ &StructureNode);
const Rtti<model::StructuredEntity> StructuredEntity =
- RttiBuilder("StructuredEntity").parent(&DocumentEntity).parent(&StructureNode).composedOf(
- {&StructuredEntity, &Anchor, &DocumentPrimitive});
+ RttiBuilder("StructuredEntity").parent(&StructureNode).composedOf(
+ {&StructureNode});
const Rtti<model::DocumentPrimitive> DocumentPrimitive =
RttiBuilder("DocumentPrimitive").parent(&StructureNode);
const Rtti<model::AnnotationEntity::Anchor> Anchor =
diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp
index 7f365b7..d22196a 100644
--- a/src/core/model/Document.hpp
+++ b/src/core/model/Document.hpp
@@ -138,7 +138,7 @@ class StructureNode;
* name.
*
*/
-class DocumentEntity : public virtual Node {
+class DocumentEntity {
private:
Owned<Descriptor> descriptor;
const Variant attributes;
@@ -151,11 +151,22 @@ private:
bool enforce) const;
public:
- DocumentEntity(Manager &mgr, Handle<Node> parent,
- Handle<Descriptor> descriptor, Variant attributes = {},
- std::string name = "")
- : Node(mgr, std::move(name), parent),
- descriptor(acquire(descriptor)),
+ /**
+ * The constructor for a DocumentEntity. Node that this does not inherit
+ * from Node. Therefore we need to have a handle to the child Node instance
+ * to create NodeVectors and Owned references.
+ *
+ * @param owner is a handle to the child instance
+ * (e.g. StructuredEntity), such that the fields vectors
+ * and the descriptor reference can be obtained.
+ * @param descriptor is the Descriptor for this DocumentEntity, which will
+ * transformed to an Owned reference of the given owner.
+ * @param attributes is a Map Variant adhering to the attribute StructType
+ * in the given descriptor.
+ */
+ DocumentEntity(Handle<Node> owner, Handle<Descriptor> descriptor,
+ Variant attributes = {})
+ : descriptor(owner->acquire(descriptor)),
attributes(std::move(attributes))
{
// TODO: Validation at construction time?
@@ -163,13 +174,27 @@ public:
if (!descriptor.isNull()) {
for (size_t f = 0; f < descriptor->getFieldDescriptors().size();
f++) {
- fields.push_back(NodeVector<StructureNode>(this));
+ fields.push_back(NodeVector<StructureNode>(owner));
}
}
}
+ virtual ~DocumentEntity(){};
+
+ /**
+ * Returns the Descriptor for this DocumentEntity.
+ *
+ * @return the Descriptor for this DocumentEntity.
+ */
Rooted<Descriptor> getDescriptor() const { return descriptor; }
+ /**
+ * Returns a Map Variant adhering to the attribute StructType in the given
+ * descriptor.
+ *
+ * @return a Map Variant adhering to the attribute StructType in the given
+ * descriptor.
+ */
Variant getAttributes() const { return attributes; }
/**
@@ -303,7 +328,7 @@ public:
* A StructureNode is a Node of the StructureTree of the document. This is a
* common superclass for StructuredEntity, Anchor and DocumentPrimitive.
*/
-class StructureNode : public virtual Node {
+class StructureNode : public Node {
public:
StructureNode(Manager &mgr, std::string name, Handle<Node> parent)
: Node(mgr, std::move(name), parent)
@@ -315,15 +340,13 @@ public:
* A StructuredEntity is an instance of a StructuredClass. For more
* information please refer to the header documentation above.
*/
-class StructuredEntity : public DocumentEntity, public StructureNode {
+class StructuredEntity : public StructureNode, public DocumentEntity {
public:
StructuredEntity(Manager &mgr, Handle<Node> parent,
Handle<StructuredClass> descriptor, Variant attributes,
std::string name = "")
- : Node(mgr, std::move(name), parent),
- DocumentEntity(mgr, parent, descriptor, std::move(attributes),
- std::move(name)),
- StructureNode(mgr, std::move(name), parent)
+ : StructureNode(mgr, std::move(name), parent),
+ DocumentEntity(this, descriptor, std::move(attributes))
{
}
};
@@ -338,17 +361,17 @@ private:
Variant content;
public:
- DocumentPrimitive(Manager &mgr, Handle<DocumentEntity> parent,
- Variant content = {})
- : Node(mgr, parent),
- StructureNode(mgr, "", parent),
- content(content)
+ DocumentPrimitive(Manager &mgr, Handle<Node> parent, Variant content = {})
+ : StructureNode(mgr, "", parent), content(content)
{
}
+ /**
+ * Returns the content of this DocumentPrimitive.
+ *
+ * @return the content of this DocumentPrimitive.
+ */
Variant getContent() const { return content; }
-
- // TODO: Override such methods like "getField" to disable them?
};
/**
@@ -371,7 +394,7 @@ public:
* the two text exerpts "emphasized" and "and" separately.
*
*/
-class AnnotationEntity : public DocumentEntity {
+class AnnotationEntity : public Node, public DocumentEntity {
public:
/**
* An Anchor is an elementary StructuredEntity without any children that
@@ -387,9 +410,8 @@ public:
* not the AnnotationEntity that references this Anchor.
* @param name is the Anchor id.
*/
- Anchor(Manager &mgr, std::string name, Handle<DocumentEntity> parent)
- : Node(mgr, std::move(name), parent),
- StructureNode(mgr, std::move(name), parent)
+ Anchor(Manager &mgr, std::string name, Handle<Node> parent)
+ : StructureNode(mgr, std::move(name), parent)
{
}
};
@@ -419,7 +441,7 @@ public:
Handle<Anchor> end, Variant attributes = {},
std::string name = "")
: Node(mgr, std::move(name), parent),
- DocumentEntity(mgr, parent, descriptor, attributes, std::move(name)),
+ DocumentEntity(this, descriptor, attributes),
start(acquire(start)),
end(acquire(end))
{
diff --git a/test/core/common/ArgumentTest.cpp b/test/core/common/ArgumentTest.cpp
index 8976fba..d555cd8 100644
--- a/test/core/common/ArgumentTest.cpp
+++ b/test/core/common/ArgumentTest.cpp
@@ -20,8 +20,10 @@
#include <gtest/gtest.h>
-#include <core/common/Logger.hpp>
#include <core/common/Argument.hpp>
+#include <core/common/Function.hpp>
+#include <core/common/Logger.hpp>
+#include <core/common/Rtti.hpp>
#include <core/managed/Managed.hpp>
@@ -30,10 +32,32 @@ namespace ousia {
//static Logger logger;
static TerminalLogger logger(std::cerr, true);
+namespace {
+
+class TestManaged1 : public Managed {
+public:
+ using Managed::Managed;
+};
+
+class TestManaged2 : public TestManaged1 {
+public:
+ using TestManaged1::TestManaged1;
+};
+}
+
+namespace RttiTypes {
+static const Rtti<ousia::TestManaged1> TestManaged1 =
+ RttiBuilder("TestManaged1");
+static const Rtti<ousia::TestManaged2> TestManaged2 =
+ RttiBuilder("TestManaged2").parent(&TestManaged1);
+}
+
TEST(Argument, validateBool)
{
Argument a = Argument::Bool("a");
+ ASSERT_FALSE(a.hasDefault);
+
{
Variant v{true};
ASSERT_TRUE(a.validate(v, logger));
@@ -60,16 +84,37 @@ TEST(Argument, validateBoolDefault)
{
Argument a = Argument::Bool("a", true);
- Variant v{1};
- ASSERT_FALSE(a.validate(v, logger));
- ASSERT_TRUE(v.isBool());
- ASSERT_TRUE(v.asBool());
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_TRUE(a.defaultValue.asBool());
+
+ {
+ Variant v{true};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isBool());
+ ASSERT_TRUE(v.asBool());
+ }
+
+ {
+ Variant v{false};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isBool());
+ ASSERT_FALSE(v.asBool());
+ }
+
+ {
+ Variant v{1};
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isBool());
+ ASSERT_TRUE(v.asBool());
+ }
}
TEST(Argument, validateInt)
{
Argument a = Argument::Int("a");
+ ASSERT_FALSE(a.hasDefault);
+
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
@@ -89,16 +134,30 @@ TEST(Argument, validateIntDefault)
{
Argument a = Argument::Int("a", 42);
- Variant v{1.1};
- ASSERT_FALSE(a.validate(v, logger));
- ASSERT_TRUE(v.isInt());
- ASSERT_EQ(42, v.asInt());
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_EQ(42, a.defaultValue.asInt());
+
+ {
+ Variant v{123};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isInt());
+ ASSERT_EQ(123, v.asInt());
+ }
+
+ {
+ Variant v{1.1};
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isInt());
+ ASSERT_EQ(42, v.asInt());
+ }
}
TEST(Argument, validateDouble)
{
Argument a = Argument::Double("a");
+ ASSERT_FALSE(a.hasDefault);
+
{
Variant v{123};
ASSERT_TRUE(a.validate(v, logger));
@@ -112,7 +171,7 @@ TEST(Argument, validateDouble)
ASSERT_TRUE(v.isDouble());
ASSERT_EQ(1.1, v.asDouble());
}
-
+
{
Variant v{"1.0"};
ASSERT_FALSE(a.validate(v, logger));
@@ -125,16 +184,37 @@ TEST(Argument, validateDoubleDefault)
{
Argument a = Argument::Double("a", 42.0);
- Variant v{"1.0"};
- ASSERT_FALSE(a.validate(v, logger));
- ASSERT_TRUE(v.isDouble());
- ASSERT_EQ(42.0, v.asDouble());
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_EQ(42.0, a.defaultValue.asDouble());
+
+ {
+ Variant v{123};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isDouble());
+ ASSERT_EQ(123.0, v.asDouble());
+ }
+
+ {
+ Variant v{1.1};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isDouble());
+ ASSERT_EQ(1.1, v.asDouble());
+ }
+
+ {
+ Variant v{"1.0"};
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isDouble());
+ ASSERT_EQ(42.0, v.asDouble());
+ }
}
TEST(Argument, validateString)
{
Argument a = Argument::String("a");
+ ASSERT_FALSE(a.hasDefault);
+
{
Variant v{"test"};
ASSERT_TRUE(a.validate(v, logger));
@@ -182,6 +262,44 @@ TEST(Argument, validateStringDefault)
{
Argument a = Argument::String("a", "test2");
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_EQ("test2", a.defaultValue.asString());
+
+ {
+ Variant v{"test"};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isString());
+ ASSERT_EQ("test", v.asString());
+ }
+
+ {
+ Variant v{true};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isString());
+ ASSERT_EQ("true", v.asString());
+ }
+
+ {
+ Variant v{nullptr};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isString());
+ ASSERT_EQ("null", v.asString());
+ }
+
+ {
+ Variant v{42};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isString());
+ ASSERT_EQ("42", v.asString());
+ }
+
+ {
+ Variant v{42.5};
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isString());
+ ASSERT_EQ("42.5", v.asString());
+ }
+
{
Variant v{{1, 2, 3}};
ASSERT_FALSE(a.validate(v, logger));
@@ -190,5 +308,300 @@ TEST(Argument, validateStringDefault)
}
}
+TEST(Argument, validateObject)
+{
+ Manager mgr;
+ Argument a = Argument::Object("a", RttiTypes::TestManaged1);
+
+ ASSERT_FALSE(a.hasDefault);
+
+ {
+ Rooted<Managed> m{new Managed(mgr)};
+ Variant v(m);
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged1> m{new TestManaged1(mgr)};
+ Variant v(m);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(m, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged2> m{new TestManaged2(mgr)};
+ Variant v(m);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(m, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged1> m1{nullptr};
+ Variant v(m1);
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+
+ {
+ Variant v("test");
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+}
+
+TEST(Argument, validateObjectDefault)
+{
+ Manager mgr;
+ Argument a = Argument::Object("a", RttiTypes::TestManaged1, nullptr);
+
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_TRUE(a.defaultValue.isObject());
+ ASSERT_EQ(nullptr, a.defaultValue.asObject());
+
+ {
+ Rooted<Managed> m{new Managed(mgr)};
+ Variant v(m);
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged1> m{new TestManaged1(mgr)};
+ Variant v(m);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(m, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged2> m{new TestManaged2(mgr)};
+ Variant v(m);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(m, v.asObject());
+ }
+
+ {
+ Rooted<TestManaged1> m1{nullptr};
+ Variant v(m1);
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+
+ {
+ Variant v("test");
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isObject());
+ ASSERT_EQ(nullptr, v.asObject());
+ }
+}
+
+static std::shared_ptr<Function> helloWorldFun{new Method<void>{[](
+ const Variant::arrayType &arr, void *) { return Variant{"Hello World"}; }}};
+
+static std::shared_ptr<Function> goodbyeWorldFun{
+ new Method<void>{[](const Variant::arrayType &arr,
+ void *) { return Variant{"Goodbye Cruel World"}; }}};
+
+TEST(Argument, validateFunction)
+{
+ Argument a = Argument::Function("a");
+
+ ASSERT_FALSE(a.hasDefault);
+
+ {
+ Variant v = Variant::fromFunction(helloWorldFun);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isFunction());
+ ASSERT_EQ("Hello World", v.asFunction()->call().asString());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isFunction());
+ ASSERT_TRUE(v.asFunction()->call().isNull());
+ }
+}
+
+TEST(Argument, validateFunctionDefault)
+{
+ Argument a = Argument::Function("a", goodbyeWorldFun);
+
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_TRUE(a.defaultValue.isFunction());
+ ASSERT_EQ(goodbyeWorldFun, a.defaultValue.asFunction());
+
+ {
+ Variant v = Variant::fromFunction(helloWorldFun);
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isFunction());
+ ASSERT_EQ("Hello World", v.asFunction()->call().asString());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isFunction());
+ ASSERT_EQ("Goodbye Cruel World", v.asFunction()->call().asString());
+ }
+}
+
+TEST(Argument, validateArray)
+{
+ Argument a = Argument::Array("a");
+
+ ASSERT_FALSE(a.hasDefault);
+
+ {
+ Variant::arrayType arr{1, "a", nullptr};
+ Variant v{arr};
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(arr, v.asArray());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(Variant::arrayType{}, v.asArray());
+ }
+}
+
+TEST(Argument, validateArrayDefault)
+{
+ Variant::arrayType arrDefault{1, "a", nullptr};
+ Argument a = Argument::Array("a", arrDefault);
+
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_TRUE(a.defaultValue.isArray());
+ ASSERT_EQ(arrDefault, a.defaultValue.asArray());
+
+ {
+ Variant::arrayType arr{"test1", 42.5};
+ Variant v{arr};
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(arr, v.asArray());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(arrDefault, v.asArray());
+ }
+}
+
+TEST(Argument, validateArrayInner)
+{
+ Argument a = Argument::Array("a", RttiTypes::String);
+
+ ASSERT_FALSE(a.hasDefault);
+
+ {
+ Variant::arrayType arr{1, "a", nullptr};
+ Variant v{arr};
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(Variant::arrayType({"1", "a", "null"}), v.asArray());
+ }
+
+ {
+ Variant::arrayType arr{1, "a", Variant::fromObject(nullptr)};
+ Variant v{arr};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(Variant::arrayType({"1", "a", ""}), v.asArray());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(Variant::arrayType{}, v.asArray());
+ }
+}
+
+TEST(Argument, validateArrayInnerDefault)
+{
+ Variant::arrayType arrDefault{1, "a", nullptr};
+ Argument a = Argument::Array("a", RttiTypes::String, arrDefault);
+
+ ASSERT_TRUE(a.hasDefault);
+ ASSERT_TRUE(a.defaultValue.isArray());
+ ASSERT_EQ(arrDefault, a.defaultValue.asArray());
+
+ {
+ Variant::arrayType arr{"test1", 42.5};
+ Variant v{arr};
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(Variant::arrayType({"test1", "42.5"}), v.asArray());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isArray());
+ ASSERT_EQ(arrDefault, v.asArray());
+ }
+}
+
+TEST(Argument, validateMap)
+{
+ Argument a = Argument::Map("a");
+
+ ASSERT_FALSE(a.hasDefault);
+
+ {
+ Variant::mapType map{{"key1", 1}, {"key2", "a"}, {"key3", nullptr}};
+ Variant v{map};
+
+ ASSERT_TRUE(a.validate(v, logger));
+ ASSERT_TRUE(v.isMap());
+ ASSERT_EQ(map, v.asMap());
+ }
+
+ {
+ Variant v{"foo"};
+
+ ASSERT_FALSE(a.validate(v, logger));
+ ASSERT_TRUE(v.isMap());
+ ASSERT_EQ(Variant::mapType{}, v.asMap());
+ }
+}
}
diff --git a/test/core/model/TestDocumentBuilder.hpp b/test/core/model/TestDocumentBuilder.hpp
index a09b081..081e934 100644
--- a/test/core/model/TestDocumentBuilder.hpp
+++ b/test/core/model/TestDocumentBuilder.hpp
@@ -135,7 +135,7 @@ Rooted<StructuredEntity> buildRootStructuredEntity(Handle<Document> document,
* contain a StructuredClass with the given name.
*/
Rooted<StructuredEntity> buildStructuredEntity(
- Handle<Document> document, Logger &logger, Handle<DocumentEntity> parent,
+ Handle<Document> document, Logger &logger, Handle<StructuredEntity> parent,
Path path, const std::string &fieldName = "", Variant attributes = {},
std::string name = "")
{
@@ -191,7 +191,7 @@ Rooted<StructuredEntity> buildStructuredEntity(
* input handle was empty.
*/
Rooted<DocumentPrimitive> buildPrimitiveEntity(
- Logger &logger, Handle<DocumentEntity> parent, Variant content = {},
+ Logger &logger, Handle<StructuredEntity> parent, Variant content = {},
const std::string &fieldName = "")
{
// If the input handles are not set, we can not build the entity.
@@ -228,7 +228,7 @@ Rooted<DocumentPrimitive> buildPrimitiveEntity(
* input handle was empty.
*/
Rooted<AnnotationEntity::Anchor> buildAnchor(Logger &logger,
- Handle<DocumentEntity> parent,
+ Handle<StructuredEntity> parent,
std::string id,
const std::string &fieldName = "")
{