Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
bus-term-test.cpp
Go to the documentation of this file.
1/*
2 BusTerm(Test) - cover the building block of the UI-Bus
3
4 Copyright (C)
5 2015, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
19#include "lib/test/run.hpp"
21#include "lib/thread.hpp"
22#include "lib/sync.hpp"
28#include "test/test-nexus.hpp"
29#include "test/mock-elm.hpp"
30#include "lib/diff/gen-node.hpp"
32#include "lib/idi/entry-id.hpp"
34#include "lib/iter-stack.hpp"
35#include "lib/call-queue.hpp"
36#include "lib/format-string.hpp"
37#include "lib/format-cout.hpp"
39#include "lib/luid.h"
40#include "lib/util.hpp"
41
42#include <boost/lexical_cast.hpp>
43
44using boost::lexical_cast;
45
46using lib::Sync;
47using lib::ClassLock;
50using lib::IterQueue;
51using lib::IterStack;
52using std::function;
53using util::contains;
54using util::isnil;
55using util::_Fmt;
56
57
58namespace stage {
59namespace model{
60namespace test {
61
74 using lib::diff::Rec;
75 using lib::diff::Ref;
76 using lib::time::Time;
78 using lib::hash::LuidH;
80 using lib::CallQueue;
81
82 using LERR_(UNBOUND_ARGUMENTS);
83 using LERR_(WRONG_TYPE);
84
85 using ID = lib::idi::BareEntryID const&;
86
87
88 namespace {// test data...
89
90 // --------random-diff-test------
91 uint const MAX_RAND_BORGS = 100; // stay below 400, verification export grows quadratic
92 uint const MAX_RAND_NUMBS = 500;
93 uint const MAX_RAND_DELAY = 5000; // throttle generation, since diff application is slower
94 // --------random-diff-test------
95
97 }
98
99
100
101
102
103
104 /**************************************************************************/
126 class BusTerm_test : public Test
127 {
128
129 virtual void
130 run (Arg)
131 {
132 seedRand();
133
139 clearStates();
140 pushDiff();
141 }
142
143
155 void
157 {
159 // our dummy will be linked with this identity
160 BareEntryID elmID = EntryID<MockElm>{"zeitgeist"};
161
162 // Access the log on the Test-Nexus hub
164 CHECK (nexusLog.ensureNot("zeitgeist"));
165
166 MockElm mock(elmID);
167 CHECK (nexusLog.verifyCall("routeAdd").on("TestNexus").arg(elmID,"Tangible") // Note: invoked from ctor, so it is just a tangible at the moment
168 .beforeEvent("TestNexus", "added route to bID-zeitgeist"));
169
170 EventLog elmLog = mock.getLog();
171 CHECK (elmLog.verifyCall("ctor").on(&mock)
172 .beforeEvent("create", "zeitgeist"));
173
174
175 // now verify there is indeed bidirectional connectivity...
176 CHECK (elmLog.ensureNot("expanded"));
177 CHECK (elmLog.ensureNot("doFlash"));
178 CHECK (nexusLog.ensureNot("zeitgeist").arg("expand"));
179 CHECK (nexusLog.ensureNot("zeitgeist").arg("Flash"));
180
181 // invoke action on element to cause upstream message (with a "state mark")
182 mock.slotExpand();
183 CHECK (elmLog.verifyEvent("expanded"));
184 CHECK (nexusLog.verifyCall("note").on("TestNexus").arg(elmID, "GenNode-ID(\"expand\")-DataCap|«bool»|true"));
185
186 // send a state mark down to the mock element
187 stage::test::Nexus::testUI().mark (elmID, GenNode(string{MARK_Flash}, 23));
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"));
191
192
193 // kill the zeitgeist and verify disconnection
194 mock.kill();
195 CHECK (elmLog.verifyEvent("destroy","zeitgeist"));
196 CHECK (nexusLog.verifyCall("routeDetach").on("TestNexus").arg(elmID)
197 .beforeEvent("TestNexus", "removed route to bID-zeitgeist"));
198
200 CHECK (nexusLog.verify("removed route to bID-zeitgeist")
201 .beforeCall("mark").on("TestNexus").arg(elmID, MARK_Flash)
202 .beforeEvent("warn","discarding mark to unknown bID-zeitgeist"));
203 CHECK (elmLog.ensureNot("Flash")
204 .afterEvent("destroy","zeitgeist"));
205
206
207 cout << "____Probe-Log_________________\n"
208 << util::join(elmLog, "\n")
209 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
210
211 cout << "____Nexus-Log_________________\n"
213 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
214 }
215
216
218 void
220 {
223 Symbol cmd = stage::test::Nexus::prepareMockCmd<string, TimeSpan, LuidH>();
224
225 MockElm mock("uiElm");
226
227 // random command arguments...
228 string text {lib::test::randStr(12)};
229 TimeSpan clip (Time(1,2,3), lib::test::randTime());
230 LuidH luid;
231
232 // we cannot invoke commands without binding required arguments
233 VERIFY_ERROR (WRONG_TYPE, mock.invoke(cmd) );
234
235 // proper argument typing is ensured while dispatching the bind message.
236 VERIFY_ERROR (WRONG_TYPE, mock.invoke(cmd, Rec({"lalala"})) );
237
238 // command can't be issued, since it's still unbound
239 CHECK (not Command::canExec(cmd));
240
241
242 mock.invoke (cmd, text, clip, luid);
243
244 CHECK (Command::canExec(cmd));
245 CHECK (stage::test::Nexus::wasBound(cmd, text, clip, luid));
246 CHECK (not stage::test::Nexus::wasBound(cmd, "lololo"));
248 CHECK (stage::test::Nexus::wasInvoked(cmd, text, clip, luid));
249 CHECK (not stage::test::Nexus::wasInvoked(cmd, " huh ", clip, luid));
250 CHECK (not stage::test::Nexus::wasInvoked(cmd, text, clip));
251
252 // Mock commands are automatically unique
253 auto cmdX = stage::test::Nexus::prepareMockCmd<>();
254 auto cmdY = stage::test::Nexus::prepareMockCmd<>();
255 CHECK (cmd != cmdX);
256 CHECK (cmd != cmdY);
257
258 CHECK (not stage::test::Nexus::wasInvoked(cmdX));
259 CHECK (not stage::test::Nexus::wasInvoked(cmdY));
260
261 cout << "____Nexus-Log_________________\n"
263 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
264
265 stage::test::Nexus::setCommandHandler(); // deinstall custom command handler
266 }
267
268
272 void
274 {
278
279 MockElm mockA("alpha"); BareEntryID alpha = mockA.getID();
280 MockElm mockB("bravo"); BareEntryID bravo = mockB.getID();
281 MockElm mockC("charly"); BareEntryID charly = mockC.getID();
282
283 mockA.slotExpand();
284
285 mockB.slotExpand();
286 mockB.slotCollapse();
287
288 CHECK (stateManager.currentState(alpha, "expand") == GenNode("expand", true ));
289 CHECK (stateManager.currentState(bravo, "expand") == GenNode("expand", false ));
290
291 // handling of missing information
292 CHECK (stateManager.currentState(charly, "expand") == Ref::NO); // no data recorded yet
293 CHECK (stateManager.currentState(bravo, "extinct") == Ref::NO); // unknown property
294
295 EntryID<MockElm> bruno("bruno");
296 CHECK (stateManager.currentState(bruno, "expand") == Ref::NO); // who knows bruno?
297
298 mockC.slotExpand();
299 CHECK (stateManager.currentState(charly, "expand") == GenNode("expand", true ));
300
301 // error states can be sticky
302 mockC.markErr("overinflated");
303 CHECK (stateManager.currentState(charly, "Error") == GenNode("Error", "overinflated"));
304
305 mockC.reset();
306 CHECK (stateManager.currentState(charly, "expand") == Ref::NO); // back to void
307
308
309 cout << "____Nexus-Log_________________\n"
311 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
312 }
313
314
316 void
318 {
321
322 MockElm mockA("alpha");
323 // no "bravo" this time
324 MockElm mockC("charly");
325
326 CHECK (not mockA.isExpanded());
327 CHECK (not mockC.isTouched());
328
329 BareEntryID alpha = mockA.getID();
330 stateManager.replayState (alpha, "expand");
331 CHECK (mockA.isExpanded());
332
333 auto& uiBus = stage::test::Nexus::testUI();
334 uiBus.mark (mockA.getID(), GenNode{"expand", false});
335
336 CHECK (not mockA.isExpanded());
337 CHECK (mockA.isTouched());
338
339 stateManager.replayAllState ("expand");
340
341 CHECK (mockA.isExpanded());
342 CHECK (not mockC.isExpanded());
343 CHECK (not mockC.isTouched());
344 }
345
346
348 void
350 {
353
354 MockElm mockA("alpha"); BareEntryID alpha = mockA.getID(); mockA.joinLog (nexusLog);
355 MockElm mockB("bravo"); BareEntryID bravo = mockB.getID(); mockB.joinLog (nexusLog);
356 MockElm mockC("charly"); BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
357
358 auto& uiBus = stage::test::Nexus::testUI();
359
360 CHECK (not mockA.isTouched());
361 CHECK (not mockB.isTouched());
362 CHECK (not mockC.isTouched());
363
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"});
368
369 CHECK ( mockA.isTouched());
370 CHECK (not mockB.isTouched());
371 CHECK ( mockC.isTouched());
372
373 CHECK (not mockA.isError());
374 CHECK (not mockB.isError());
375 CHECK ( mockC.isError());
376
377 CHECK ("Centauri" == mockA.getMessage());
378 CHECK ("Delta" == mockC.getMessage());
379
380 CHECK ("Echo" == mockC.getError());
381
382 // verify the message passing in the combined log...
383 CHECK (nexusLog.verifyEvent("create", "alpha")
384 .beforeCall("mark").on("TestNexus").arg("alpha", "Centauri") // bus API invoked
385 .beforeCall("doMsg").on("alpha").arg("Centauri") // handler on target invoked
386 .beforeEvent("mark", "Centauri") // target action activated
387 .beforeEvent("TestNexus","delivered mark to bID-alpha")); // dispatch done within UI-Bus
388
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"));
393
394 // NOTE: calls are passed down synchronously, in one hop, and in sequence
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"));
404
405
406 // broadcast message
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());
420
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"));
427
428 // the order of dispatch is unspecified,
429 // but we know a regular mark call sequence happens for each connected terminal
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"));
434
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"));
439
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"));
444
445
446 cout << "____Nexus-Log_________________\n"
447 << util::join(nexusLog, "\n")
448 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
449 }
450
451
453 void
455 {
458
459 MockElm mockA("alpha"); BareEntryID alpha = mockA.getID(); mockA.joinLog (nexusLog);
460 MockElm mockB("bravo"); BareEntryID bravo = mockB.getID(); mockB.joinLog (nexusLog);
461 MockElm mockC("charly"); BareEntryID charly = mockC.getID(); mockC.joinLog (nexusLog);
462
463 auto& uiBus = stage::test::Nexus::testUI();
464
465 CHECK (not mockA.isTouched());
466 CHECK (not mockB.isTouched());
467 CHECK (not mockC.isTouched());
468
469 mockB.slotExpand();
470 uiBus.mark (alpha, GenNode{"Message", "Centauri"});
471 uiBus.mark (charly, GenNode{"Message", "Delta"});
472 uiBus.mark (charly, GenNode{"Error", "Echo"});
473
474 CHECK (mockB.isExpanded());
475 CHECK (mockC.isError());
476 CHECK ("Delta" == mockC.getMessage());
477 CHECK ("Centauri" == mockA.getMessage());
478
479 // reset all notification messages
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());
486
487 uiBus.mark (bravo, GenNode{"Message", "miss"});
488 mockA.slotExpand();
489 mockA.slotCollapse();
490
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")); // sticky error state was recorded
496
497 // reset error state(s)
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());
503
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); // sticky error state was cleared,
508 // because charly sent a clearErr state mark notification back
509
510 // send global sweeping reset
511 uiBus.markAll (GenNode{"reset", true});
512
513 CHECK (not mockA.isTouched());
514 CHECK (not mockB.isTouched());
515 CHECK (not mockC.isTouched());
516
517 CHECK (not mockA.isExpanded());
518 CHECK (not mockB.isExpanded());
519
520 CHECK (isnil (mockA.getMessage()));
521 CHECK (isnil (mockB.getMessage()));
522 CHECK (isnil (mockC.getMessage()));
523
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);
528
529
530 cout << "____Nexus-Log_________________\n"
531 << util::join(nexusLog, "\n")
532 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
533
534 stage::test::Nexus::setStateMarkHandler(); // deinstall custom state mark handler
535 }
536
537
538
539
540
555 void
557 {
559
560 struct SessionThread
561 : Sync<>
563 {
564 // shared data
565 uint64_t borgChecksum_ = 0;
566 IterStack<uint> sessionBorgs_;
567
568 // access to shared session data
569 void
570 scheduleBorg (uint id)
571 {
572 Lock sync{this};
573 borgChecksum_ += id;
574 sessionBorgs_.push(id);
575 }
576
577 auto
578 dispatchBorgs()
579 {
580 Lock sync{this};
581 return dischargeToSnapshot (sessionBorgs_);
582 }
583
584
585
594 struct BorgGenerator
597 , DiffSource
598 {
599 uint generatorID_;
600 SessionThread& theCube_;
601 IterQueue<DiffStep> steps_;
602
603 BorgGenerator (SessionThread& motherShip, uint id)
604 : generatorID_{id}
605 , theCube_{motherShip}
606 {
608 ++generator_instances;
609 }
610 ~BorgGenerator()
611 {
613 --generator_instances;
614 }
615
616
617 /* == Interface IterSource<DiffStep> == */
618
619 virtual DiffStep*
620 firstResult () override
621 {
622 REQUIRE (not steps_);
623 auto plannedBorgs = theCube_.dispatchBorgs();
624 uint max = plannedBorgs.size();
625 uint cur = 0;
626
627 _Fmt borgName{"%d of %d ≺%03d.gen%03d≻"};
628
629
630 steps_.feed (after(Ref::ATTRIBS)); // important: retain all existing attributes
631 for (uint id : plannedBorgs) // Generate diff to inject a flock of Borg
632 {
633 GenNode borg = MakeRec().genNode(borgName % ++cur % max % id % generatorID_);
634 steps_.feed (ins(borg));
635 steps_.feed (mut(borg)); // open nested scope for this Borg
636 steps_.feed ( ins(GenNode{"borgID", int(id)}));
637 steps_.feed (emu(borg)); // close nested scope
638 }
639 steps_.feed (after(Ref::END)); // important: fast-forward and accept already existing Borgs
640
641 return & *steps_; // the IterSource protocol requires us to return a ptr to current element
642 }
643
644
645 virtual void
646 nextResult (DiffStep*& pos) override
647 {
648 if (!pos) return;
649 if (steps_) ++steps_;
650 if (steps_)
651 pos = & *steps_; // pointer to current element
652 else
653 pos = NULL; // signal iteration end
654 }
655 };
656
657
661 SessionThread(function<void(DiffSource*)> notifyGUI)
662 : ThreadJoinable{"BusTerm_test: asynchronous diff mutation"
663 , [this,notifyGUI]
664 {
665 uint cnt = randGen_.i(MAX_RAND_BORGS);
666 for (uint i=0; i<cnt; ++i)
667 {
668 uint delay = randGen_.i(MAX_RAND_DELAY);
669 uint id = randGen_.i(MAX_RAND_NUMBS);
670 usleep (delay);
671 scheduleBorg (id);
672 notifyGUI (new BorgGenerator{*this, i});
673 }
674 }}
675 { }
676
677 private:
679 };
680
681
682
684
685 // the simulated »GUI model«
686 // — to be infested by hosts of Borg sent via Diff-Message...
687 MockElm rootMock("alpha zero");
688 ID rootID = rootMock.getID();
689
690 rootMock.attrib["α"] = "Quadrant";
691 CHECK ("Quadrant" == rootMock.attrib["α"]);
692 CHECK (isnil (rootMock.scope));
693
694 CHECK (0 == generator_instances);
695
696
697 // The final part in the puzzle is to dispatch the diff messages into the UI
698 // In the real application, this operation is provided by the NotificationService.
699 // It has access to the UI-Bus, but has to ensure all bus operations are actually
700 // performed on the UI event thread.
701 auto& uiBus = stage::test::Nexus::testUI();
702 CallQueue uiDispatcher;
703 auto notifyGUI = [&](DiffSource* diffGenerator)
704 {
705 uiDispatcher.feed ([&, diffGenerator]()
706 {
707 // apply and consume diff message stored within closure
708 uiBus.change (rootID, MutationMessage{diffGenerator});
709 });
710 };
711
712
713
714 //----start-multithreaded-mutation---
715 SessionThread session{notifyGUI};
716 usleep (2 * MAX_RAND_DELAY);
717 while (not isnil(uiDispatcher))
718 {
719 usleep (100);
720 uiDispatcher.invoke();
721 }
722 auto ok = session.join();
723 //------end-multithreaded-mutation---
724 CHECK (ok);
725
726 // on rare occasions we (consumer thread)
727 // prematurely empty the queue...
728 while (not isnil(uiDispatcher))
729 {
730 uiDispatcher.invoke();
731 }
732
733
734 // now verify rootMock has been properly assimilated...
735 uint generatedBorgs = rootMock.scope.size();
736
737 // root and all Borg child nodes are connected to the UI-Bus
738 CHECK (1 + generatedBorgs == stage::test::Nexus::size());
739
740 uint64_t borgChecksum = 0;
741 for (uint i=0; i<generatedBorgs; ++i)
742 {
743 MockElm& borg = *rootMock.scope[i];
744 CHECK (contains (borg.attrib, "borgID"));
745 string borgID = borg.attrib["borgID"];
746 borgChecksum += lexical_cast<int> (borgID);
747 string childID = borg.getID().getSym();
748 CHECK (contains (childID, borgID));
749 CHECK (contains (childID, " of ")); // e.g. "3 of 5"
750
751 CHECK (nexusLog.verifyCall("routeAdd").arg(rootMock.getID(), memLocation(rootMock)) // rootMock was attached to Nexus
752 .beforeCall("change") .argMatch(rootMock.getID(), // diff message sent via UI-Bus
753 "after.+?_ATTRIBS_.+?" // verify diff pattern generated for each Borg
754 "ins.+?"+childID+".+?"
755 "mut.+?"+childID+".+?"
756 "ins.+?borgID.+?"+borgID+".+?"
757 "emu.+?"+childID)
758 .beforeCall("routeAdd").arg(borg.getID(), memLocation(borg)) // Borg was inserted as child and attached to Nexus
759 .beforeEvent("applied diff to "+string(rootMock.getID()))
760 );
761 }
762
763 CHECK (rootMock.attrib["α"] == "Quadrant"); // attribute alpha was preserved while injecting all those Borg
764
765
766 // sanity checks
767 CHECK (borgChecksum == session.borgChecksum_); // no Borgs got lost
768 CHECK (0 == generator_instances); // no generator instance leaks
769
770
771
772 cout << "____Event-Log_________________\n"
773 << util::join(rootMock.getLog(), "\n")
774 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
775
776 cout << "____Nexus-Log_________________\n"
777 << util::join(nexusLog, "\n")
778 << "\n───╼━━━━━━━━━╾────────────────"<<endl;
779 }
780
781
782 static string
784 {
785 return lib::idi::instanceTypeID (&uiElm);
786 }
787 };
788
789
791 LAUNCHER (BusTerm_test, "unit stage");
792
793
794}}} // namespace stage::model::test
static snd_pcm_sframes_t delay
Definition alsa.c:31
Attachment point to the UI-Bus.
A Queue for function invocations, allowing them to be dispatched on demand.
A threadsafe queue for bound void(void) functors.
CallQueue & feed(Operation &&op)
CallQueue & invoke()
A synchronisation protection guard employing a lock scoped to the parameter type as a whole,...
Iteration source interface to abstract a data source, which then can be accessed through IterAdapter ...
Token or Atom with distinct identity.
Definition symbol.hpp:120
Facility for monitor object based locking.
Definition sync.hpp:210
Variant of the standard case, requiring to wait and join() on the termination of this thread.
Definition thread.hpp:670
object-like record of data.
Definition record.hpp:142
Hash implementation based on a lumiera unique object id (LUID) When invoking the default ctor,...
type erased baseclass for building a combined hash and symbolic ID.
Definition entry-id.hpp:134
Helper to log and verify the occurrence of events.
EventMatch verify(string match) const
start a query to match for some substring.
EventMatch verifyCall(string match) const
start a query to match especially a function call
EventMatch verifyEvent(string match) const
start a query to match for some event.
EventMatch ensureNot(string match) const
start a query to ensure the given expression does not match.
EventMatch & arg(ARGS const &...args)
refine filter to additionally require specific arguments
EventMatch & beforeEvent(string match)
find a match for an "event" after the current point of reference
EventMatch & afterEvent(string match)
EventMatch & on(string targetID)
refine filter to additionally match the ‘'this’` attribute
EventMatch & beforeCall(string match)
find a match for some function invocation after the current point of reference
A time interval anchored at a specific point in time.
Lumiera's internal time value datatype.
connection point at the UI-Bus.
Definition bus-term.hpp:98
virtual bool mark(ID subject, GenNode const &mark)
route a state update or notification to the given subject.
Definition ui-bus.cpp:151
Interface: handling of persistent interface state.
Interface common to all UI elements of relevance for the Lumiera application.
Definition tangible.hpp:160
void invoke(Symbol cmdID, ARGS &&...)
void slotCollapse()
Collapse or minimise this element and remember the collapsed state.
Definition tangible.cpp:173
void markErr(string error)
push an error state tag to the element
Definition tangible.cpp:141
void reset()
invoke the generic reset hook
Definition tangible.cpp:65
void slotExpand()
Expand this element and remember the expanded state.
Definition tangible.cpp:161
static string memLocation(Tangible &uiElm)
Mock UI element or controller.
Definition mock-elm.hpp:101
bool isError() const
Definition mock-elm.hpp:378
string getMessage() const
Definition mock-elm.hpp:384
string getError() const
Definition mock-elm.hpp:390
EventLog const & getLog() const
Definition mock-elm.hpp:459
bool isExpanded() const
Definition mock-elm.hpp:372
std::map< string, string > attrib
Definition mock-elm.hpp:354
std::vector< PMockElm > scope
Definition mock-elm.hpp:355
void kill()
commit suicide.
Definition mock-elm.hpp:340
bool isTouched() const
Definition mock-elm.hpp:366
EventLog & joinLog(MockElm &otherMock)
Definition mock-elm.hpp:465
static size_t size()
static ctrl::BusTerm & testUI()
get a connection point to a UI backbone faked for test
static ctrl::StateManager & getMockStateManager()
static void setStateMarkHandler(StateMarkHandler=StateMarkHandler())
similar to the custom command handler this hook allows to install a closure to intercept any "state m...
static void setCommandHandler(CommandHandler=CommandHandler())
install a closure (custom handler function) to deal with any command invocations encountered in the t...
static bool wasInvoked(Symbol)
Test predicate: verify at least one actual invocation happened for the given commend,...
static lib::test::EventLog const & getLog()
static ctrl::StateManager & useMockStateManager()
install a standard handler for state mark messages, which is actually backed by a mock implementation...
static lib::test::EventLog const & startNewLog()
static bool wasBound(Symbol, ARGS const &...args)
Test predicate: verify by string match that the denoted command was actually bound against the given ...
Handle object representing a single Command instance to be used by client code.
Definition command.hpp:120
Any copy and copy construction prohibited.
Definition nocopy.hpp:38
A front-end for using printf-style formatting.
Steam-Layer command frontend.
Bare symbolic and hash ID used for accounting of asset like entries.
#define LERR_(_NAME_)
Definition error.hpp:45
Automatically use custom string conversion in C++ stream output.
Front-end for printf-style string template interpolation.
Generic building block for tree shaped (meta)data structures.
unsigned int uint
Definition integral.hpp:29
Preconfigured adapters for some STL container standard usage situations.
Conveniently iterable stack and queue containers.
return NULL
Definition llist.h:586
Lumiera unique object identifier.
A generic interface element instrumented for unit testing.
Generic Message with an embedded diff, to describe changes to model elements.
TreeDiffLanguage::DiffStep DiffStep
string instanceTypeID(const TY *const obj)
designation of an distinct object instance
Definition genfunc.hpp:116
ContentSnapshot< IT > dischargeToSnapshot(IT &ii)
Take a snapshot of the given LumieraIterator, which is thereby consumed.
SeedNucleus & seedFromDefaultGen()
draw seed another Generator from the default RandomSequencer
Definition random.cpp:74
lib::idi::BareEntryID const & ID
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
const Symbol MARK_Flash
Namespace of Session and user visible high-level objects.
Definition sequence.hpp:65
Test runner and basic definitions for tests.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
Definition util.hpp:230
string join(COLL &&coll, string const &delim=", ")
enumerate a collection's contents, separated by delimiter.
bool isnil(lib::time::Duration const &dur)
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Interface: a component to maintain persistent interface state.
A Queue which can be pulled by iterating.
A Stack which can be popped by iterating.
IterStack & push(TY const &elm)
generic data element node within a tree
Definition gen-node.hpp:224
Opaque message to effect a structural change on a target, which is likewise only known in an abstract...
Constructor for a specially crafted 'ref GenNode'.
Definition gen-node.hpp:843
static const Ref NO
symbolic ID ref "_NO_"
Definition gen-node.hpp:862
typed symbolic and hash ID for asset-like position accounting.
Definition entry-id.hpp:219
A special implementation of lib::Sync, where the storage of the object monitor is associated directly...
Object Monitor based synchronisation.
A collection of frequently used helper functions to support unit testing.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
#define MARK_TEST_FUN
Macro to mark the current test function in STDOUT.
A fake UI backbone for investigations and unit testing.
Convenience front-end to simplify and codify basic thread handling.
a family of time value like entities and their relationships.
Hard wired key constants and basic definitions for communication with the GUI.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...