diff --git a/tests/vault/gear/activity-detector-test.cpp b/tests/vault/gear/activity-detector-test.cpp index d7ee3da0b..47fe352f1 100644 --- a/tests/vault/gear/activity-detector-test.cpp +++ b/tests/vault/gear/activity-detector-test.cpp @@ -94,7 +94,10 @@ namespace test { /** @test verify the setup and detection of instrumented invocations - * @todo WIP 7/23 ✔ define ✔ implement + * - a _sequence number_ is embedded into the ActivityDetector + * - this sequence number is recorded into an attribute at each invocation + * - a DSL for verification is provided (based on the EventLog) + * - arguments and sequence numbers can be explicitly checked */ void verifyMockInvocation() @@ -107,7 +110,7 @@ namespace test { CHECK (1 == detector.currSeq()); CHECK (detector.ensureNoInvocation ("funny")); - detector.markSequence(); + ++detector; CHECK (2 == detector.currSeq()); CHECK (detector.verifySeqIncrement(2)); @@ -117,13 +120,13 @@ namespace test { CHECK (detector.verifyInvocation ("funny").seq(2)); CHECK (detector.verifyInvocation ("funny").arg(rnd).seq(2)); CHECK (detector.verifyInvocation ("funny").seq(2).arg(rnd)); - CHECK (detector.ensureNoInvocation ("bunny")); - CHECK (detector.ensureNoInvocation ("funny").arg()); - CHECK (detector.ensureNoInvocation ("funny").arg(-rnd)); - CHECK (detector.ensureNoInvocation ("funny").seq(5)); - CHECK (detector.ensureNoInvocation ("funny").arg(rnd).seq(1)); + CHECK (detector.ensureNoInvocation ("bunny")); // wrong name + CHECK (detector.ensureNoInvocation ("funny").arg()); // fails since empty argument list expected + CHECK (detector.ensureNoInvocation ("funny").arg(rnd+5)); // expecting wrong argument + CHECK (detector.ensureNoInvocation ("funny").seq(5)); // expecting wrong sequence number + CHECK (detector.ensureNoInvocation ("funny").arg(rnd).seq(1)); // expecting correct argument, but wrong sequence - detector.markSequence(); + ++detector; fun (rnd+1); CHECK (detector.verifyInvocation ("funny").seq(2) .beforeSeqIncrement(3) diff --git a/tests/vault/gear/activity-detector.hpp b/tests/vault/gear/activity-detector.hpp index 1c9ef062f..69de4fc08 100644 --- a/tests/vault/gear/activity-detector.hpp +++ b/tests/vault/gear/activity-detector.hpp @@ -31,12 +31,29 @@ ** means of indirection and extension. As a remedy, a set of preconfigured ** _detector Activity records_ is provided, which drop off event log messages ** by side effect. These detector probes can be wired in as decorators into - ** a otherwise valid Activity-Term, allowing to watch and verify patterns + ** an otherwise valid Activity-Term, allowing to watch and verify patterns ** of invocation -- which might even happen concurrently. - ** - ** @todo WIP-WIP-WIP 7/2023 right now this is a rather immature attempt - ** towards a scaffolding to propel the build-up of the scheduler. + ** + ** # Usage + ** + ** An ActivityDetector instance can be created in local storage to get an arsenal + ** of probing tools and detectors, which are internally wired to record activation + ** into an lib::test::EventLog embedded into the ActivityDetector instance. A + ** _verification DSL_ is provided, internally relying on the building blocks and + ** the chained-search mechanism known from the EventLog. To distinguish similar + ** invocations and activations, a common _sequence number_ is maintained within + ** the ActivityDetector instance, which can be incremented explicitly. All + ** relevant events also capture the current sequence number as an attribute + ** of the generated log record. + ** + ** ## Observation tools + ** - ActivityDetector::buildDiadnosticFun(id) generates a functor object with + ** _arbitrary signature,_ which records any invocation and arguments. + ** The corresponding verification matcher is #verifyInvocation(id) + ** + ** @todo WIP-WIP-WIP 8/2023 gradually gaining traction. ** @see SchedulerActivity_test + ** @see EventLog_test (demonstration of EventLog capbabilities) */ @@ -97,40 +114,6 @@ namespace test { // using vault::gear::JobClosure; - /** Marker for invocation sequence */ - class Seq - { - uint step_; - - public: - Seq (uint start =0) - : step_{start} - { } - - operator uint() const - { - return step_; - } - operator string() const - { - return util::toString (step_); - } - - uint - operator++() - { - ++step_; - return step_; - } - - bool - operator== (Seq const& o) - { - return step_ == o.step_; - } - }; - - namespace {// Event markers const string MARK_INC{"IncSeq"}; const string MARK_SEQ{"Seq"}; @@ -139,6 +122,12 @@ namespace test { class ActivityDetector; + /** + * @internal ongoing evaluation and match of observed activities. + * @remark this temporary object provides a builder API for creating + * chained verifications, similar to the usage of lib::test::EventLog. + * Moreover, it is convertible to `bool` to retrieve the verification result. + */ class ActivityMatch : private lib::test::EventMatch { @@ -153,6 +142,10 @@ namespace test { public: // standard copy acceptable + /** final evaluation of the verification query, + * usually triggered from the unit test `CHECK()`. + * @note failure cause is printed to STDERR. + */ operator bool() const { return _Parent::operator bool(); } @@ -178,7 +171,7 @@ namespace test { // EventMatch& afterMatch (string regExp); // EventMatch& afterEvent (string match); // EventMatch& afterEvent (string classifier, string match); -// EventMatch& afterCall (string match); + ActivityMatch& afterInvocation (string match) { return delegate (&EventMatch::afterCall, move(match)); } /** qualifier: additionally match the function arguments */ template @@ -196,6 +189,7 @@ namespace test { return *this; } + /** special query to match an increment of the sequence number */ ActivityMatch& beforeSeqIncrement (uint seqNr) { @@ -203,7 +197,13 @@ namespace test { return *this; } + private: + /** @internal helper to delegate to the inherited matcher building blocks + * @note since ActivityMatch can only be created by ActivityDetector, + * we can be sure the EventMatch reference returned from these calls + * is actually a reference to `*this`, and can thus be downcasted. + * */ template ActivityMatch& delegate (_Parent& (_Parent::*fun) (ARGS...), ARGS&& ...args) @@ -216,7 +216,11 @@ namespace test { /** * Diagnostic context to record and evaluate activations within the Scheduler. - * @todo WIP-WIP-WIP 7/23 a new loopy hope + * The provided tools and detectors are wired back internally, such as to record + * any observations into an lib::test::EventLog instance. Thus, after performing + * rigged functionality, the expected activities and their order can be verified. + * @see ActivityDetector_test + * @todo WIP-WIP-WIP 8/23 gradually building the verification tools needed... */ class ActivityDetector : util::NonCopyable @@ -224,7 +228,7 @@ namespace test { using EventLog = lib::test::EventLog; EventLog eventLog_; - Seq invocationSeq_; + uint invocationSeq_; /** * A Mock functor, logging all invocations into the EventLog @@ -236,14 +240,14 @@ namespace test { string id_; EventLog* log_; - Seq const* seqNr_; + uint const* seqNr_; RetVal retVal_; public: - DiagnosticFun (string id, EventLog& masterLog, Seq const& seqNr) + DiagnosticFun (string id, EventLog& masterLog, uint const& invocationSeqNr) : id_{id} , log_{&masterLog} - , seqNr_{&seqNr} + , seqNr_{&invocationSeqNr} , retVal_{} { } @@ -261,7 +265,7 @@ namespace test { operator() (ARGS const& ...args) { log_->call (log_->getID(), id_, args...) - .addAttrib (MARK_SEQ, *seqNr_); + .addAttrib (MARK_SEQ, util::toString(*seqNr_)); return *retVal_; } }; @@ -278,6 +282,15 @@ namespace test { return util::join (eventLog_); } + string + showLog() const + { + return "\n____Event-Log___________________________\n" + + util::join (eventLog_, "\n") + + "\n────╼━━━━━━━━╾──────────────────────────" + ; + } + void clear(string newID) { @@ -287,11 +300,12 @@ namespace test { eventLog_.clear (newID); } + /** increment the internal invocation sequence number */ uint operator++() { ++invocationSeq_; - eventLog_.event (MARK_INC, invocationSeq_); + eventLog_.event (MARK_INC, util::toString(invocationSeq_)); return invocationSeq_; } @@ -301,12 +315,6 @@ namespace test { return invocationSeq_; } - uint - markSequence() - { - return operator++(); - } - /** * Generic testing helper: build a λ-mock, logging all invocations @@ -348,16 +356,6 @@ namespace test { } - string - showLog() const - { - return "\n____Event-Log___________________________\n" - + util::join (eventLog_, "\n") - + "\n────╼━━━━━━━━╾──────────────────────────" - ; - } - - private: }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index a4daf9648..45f7e8ea6 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -79423,14 +79423,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + - + @@ -79439,11 +79439,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+
- + + + + +

+ ...paßt perfekt hier; muß lediglich die elementaren Verifikations-Primitive hier verpacken, um semantisch relevante Elemente direkt zu prüfen +

+ +
-
@@ -81640,6 +81648,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -81673,7 +81682,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -81727,12 +81736,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + @@ -81740,18 +81749,23 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + - + - - + + + + @@ -81814,8 +81828,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81834,12 +81848,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- +

- ...allerdings liegt das an der Natur der logischen Negation selber, nicht an der unterstützung im Verifkations-Framework; ein Check ist eine Existenz-Aussage, und daher müßte zur Negation eine All-Aussage geprüft werden, durch eine erschöpfende Suche aller möglichen alternativen Prüf-Ketten. Ich hatte Fälle, in denen das durchaus vorhandene Backtracking das nicht leisten konnte + ...allerdings liegt das an der Natur der logischen Negation selber, nicht an der unterstützung im Verifkations-Framework; ein Check ist eine Existenz-Aussage, und daher müßte zur Negation eine All-Aussage geprüft werden, durch eine erschöpfende Suche aller möglichen alternativen Prüf-Ketten. Anfangs habe ich das nicht gemacht, aber 9/2018 habe ich richtiges Backtracking eingebaut; damit sollte das nun korrekt funktionieren (was ich aber nie abschließend verifiziert habe, nur durch einzelne Testfälle geprüft)

@@ -81856,28 +81870,53 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + - - - + + + + + + + + + +

+ ein Funktionsaufruf (typischwerweise von einem rigged-Functor) +

+ +
+ +
+
+
+
+ + + + + - + - + - + - + - - + + @@ -81895,13 +81934,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + +
+ + - + + + + + @@ -81934,10 +81979,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + + @@ -81959,6 +82005,18 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +
+ + + + + + + +