From e3f1aa4f7cf28d5a12a575e487378664261a2709 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 14 Aug 2023 19:22:18 +0200 Subject: [PATCH] Activity-Lang: support negative assertions for tests Testcase (detect function invocation) passes now as expected Some Library / Framework changes - rename event-log-test.cpp - allow the ExpectString also to work with concatenated expectation strings Remark: there was a warning in the comment in event-log.hpp, pointing out that negative assertions are shallow. However, after the rework in 9/2018 (commit: d923138d1) ...this should no longer be true, since we perform proper backtracking, leading to an exhaustive search. --- src/lib/test/event-log.cpp | 9 ++- src/lib/test/event-log.hpp | 6 +- src/lib/test/test-helper.hpp | 6 ++ tests/00support.tests | 6 +- ...-event-log-test.cpp => event-log-test.cpp} | 10 +-- tests/vault/gear/activity-detector-test.cpp | 34 +++++++--- tests/vault/gear/activity-detector.hpp | 31 +++++++-- wiki/thinkPad.ichthyo.mm | 65 +++++++++++++++++++ 8 files changed, 136 insertions(+), 31 deletions(-) rename tests/library/test/{test-event-log-test.cpp => event-log-test.cpp} (98%) diff --git a/src/lib/test/event-log.cpp b/src/lib/test/event-log.cpp index 9fdc8e0a0..44d409c8c 100644 --- a/src/lib/test/event-log.cpp +++ b/src/lib/test/event-log.cpp @@ -35,7 +35,7 @@ ** (non-inline) functions and package all the actual implementation ** code into this dedicated translation unit. ** - ** @see TestEventLog_test + ** @see EventLog_test ** @see IterChainSearch_test ** @see iter-explorer.hpp ** @@ -785,10 +785,9 @@ namespace test{ * @remarks the query expression is built similar to the other queries, * but the logic of evaluation is flipped: whenever we find any match * the overall result (when evaluating to `bool`) will be `false`. - * @warning this is not an proper exhaustive negation, since the implementation - * does not proper backtracking with a stack of choices. This becomes - * evident, when you combine `ensureNot()` with a switch in search - * direction, like e.g. using `afterXXX` at some point in the chain. + * @note since the chained search involves backtracking, this should perform + * an exhaustive negation, searching for a possible match until no + * further search options are left. */ EventMatch EventLog::ensureNot (string match) const diff --git a/src/lib/test/event-log.hpp b/src/lib/test/event-log.hpp index 1d1f36b25..5644cc04a 100644 --- a/src/lib/test/event-log.hpp +++ b/src/lib/test/event-log.hpp @@ -69,7 +69,7 @@ ** diagnostics. This means: the sequence of matches you see in this diagnostic ** output is not necessarily the last match patch, which lead to the final failure ** - ** @see TestEventLog_test + ** @see EventLog_test ** @see [usage example](\ref AbstractTangible_test) ** */ @@ -268,7 +268,7 @@ namespace test{ * [information records](\ref lib::Record) into a possibly shared (vector) * buffer in heap storage. An extended query DSL allows to write * assertions to cover the occurrence of events in unit tests. - * @see TestEventLog_test + * @see EventLog_test */ class EventLog { @@ -321,7 +321,7 @@ namespace test{ /** Merge this log into another log, forming a combined log * @param otherLog target to integrate this log's contents into. * @return reference to the merged new log instance - * @see TestEventLog_test::verify_logJoining() + * @see EventLog_test::verify_logJoining() */ EventLog& joinInto (EventLog& otherLog); diff --git a/src/lib/test/test-helper.hpp b/src/lib/test/test-helper.hpp index ef22c94be..115a44919 100644 --- a/src/lib/test/test-helper.hpp +++ b/src/lib/test/test-helper.hpp @@ -302,6 +302,12 @@ namespace test{ return expected.verify (actual); } + friend ExpectString + operator+ (std::string&& l, ExpectString&& r) + { + return ExpectString{(l+r).c_str()}; + } + bool verify (std::string const& actual) const; }; diff --git a/tests/00support.tests b/tests/00support.tests index 68857d8d1..c3bae974f 100644 --- a/tests/00support.tests +++ b/tests/00support.tests @@ -20,14 +20,14 @@ return: 0 END -TEST "Helper for event registration and verification" TestEventLog_test < @@ -20,8 +20,8 @@ * *****************************************************/ -/** @file test-event-log-test.cpp - ** unit test \ref TestEventLog_test +/** @file event-log-test.cpp + ** unit test \ref EventLog_test */ @@ -58,7 +58,7 @@ namespace test{ * printed to STDERR * @see event-log.hpp */ - class TestEventLog_test : public Test + class EventLog_test : public Test { void run (Arg) @@ -384,7 +384,7 @@ namespace test{ } }; - LAUNCHER (TestEventLog_test, "unit common"); + LAUNCHER (EventLog_test, "unit common"); }}} // namespace lib::test::test diff --git a/tests/vault/gear/activity-detector-test.cpp b/tests/vault/gear/activity-detector-test.cpp index 105385f49..d7ee3da0b 100644 --- a/tests/vault/gear/activity-detector-test.cpp +++ b/tests/vault/gear/activity-detector-test.cpp @@ -29,7 +29,7 @@ #include "activity-detector.hpp" #include "lib/test/test-helper.hpp" #include "lib/time/timevalue.hpp" -//#include "lib/format-cout.hpp" +#include "lib/format-cout.hpp" //#include "lib/util.hpp" //#include @@ -94,7 +94,7 @@ namespace test { /** @test verify the setup and detection of instrumented invocations - * @todo WIP 7/23 ✔ define 🔁 implement + * @todo WIP 7/23 ✔ define ✔ implement */ void verifyMockInvocation() @@ -105,20 +105,36 @@ namespace test { ++detector; CHECK (1 == detector.currSeq()); - CHECK (not detector.verifyInvocation ("funny")); + CHECK (detector.ensureNoInvocation ("funny")); detector.markSequence(); - fun(rnd); + CHECK (2 == detector.currSeq()); + CHECK (detector.verifySeqIncrement(2)); + + fun (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").arg()); - CHECK (not detector.verifyInvocation ("funny").arg(-rnd)); - CHECK (not detector.verifyInvocation ("funny").seq(5)); - CHECK (not detector.verifyInvocation ("funny").arg(rnd).seq(1)); + 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)); + + detector.markSequence(); + fun (rnd+1); + CHECK (detector.verifyInvocation ("funny").seq(2) + .beforeSeqIncrement(3) + .beforeInvocation ("funny").seq(3).arg(rnd+1)); + + CHECK (detector == "Rec(EventLogHeader| this = ActivityDetector )" + ", Rec(event| ID = IncSeq |{1})" + ", Rec(event| ID = IncSeq |{2})" + ", Rec(call| fun = funny, this = ActivityDetector, Seq = 2 |{"+util::toString(rnd)+"})" + ", Rec(event| ID = IncSeq |{3})" + ", Rec(call| fun = funny, this = ActivityDetector, Seq = 3 |{"+util::toString(rnd+1)+"})"_expect); } diff --git a/tests/vault/gear/activity-detector.hpp b/tests/vault/gear/activity-detector.hpp index db2ee686d..1c9ef062f 100644 --- a/tests/vault/gear/activity-detector.hpp +++ b/tests/vault/gear/activity-detector.hpp @@ -132,7 +132,7 @@ namespace test { namespace {// Event markers - const string MARK_INC{"Inc"}; + const string MARK_INC{"IncSeq"}; const string MARK_SEQ{"Seq"}; } @@ -196,6 +196,13 @@ namespace test { return *this; } + ActivityMatch& + beforeSeqIncrement (uint seqNr) + { + _Parent::beforeEvent(MARK_INC, util::toString(seqNr)); + return *this; + } + private: template ActivityMatch& @@ -297,7 +304,6 @@ namespace test { uint markSequence() { - eventLog_.event (MARK_SEQ, invocationSeq_); return operator++(); } @@ -329,12 +335,25 @@ namespace test { return ActivityMatch{move (eventLog_.verifyCall(fun))}; } - string - getLog() const + ActivityMatch + ensureNoInvocation (string fun) { - return "\n_______Event-Log_____________________\n" + return ActivityMatch{move (eventLog_.ensureNot(fun).locateCall(fun))}; + } + + ActivityMatch + verifySeqIncrement (uint seqNr) + { + return ActivityMatch{move (eventLog_.verifyEvent(MARK_INC, util::toString(seqNr)))}; + } + + + string + showLog() const + { + return "\n____Event-Log___________________________\n" + util::join (eventLog_, "\n") - + "\n───────╼━━━━━━━━╾────────────────────" + + "\n────╼━━━━━━━━╾──────────────────────────" ; } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 4ed5980b3..a4daf9648 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81814,6 +81814,47 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ CHECK (not ... ) führt zu irrelevanten Fehlermeldungen im Output +

+ +
+ + + +

+ ....weil ich seinerzeit Diagnose-Ausgaben per Seiteneffekt eingeführt habe — sowas ist unabdingbar zur Fehlersuche, aber lästig, wenn es aus einem negierten CHECK resultiert +

+ +
+
+ + + + +

+ ...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 +

+ +
+
+ + + + +

+ das Schema dafür wurde im EventLog bereits geschaffen +

+ +
+
+
@@ -81895,6 +81936,30 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + +

+ detector.verifyInvocation ("funny").arg(-rnd) +

+ +
+
+ + + + +

+ Log-Ausgabe: FAILED to match-arguments(4294965953) +

+ +
+ +
+