implement refinement filter on log entry's arguments.
Whew! functional programming is such a powerful concept. You get additional refinement and lazy backtracking basically for free....
This commit is contained in:
parent
5bc6919bdb
commit
33f7fe116a
3 changed files with 61 additions and 10 deletions
|
|
@ -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<typename X>
|
||||
|
|
@ -131,6 +132,19 @@ namespace util {
|
|||
}
|
||||
catch(...) { return ""; }
|
||||
};
|
||||
template<>
|
||||
struct _InvokeFailsafe<float>
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ namespace test{
|
|||
using Iter = lib::IterCursor<Log::const_iterator>;
|
||||
using Filter = ExtensibleFilterIter<Iter>;
|
||||
|
||||
using ArgSeq = lib::diff::RecordSetup<string>::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<typename...ARGS>
|
||||
EventMatch&
|
||||
arg ()
|
||||
arg (ARGS const& ...args)
|
||||
{
|
||||
UNIMPLEMENTED("process match on no-arg call argument list");
|
||||
}
|
||||
|
||||
template<typename... MORE>
|
||||
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<typename... MORE>
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Reference in a new issue