Adds Args struct for getting all arguments unprocessed in batch mode 89/167589/38
authorRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Thu, 18 Jan 2018 07:03:44 +0000 (08:03 +0100)
committerRadoslaw Cybulski <r.cybulski@partner.samsung.com>
Thu, 25 Jan 2018 15:11:52 +0000 (16:11 +0100)
Adds EvaluationValueFunction::Args struct. Object of this type will
hold all arguments passed to a function in unprocessed form. Functor
must only take single parameter of this type, for example

EvaluationValue func = [](EvaluationValueFunction::Args args) { ... }

Change-Id: I31c66104e70525bd86bfdc5ca86977e7263e1858

src/batch/BatchRunner.cpp
src/batch/EvaluationValue.hpp
tests/no-ui-scenarios/BatchExecTests.cpp

index 251ffb7..33fbffe 100644 (file)
@@ -237,7 +237,7 @@ struct TestExecutor : ExecutorInterface {
                        if (!condition) throw EvaluationFailure{} << "assertion failed";
                        return {};
                };
-               variables["wait_for_tts"] = [&](std::string pattern) -> EvaluationValue_ {
+               variables["wait_for_tts"] = EvaluationValueFunction{ [&](std::string pattern) -> EvaluationValue_ {
                        std::regex regex;
                        try
                        {
@@ -264,7 +264,7 @@ struct TestExecutor : ExecutorInterface {
                                        throw EvaluationFailure{} << "wait_for_dlog('" << pattern << "'): operation timeouted";
                                return {};
                        }
-               };
+               }, { { "pattern", EvaluationValue_{} } } };
                variables["wait_for_application"] = [&](std::string name) -> EvaluationValue_ {
                        auto h = contextInfo.lock();
                        auto untilMoment = std::chrono::high_resolution_clock::now() + 3000ms;
@@ -296,7 +296,7 @@ struct TestExecutor : ExecutorInterface {
                        }, monitor);
                };
                for (auto activityName : ActivityFactory::getInstance()->getAllActivityTypes()) {
-                       variables[activityName] = [ = ](std::vector<EvaluationValue_> args) -> EvaluationValue_ {
+                       variables[activityName] = [ = ](EvaluationValueFunction::Args args) -> EvaluationValue_ {
                                auto activity = executeOnMainThread([&]()
                                {
                                        return ActivityFactory::getInstance()->createActivity(activityName);
index be03628..1224d25 100644 (file)
@@ -33,6 +33,7 @@
 #include <tuple>
 #include <ostream>
 #include <type_traits>
+#include <algorithm>
 
 class EvaluationFailure : public std::exception
 {
@@ -133,8 +134,35 @@ public:
        void convertTo(unsigned short &v) const;
        void convertTo(signed char &v) const;
        void convertTo(unsigned char &v) const;
-       template <typename T> void convertTo(std::vector<T> &v) const {
-               
+       template <typename T> void convertTo(std::vector<T> &v) const
+       {
+               auto src = convertToVector();
+               v.reserve(src.size());
+               for (auto &s : src) {
+                       T t;
+                       s.convertTo(t);
+                       v.push_back(std::move(t));
+               }
+       }
+       template <typename T> void convertTo(std::unordered_set<T> &v) const
+       {
+               auto src = convertToSet();
+               for (auto &s : src) {
+                       T t;
+                       s.convertTo(t);
+                       v.insert(std::move(t));
+               }
+       }
+       template <typename K, typename V> void convertTo(std::unordered_map<K, V> &v) const
+       {
+               auto src = convertToDict();
+               for (auto &s : src) {
+                       K k;
+                       V v;
+                       s.first.convertTo(k);
+                       s.second.convertTo(v);
+                       v.insert({ std::move(k), std::move(v) });
+               }
        }
 #define Q(type) \
        EvaluationValue_(EvaluationValue ## type); \
@@ -187,24 +215,27 @@ public:
 private:
        EvaluationValuePtr value;
 
-       template <typename T> static EvaluationValueVector fromVector(std::vector<T> tmp) {
+       template <typename T> static EvaluationValueVector fromVector(std::vector<T> tmp)
+       {
                EvaluationValueVector res;
                res.reserve(tmp.size());
-               for(auto &t : tmp)
+               for (auto &t : tmp)
                        res.push_back(std::move(t));
                return res;
        }
-       template <typename T> static EvaluationValueSet fromSet(std::unordered_set<T> tmp) {
+       template <typename T> static EvaluationValueSet fromSet(std::unordered_set<T> tmp)
+       {
                EvaluationValueSet res;
                res.reserve(tmp.size());
-               for(auto &t : tmp)
+               for (auto &t : tmp)
                        res.insert(std::move(t));
                return res;
        }
-       template <typename K, typename EvaluationValuePtr> static EvaluationValueDict fromMap(std::unordered_map<K, EvaluationValuePtr> tmp) {
+       template <typename K, typename V> static EvaluationValueDict fromMap(std::unordered_map<K, V> tmp)
+       {
                EvaluationValueDict res;
                res.reserve(tmp.size());
-               for(auto &t : tmp)
+               for (auto &t : tmp)
                        res.insert({ t.first, std::move(t.second) });
                return res;
        }
@@ -236,19 +267,24 @@ namespace detail
                return ah.apply_1();
        }
        template <size_t I, size_t S> struct Converter {
-               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &dst, const std::vector<EvaluationValue_> &sourceArgs)
+               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &dst,
+                               const std::vector<EvaluationValue_> &sourceArgs,
+                               size_t firstDefaultArgIndex,
+                               const std::vector<EvaluationValue_> &defaultArguments)
                {
                        try {
-                               sourceArgs[I].convertTo(std::get<I>(dst));
+                               auto &s = I < sourceArgs.size() ? sourceArgs[I] : defaultArguments[I - firstDefaultArgIndex];
+                               s.convertTo(std::get<I>(dst));
                        } catch (EvaluationFailure &e) {
                                e << ", when converting " << (I + 1) << " argument";
                                throw;
                        }
-                       Converter < I + 1, S >::convert(dst, sourceArgs);
+                       Converter < I + 1, S >::convert(dst, sourceArgs, firstDefaultArgIndex, defaultArguments);
                }
        };
        template <size_t S> struct Converter<S, S> {
-               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &, const std::vector<EvaluationValue_> &)
+               template <typename ... ARGS> static void convert(std::tuple<ARGS...> &, const std::vector<EvaluationValue_> &,
+                               size_t, const std::vector<EvaluationValue_> &)
                {
                }
        };
@@ -260,28 +296,72 @@ namespace detail
                enum { value = 0 };
        };
 
-       template <typename T> struct is_allowed_evaluatation_value_type { enum { value = 0 }; };
-       template <typename T> struct is_allowed_evaluatation_value_type<T&> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
-       template <typename T> struct is_allowed_evaluatation_value_type<const T&> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
-       template <typename T> struct is_allowed_evaluatation_value_type<const T> { enum { value = is_allowed_evaluatation_value_type<T>::value }; };
-       template <> struct is_allowed_evaluatation_value_type<int> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<unsigned int> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<short> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<unsigned short> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<signed char> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<unsigned char> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValue_> { enum { value = 1 }; };        
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueEmpty> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueString> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueInteger> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDouble> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueUIElement> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueBoolean> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValuePoint> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueFunction> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueVector> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueSet> { enum { value = 1 }; };
-       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDict> { enum { value = 1 }; };
+       template <typename T> struct is_allowed_evaluatation_value_type {
+               enum { value = 0 };
+       };
+       template <typename T> struct is_allowed_evaluatation_value_type<T &> {
+               enum { value = is_allowed_evaluatation_value_type<T>::value };
+       };
+       template <typename T> struct is_allowed_evaluatation_value_type<const T &> {
+               enum { value = is_allowed_evaluatation_value_type<T>::value };
+       };
+       template <typename T> struct is_allowed_evaluatation_value_type<const T> {
+               enum { value = is_allowed_evaluatation_value_type<T>::value };
+       };
+       template <> struct is_allowed_evaluatation_value_type<int> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<unsigned int> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<short> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<unsigned short> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<signed char> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<unsigned char> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValue_> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueEmpty> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueString> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueInteger> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDouble> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueUIElement> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueBoolean> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValuePoint> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueFunction> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueVector> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueSet> {
+               enum { value = 1 };
+       };
+       template <> struct is_allowed_evaluatation_value_type<EvaluationValueDict> {
+               enum { value = 1 };
+       };
        template <typename T> struct is_allowed_evaluatation_value_type<std::vector<T>> {
                enum { value = is_allowed_evaluatation_value_type<T>::value };
        };
@@ -322,42 +402,109 @@ class EvaluationValueFunction
 {
 public:
        using Type = std::function<EvaluationValue_(const std::vector<EvaluationValue_>&)>;
+       class Arg
+       {
+       public:
+               Arg(std::string name) : name(std::move(name))
+               {
+                       ASSERT(!this->name.empty());
+               }
+               Arg(const char *name) : name(name)
+               {
+                       ASSERT(!this->name.empty());
+               }
+               Arg(std::string name, EvaluationValue_ val) : name(std::move(name)), defaultValue(std::move(val)) { }
+
+               std::string getName() const
+               {
+                       return name;
+               }
+               bool hasDefaultValue() const
+               {
+                       return bool(defaultValue);
+               }
+               EvaluationValue_ stealDefaultValue()
+               {
+                       auto tmp = std::move(*defaultValue);
+                       defaultValue = {};
+                       return tmp;
+               }
+       private:
+               std::string name;
+               Optional<EvaluationValue_> defaultValue;
+       };
+       class Args
+       {
+       public:
+               Args(const std::vector<EvaluationValue_> &args) : args(args) { }
 
+               bool empty() const
+               {
+                       return args.empty();
+               }
+               size_t size() const
+               {
+                       return args.size();
+               }
+               const EvaluationValue_ &operator [](size_t index) const
+               {
+                       return args[index];
+               }
+       private:
+               const std::vector<EvaluationValue_> &args;
+       };
        EvaluationValueFunction() = default;
        template <typename T, typename ARGS_TUPLE = typename detail::get_args_as_tuple_from_lambda<T>::type,
-               typename = typename std::enable_if<detail::are_args_allowed_evaluation_value_from_tuple<ARGS_TUPLE>::value>::type> 
-       EvaluationValueFunction(T && f) : function(constructConvertingArgsFunction<ARGS_TUPLE>(std::move(f))) { }
-       EvaluationValueFunction(std::function<EvaluationValue_(const std::vector<EvaluationValue_> &)> f) : function(std::move(f)) {}
+                         typename = typename std::enable_if<detail::are_args_allowed_evaluation_value_from_tuple<ARGS_TUPLE>::value>::type>
+       EvaluationValueFunction(T && f, std::vector<Arg> argDescriptions = {}) :
+               function(constructConvertingArgsFunction<ARGS_TUPLE>(std::move(f), std::move(argDescriptions))) { }
+
+       template <typename T, typename = typename std::enable_if<std::is_constructible<std::function<EvaluationValue_(Args)>, T>::value>::type>
+       EvaluationValueFunction(T && f) : function([f = std::forward<T>(f)](const std::vector<EvaluationValue_> & args)
+       {
+               return f(Args{ args });
+       }) {}
 
        explicit operator bool () const
        {
                return bool(function);
        }
 
-       EvaluationValue_ operator () (const std::vector<EvaluationValue_> &args) const
+       EvaluationValue_ operator()(const std::vector<EvaluationValue_> &args) const
        {
                return function(args);
        }
-protected:     
+protected:
        Type function;
 
-       static void validateArgumentCount(size_t expected, size_t got)
+       static void validateArgumentCount(size_t got, size_t expectedMin, size_t expectedMax)
        {
-               if (got < expected)
-                       throw EvaluationFailure{} << "not enough arguments, expected " << expected << ", got " << got;
-               if (got > expected)
-                       throw EvaluationFailure{} << "too many arguments, expected " << expected << ", got " << got;
+               if (got < expectedMin)
+                       throw EvaluationFailure{} << "not enough arguments, expected " <<
+                                                                         (expectedMin < expectedMax ? "at least " : "") << expectedMin << ", got " << got;
+               if (got > expectedMax)
+                       throw EvaluationFailure{} << "too many arguments, expected " <<
+                                                                         (expectedMin < expectedMax ? "at most " : "") << expectedMax << ", got " << got;
        }
 private:
        template <typename ARGS_TUPLE, typename T>
-       static EvaluationValueFunction::Type constructConvertingArgsFunction(T &&f)
+       static EvaluationValueFunction::Type constructConvertingArgsFunction(T &&f, std::vector<Arg> argDescriptions)
        {
-               return [f = std::move(f)](const std::vector<EvaluationValue_> &sourceArgs) -> EvaluationValue_ {
-                       constexpr auto expectedArgs = std::tuple_size<ARGS_TUPLE>::value;
-                       validateArgumentCount(expectedArgs, sourceArgs.size());
-                       //std::tuple<ARGS...>
+               constexpr auto expectedArgCount = std::tuple_size<ARGS_TUPLE>::value;
+               ASSERT(expectedArgCount >= argDescriptions.size());
+               std::vector<EvaluationValue_> defaultArguments;
+
+               for (auto it = argDescriptions.rbegin(); it != argDescriptions.rend() && it->hasDefaultValue(); ++it) {
+                       defaultArguments.push_back(std::move(it->stealDefaultValue()));
+               }
+               std::reverse(defaultArguments.begin(), defaultArguments.end());
+               auto firstDefaultArgIndex = expectedArgCount - defaultArguments.size();
+
+               return [f = std::move(f), defaultArguments = std::move(defaultArguments), firstDefaultArgIndex]
+               (const std::vector<EvaluationValue_> &sourceArgs) -> EvaluationValue_ {
+                       validateArgumentCount(sourceArgs.size(), firstDefaultArgIndex, expectedArgCount);
                        ARGS_TUPLE args;
-                       detail::Converter<0, expectedArgs>::convert(args, sourceArgs);
+                       detail::Converter<0, expectedArgCount>::convert(args, sourceArgs, firstDefaultArgIndex, defaultArguments);
                        return detail::apply(f, args);
                };
        }
index 77c385a..434d9dc 100644 (file)
@@ -149,80 +149,96 @@ TEST(TestExec, simpleParser)
 class ScriptTest : public ::testing::Test
 {
 protected:
+       size_t assertCount = 0;
+       std::ostringstream output;
+       VarsType vars;
+
+       ScriptTest()
+       {
+               vars["assert"] = [this](bool val) -> EvaluationValue_ {
+                       if (!val) throw EvaluationFailure{} << "assertion failed";
+                       ++assertCount;
+                       return {};
+               };
+               vars["print"] = [this](EvaluationValue_ val) -> EvaluationValue_ {
+                       output << ">>> " << val << "\n";
+                       return {};
+               };
+       }
+
        void SetUp(void) override
        {
        }
        void TearDown() override
        {
        }
-       void execute(std::string txt, size_t count = 1)
+       void execute(std::string txt, EvaluationContext &ec, bool printException)
        {
                std::string error;
                auto tokens = lexTest(error, "test", txt);
-               ASSERT_TRUE(error.empty()) << error;
 
-               // {
-               //      size_t index = 0;
-               //      for(auto &t : tokens)
-               //              std::cout << t.location().toString() << ": " << (index++) << " '" << t.text() << "' " << toString(t.type()) << "\n";
-               // }
+               if (!error.empty()) {
+                       size_t index = 0;
+                       for (auto &t : tokens)
+                               std::cout << t.location().toString() << ": " << (index++) << " '" << t.text() << "' " << toString(t.type()) << "\n";
+                       ASSERT_TRUE(error.empty()) << error;
+               }
 
                std::vector<std::string> errors;
                auto result = parseTokens(errors, tokens);
 
-               for (auto &e : errors) {
-                       std::cout << e << "\n";
+               if (!errors.empty()) {
+                       std::ostringstream tmp;
+                       result->printSelfInfo(tmp, 0);
+                       std::cout << tmp.str();
+                       for (auto &e : errors) {
+                               std::cout << e << "\n";
+                       }
+                       FAIL();
                }
-               ASSERT_TRUE(errors.empty());
                ASSERT_TRUE(result);
 
-               // {
-               //      std::ostringstream tmp;
-               //      result->printSelfInfo(tmp, 0);
-               //      std::cout << tmp.str();
-               // }
-
-               size_t callCount = 0;
-               auto vars = VarsType { };
-               std::ostringstream output;
-               vars["assert"] = [&](bool val) -> EvaluationValue_ {
-                       if (!val) throw EvaluationFailure{} << "assertion failed";
-                       ++callCount;
-                       return {};
-               };
-               vars["print"] = [&](EvaluationValue_ val) -> EvaluationValue_ {
-                       output << ">>> " << val << "\n";
-                       return {};
-               };
-               TestExecutor exec{ std::move(vars) };
-               EvaluationContext ec{ exec };
-
                try {
                        result->evaluate();
                } catch (EvaluationFailure &e) {
-                       size_t i = 0, c = 1;
-                       while (i < txt.size()) {
-                               auto n = txt.find('\n', i);
-                               if (n == std::string::npos) n = txt.size();
-                               output << std::setw(2) << c << ": " << txt.substr(i, n - i) << "\n";
-                               if (e.hasLocation() && c == e.location().lineNum()) {
-                                       for (auto i = 1u; i < e.location().offsetNum(); ++i)
-                                               output << " ";
-                                       output << "    ^\n";
+                       if (printException) {
+                               size_t i = 0, c = 1;
+                               while (i < txt.size()) {
+                                       auto n = txt.find('\n', i);
+                                       if (n == std::string::npos) n = txt.size();
+                                       output << std::setw(2) << c << ": " << txt.substr(i, n - i) << "\n";
+                                       if (e.hasLocation() && c == e.location().lineNum()) {
+                                               for (auto i = 1u; i < e.location().offsetNum(); ++i)
+                                                       output << " ";
+                                               output << "    ^\n";
+                                       }
+                                       i = n + 1;
+                                       ++c;
                                }
-                               i = n + 1;
-                               ++c;
                        }
+                       throw;
+               }
+       }
+       void execute(std::string txt, bool printException)
+       {
+               TestExecutor exec{ std::move(vars) };
+               EvaluationContext ec{ exec };
+               execute(std::move(txt), ec, printException);
+       }
+       void executeCountAsserts(std::string txt, size_t count = 1)
+       {
+               try {
+                       execute(std::move(txt), true);
+               } catch (EvaluationFailure &e) {
                        FAIL() << output.str() << (e.hasLocation() ? e.location().toString() + ": " : std::string{}) << e.message();
                }
-
-               ASSERT_EQ(callCount, count);
+               ASSERT_EQ(assertCount, count);
        }
 };
 
 TEST_F(ScriptTest, simpleComparisions)
 {
-       execute(
+       executeCountAsserts(
                "assert(1 == 1)\n"
                "assert(1 != 2)\n"
                "assert(1 < 2)\n"
@@ -272,7 +288,7 @@ TEST_F(ScriptTest, simpleComparisions)
 
 TEST_F(ScriptTest, vector)
 {
-       execute(
+       executeCountAsserts(
                "v = [1, 2, 3]\n"
                "assert(v[0] == 1)\n"
                "assert(v[1] == 2)\n"
@@ -302,7 +318,7 @@ TEST_F(ScriptTest, vector)
 
 TEST_F(ScriptTest, set)
 {
-       execute(
+       executeCountAsserts(
                "v = {1, 2, 3, '1', '2', '3'}\n"
                "assert(1 in v)\n"
                "assert(2 in v)\n"
@@ -317,7 +333,7 @@ TEST_F(ScriptTest, set)
 
 TEST_F(ScriptTest, map)
 {
-       execute(
+       executeCountAsserts(
                "v = {1: 1, 2: 2, '1': 3}\n"
                "assert(1 in v)\n"
                "assert(2 in v)\n"
@@ -331,7 +347,7 @@ TEST_F(ScriptTest, map)
 
 TEST_F(ScriptTest, point)
 {
-       execute(
+       executeCountAsserts(
                "v = <1,2>\n"
                "assert(v == <1,2>)\n"
                , 1);
@@ -347,6 +363,57 @@ TEST_F(ScriptTest, comments)
                , 1);
 }
 
+TEST_F(ScriptTest, defaultArguments)
+{
+       std::tuple<int, int, int, int> val, expected;
+
+       vars["func"] = EvaluationValueFunction{
+               [&](int a1, int a2, int a3, int a4) -> EvaluationValue_ {
+                       std::get<0>(val) = a1;
+                       std::get<1>(val) = a2;
+                       std::get<2>(val) = a3;
+                       std::get<3>(val) = a4;
+                       return {};
+               }, {
+                       { "a2" },
+                       { "a3", 1 },
+                       { "a4", 2 }
+               } };
+
+       TestExecutor exec{ std::move(vars) };
+       EvaluationContext ec{ exec };
+
+       execute("func(6,7,8,9)", ec, true);
+       expected = { 6, 7, 8, 9};
+       ASSERT_EQ(val, expected);
+
+       execute("func(5, 6)", ec, true);
+       expected = { 5, 6, 1, 2};
+       ASSERT_EQ(val, expected);
+
+       execute("func(2, 3, 4)", ec, true);
+       expected = { 2, 3, 4, 2};
+       ASSERT_EQ(val, expected);
+
+       try {
+               execute("func(2)", ec, true);
+               FAIL() << "didn't throw";
+       } catch (EvaluationFailure &) {
+       }
+
+       try {
+               execute("func()", ec, true);
+               FAIL() << "didn't throw";
+       } catch (EvaluationFailure &) {
+       }
+
+       try {
+               execute("func(1,2,3,4,5)", ec, true);
+               FAIL() << "didn't throw";
+       } catch (EvaluationFailure &) {
+       }
+}
+
 int main(int argc, char *argv[])
 {
        try {