I think it is a shame to waste the nice name "nexus"
just for a test facility; rather I've named our central
routing hub in the UI-Bus gui::ctrl::Nexus
So it makes sense to name the fake for unit testing
the test-nexus (we're not at nexus 5 yet)
next step will be to rig the mock element and set up
and cover the basic / generic element behaviour
This changeset
- adapts the (planned) unit test to the semantic of
the EventLog, which is now fully implemented
- adjusts the function names on the public Tangible interface,
to be better in line with the naming convention of the
corrsponding operations on the UI-Bus:
* "mark" operations are towards the UI element
* "note" messages are from the UI element towards some
state manager, which can be reached via the bus
so this turned out to be rather expensive,
while actually not difficult to implement.
On the way, I've learned
- how to build a backtracking matcher, based on
a filtering (monadic) structure and chained lambdas
- learned the hard way how (not) to return a container
by move-reference
- made first contact with the regular expressions
now available from the standard library
this function is of use also for creating a vector of strings
from a bunch of C-Strings, but it could also be used to
construct other stuff initialised by strings (e.g. RegExps)
this deals with a recurring problem in test code:
very common "simple" fractional values can not be represented
precisely as binary floating point. The classical example is 0.1
Since this is a diagnostics facility, we can cheat around this
insidious problem by just setting a limited rendering precision.
Floating point numbers behave deterministic; you just need
to know how to deal with limited precision.
abandon the use of an assertion exception to signal match failure,
rather use a final bool conversion to retrieve the results.
Error messages are now delivered by side effect into STDERR
The reason is we're unable to deliver the desisred behaviour
with the chosen DSL syntax in C++ ; on a second thought the
new approach is even better aligned with the overall way
we're writing tests in Lumiera. And we produce match-trace
messages to indicate the complete matching path now
implemented a solution to determine negative matches.
But because this solution relies on throwing from a destructor,
it is not possible to catch the resulting assertion failure.
Not sure why (AFAIK there is no second exception thrown
while unwinding the stack), but throwing from dtors is
considered "undefined behaviour" anyway.
So this solution is of limited use
beyond that solution, I'm not sure if the desired syntax
can be implemented at all in C++. Seems that we need to build
a bracketing construct, first to initiate a negated match
and finally, after all queries, to detect if there happened
any failure or not
...no need to enclose empty sections when there are no
attributes or no children. Makes test code way more readable.
TestEventLog_test PASS as far as implemented
...and fix an error (header include order of diagnostics facility)
which prevented the first matcher implementation to work
the after()-match now works as expected
this is the tiny bit of operational functionality needed on top:
whenever we're reconfiguring the predicate, we need to re-trigger
the evaluation (and clear the cached value)
n.b.: I've verified in debugger that the closure is
allocated on the heap and the functors are passed by value
after looking into our various iterator tools,
it seems obvious that our filtering iterator implementation
has almost all of the required behaviour; we only need to
add a hook to rewrite and extend the filtering functor,
which can now nicely done with a lambda closure.
This means all memory management, if necessary, is
pushed into std::function and the automated memory
management for closures provided by the runtime.
...providing the standard implementation of UI-Bus connectivity.
It seems reasonable to place all of the UI-Bus implementation into
a single translation unit