over time, we got quite a jungle with all those
shome-me-the-type-of helper functions.
Reduced and unified all those into
- typeString : a human readable, slightly simplified full type
- typeSymbol : a single word identifier, extracted lexically from the type
note: this changeset causes a lot of tests to break,
since we're using unmangeled type-IDs pretty much everywhere now.
Beore fixing those, I'll have to implement a better simplification
scheme for the "human readable" type names....
due to the new automatic string conversion in operator<<
the representation of objects has changed occasionally.
I've investigated and verified all those incidents.
...other than intended, the bomb did explode on random occasions,
with an probability of about 4% (when rr >= 96).
Btw, there was also the mistake to throw an heap allocated
object by pointer. Damn Java habits.
- remove unnecessary includes
- expunge all remaining usages of boost::format
- able to leave out the expliti string(elm) in output
- drop various operator<<, since we're now picking up
custom string conversions automatically
- delete diagnostics headers, which are now largely superfluous
- use newer helper functions occasionally
I didn't blindly change any usage of <iostream> though;
sometimes, just using the output streams right away
seems adequate.
- simple function to pick up the mangled type
- pretty-printing is implemented in format-obj.cpp
- also move the demangleCxx()-Function to that location,
it starts to be used for real, outside the test framework
our minimal compiler requirement is gcc-4.9 since the
transition to Debian/Jessie as reference system.
gcc-4.9 is known to treat SFINAE on private fields properly
this is a stripped-down and very leightweight variant
of the well-known enable_if metaprogramming trick.
Providing this standard variant in a header with minimal
dependencies will allow us to phase out boost inclusions
from many further headers. As a plus, our own variant
is written such as to be more conciese in usage
(no "typename" and no acces of an embedded "::type" menber)
...and learned a lot about the new type_traits on the way.
As it seems, it is not possible to get a clean error message
when passing an "object" with no custom string conversion;
instead, some overload for an rvalue-ostream kicks in.
probably I'll go for shoing a type string in these cases
now we use boost::format through our own front-end util::_Fmt
solely, which both helps to reduce compilation time and code size,
and gives us a direct string conversion, which automatically
uses any custom operator string() available on arguments.
While desirable as such, I did this conversion now, since
it allows us to get rid of boost::str, which in turn helps
to drill down any remaning uses of our own util::str
...this is necessary whenever the mocked facility covered
by log matching is managed automatically as singleton,
because then other test cases will leave garbage
in the log
this test is intended as counterpart to
AbstractTangible_test::verify_mockManipulation()
It creates a mock element and verifies bidirectional
connnectivity to the UI-Bus
I worked under the erroneous assumption, that Doxygen
will use its internal entity-IDs as the link-IDs when
generating mardown-links. Yes, this seemed logical and
this would be the way I'd implement it....
But seemingly, Doxygen is not so consistent when it
comes to questions of syntax. The same holds true for
markdown, which lacking a coherent definition anyway.
Another problem is that Doxygen's auto-link generation
frequently fails, for reasons not yet clear to me.
Sometimes it seems to be necessary to give it a nudge
by including the \ref command. While I'm not willing
to go into focussed invstigation of Doxygen syntax
right now, at least I've done a search-and-replace
to remove the malformed links I've written the
last days
the initial draft of this concept is in place now, and
the first round of unit tests pass. I've got some understanding
of the purpose of the interactions and involved elements
and I'm confident this design is evolving in a sane way.
Note: extensive documentation is in the TiddlyWiki,
here I've just pasted and reworded some paragraphs from there
and integrated them into the Doxygen docs
the "log joining" functionality was already implemented
and covered with the generic event log facility, but this test
here was drafted even before that, meaning that the semantics
of matchingn on the log, especially on events, as been
implemented slightly different than planned
Explanation: sigC++ was already linked as transitive dependency
from gtkmm, since it is used for the "signal-slot" system wihin GTK.
But now we want to use sigC++ itself from our generic UI-Backbone,
so we need to pick up the additional compiler and linker flags
and use them when building the relevant parts of both the application
and the test suite
since, by definition, the Nexus is "the" up-link,
all we need is clever overriding of the relevant
handling functions, so the nexus will care for the routing,
while the CoreService cares for command and presentation
state handling
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
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
...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
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
some tests rely on additional diagnostics code being linked in,
which happens, when lib/format-util.hpp is included prior to
the instantiation of lib::diff::Record rsp. lib::Variant.
The reason why i opended this can of worms was to avoid includion
of this formatting and diagnostics code into such basic headers
as lib/variant.hpp or lib/diff/gen-node.hpp
Now it turns out, that on some platforms the linker will use
a later instantiation of lib::Variant::Buff<GenNode>::operator string
in spite of a complete instantiation of this virtual function
being available already in liblumierasupport.so
But the real reason is that -- with this trickery -- we're violating
the single definition rule, so we get what we deserved.
TODO (Ticket #973): at a later point in development we have to re-assess,
the precise impact of including lib/format-util.hpp into
lib/diff/gen-node.hpp
Right now I expect GenNode to be used pervasively, so I am
reluctant to make that header too heavyweight.
yet another instance of that obnoxious problem that "long"
is just 32bit on i386 platforms. Why the hell does such
a broken type get the preference of convenient notation??
Hehe...
with GenNode, we started to use these global Type-IDs to generate
unique Names for unnamed Children in a diff::Record. This means,
when running in the test-suite, the TypeID for 'short' and 'long' are
likely to be allready allocated, so our Test can not not observe the
allocateion, nor is it sensible to assume fixed numbers for these Type-IDs.
Instead, we create two local types right within the test function, to force
generation of new unique type-IDs, which we can observe
well... this was quite a piece of work
Added some documentation, but a complete documentation,
preferably to the website, would be desirable, as would
be a more complete test covering the negative corner cases
while implementing this, I've discovered a conceptual error:
we allow to accept attributes, even when we've already entered
the child scope. This means that we can not predictable get back
at the "last" (i.e. the currently touched) element, because this
might be such an attribute. So a really correct implementation
would have to memorise the "current" element, which is really
tricky, given the various ways of touching elements in our
diff language.
In the end I've decided to ignore this problem (maybe a better
solution would have been to disallow those "late" attributes?)
My reasoning is that attributes are unlikely to be full records,
rather just values, and values are never mutated. (but note
that it is definitively possible to have an record as attribute!)
...while I must admit that I'm a bit doubtful about that
language feature, but it does come in handy when manually
writing diff messages. The reason is the automatic naming
of child objects, which makes it often hard to refer to
a child after the fact, since the name can not be
reconstructed systematically.
Obviously the downside of this "anonymous pick / delete"
is that we allow to pick (accept) or even delete just
any child, which happens to sit there, without being
able to detect a synchronisation mismatch between
sender and receiver.
...so now the stage is set. We can reimplement
the handling of the list diff cases here in the context
of tree diff application. The additional twist of course
being the distinction between attribute and child scope
so basically it's time to explicate the way
our diff language will actually be written.
Similar to the list diff case, it's a linear sequence
of verb tokens, but in this case, the payload value
in each token is a GenNode. This is the very reason
why GenNode was conceived as value object with an
opaque DataCap payload
while it's still not really clear how we'll use this helper
and if we need it at all -- some weeks ago I changed its
semantics to be strictly based on the delta to a reference level.
Now this means, we could go below level zero, but this doesn't
make any sense in the context of navigating a tree. Actually,
our test case triggered this situation, which caused the
reference level to wrap around, since it is stored in an
unsigned variable.
Thus I'll add a precondition to keep the level positive,
and I'll change the test to comply.
Initially I've deliberately omitted those, to nudge towards
using time quantisation and TCode formatting for any external
representation of time values.
While this recommendation is still valid, the overloaded
string conversion turns out to be helpful for unit testing
and diagnostics in compound data structures.
See Record<GenNode>
initially the intention was to include a "bracketing construct"
into the values returned by the iterator. After considering
the various implementation and representation approaches,
it seems more appropriate just to expose a measure for the
depth-in-tree through the iterator itself, leaving any concerns
about navigation and structure reconstruction to the usage site.
As rationale we consider the full tree reconstruction as a very
specialised use case, and as such the normal "just iteration" usage
should not pay for this in terms of iterator size and implementation
complexity. Once a "level" measure is exposed, the usage site
can do precisely the same, with the help of the
HierarchyOrientationIndicator.
Whooa!
Templates are powerful.
programming this way is really fun.
under the assumption that the parts are logical,
all conceivable combinations of theses parts are bound to be correct