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.
This commit is contained in:
parent
25ad461a28
commit
e3f1aa4f7c
8 changed files with 136 additions and 31 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Helper for event registration and verification" TestEventLog_test <<END
|
||||
TEST "Helper for event registration and verification" EventLog_test <<END
|
||||
err-lit: __Log_condition_violated__
|
||||
err-lit: FAILED to match("γ")
|
||||
err: ..after HEAD TestEventLog_test.+
|
||||
err: ..after HEAD EventLog_test.+
|
||||
err-lit: __Log_condition_violated__
|
||||
err-lit: FAILED to match("α")
|
||||
err-lit: ..after match("β") @ Rec(event|{β})
|
||||
err: ..after HEAD TestEventLog_test.+
|
||||
err: ..after HEAD EventLog_test.+
|
||||
err-lit: __Log_condition_violated__
|
||||
err-lit: FAILED to match("ham")
|
||||
err-lit: ..before match("beans") @ Rec(EventLogHeader| this = baked beans )
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
TestEventLog(Test) - helper for event registration and verification
|
||||
EventLog(Test) - helper for event registration and verification
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2015, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -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
|
||||
|
|
@ -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 <utility>
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<typename...ARGS>
|
||||
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────╼━━━━━━━━╾──────────────────────────"
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81814,6 +81814,47 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1692022438369" ID="ID_1637851255" MODIFIED="1692022901645" TEXT="negativ-Checks unterstützen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1692022449108" ID="ID_1801262965" MODIFIED="1692022587083">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<font face="Monospaced" size="2" color="#35298d">CHECK (not ... )</font> führt zu irrelevanten Fehlermeldungen im Output
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
....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
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1692022627772" ID="ID_13278224" MODIFIED="1692022860849" TEXT="sowas ist offensichtlich plausibel — aber auch problematisch">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...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
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1692022870883" ID="ID_1195200670" MODIFIED="1692022899343" TEXT="eigentlich einfach, nur repetitiv">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das Schema dafür wurde im EventLog bereits geschaffen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1690899978840" ID="ID_70827658" MODIFIED="1690899987515" TEXT="einen Funktionsaufruf verifizieren">
|
||||
|
|
@ -81895,6 +81936,30 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</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 BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1692022948289" ID="ID_1815506838" MODIFIED="1692022990708" TEXT="unerwartete Konversion ⟼ unsigned">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1692023011767" ID="ID_1384711805" MODIFIED="1692023028638">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
<font face="Monospaced" size="2" color="#241569">detector.verifyInvocation ("funny").arg(-rnd)</font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1692023048955" ID="ID_1364393445" MODIFIED="1692023323332">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Log-Ausgabe: <font color="#3d0f59" face="Monospaced" size="2">FAILED to match-arguments(</font><font color="#ed4669" face="Monospaced" size="2"><b>4294965953</b></font><font color="#3d0f59" face="Monospaced" size="2">)</font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue