TreeMutator: combine no-op layer with selective other diff binding
...and complete unit test coverage. This is complex stuff and we'd better be careful it actually works
This commit is contained in:
parent
0d5f29446b
commit
e81b0592d3
3 changed files with 119 additions and 19 deletions
|
|
@ -51,14 +51,10 @@
|
|||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
#include "lib/diff/tree-mutator.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/idi/entry-id.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace lib {
|
||||
namespace diff{
|
||||
|
|
@ -85,7 +81,7 @@ namespace diff{
|
|||
|
||||
bool hasSrc() override { return true; } ///< always keen to do yet more
|
||||
|
||||
bool injectNew (Elm) override { return true; } ///< pretend to inject a new element
|
||||
bool injectNew (Elm) override { return true; } ///< pretend to inject something new
|
||||
bool matchSrc (Elm) override { return true; } ///< purport suitable element is waiting
|
||||
bool acceptSrc (Elm) override { return true; } ///< claim to handle any diff task
|
||||
bool accept_until (Elm) override { return true; } ///< profess to forward anywhere
|
||||
|
|
@ -93,7 +89,7 @@ namespace diff{
|
|||
bool assignElm (Elm) override { return true; } ///< accept any assignment
|
||||
|
||||
bool
|
||||
mutateChild (Elm, Buff buff) override ///< bluff to care for children, while just reproducing ourselves
|
||||
mutateChild (Elm, Buff buff) override ///< ignore inferiors, yet reproduce yourself
|
||||
{
|
||||
buff.create (BlackHoleMutation());
|
||||
return true;
|
||||
|
|
@ -102,11 +98,21 @@ namespace diff{
|
|||
|
||||
|
||||
|
||||
/** Entry point for DSL builder */
|
||||
/** Entry point for DSL builder: create a binding which consumes any diff without effect.
|
||||
* @warning must be used as bottom most layer in a custom TreeMutator, since it would
|
||||
* otherwise shadow and disable any binding layer below.
|
||||
* @note however it is possible to add a (typically selective) binding layer on top;
|
||||
* any diff verb _not handled_ by such a top layer will fall through and
|
||||
* be silently ignored. Such a setup can be used to "fish" for some specific
|
||||
* attributes within a diff stream.
|
||||
*/
|
||||
template<class PAR>
|
||||
inline auto
|
||||
Builder<PAR>::ignoreAllChanges()
|
||||
{
|
||||
static_assert (std::is_same<PAR, TreeMutator>()
|
||||
,"ignoreAllChanges() must be used as bottom layer.");
|
||||
|
||||
return Builder<BlackHoleMutation> (BlackHoleMutation{});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,15 +145,35 @@ namespace test{
|
|||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
fail_or_ignore();
|
||||
fish_for_content();
|
||||
}
|
||||
|
||||
|
||||
/** @test fail or ignore, depending on toggle.
|
||||
* - the TreeMutator default implementation produces a failure,
|
||||
* when it actually has to handle some diff verb
|
||||
* - yet a custom TreeMutator can be configured to `ignoreAllChanges()`,
|
||||
* in which case it will consume any diff without effect.
|
||||
* This test also demonstrates that the actual TreeMutator is built anew
|
||||
* for each diff application (TreeMutator is meant to be disposable).
|
||||
* Thus we may alter the behaviour of the diff binding dynamically.
|
||||
* @remark the actual use case for this is the TimelineGui, which
|
||||
* either forwards changes to a TimelineWidget, or silently
|
||||
* ignores them when the corresponding timeline is not opened.
|
||||
*/
|
||||
void
|
||||
fail_or_ignore()
|
||||
{
|
||||
struct HappyBlackHole
|
||||
{
|
||||
bool grumpy = true;
|
||||
bool diligent = true;
|
||||
|
||||
void
|
||||
buildMutator (TreeMutator::Handle buff)
|
||||
{
|
||||
if (grumpy)
|
||||
if (diligent)
|
||||
buff.create(
|
||||
TreeMutator());
|
||||
else
|
||||
|
|
@ -170,12 +190,58 @@ namespace test{
|
|||
VERIFY_ERROR(DIFF_CONFLICT, application.consume(reorderingDiff()) );
|
||||
VERIFY_ERROR(DIFF_CONFLICT, application.consume(mutationDiff()) );
|
||||
|
||||
subject.grumpy = false;
|
||||
subject.diligent = false;
|
||||
|
||||
application.consume(populationDiff());
|
||||
application.consume(reorderingDiff());
|
||||
application.consume(mutationDiff());
|
||||
}
|
||||
|
||||
|
||||
/** @test fish some content and ignore everything else.
|
||||
* While the BlackHoleMutation binding generated by `ignoreAllChanges()`
|
||||
* must be used as bottom layer of a custom TreeMutator, it is possible
|
||||
* to layer a partial diff binding on top. This test demonstrates this
|
||||
* with a single attribute binding, which just "fishes" any value
|
||||
* mentioned in the diff for that specific attribute. Any other
|
||||
* changes are silently ignored non the less...
|
||||
*/
|
||||
void
|
||||
fish_for_content()
|
||||
{
|
||||
struct Scrounger
|
||||
{
|
||||
double loot = 0.0;
|
||||
|
||||
void
|
||||
buildMutator (TreeMutator::Handle buff)
|
||||
{
|
||||
buff.create(
|
||||
TreeMutator::build()
|
||||
.ignoreAllChanges()
|
||||
.change("γ", [&](double val) { loot = val; }));
|
||||
}
|
||||
};
|
||||
|
||||
Scrounger subject;
|
||||
DiffApplicator<Scrounger> application(subject);
|
||||
|
||||
const auto NOTHING = 0.0;
|
||||
const auto VAL_1 = ATTRIB3.data.get<double>();
|
||||
const auto VAL_2 = GAMMA_PI.data.get<double>();
|
||||
|
||||
CHECK (subject.loot == NOTHING);
|
||||
|
||||
application.consume(populationDiff());
|
||||
CHECK (subject.loot == VAL_1);
|
||||
|
||||
application.consume(reorderingDiff());
|
||||
CHECK (subject.loot == VAL_1);
|
||||
|
||||
application.consume(mutationDiff());
|
||||
CHECK (subject.loot == VAL_2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16549,7 +16549,7 @@
|
|||
</node>
|
||||
<node CREATED="1539270808827" ID="ID_1352270227" MODIFIED="1539270817730" TEXT="für TimelineGui">
|
||||
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1352270227" ENDARROW="Default" ENDINCLINATION="117;0;" ID="Arrow_ID_1672775567" SOURCE="ID_1624846094" STARTARROW="None" STARTINCLINATION="117;0;"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1539294555064" HGAP="45" ID="ID_1365984217" MODIFIED="1539299038616" TEXT="Problem: diff ignorieren" VSHIFT="23">
|
||||
<node COLOR="#435e98" CREATED="1539294555064" HGAP="45" ID="ID_1365984217" MODIFIED="1539302548248" TEXT="Problem: diff ignorieren" VSHIFT="23">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1539294576338" ID="ID_485684974" MODIFIED="1539294587881" TEXT="kann das auftreten....?">
|
||||
<icon BUILTIN="help"/>
|
||||
|
|
@ -16579,12 +16579,14 @@
|
|||
<node CREATED="1539294678444" ID="ID_934706379" MODIFIED="1539294693604" TEXT="TreeMutator scheitert per Default">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1539294698801" ID="ID_1533611583" MODIFIED="1539299026168" TEXT="also brauche ich einen /dev/null-Mutator">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1539294698801" ID="ID_1533611583" MODIFIED="1539302545239" TEXT="also brauche ich einen /dev/null-Mutator">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1539294727470" ID="ID_1958316881" MODIFIED="1539299017213" TEXT="speziellen Binding-Layer fabrizieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1539294807066" ID="ID_1137741867" MODIFIED="1539294809654" TEXT="wie?"/>
|
||||
<node CREATED="1539294812306" ID="ID_1564927840" MODIFIED="1539294826763" TEXT="muß das Standard-Mapping anschauen"/>
|
||||
<node CREATED="1539294812306" ID="ID_1564927840" MODIFIED="1539302566302" TEXT="muß das Standard-Mapping anschauen">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
<node CREATED="1539294846845" ID="ID_1839295475" MODIFIED="1539294935855" TEXT="TreeDiffMutatorBinding">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1539294859537" ID="ID_637091190" MODIFIED="1539294928138" TEXT="__expect_further_elements -> immer true">
|
||||
|
|
@ -16600,20 +16602,46 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1539302456636" ID="ID_809868228" MODIFIED="1539302478177" TEXT="Idee: mit anderen Layern kombinieren...">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1539302481080" ID="ID_126724611" MODIFIED="1539302542052" TEXT="static_assertion">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...damit es nicht versehentlich über einen anderen Layer gelegt wird,
|
||||
</p>
|
||||
<p>
|
||||
welchen es dann überdecken und außer Gefecht setzen würde.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Habe verifiziert, daß diese Assertion tatsächlich greift
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1539294743739" ID="ID_1596076772" MODIFIED="1539294758145" TEXT="Builder().ignoreAll()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1539294760464" ID="ID_1376112641" MODIFIED="1539294792408" TEXT="DiffIgnoreChanges_test">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1539294760464" ID="ID_1376112641" MODIFIED="1539302371782" TEXT="DiffIgnoreChanges_test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1539298953819" ID="ID_1706428916" MODIFIED="1539298972769" TEXT="leerer TreeMutator produziert Fehler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1539298974312" ID="ID_986781359" MODIFIED="1539298992271" TEXT="BlackHoleMutation frißt alles">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1539298993222" ID="ID_647799125" MODIFIED="1539299007509" TEXT="Kombinieren mit speziellem Overlay">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1539298993222" ID="ID_647799125" MODIFIED="1539302373522" TEXT="Kombinieren mit speziellem Overlay">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue