42 #include <boost/lexical_cast.hpp> 44 using boost::lexical_cast;
71 using lib::diff::DiffStep;
82 using LERR_(UNBOUND_ARGUMENTS);
83 using LERR_(WRONG_TYPE);
91 uint
const MAX_RAND_BORGS = 100;
92 uint
const MAX_RAND_NUMBS = 500;
93 uint
const MAX_RAND_DELAY = 5000;
96 int generator_instances = 0;
163 EventLog nexusLog = stage::test::Nexus::startNewLog();
167 CHECK (nexusLog.
verifyCall(
"routeAdd").
on(
"TestNexus").
arg(elmID,
"Tangible")
168 .
beforeEvent(
"TestNexus",
"added route to bID-zeitgeist"));
171 CHECK (elmLog.verifyCall(
"ctor").on(&mock)
172 .beforeEvent(
"create",
"zeitgeist"));
176 CHECK (elmLog.ensureNot(
"expanded"));
177 CHECK (elmLog.ensureNot(
"doFlash"));
183 CHECK (elmLog.verifyEvent(
"expanded"));
184 CHECK (nexusLog.
verifyCall(
"note").
on(
"TestNexus").
arg(elmID,
"GenNode-ID(\"expand\")-DataCap|«bool»|true"));
188 CHECK (nexusLog.
verifyCall(
"mark").
on(
"TestNexus").
arg(elmID, MARK_Flash)
189 .
beforeEvent(
"TestNexus",
"mark to bID-zeitgeist"));
190 CHECK (elmLog.verifyCall(
"doFlash").on(
"zeitgeist"));
195 CHECK (elmLog.verifyEvent(
"destroy",
"zeitgeist"));
197 .
beforeEvent(
"TestNexus",
"removed route to bID-zeitgeist"));
200 CHECK (nexusLog.
verify(
"removed route to bID-zeitgeist")
202 .
beforeEvent(
"warn",
"discarding mark to unknown bID-zeitgeist"));
203 CHECK (elmLog.ensureNot(
"Flash")
204 .afterEvent(
"destroy",
"zeitgeist"));
207 cout <<
"____Probe-Log_________________\n" 208 << util::join(elmLog,
"\n")
209 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
211 cout <<
"____Nexus-Log_________________\n" 212 << util::join(stage::test::Nexus::getLog(),
"\n")
213 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
222 stage::test::Nexus::startNewLog();
223 Symbol cmd = stage::test::Nexus::prepareMockCmd<string, TimeSpan, LuidH>();
228 string text {lib::test::randStr(12)};
236 VERIFY_ERROR (WRONG_TYPE, mock.invoke(cmd, Rec({
"lalala"})) );
239 CHECK (not Command::canExec(cmd));
242 mock.invoke (cmd, text, clip, luid);
244 CHECK (Command::canExec(cmd));
253 auto cmdX = stage::test::Nexus::prepareMockCmd<>();
254 auto cmdY = stage::test::Nexus::prepareMockCmd<>();
261 cout <<
"____Nexus-Log_________________\n" 262 << util::join(stage::test::Nexus::getLog(),
"\n")
263 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
276 stage::test::Nexus::startNewLog();
288 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
true ));
289 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
false ));
292 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
293 CHECK (stateManager.currentState(bravo,
"extinct") ==
Ref::NO);
296 CHECK (stateManager.currentState(bruno,
"expand") ==
Ref::NO);
299 CHECK (stateManager.currentState(charly,
"expand") ==
GenNode(
"expand",
true ));
303 CHECK (stateManager.currentState(charly,
"Error") ==
GenNode(
"Error",
"overinflated"));
306 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
309 cout <<
"____Nexus-Log_________________\n" 310 << util::join(stage::test::Nexus::getLog(),
"\n")
311 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
320 StateManager& stateManager = stage::test::Nexus::getMockStateManager();
326 CHECK (not mockA.isExpanded());
327 CHECK (not mockC.isTouched());
330 stateManager.replayState (alpha,
"expand");
331 CHECK (mockA.isExpanded());
334 uiBus.mark (mockA.getID(),
GenNode{
"expand",
false});
336 CHECK (not mockA.isExpanded());
337 CHECK (mockA.isTouched());
339 stateManager.replayAllState (
"expand");
341 CHECK (mockA.isExpanded());
342 CHECK (not mockC.isExpanded());
343 CHECK (not mockC.isTouched());
352 EventLog nexusLog = stage::test::Nexus::startNewLog();
356 MockElm mockC(
"charly");
BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
360 CHECK (not mockA.isTouched());
361 CHECK (not mockB.isTouched());
362 CHECK (not mockC.isTouched());
364 uiBus.mark (alpha,
GenNode{
"Message",
"Centauri"});
365 uiBus.mark (bravo,
GenNode{
"Flash",
true});
366 uiBus.mark (charly,
GenNode{
"Message",
"Delta"});
367 uiBus.mark (charly,
GenNode{
"Error",
"Echo"});
369 CHECK ( mockA.isTouched());
370 CHECK (not mockB.isTouched());
371 CHECK ( mockC.isTouched());
373 CHECK (not mockA.isError());
374 CHECK (not mockB.isError());
375 CHECK ( mockC.isError());
377 CHECK (
"Centauri" == mockA.getMessage());
378 CHECK (
"Delta" == mockC.getMessage());
380 CHECK (
"Echo" == mockC.getError());
383 CHECK (nexusLog.verifyEvent(
"create",
"alpha")
384 .beforeCall(
"mark").on(
"TestNexus").arg(
"alpha",
"Centauri")
385 .beforeCall(
"doMsg").on(
"alpha").arg(
"Centauri")
386 .beforeEvent(
"mark",
"Centauri")
387 .beforeEvent(
"TestNexus",
"delivered mark to bID-alpha"));
389 CHECK (nexusLog.verifyEvent(
"TestNexus",
"delivered mark to bID-alpha")
390 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"GenNode-ID(\"Flash\")-DataCap|«bool»|true")
391 .beforeCall(
"doFlash").on(
"bravo")
392 .beforeEvent(
"TestNexus",
"delivered mark to bID-bravo"));
395 CHECK (nexusLog.verifyEvent(
"TestNexus",
"delivered mark to bID-bravo")
396 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"GenNode-ID(\"Message\")-DataCap|«string»|Delta")
397 .beforeCall(
"doMsg").on(
"charly").arg(
"Delta")
398 .beforeEvent(
"mark",
"Delta").id(
"Message")
399 .beforeEvent(
"TestNexus",
"delivered mark to bID-charly")
400 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"GenNode-ID(\"Error\")-DataCap|«string»|Echo")
401 .beforeCall(
"doErr").on(
"charly").arg(
"Echo")
402 .beforeEvent(
"mark",
"Echo").id(
"Error")
403 .beforeEvent(
"TestNexus",
"delivered mark to bID-charly"));
407 uiBus.markAll (
GenNode{
"Message",
"Foxtrot"});
408 CHECK (not mockA.isError());
409 CHECK (not mockB.isError());
410 CHECK ( mockC.isError());
411 CHECK ( mockA.isTouched());
412 CHECK ( mockB.isTouched());
413 CHECK ( mockC.isTouched());
414 CHECK (
"Foxtrot" == mockA.getMessage());
415 CHECK (
"Foxtrot" == mockB.getMessage());
416 CHECK (
"Foxtrot" == mockC.getMessage());
417 CHECK (
"" == mockA.getError());
418 CHECK (
"" == mockB.getError());
419 CHECK (
"Echo" == mockC.getError());
421 CHECK (nexusLog.verifyEvent(
"mark",
"Echo").id(
"Error")
422 .beforeCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
423 .beforeEvent(
"Broadcast",
"Foxtrot")
424 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"GenNode-ID(\"Message\")-DataCap|«string»|Foxtrot")
425 .beforeCall(
"doMsg").on(
"bravo").arg(
"Foxtrot")
426 .beforeEvent(
"TestNexus",
"broadcasted mark to 3 terminals"));
430 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
431 .beforeCall(
"mark").on(
"TestNexus").arg(
"alpha",
"Foxtrot")
432 .beforeCall(
"doMsg").on(
"alpha").arg(
"Foxtrot")
433 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
435 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
436 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"Foxtrot")
437 .beforeCall(
"doMsg").on(
"bravo").arg(
"Foxtrot")
438 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
440 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
441 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"Foxtrot")
442 .beforeCall(
"doMsg").on(
"charly").arg(
"Foxtrot")
443 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
446 cout <<
"____Nexus-Log_________________\n" 447 << util::join(nexusLog,
"\n")
448 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
457 EventLog nexusLog = stage::test::Nexus::startNewLog();
461 MockElm mockC(
"charly");
BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
465 CHECK (not mockA.isTouched());
466 CHECK (not mockB.isTouched());
467 CHECK (not mockC.isTouched());
470 uiBus.mark (alpha,
GenNode{
"Message",
"Centauri"});
471 uiBus.mark (charly,
GenNode{
"Message",
"Delta"});
472 uiBus.mark (charly,
GenNode{
"Error",
"Echo"});
474 CHECK (mockB.isExpanded());
475 CHECK (mockC.isError());
476 CHECK (
"Delta" == mockC.getMessage());
477 CHECK (
"Centauri" == mockA.getMessage());
480 uiBus.markAll (
GenNode{
"clearMsg",
true});
481 CHECK (mockB.isExpanded());
482 CHECK (mockC.isError());
483 CHECK (isnil (mockA.getMessage()));
484 CHECK (isnil (mockC.getMessage()));
485 CHECK (
"Echo" == mockC.getError());
487 uiBus.mark (bravo,
GenNode{
"Message",
"miss"});
491 auto& stateManager = stage::test::Nexus::getMockStateManager();
492 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
false ));
493 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
true ));
494 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
495 CHECK (stateManager.currentState(charly,
"Error") ==
GenNode(
"Error",
"Echo"));
498 uiBus.markAll (
GenNode{
"clearErr",
true});
499 CHECK (not mockA.isExpanded());
500 CHECK (mockB.isExpanded());
501 CHECK (
"miss" == mockB.getMessage());
502 CHECK (not mockC.isError());
504 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
false ));
505 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
true ));
506 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
507 CHECK (stateManager.currentState(charly,
"Error") ==
Ref::NO);
511 uiBus.markAll (
GenNode{
"reset",
true});
513 CHECK (not mockA.isTouched());
514 CHECK (not mockB.isTouched());
515 CHECK (not mockC.isTouched());
517 CHECK (not mockA.isExpanded());
518 CHECK (not mockB.isExpanded());
520 CHECK (isnil (mockA.getMessage()));
521 CHECK (isnil (mockB.getMessage()));
522 CHECK (isnil (mockC.getMessage()));
524 CHECK (stateManager.currentState(alpha,
"expand") ==
Ref::NO);
525 CHECK (stateManager.currentState(bravo,
"expand") ==
Ref::NO);
526 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
527 CHECK (stateManager.currentState(charly,
"Error" ) ==
Ref::NO);
530 cout <<
"____Nexus-Log_________________\n" 531 << util::join(nexusLog,
"\n")
532 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
565 uint64_t borgChecksum_ = 0;
570 scheduleBorg (uint
id)
574 sessionBorgs_.push(
id);
581 return dischargeToSnapshot (sessionBorgs_);
600 SessionThread& theCube_;
603 BorgGenerator (SessionThread& motherShip, uint
id)
605 , theCube_{motherShip}
608 ++generator_instances;
613 --generator_instances;
620 firstResult ()
override 622 REQUIRE (not steps_);
623 auto plannedBorgs = theCube_.dispatchBorgs();
624 uint max = plannedBorgs.size();
627 _Fmt borgName{
"%d of %d ≺%03d.gen%03d≻"};
631 for (uint
id : plannedBorgs)
633 GenNode borg = MakeRec().genNode(borgName % ++cur % max %
id % generatorID_);
634 steps_.feed (ins(borg));
635 steps_.feed (mut(borg));
636 steps_.feed ( ins(
GenNode{
"borgID", int(
id)}));
637 steps_.feed (emu(borg));
646 nextResult (DiffStep*& pos)
override 649 if (steps_) ++steps_;
661 SessionThread(
function<
void(DiffSource*)> notifyGUI)
665 uint cnt = randGen_.i(MAX_RAND_BORGS);
666 for (uint i=0; i<cnt; ++i)
668 uint delay = randGen_.i(MAX_RAND_DELAY);
669 uint
id = randGen_.i(MAX_RAND_NUMBS);
672 notifyGUI (
new BorgGenerator{*
this, i});
683 EventLog nexusLog = stage::test::Nexus::startNewLog();
687 MockElm rootMock(
"alpha zero");
688 ID rootID = rootMock.getID();
690 rootMock.attrib[
"α"] =
"Quadrant";
691 CHECK (
"Quadrant" == rootMock.attrib[
"α"]);
692 CHECK (isnil (rootMock.scope));
694 CHECK (0 == generator_instances);
703 auto notifyGUI = [&](DiffSource* diffGenerator)
705 uiDispatcher.feed ([&, diffGenerator]()
715 SessionThread
session{notifyGUI};
716 usleep (2 * MAX_RAND_DELAY);
717 while (not isnil(uiDispatcher))
720 uiDispatcher.invoke();
727 while (not isnil(uiDispatcher))
729 uiDispatcher.invoke();
734 uint generatedBorgs = rootMock.scope.size();
737 CHECK (1 + generatedBorgs == stage::test::Nexus::size());
739 uint64_t borgChecksum = 0;
740 for (uint i=0; i<generatedBorgs; ++i)
742 MockElm& borg = *rootMock.scope[i];
743 CHECK (contains (borg.attrib,
"borgID"));
744 string borgID = borg.attrib[
"borgID"];
745 borgChecksum += lexical_cast<
int> (borgID);
746 string childID = borg.getID().getSym();
747 CHECK (contains (childID, borgID));
748 CHECK (contains (childID,
" of "));
750 CHECK (nexusLog.
verifyCall(
"routeAdd").
arg(rootMock.getID(), memLocation(rootMock))
751 .beforeCall(
"change") .
argMatch(rootMock.getID(),
752 "after.+?_ATTRIBS_.+?" 753 "ins.+?"+childID+
".+?" 754 "mut.+?"+childID+
".+?" 755 "ins.+?borgID.+?"+borgID+
".+?" 757 .beforeCall(
"routeAdd").
arg(borg.getID(), memLocation(borg))
758 .beforeEvent(
"applied diff to "+
string(rootMock.getID()))
762 CHECK (rootMock.attrib[
"α"] ==
"Quadrant");
766 CHECK (borgChecksum ==
session.borgChecksum_);
767 CHECK (0 == generator_instances);
771 cout <<
"____Event-Log_________________\n" 772 << util::join(rootMock.getLog(),
"\n")
773 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
775 cout <<
"____Nexus-Log_________________\n" 776 << util::join(nexusLog,
"\n")
777 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
Facility for monitor object based locking.
type erased baseclass for building a combined hash and symbolic ID.
Variant of the standard case, requiring to wait and join() on the termination of this thread...
Generic Message with an embedded diff, to describe changes to model elements.
void slotExpand()
Expand this element and remember the expanded state.
Constructor for a specially crafted 'ref GenNode'.
Hard wired key constants and basic definitions for communication with the GUI.
connection point at the UI-Bus.
A Stack which can be popped by iterating.
A threadsafe queue for bound void(void) functors.
static void setCommandHandler(CommandHandler=CommandHandler())
install a closure (custom handler function) to deal with any command invocations encountered in the t...
A fake UI backbone for investigations and unit testing.
void reset()
invoke the generic reset hook
Conveniently iterable stack and queue containers.
Any copy and copy construction prohibited.
EventMatch & beforeCall(string match)
find a match for some function invocation after the current point of reference
Interface: a component to maintain persistent interface state.
void verifyNotifications()
Helper to log and verify the occurrence of events.
typed symbolic and hash ID for asset-like position accounting.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
EventMatch & arg(ARGS const &...args)
refine filter to additionally require specific arguments
Opaque message to effect a structural change on a target, which is likewise only known in an abstract...
A front-end for using printf-style formatting.
Namespace of Session and user visible high-level objects.
A Queue which can be pulled by iterating.
Lumiera's internal time value datatype.
SeedNucleus & seedFromDefaultGen()
draw seed another Generator from the default RandomSequencer
Lumiera unique object identifier.
Attachment point to the UI-Bus.
Object Monitor based synchronisation.
ThreadJoinable(string const &, FUN &&, ARGS &&...) -> ThreadJoinable< std::invoke_result_t< FUN, ARGS... >>
deduction guide: find out about result value to capture from a generic callable.
Token or Atom with distinct identity.
Iteration source interface to abstract a data source, which then can be accessed through IterAdapter ...
static ctrl::StateManager & useMockStateManager()
install a standard handler for state mark messages, which is actually backed by a mock implementation...
EventMatch verifyCall(string match) const
start a query to match especially a function call
A Queue for function invocations, allowing them to be dispatched on demand.
EventMatch ensureNot(string match) const
start a query to ensure the given expression does not match.
static const Ref END
symbolic ID ref "_END_"
#define MARK_TEST_FUN
Macro to mark the current test function in STDOUT.
EventMatch & beforeEvent(string match)
find a match for an "event" after the current point of reference
Simplistic test class runner.
virtual bool mark(ID subject, GenNode const &mark)
route a state update or notification to the given subject.
void markErr(string error)
push an error state tag to the element
Lumiera GTK UI implementation root.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
static bool wasInvoked(Symbol)
Test predicate: verify at least one actual invocation happened for the given commend, without matching any concrete arguments.
static bool wasBound(Symbol, ARGS const &...args)
Test predicate: verify by string match that the denoted command was actually bound against the given ...
ContentSnapshot< IT > dischargeToSnapshot(IT &ii)
Take a snapshot of the given LumieraIterator, which is thereby consumed.
Generic building block for tree shaped (meta)data structures.
Steam-Layer command frontend.
Convenience front-end to simplify and codify basic thread handling.
A special implementation of lib::Sync, where the storage of the object monitor is associated directly...
static void setStateMarkHandler(StateMarkHandler=StateMarkHandler())
similar to the custom command handler this hook allows to install a closure to intercept any "state m...
A collection of frequently used helper functions to support unit testing.
EventMatch & argMatch(ARGS const &...regExps)
refine filter to additionally cover all arguments with a series of regular expressions.
static const Ref NO
symbolic ID ref "_NO_"
Interface: handling of persistent interface state.
void slotCollapse()
Collapse or minimise this element and remember the collapsed state.
string instanceTypeID(const TY *const obj)
designation of an distinct object instance
A synchronisation protection guard employing a lock scoped to the parameter type as a whole...
static ctrl::BusTerm & testUI()
get a connection point to a UI backbone faked for test
Hash implementation based on a lumiera unique object id (LUID) When invoking the default ctor...
Mock UI element or controller.
static const Ref ATTRIBS
symbolic ID ref "_ATTRIBS_"
Handle object representing a single Command instance to be used by client code.
EventMatch verify(string match) const
start a query to match for some substring.
Bare symbolic and hash ID used for accounting of asset like entries.
Interface common to all UI elements of relevance for the Lumiera application.
A time interval anchored at a specific point in time.
EventMatch & on(string targetID)
refine filter to additionally match the 'this' attribute
Preconfigured adapters for some STL container standard usage situations.
a family of time value like entities and their relationships.
object-like record of data.
A generic interface element instrumented for unit testing.
generic data element node within a tree
bool contains(SEQ const &cont, typename SEQ::const_reference val)
shortcut for brute-force containment test in any sequential container