51 #include <boost/lexical_cast.hpp> 53 using boost::lexical_cast;
80 using lib::diff::DiffStep;
91 using LERR_(UNBOUND_ARGUMENTS);
92 using LERR_(WRONG_TYPE);
100 uint
const MAX_RAND_BORGS = 100;
101 uint
const MAX_RAND_NUMBS = 500;
102 uint
const MAX_RAND_DELAY = 5000;
105 int generator_instances = 0;
170 EventLog nexusLog = stage::test::Nexus::startNewLog();
174 CHECK (nexusLog.
verifyCall(
"routeAdd").
on(
"TestNexus").
arg(elmID,
"Tangible")
175 .
beforeEvent(
"TestNexus",
"added route to bID-zeitgeist"));
178 CHECK (elmLog.verifyCall(
"ctor").on(&mock)
179 .beforeEvent(
"create",
"zeitgeist"));
183 CHECK (elmLog.ensureNot(
"expanded"));
184 CHECK (elmLog.ensureNot(
"doFlash"));
190 CHECK (elmLog.verifyEvent(
"expanded"));
191 CHECK (nexusLog.
verifyCall(
"note").
on(
"TestNexus").
arg(elmID,
"GenNode-ID(\"expand\")-DataCap|«bool»|true"));
195 CHECK (nexusLog.
verifyCall(
"mark").
on(
"TestNexus").
arg(elmID, MARK_Flash)
196 .
beforeEvent(
"TestNexus",
"mark to bID-zeitgeist"));
197 CHECK (elmLog.verifyCall(
"doFlash").on(
"zeitgeist"));
202 CHECK (elmLog.verifyEvent(
"destroy",
"zeitgeist"));
204 .
beforeEvent(
"TestNexus",
"removed route to bID-zeitgeist"));
207 CHECK (nexusLog.
verify(
"removed route to bID-zeitgeist")
209 .
beforeEvent(
"warn",
"discarding mark to unknown bID-zeitgeist"));
210 CHECK (elmLog.ensureNot(
"Flash")
211 .afterEvent(
"destroy",
"zeitgeist"));
214 cout <<
"____Probe-Log_________________\n" 215 << util::join(elmLog,
"\n")
216 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
218 cout <<
"____Nexus-Log_________________\n" 219 << util::join(stage::test::Nexus::getLog(),
"\n")
220 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
229 stage::test::Nexus::startNewLog();
230 Symbol cmd = stage::test::Nexus::prepareMockCmd<string, TimeSpan, LuidH>();
235 string text {lib::test::randStr(12)};
243 VERIFY_ERROR (WRONG_TYPE, mock.invoke(cmd, Rec({
"lalala"})) );
246 CHECK (not Command::canExec(cmd));
249 mock.invoke (cmd, text, clip, luid);
251 CHECK (Command::canExec(cmd));
260 auto cmdX = stage::test::Nexus::prepareMockCmd<>();
261 auto cmdY = stage::test::Nexus::prepareMockCmd<>();
268 cout <<
"____Nexus-Log_________________\n" 269 << util::join(stage::test::Nexus::getLog(),
"\n")
270 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
283 stage::test::Nexus::startNewLog();
295 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
true ));
296 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
false ));
299 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
300 CHECK (stateManager.currentState(bravo,
"extinct") ==
Ref::NO);
303 CHECK (stateManager.currentState(bruno,
"expand") ==
Ref::NO);
306 CHECK (stateManager.currentState(charly,
"expand") ==
GenNode(
"expand",
true ));
310 CHECK (stateManager.currentState(charly,
"Error") ==
GenNode(
"Error",
"overinflated"));
313 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
316 cout <<
"____Nexus-Log_________________\n" 317 << util::join(stage::test::Nexus::getLog(),
"\n")
318 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
327 StateManager& stateManager = stage::test::Nexus::getMockStateManager();
333 CHECK (not mockA.isExpanded());
334 CHECK (not mockC.isTouched());
337 stateManager.replayState (alpha,
"expand");
338 CHECK (mockA.isExpanded());
341 uiBus.mark (mockA.getID(),
GenNode{
"expand",
false});
343 CHECK (not mockA.isExpanded());
344 CHECK (mockA.isTouched());
346 stateManager.replayAllState (
"expand");
348 CHECK (mockA.isExpanded());
349 CHECK (not mockC.isExpanded());
350 CHECK (not mockC.isTouched());
359 EventLog nexusLog = stage::test::Nexus::startNewLog();
363 MockElm mockC(
"charly");
BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
367 CHECK (not mockA.isTouched());
368 CHECK (not mockB.isTouched());
369 CHECK (not mockC.isTouched());
371 uiBus.mark (alpha,
GenNode{
"Message",
"Centauri"});
372 uiBus.mark (bravo,
GenNode{
"Flash",
true});
373 uiBus.mark (charly,
GenNode{
"Message",
"Delta"});
374 uiBus.mark (charly,
GenNode{
"Error",
"Echo"});
376 CHECK ( mockA.isTouched());
377 CHECK (not mockB.isTouched());
378 CHECK ( mockC.isTouched());
380 CHECK (not mockA.isError());
381 CHECK (not mockB.isError());
382 CHECK ( mockC.isError());
384 CHECK (
"Centauri" == mockA.getMessage());
385 CHECK (
"Delta" == mockC.getMessage());
387 CHECK (
"Echo" == mockC.getError());
390 CHECK (nexusLog.verifyEvent(
"create",
"alpha")
391 .beforeCall(
"mark").on(
"TestNexus").arg(
"alpha",
"Centauri")
392 .beforeCall(
"doMsg").on(
"alpha").arg(
"Centauri")
393 .beforeEvent(
"mark",
"Centauri")
394 .beforeEvent(
"TestNexus",
"delivered mark to bID-alpha"));
396 CHECK (nexusLog.verifyEvent(
"TestNexus",
"delivered mark to bID-alpha")
397 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"GenNode-ID(\"Flash\")-DataCap|«bool»|true")
398 .beforeCall(
"doFlash").on(
"bravo")
399 .beforeEvent(
"TestNexus",
"delivered mark to bID-bravo"));
402 CHECK (nexusLog.verifyEvent(
"TestNexus",
"delivered mark to bID-bravo")
403 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"GenNode-ID(\"Message\")-DataCap|«string»|Delta")
404 .beforeCall(
"doMsg").on(
"charly").arg(
"Delta")
405 .beforeEvent(
"mark",
"Delta").id(
"Message")
406 .beforeEvent(
"TestNexus",
"delivered mark to bID-charly")
407 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"GenNode-ID(\"Error\")-DataCap|«string»|Echo")
408 .beforeCall(
"doErr").on(
"charly").arg(
"Echo")
409 .beforeEvent(
"mark",
"Echo").id(
"Error")
410 .beforeEvent(
"TestNexus",
"delivered mark to bID-charly"));
414 uiBus.markAll (
GenNode{
"Message",
"Foxtrot"});
415 CHECK (not mockA.isError());
416 CHECK (not mockB.isError());
417 CHECK ( mockC.isError());
418 CHECK ( mockA.isTouched());
419 CHECK ( mockB.isTouched());
420 CHECK ( mockC.isTouched());
421 CHECK (
"Foxtrot" == mockA.getMessage());
422 CHECK (
"Foxtrot" == mockB.getMessage());
423 CHECK (
"Foxtrot" == mockC.getMessage());
424 CHECK (
"" == mockA.getError());
425 CHECK (
"" == mockB.getError());
426 CHECK (
"Echo" == mockC.getError());
428 CHECK (nexusLog.verifyEvent(
"mark",
"Echo").id(
"Error")
429 .beforeCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
430 .beforeEvent(
"Broadcast",
"Foxtrot")
431 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"GenNode-ID(\"Message\")-DataCap|«string»|Foxtrot")
432 .beforeCall(
"doMsg").on(
"bravo").arg(
"Foxtrot")
433 .beforeEvent(
"TestNexus",
"broadcasted mark to 3 terminals"));
437 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
438 .beforeCall(
"mark").on(
"TestNexus").arg(
"alpha",
"Foxtrot")
439 .beforeCall(
"doMsg").on(
"alpha").arg(
"Foxtrot")
440 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
442 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
443 .beforeCall(
"mark").on(
"TestNexus").arg(
"bravo",
"Foxtrot")
444 .beforeCall(
"doMsg").on(
"bravo").arg(
"Foxtrot")
445 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
447 CHECK (nexusLog.verifyCall(
"markAll").on(
"TestNexus").arg(
"Foxtrot")
448 .beforeCall(
"mark").on(
"TestNexus").arg(
"charly",
"Foxtrot")
449 .beforeCall(
"doMsg").on(
"charly").arg(
"Foxtrot")
450 .beforeEvent(
"TestNexus",
"successfully broadcasted"));
453 cout <<
"____Nexus-Log_________________\n" 454 << util::join(nexusLog,
"\n")
455 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
464 EventLog nexusLog = stage::test::Nexus::startNewLog();
468 MockElm mockC(
"charly");
BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
472 CHECK (not mockA.isTouched());
473 CHECK (not mockB.isTouched());
474 CHECK (not mockC.isTouched());
477 uiBus.mark (alpha,
GenNode{
"Message",
"Centauri"});
478 uiBus.mark (charly,
GenNode{
"Message",
"Delta"});
479 uiBus.mark (charly,
GenNode{
"Error",
"Echo"});
481 CHECK (mockB.isExpanded());
482 CHECK (mockC.isError());
483 CHECK (
"Delta" == mockC.getMessage());
484 CHECK (
"Centauri" == mockA.getMessage());
487 uiBus.markAll (
GenNode{
"clearMsg",
true});
488 CHECK (mockB.isExpanded());
489 CHECK (mockC.isError());
490 CHECK (isnil (mockA.getMessage()));
491 CHECK (isnil (mockC.getMessage()));
492 CHECK (
"Echo" == mockC.getError());
494 uiBus.mark (bravo,
GenNode{
"Message",
"miss"});
498 auto& stateManager = stage::test::Nexus::getMockStateManager();
499 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
false ));
500 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
true ));
501 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
502 CHECK (stateManager.currentState(charly,
"Error") ==
GenNode(
"Error",
"Echo"));
505 uiBus.markAll (
GenNode{
"clearErr",
true});
506 CHECK (not mockA.isExpanded());
507 CHECK (mockB.isExpanded());
508 CHECK (
"miss" == mockB.getMessage());
509 CHECK (not mockC.isError());
511 CHECK (stateManager.currentState(alpha,
"expand") ==
GenNode(
"expand",
false ));
512 CHECK (stateManager.currentState(bravo,
"expand") ==
GenNode(
"expand",
true ));
513 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
514 CHECK (stateManager.currentState(charly,
"Error") ==
Ref::NO);
518 uiBus.markAll (
GenNode{
"reset",
true});
520 CHECK (not mockA.isTouched());
521 CHECK (not mockB.isTouched());
522 CHECK (not mockC.isTouched());
524 CHECK (not mockA.isExpanded());
525 CHECK (not mockB.isExpanded());
527 CHECK (isnil (mockA.getMessage()));
528 CHECK (isnil (mockB.getMessage()));
529 CHECK (isnil (mockC.getMessage()));
531 CHECK (stateManager.currentState(alpha,
"expand") ==
Ref::NO);
532 CHECK (stateManager.currentState(bravo,
"expand") ==
Ref::NO);
533 CHECK (stateManager.currentState(charly,
"expand") ==
Ref::NO);
534 CHECK (stateManager.currentState(charly,
"Error" ) ==
Ref::NO);
537 cout <<
"____Nexus-Log_________________\n" 538 << util::join(nexusLog,
"\n")
539 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
572 uint64_t borgChecksum_ = 0;
577 scheduleBorg (uint
id)
581 sessionBorgs_.push(
id);
588 return dischargeToSnapshot (sessionBorgs_);
607 SessionThread& theCube_;
610 BorgGenerator (SessionThread& motherShip, uint
id)
612 , theCube_{motherShip}
615 ++generator_instances;
620 --generator_instances;
627 firstResult ()
override 629 REQUIRE (not steps_);
630 auto plannedBorgs = theCube_.dispatchBorgs();
631 uint max = plannedBorgs.size();
634 _Fmt borgName{
"%d of %d ≺%03d.gen%03d≻"};
638 for (uint
id : plannedBorgs)
640 GenNode borg = MakeRec().genNode(borgName % ++cur % max %
id % generatorID_);
641 steps_.feed (ins(borg));
642 steps_.feed (mut(borg));
643 steps_.feed ( ins(
GenNode{
"borgID", int(
id)}));
644 steps_.feed (emu(borg));
653 nextResult (DiffStep*& pos)
override 656 if (steps_) ++steps_;
668 SessionThread(
function<
void(DiffSource*)> notifyGUI)
672 uint cnt = rand() % MAX_RAND_BORGS;
673 for (uint i=0; i<cnt; ++i)
675 uint delay = rand() % MAX_RAND_DELAY;
676 uint
id = rand() % MAX_RAND_NUMBS;
679 notifyGUI (
new BorgGenerator{*
this, i});
687 EventLog nexusLog = stage::test::Nexus::startNewLog();
691 MockElm rootMock(
"alpha zero");
692 ID rootID = rootMock.getID();
694 rootMock.attrib[
"α"] =
"Quadrant";
695 CHECK (
"Quadrant" == rootMock.attrib[
"α"]);
696 CHECK (isnil (rootMock.scope));
698 CHECK (0 == generator_instances);
707 auto notifyGUI = [&](DiffSource* diffGenerator)
709 uiDispatcher.feed ([&, diffGenerator]()
719 SessionThread
session{notifyGUI};
720 usleep (2 * MAX_RAND_DELAY);
721 while (not isnil(uiDispatcher))
724 uiDispatcher.invoke();
731 while (not isnil(uiDispatcher))
733 uiDispatcher.invoke();
738 uint generatedBorgs = rootMock.scope.size();
741 CHECK (1 + generatedBorgs == stage::test::Nexus::size());
743 uint64_t borgChecksum = 0;
744 for (uint i=0; i<generatedBorgs; ++i)
746 MockElm& borg = *rootMock.scope[i];
747 CHECK (contains (borg.attrib,
"borgID"));
748 string borgID = borg.attrib[
"borgID"];
749 borgChecksum += lexical_cast<
int> (borgID);
750 string childID = borg.getID().getSym();
751 CHECK (contains (childID, borgID));
752 CHECK (contains (childID,
" of "));
754 CHECK (nexusLog.
verifyCall(
"routeAdd").
arg(rootMock.getID(), memLocation(rootMock))
755 .beforeCall(
"change") .
argMatch(rootMock.getID(),
756 "after.+?_ATTRIBS_.+?" 757 "ins.+?"+childID+
".+?" 758 "mut.+?"+childID+
".+?" 759 "ins.+?borgID.+?"+borgID+
".+?" 761 .beforeCall(
"routeAdd").
arg(borg.getID(), memLocation(borg))
762 .beforeEvent(
"applied diff to "+
string(rootMock.getID()))
766 CHECK (rootMock.attrib[
"α"] ==
"Quadrant");
770 CHECK (borgChecksum ==
session.borgChecksum_);
771 CHECK (0 == generator_instances);
775 cout <<
"____Event-Log_________________\n" 776 << util::join(rootMock.getLog(),
"\n")
777 <<
"\n───╼━━━━━━━━━╾────────────────"<<endl;
779 cout <<
"____Nexus-Log_________________\n" 780 << util::join(nexusLog,
"\n")
781 <<
"\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.
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
Simple 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