Activity-Lang: switch invocation detection to delegated matcher

ActivityMatch inherits privately from the EventMatch object,
and is thus able to delegate relevant matching queries, but
also to provide high-level special matchers.

This new design resolves the ambiguity regarding function arguments.
Moreover, we can now record the current sequence-Number as *attribute*
in the respective log record (this is the benefit of using structured
log entries instead of just a textual log), thereby avoiding the various
pitfalls with explicit bracketing sequence-number log entries

bottom line: this reworked design seems to be a better fit,
even while technically the implementation with the wrapped matcher
is somewhat ugly...
This commit is contained in:
Fischlurch 2023-08-13 23:42:04 +02:00
parent ff4acb04d7
commit 25ad461a28
4 changed files with 147 additions and 50 deletions

View file

@ -415,6 +415,18 @@ namespace test{
EventLog& destroy (string text);
/** Qualify the latest entry: set further attribute(s) */
template<typename X, typename...ARGS>
EventLog&
addAttrib (string const& key, X&& initialiser, ARGS&& ...args)
{
REQUIRE (not isnil (*log_));
mutateInPlace (log_->back())
.attrib(key,initialiser, std::forward<ARGS>(args)...);
return *this;
}
/* ==== Iteration ==== */

View file

@ -88,7 +88,7 @@ namespace test {
CHECK (55 == trap (1.23, Time{FSecs{3,2}}));
CHECK (detector == "Rec(EventLogHeader| this = ActivityDetector(spectre) ), "
"Rec(call| fun = trap, this = ActivityDetector(spectre) |{1.23, 0:00:01.500})"_expect);
"Rec(call| fun = trap, this = ActivityDetector(spectre), Seq = 0 |{1.23, 0:00:01.500})"_expect);
}
@ -109,14 +109,16 @@ namespace test {
detector.markSequence();
fun(rnd);
CHECK (detector.verifyCall ("funny"));
CHECK (detector.verifyCall ("funny").arg(rnd));
CHECK (detector.verifyInvocation ("funny", Seq(1)));
CHECK (detector.verifyInvocation ("funny", Seq(1), rnd));
CHECK (detector.verifyInvocation ("funny"));
CHECK (detector.verifyInvocation ("funny").arg(rnd));
CHECK (detector.verifyInvocation ("funny").seq(2));
CHECK (detector.verifyInvocation ("funny").arg(rnd).seq(2));
CHECK (detector.verifyInvocation ("funny").seq(2).arg(rnd));
CHECK (not detector.verifyInvocation ("bunny"));
CHECK (not detector.verifyInvocation ("funny", -rnd));
CHECK (not detector.verifyInvocation ("funny", Seq(5)));
CHECK (not detector.verifyInvocation ("funny", rnd, Seq(1)));
CHECK (not detector.verifyInvocation ("funny").arg());
CHECK (not detector.verifyInvocation ("funny").arg(-rnd));
CHECK (not detector.verifyInvocation ("funny").seq(5));
CHECK (not detector.verifyInvocation ("funny").arg(rnd).seq(1));
}

View file

