summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-13 02:01:30 +0100
committerAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2015-01-13 02:01:30 +0100
commitdcf154aaf037ac67260abcec0b0ed3db32bc65ac (patch)
tree94dd32865be508d70617c351c609f398c9ec6f06
parent742b76b006daf27ea19b2834e56696cb3c5a0e18 (diff)
allowing validated methods
-rw-r--r--src/core/common/Function.cpp12
-rw-r--r--src/core/common/Function.hpp147
-rw-r--r--test/core/common/ArgumentTest.cpp23
-rw-r--r--test/core/common/FunctionTest.cpp17
4 files changed, 162 insertions, 37 deletions
diff --git a/src/core/common/Function.cpp b/src/core/common/Function.cpp
index eeabbc3..6aedb7b 100644
--- a/src/core/common/Function.cpp
+++ b/src/core/common/Function.cpp
@@ -17,9 +17,19 @@
*/
#include "Function.hpp"
+#include "Logger.hpp"
namespace ousia {
-
+Variant::arrayType &ValidatingFunction::validate(Variant::arrayType &args) const
+{
+ // If an argument descriptor was given, use it to validate the arguments.
+ // Throw any violation as exception.
+ if (checkArguments) {
+ ExceptionLogger logger;
+ arguments.validateArray(args, logger);
+ }
+ return args;
+}
}
diff --git a/src/core/common/Function.hpp b/src/core/common/Function.hpp
index 79ee6b9..0e8af12 100644
--- a/src/core/common/Function.hpp
+++ b/src/core/common/Function.hpp
@@ -30,6 +30,7 @@
#include <cassert>
+#include "Argument.hpp"
#include "Variant.hpp"
namespace ousia {
@@ -38,17 +39,18 @@ namespace ousia {
* The Function interface defines all the methods needed to represent a
* generic function. Function objects can be called using the "call" function in
* which an array of Variant is supplied to the function and a Variant is
- * returned to the caller.
+ * returned to the caller. The actual function that is being represented by an
+ * instance of the Function class may either be a C++ function or a function
+ * residing in some script.
*/
class Function {
protected:
+ /**
+ * Protecte default constructor -- prevents the Function class from being
+ * created. Use one of the child classes instead.
+ */
Function(){};
-public:
- Function(const Function &) = delete;
- Function(Function &&) = delete;
- virtual ~Function(){};
-
/**
* Abstract function which is meant to call the underlying function (be it
* a host or a script function) with the given arguments.
@@ -57,8 +59,50 @@ public:
* the function.
* @return a Variant containing the return value.
*/
- virtual Variant call(const Variant::arrayType &args = Variant::arrayType{},
- void *thisRef = nullptr) const = 0;
+ virtual Variant doCall(Variant::arrayType &args, void *thisRef) const = 0;
+
+public:
+ // No copy constructor
+ Function(const Function &) = delete;
+
+ // No move constructor
+ Function(Function &&) = delete;
+
+ /**
+ * Virtual destructor of the Function class.
+ */
+ virtual ~Function(){};
+
+ /**
+ * Calls the function.
+ *
+ * @param args is an array of variants that should be passed to the
+ * function. Note that the arguments might be modified, e.g. by a validation
+ * process or the called function itself.
+ * @param thisRef is a user-defined reference which may be pointing at the
+ * object the function should be working on.
+ * @return a Variant containing the result of the function call.
+ */
+ Variant call(Variant::arrayType &args, void *thisRef = nullptr) const
+ {
+ return doCall(args, thisRef);
+ }
+
+ /**
+ * Calls the function.
+ *
+ * @param args is an array of variants that should be passed to the
+ * function.
+ * @param thisRef is a user-defined reference which may be pointing at the
+ * object the function should be working on.
+ * @return a Variant containing the result of the function call.
+ */
+ Variant call(const Variant::arrayType &args = Variant::arrayType{},
+ void *thisRef = nullptr) const
+ {
+ Variant::arrayType argsCopy = args;
+ return doCall(argsCopy, thisRef);
+ }
};
/**
@@ -66,16 +110,55 @@ public:
* for instances of the Function class.
*/
class FunctionStub : public Function {
+protected:
+ Variant doCall(Variant::arrayType &, void *) const override
+ {
+ return nullptr;
+ }
+
public:
/**
* Constructor of the FunctionStub class.
*/
FunctionStub() {}
+};
- Variant call(const Variant::arrayType &, void *) const override
- {
- return nullptr;
- }
+/**
+ * Function class providing factilities for the validation of arguments.
+ */
+class ValidatingFunction : public Function {
+private:
+ /**
+ * List describing a valid set to arguments.
+ */
+ Arguments arguments;
+
+ /**
+ * Set to true if any arguments for checking were given in the constructor.
+ * If set to false, no argument checks are performed.
+ */
+ bool checkArguments;
+
+protected:
+ /**
+ * Default constructor. Disables validation, all arguments are allowed.
+ */
+ ValidatingFunction() : checkArguments(false){};
+
+ /**
+ * Default constructor. Disables validation, all arguments are allowed.
+ */
+ ValidatingFunction(Arguments arguments)
+ : arguments(std::move(arguments)), checkArguments(true){};
+
+ /**
+ * Function which cares about validating a set of arguments.
+ *
+ * @param args is an array containing the arguments that should be
+ * validated.
+ * @return the reference to the array.
+ */
+ Variant::arrayType &validate(Variant::arrayType &args) const;
};
/**
@@ -85,7 +168,7 @@ public:
* @tparam T is the type of the method that should be called.
*/
template <class T>
-class Method : public Function {
+class Method : public ValidatingFunction {
public:
/**
* Type of the Callback function that is being called by the "call"
@@ -96,7 +179,7 @@ public:
* @param thisRef is a pointer pointing at an instance of type T.
* @return the return value of the function as Variant instance.
*/
- using Callback = Variant (*)(const Variant::arrayType &args, T *thisRef);
+ using Callback = Variant (*)(Variant::arrayType &args, T *thisRef);
private:
/**
@@ -104,14 +187,7 @@ private:
*/
const Callback method;
-public:
- /**
- * Constructor of the Method class.
- *
- * @param method is a pointer at the C++ function that should be called.
- */
- Method(Callback method) : method(method){};
-
+protected:
/**
* Calls the underlying method.
*
@@ -119,12 +195,31 @@ public:
* to the method.
* @return a Variant containing the return value.
*/
- Variant call(const Variant::arrayType &args = Variant::arrayType{},
- void *thisRef = nullptr) const override
+ Variant doCall(Variant::arrayType &args, void *thisRef) const override
{
- // Call the method
- return method(args, static_cast<T *>(thisRef));
+ return method(validate(args), static_cast<T *>(thisRef));
}
+
+public:
+ /**
+ * Constructor of the Method class with a description of the arguments that
+ * are to be passed to the callback method.
+ *
+ * @param arguments is a type description restricting the arguments that are
+ * being passed to the callback function.
+ * @param method is the actual callback function that is being called once
+ * the method is executed. The arguments passed to the method are validated
+ * using the given argument descriptor.
+ */
+ Method(Arguments arguments, Callback method)
+ : ValidatingFunction(arguments), method(method){};
+
+ /**
+ * Constructor of the Method class.
+ *
+ * @param method is a pointer at the C++ function that should be called.
+ */
+ Method(Callback method) : method(method){};
};
}
diff --git a/test/core/common/ArgumentTest.cpp b/test/core/common/ArgumentTest.cpp
index d58f71b..0dec809 100644
--- a/test/core/common/ArgumentTest.cpp
+++ b/test/core/common/ArgumentTest.cpp
@@ -471,11 +471,11 @@ TEST(Argument, validateObjectDefault)
}
}
-static std::shared_ptr<Function> helloWorldFun{new Method<void>{[](
- const Variant::arrayType &arr, void *) { return Variant{"Hello World"}; }}};
+static std::shared_ptr<Function> helloWorldFun{new Method<void>{
+ [](Variant::arrayType &arr, void *) { return Variant{"Hello World"}; }}};
static std::shared_ptr<Function> goodbyeWorldFun{
- new Method<void>{[](const Variant::arrayType &arr,
+ new Method<void>{[](Variant::arrayType &arr,
void *) { return Variant{"Goodbye Cruel World"}; }}};
TEST(Argument, validateFunction)
@@ -835,31 +835,38 @@ TEST(Arguments, validateMap)
{
Variant::mapType map{{"a", 2}, {"c", false}};
ASSERT_TRUE(args.validateMap(map, logger, false));
- ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", false}}), map);
+ ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", false}}),
+ map);
}
{
Variant::mapType map{{"a", 2}};
ASSERT_TRUE(args.validateMap(map, logger, false));
- ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", true}}), map);
+ ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", true}}),
+ map);
}
{
Variant::mapType map{};
ASSERT_FALSE(args.validateMap(map, logger, false));
- ASSERT_EQ(Variant::mapType({{"a", 0}, {"b", "test"}, {"c", true}}), map);
+ ASSERT_EQ(Variant::mapType({{"a", 0}, {"b", "test"}, {"c", true}}),
+ map);
}
{
Variant::mapType map{{"a", 2}, {"d", nullptr}};
ASSERT_FALSE(args.validateMap(map, logger, false));
- ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}), map);
+ ASSERT_EQ(Variant::mapType(
+ {{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}),
+ map);
}
{
Variant::mapType map{{"a", 2}, {"d", nullptr}};
ASSERT_TRUE(args.validateMap(map, logger, true));
- ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}), map);
+ ASSERT_EQ(Variant::mapType(
+ {{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}),
+ map);
}
}
}
diff --git a/test/core/common/FunctionTest.cpp b/test/core/common/FunctionTest.cpp
index 7225f9c..ed20695 100644
--- a/test/core/common/FunctionTest.cpp
+++ b/test/core/common/FunctionTest.cpp
@@ -29,10 +29,10 @@ public:
void visit() { visited = true; }
};
-TEST(Method, simpleTest)
+TEST(Method, simple)
{
Method<MethodTestClass> m{
- [](const Variant::arrayType &args, MethodTestClass *thisRef) {
+ [](Variant::arrayType &args, MethodTestClass *thisRef) {
thisRef->visit();
return Variant{};
}};
@@ -40,5 +40,18 @@ TEST(Method, simpleTest)
MethodTestClass inst;
m.call({}, &inst);
}
+
+TEST(Method, validation)
+{
+ Method<void> m{{Argument::Int("a"), Argument::Int("b")},
+ [](Variant::arrayType &args, void *thisRef) {
+ return Variant{args[0].asInt() + args[1].asInt()};
+ }};
+
+ MethodTestClass inst;
+ ASSERT_EQ(3, m.call({1, 2}, &inst).asInt());
+ ASSERT_THROW(m.call({1}, &inst), LoggableException);
+ ASSERT_THROW(m.call({1, "bla"}, &inst), LoggableException);
+}
}