diff --git a/src/lib/format-util.hpp b/src/lib/format-util.hpp index 5063d8aaf..0fcef6ec4 100644 --- a/src/lib/format-util.hpp +++ b/src/lib/format-util.hpp @@ -73,6 +73,7 @@ namespace util { // precision for rendering of double values const auto DIAGNOSTICS_DOUBLE_PRECISION = 8; + const auto DIAGNOSTICS_FLOAT_PRECISION = 5; template @@ -131,6 +132,19 @@ namespace util { } catch(...) { return ""; } }; + template<> + struct _InvokeFailsafe + { + static string + toString (float const& val) + try { + std::ostringstream buffer; + buffer.precision(DIAGNOSTICS_FLOAT_PRECISION); + buffer << val; + return buffer.str(); + } + catch(...) { return ""; } + }; }//(End) guards/helpers diff --git a/src/lib/test/event-log.hpp b/src/lib/test/event-log.hpp index 943e44e5c..f66e52a4d 100644 --- a/src/lib/test/event-log.hpp +++ b/src/lib/test/event-log.hpp @@ -104,6 +104,9 @@ namespace test{ using Iter = lib::IterCursor; using Filter = ExtensibleFilterIter; + using ArgSeq = lib::diff::RecordSetup::Storage; + + /** match predicate evaluator */ Filter solution_; @@ -225,6 +228,32 @@ namespace test{ }; } + + /** this filter functor is for refinement of an existing filter + * @param argSeq perform a substring match consecutively + * for each of the log entry's arguments + * @note the match also fails, when the given log entry + * has more or less arguments, than the number of + * given match expressions in `argSeq` + * @see ExtensibleFilterIter::andFilter() + */ + auto + matchArguments(ArgSeq&& argSeq) + { + return [=](Entry const& entry) + { + auto scope = entry.scope(); + for (auto const& match : argSeq) + if (isnil (scope) or not contains(*scope, match)) + return false; + else + ++scope; + + return isnil(scope); // must be exhausted by now + }; // otherwise the sizes do not match... + } + + public: /** final evaluation of the match query, * usually triggered from the unit test `CHECK()`. @@ -351,17 +380,23 @@ namespace test{ return *this; } + /** refine filter to additionally require specific arguments + * @remarks the refined filter works on each record qualified by the + * query expression established thus far; it additionally + * looks into the arguments (children list) of the log entry. + * @warning match is processed by comparision of string representation. + */ + template EventMatch& - arg () + arg (ARGS const& ...args) { - UNIMPLEMENTED("process match on no-arg call argument list"); - } - - template - EventMatch& - arg (string match, MORE...args) - { - UNIMPLEMENTED("process match on call argument list"); + ArgSeq argSeq; + argSeq.reserve(sizeof...(ARGS)); + stringify (argSeq, args...); + + solution_.andFilter (matchArguments(std::move(argSeq))); + evaluateQuery ("match-arguments("+util::join(argSeq)+")"); + return *this; } template diff --git a/tests/library/test/test-event-log-test.cpp b/tests/library/test/test-event-log-test.cpp index be02c37d9..5c48ad01a 100644 --- a/tests/library/test/test-event-log-test.cpp +++ b/tests/library/test/test-event-log-test.cpp @@ -217,7 +217,9 @@ namespace test{ CHECK (log.verifyCall("fun3").arg(string("facts"), 3.2f, int64_t(1))); CHECK (log.verifyCall("fun3").arg("facts", "3.2", "1")); - CHECK (log.ensureNot("fun").arg(" facts ", "3.20", "1L")); + CHECK (log.ensureNot("fun").arg(" facts ","3.2", "1")); + CHECK (log.ensureNot("fun").arg("facts", "3.20","1")); + CHECK (log.ensureNot("fun").arg("facts", "3.2", "1L")); CHECK (log.verifyCall("fun1").arg()); CHECK (log.verifyCall("fun2").arg());