@ -155,12 +155,6 @@ namespace test {
operator bool() const { return _Parent::operator bool(); }
template<typename...ARGS>
ActivityMatch&
arg (ARGS const& ...args)
{
return delegate (&EventMatch::arg<ARGS...>, args...);
}
// EventMatch& locate (string match);
// EventMatch& locateMatch (string regExp);
@ -175,7 +169,7 @@ namespace test {
// EventMatch& beforeMatch (string regExp);
// EventMatch& beforeEvent (string match);
// EventMatch& beforeEvent (string classifier, string match);
ActivityMatch& beforeCall (string match) { return delegate (&EventMatch::beforeCall, move(match)); }
ActivityMatch& beforeInvocation (string match) { return delegate (&EventMatch::beforeCall, move(match)); }
//
//
// /* query builders to find a match stepping backwards */
@ -186,6 +180,22 @@ namespace test {
// EventMatch& afterEvent (string classifier, string match);
// EventMatch& afterCall (string match);
/** qualifier: additionally match the function arguments */
template<typename...ARGS>
ActivityMatch&
arg (ARGS const& ...args)
{
return delegate (&EventMatch::arg<ARGS...>, args...);
}
/** qualifier: additionally require the indicated sequence number */
ActivityMatch&
seq (uint seqNr)
{
_Parent::attrib (MARK_SEQ, util::toString (seqNr));
return *this;
}
private:
template<typename...ARGS>
ActivityMatch&
@ -219,12 +229,14 @@ namespace test {
string id_;
EventLog* log_;
Seq const* seqNr_;
RetVal retVal_;
public:
DiagnosticFun (string id, EventLog& masterLog)
DiagnosticFun (string id, EventLog& masterLog, Seq const& seqNr)
: id_{id}
, log_{&masterLog}
, seqNr_{&seqNr}
, retVal_{}
{ }
@ -241,7 +253,8 @@ namespace test {
RET
operator() (ARGS const& ...args)
{
log_->call (log_->getID(), id_, args...);
log_->call (log_->getID(), id_, args...)
.addAttrib (MARK_SEQ, *seqNr_);
return *retVal_;
}
};
@ -305,43 +318,26 @@ namespace test {
using SigTypes = typename lib::meta::Prepend<Ret, ArgsX>::Seq;
using Functor = typename RebindVariadic<DiagnosticFun, SigTypes>::Type;
return Functor{id, eventLog_};
return Functor{id, eventLog_, invocationSeq_};
}
template<typename...ARGS>
bool
verifyInvocation (string fun, Seq const& seq, ARGS const& ...args)
{
bool valid = eventLog_.verifyEvent(seq).id(MARK_INC)
.beforeCall(fun).arg(args...)
.beforeEvent(seq).id(MARK_SEQ);
if (not valid)
{
cerr << "FAIL___Function_invocation___________"
<< "\nfunction:"<<fun<<util::joinArgList (args...)
<< "\nsequence:"<<seq
<< "\n_______Event-Log_____________________\n"
<< util::join(eventLog_, "\n")
<< "\n───────╼━━━━━━━━╾────────────────────"
<< endl;
}
return valid;
}
template<typename...ARGS>
bool
verifyInvocation (string fun, ARGS const& ...args)
{
return verifyInvocation (fun, invocationSeq_, args...);
}
ActivityMatch
verifyCall (string fun)
verifyInvocation (string fun)
{
return ActivityMatch{move (eventLog_.verifyCall(fun))};
}
string
getLog() const
{
return "\n_______Event-Log_____________________\n"
+ util::join (eventLog_, "\n")
+ "\n───────╼━━━━━━━━╾────────────────────"
;
}
private:
};

View file

@ -81743,7 +81743,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1690900159528" ID="ID_689193567" MODIFIED="1690918955037" TEXT="Wrapper-Typ verwenden (keinen primitiven Typ)">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1690899920322" ID="ID_67461983" MODIFIED="1690899953072" TEXT="den Einzel-Aufruf mit der Nummer einklammern">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1690899920322" ID="ID_67461983" MODIFIED="1691967256168" TEXT="den Einzel-Aufruf mit der Sequenz-Nummer markieren">
<arrowlink COLOR="#fddadc" DESTINATION="ID_67251959" ENDARROW="Default" ENDINCLINATION="250;-68;" ID="Arrow_ID_996698966" STARTARROW="None" STARTINCLINATION="142;7;"/>
<icon BUILTIN="idea"/>
</node>
</node>
@ -81782,19 +81783,88 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1691876841330" ID="ID_1105562804" MODIFIED="1691877303577" TEXT="die EventLog-DSL verwendet daf&#xfc;r einen EventMatch(Builder)">
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1691877252417" ID="ID_1984871622" MODIFIED="1691951648662" TEXT="diesen k&#xf6;nnte man dekorieren und erweitern">
<node COLOR="#435e98" CREATED="1691877252417" ID="ID_1984871622" MODIFIED="1691970627322" TEXT="diesen k&#xf6;nnte man dekorieren und erweitern">
<linktarget COLOR="#ebfec9" DESTINATION="ID_1984871622" ENDARROW="Default" ENDINCLINATION="-28;49;" ID="Arrow_ID_850495720" SOURCE="ID_761662231" STARTARROW="None" STARTINCLINATION="-304;29;"/>
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1691970693305" ID="ID_19920544" MODIFIED="1691970777582" TEXT="nicht ganz einfach...">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...das war vom Design her nicht vorgesehen, und w&#228;re auch nicht ganz einfach zu realisieren; man m&#252;&#223;te den EventMatch per CRTP definieren (und damit m&#252;&#223;te er Header-only sein, mit den bekannten Folgen f&#252;r die Gr&#246;&#223;e des Debug-Build)
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#435e98" CREATED="1691970806346" ID="ID_1508518510" MODIFIED="1691970872329" TEXT="kann aber den R&#xfc;ckgabewert downcasten">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...denn dies hier ist ein geschlossenes &#214;kosystem; daher ist sichergestellt, da&#223; *this stets ein ActivityMatch ist
</p>
</body>
</html></richcontent>
</node>
<node COLOR="#338800" CREATED="1691970781106" ID="ID_411948478" MODIFIED="1691970802181" TEXT="verwende abk&#xfc;rzende Notation mit Argument-Forwarding">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1691970876168" ID="ID_1869522832" MODIFIED="1691970894037" TEXT="besser: privat erben und nur die wirklich ben&#xf6;tigten Funktionen forwarden">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
<node CREATED="1690899978840" ID="ID_70827658" MODIFIED="1690899987515" TEXT="einen Funktionsaufruf verifizieren">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1690900023906" ID="ID_1470650457" MODIFIED="1690918796008" TEXT="markSequence()">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1691967036611" ID="ID_1281722986" MODIFIED="1691967047702" TEXT="was bedeutet das &#xfc;berhaupt?"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1691967048250" ID="ID_1226565848" MODIFIED="1691967068615" TEXT="Ansatz: eine interne Sequenznummer hochsetzen">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1690900069493" ID="ID_917256156" MODIFIED="1690900150148" TEXT="verifyInvocation(fun, Seq(i), args...)">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1691622557790" ID="ID_307528565" MODIFIED="1691622593416" TEXT="lenient arguments?">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1691967069495" ID="ID_67251959" MODIFIED="1691967245462" TEXT="wie/wo kann die zuverl&#xe4;ssig gepr&#xfc;ft werden?">
<linktarget COLOR="#fddadc" DESTINATION="ID_67251959" ENDARROW="Default" ENDINCLINATION="250;-68;" ID="Arrow_ID_996698966" SOURCE="ID_67461983" STARTARROW="None" STARTINCLINATION="142;7;"/>
<icon BUILTIN="help"/>
<node COLOR="#5b280f" CREATED="1691967116385" ID="ID_1378863406" MODIFIED="1691967128672" TEXT="erste Idee: zus&#xe4;tzliche Eintr&#xe4;ge im Log">
<icon BUILTIN="button_cancel"/>
<node CREATED="1691967129967" ID="ID_904829426" MODIFIED="1691967134017" TEXT="einfach umzusetzen"/>
<node CREATED="1691967134523" ID="ID_564127342" MODIFIED="1691967140537" TEXT="aber umst&#xe4;ndlich in der Handhabung"/>
<node CREATED="1691967149276" ID="ID_291271617" MODIFIED="1691967157215" TEXT="und noch schlimmer: nicht eindeutig"/>
<node CREATED="1691967141625" ID="ID_1932163820" MODIFIED="1691967147977" TEXT="und m&#xfc;llt das Log zu"/>
</node>
<node CREATED="1691967161499" ID="ID_368230212" MODIFIED="1691967174065" TEXT="das strukturierte EventLog nutzen">
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1691967175689" ID="ID_746233199" MODIFIED="1691967185000" TEXT="Attribut &quot;Seq&quot; einf&#xfc;hren">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1691967277027" ID="ID_1776684493" MODIFIED="1691967284636" TEXT="Problem: Logging API">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1691967309343" ID="ID_244666662" MODIFIED="1691967318610" TEXT="hat typischerweise bereits eine offene Argumentliste"/>
<node CREATED="1691967323722" ID="ID_137219277" MODIFIED="1691967342183" TEXT="man m&#xfc;&#xdf;te Erg&#xe4;nzungen oder Qualifier nutzen"/>
<node CREATED="1691967444533" ID="ID_1942563471" MODIFIED="1691967456767" TEXT="w&#xfc;rde dann auf den letzten Eintrag wirken"/>
</node>
<node CREATED="1691967345874" ID="ID_1693656780" MODIFIED="1691967361490" TEXT="Record-Typ ist eigentlich immutable">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#fe2ee7" CREATED="1691967494714" ID="ID_1135212108" MODIFIED="1691967548854" TEXT="(es g&#xe4;be eine Hintert&#xfc;r....)">
<font NAME="SansSerif" SIZE="11"/>
<icon BUILTIN="smiley-oh"/>
</node>
<node COLOR="#5b280f" CREATED="1691967521418" ID="ID_1774670461" MODIFIED="1691967534653" TEXT="was sagt uns das??">
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1691967188541" ID="ID_190903532" MODIFIED="1691967210908" TEXT="dieses dann per Zusatz-Match pr&#xfc;fbar machen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
<node COLOR="#5b280f" CREATED="1690900069493" ID="ID_917256156" MODIFIED="1691966998192" TEXT="verifyInvocation(fun, Seq(i), args...)">
<icon BUILTIN="button_cancel"/>
<node COLOR="#5b280f" CREATED="1691622557790" ID="ID_307528565" MODIFIED="1691966784058" TEXT="lenient arguments?">
<icon BUILTIN="help"/>
<icon BUILTIN="button_cancel"/>
<node CREATED="1691622603918" ID="ID_85657456" MODIFIED="1691622614224" TEXT="manchmal sind die Argumente egal"/>
<node CREATED="1691622615042" ID="ID_1956964914" MODIFIED="1691622630486" TEXT="oder man wei&#xdf; sie nicht einmal..."/>
<node CREATED="1691622633914" ID="ID_1240512860" MODIFIED="1691622650564" TEXT="L&#xf6;sung-1">
@ -81807,7 +81877,24 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="stop-sign"/>
</node>
</node>
<node CREATED="1691966737035" ID="ID_367147170" MODIFIED="1691966774672" TEXT="Nein! warum &#xfc;berhaupt diese Frage? &#x27f9; das ganze Design ist schlecht">
<icon BUILTIN="stop-sign"/>
</node>
<node COLOR="#435e98" CREATED="1691966791292" ID="ID_761662231" MODIFIED="1691966961557" TEXT="besser: Matcher verfeinern">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Der Ansatz, alles ein einen Pr&#252;f-Aufruf zu packen, ist insgeseamt ungeschickt; genau deshalb wurde doch f&#252;r das EventLog dieser komplizierte Builder / Verfeinerungs-Ansatz gemacht: dar&#252;ber kann man ganz nat&#252;rlich ausdr&#252;cken, wenn man etwas &#252;ber die Argumente speziell gepr&#252;ft haben m&#246;chte, oder eben nicht...
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#ebfec9" DESTINATION="ID_1984871622" ENDARROW="Default" ENDINCLINATION="-28;49;" ID="Arrow_ID_850495720" STARTARROW="None" STARTINCLINATION="-304;29;"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1690900069493" ID="ID_1755197034" MODIFIED="1691967022305" TEXT="verifyInvocation(fun).args(args...).seq(i)">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>