From 8bcd37df0a1f0ac51abab365f40c0d85511acb58 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 27 Feb 2016 01:47:33 +0100 Subject: [PATCH] stub first round of mutation primitives to pass compiler again now this feels like making progress again, even when just writing stubs ;-) Moreover, it became clear that the "typing" of typed child collections will always be ad hoc, and thus needs to be ensured on a case by case base. As a consequence, all mutation primitives must carry the necessary information for the internal selector to decide if this primitive is applicable to a given decorator layer. Because otherwise it is not possible to uphold the concept of a single, abstracted "source position", where in fact each typed sub-collection of children (and thus each "onion layer" in the decorator chain) maintains its own private position --- src/lib/diff/test-mutation-target.hpp | 184 ++++++++++++++++++ src/lib/diff/tree-diff-mutator-binding.hpp | 83 +++++++- src/lib/diff/tree-mutator.hpp | 42 +++- .../diff/tree-manipulation-binding-test.cpp | 4 +- wiki/thinkPad.ichthyo.mm | 15 +- 5 files changed, 315 insertions(+), 13 deletions(-) create mode 100644 src/lib/diff/test-mutation-target.hpp diff --git a/src/lib/diff/test-mutation-target.hpp b/src/lib/diff/test-mutation-target.hpp new file mode 100644 index 000000000..0c2aa32b4 --- /dev/null +++ b/src/lib/diff/test-mutation-target.hpp @@ -0,0 +1,184 @@ +/* + TEST-MUTATION-TARGET.hpp - diagnostic helper for TreeMutator bindings + + Copyright (C) Lumiera.org + 2016, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file test-mutation-target.hpp + ** Diagnostic helper for unit tests regarding mutation of custom data. + ** The TreeMutator provides a specialised adapter to attach to a TestMutationTarget. + ** This adapter is optional and can be combined with any other binding for arbitrary + ** hierarchical data structures. It operates in the way of a "wire tap", where the + ** observed "mutation primitives" are recorded within the TestMutationTarget, + ** which offers query functions for the unit test to verify what happened. + ** + ** @remarks this facility was created during the attempt to shape the internal API + ** of TreeMutator, including definition of the "mutation primitives"; + ** it might be helpful later to diagnose problems with data mutation. + ** + ** @todo WIP 2/2016 + ** + ** @see TreeManipulationBinding_test + ** @see TreeMutator + ** + */ + + +#ifndef LIB_DIFF_TEST_MUTATION_TARGET_H +#define LIB_DIFF_TEST_MUTATION_TARGET_H + + +#include "lib/error.hpp" +#include "lib/symbol.hpp" +#include "lib/diff/record.hpp" +#include "lib/diff/tree-mutator.hpp" +#include "lib/idi/genfunc.hpp" +#include "lib/test/event-log.hpp" +//#include "lib/util.hpp" +//#include "lib/format-string.hpp" + +//#include +#include +//#include +//#include + + +namespace lib { +namespace diff{ + + namespace error = lumiera::error; + +//using util::_Fmt; + using lib::test::EventLog; + using lib::test::EventMatch; + using lib::Literal; +// using std::function; + using std::string; + + namespace { + } + + + /** + * Test adapter to watch and verify how the + * TreeMutator binds to custom tree data structures. + * @todo WIP 2/2016 + */ + class TestMutationTarget + { + + EventLog log_{this->identify()}; + + public: + + /* === Diagnostic / Verification === */ + + bool + empty() const + { + UNIMPLEMENTED ("NIL check"); + } + + bool + contains (string spec) const + { + UNIMPLEMENTED ("check for recorded element"); + } + + EventMatch + verify (string match) const + { + return getLog().verify(match); + } + + EventMatch + verifyMatch (string regExp) const + { + return getLog().verifyMatch(regExp); + } + + EventMatch + verifyEvent (string match) const + { + return getLog().verifyEvent(match); + } + + EventMatch + verifyEvent (string classifier, string match) const + { + return getLog().verifyEvent (classifier,match); + } + + EventMatch + verifyCall (string match) const + { + return getLog().verifyCall(match); + } + + EventMatch + ensureNot (string match) const + { + return getLog().ensureNot(match); + } + + EventLog const& + getLog() const + { + return log_; + } + + + private: + string + identify() const + { + return lib::idi::instanceTypeID(this); + } + }; + + + + namespace { // supply a suitable decorator for the TreeMutator + + template + struct TestWireTap + : PAR + { + TestMutationTarget& target_; + + TestWireTap(TestMutationTarget& dummy, PAR const& chain) + : PAR(chain) + , target_(dummy) + { } + }; + + template + Builder> + Builder::attachDummy (TestMutationTarget& dummy) + { + return WireTap (dummy, *this); + } + + } + + + +}} // namespace lib::diff +#endif /*LIB_DIFF_TREE_MUTATOR_H*/ diff --git a/src/lib/diff/tree-diff-mutator-binding.hpp b/src/lib/diff/tree-diff-mutator-binding.hpp index dbcd0ce61..c27c12456 100644 --- a/src/lib/diff/tree-diff-mutator-binding.hpp +++ b/src/lib/diff/tree-diff-mutator-binding.hpp @@ -254,18 +254,90 @@ namespace diff{ out().appendChild (move(*pos)); } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #992 + + /* == Forwarding: error handling == */ + void - locate_and_assign (GenNode const& n) + __expect_in_target (GenNode const& elm, Literal oper) { } void - locate_and_open_for_mutation (GenNode const& n) + __expect_further_elements (GenNode const& elm) { } + void + __fail_not_found (GenNode const& elm) + { + + } + + void + __expect_end_of_scope (GenNode::ID const& idi) + { + + } + + void + __expect_valid_parent_scope (GenNode::ID const& idi) + { + + } + + + /* == Forwarding: mutation primitives == */ + + void + skip_src (GenNode const& n) + { + UNIMPLEMENTED("skip matching src element and advance abstract source position"); + } + + void + accept_src (GenNode const& n) + { + UNIMPLEMENTED("accept existing element"); + } + + void + inject (GenNode const& n) + { + UNIMPLEMENTED("inject a new element at current abstract position"); + } + + bool + find_and_accept (GenNode const& n) + { + UNIMPLEMENTED("locate designated element and accept it at current position"); + } + + bool + accept_until (GenNode const& refMark) + { + UNIMPLEMENTED("repeatedly accept until encountering the mark"); + } + + void + locate_and_assign (GenNode const& n) + { + UNIMPLEMENTED("locate allready accepted element and assign given new payload"); + } + + void + locate_and_open_for_mutation (GenNode const& n) + { + UNIMPLEMENTED("locate allready accepted element and open recursive sub-scope for mutation"); + } + + void + close_subScope() + { + UNIMPLEMENTED("finish and leave sub scope and return to invoking parent scope"); + } + /* == Implementation of the list diff application primitives == */ @@ -280,22 +352,21 @@ namespace diff{ del (GenNode const& n) override { __expect_in_target(n, "remove"); - next_src(); + skip_src (n); } virtual void pick (GenNode const& n) override { __expect_in_target(n, "pick"); - accept_src(); - next_src(); + accept_src (n); } virtual void skip (GenNode const& n) override { __expect_further_elements (n); - next_src(); + skip_src (n); } // assume the actual content has been moved away by a previous find() virtual void diff --git a/src/lib/diff/tree-mutator.hpp b/src/lib/diff/tree-mutator.hpp index cc82d346c..8c6474a64 100644 --- a/src/lib/diff/tree-mutator.hpp +++ b/src/lib/diff/tree-mutator.hpp @@ -41,6 +41,24 @@ ** can be replaced by a binding closure, which allows to invoke arbitrary code in the ** context of the given object's implementation internals. ** + ** ## Builder/Adapter concept + ** TreeMutator is both an interface and a set of building blocks. + ** On concrete usage, the (private, non disclosed) target data structure is assumed + ** to _build a subclass of TreeMutator._ To this end, the TreeMutator is complemented + ** by a builder API. Each call on this builder -- typically providing some closure -- + ** will add yet another decorating layer on top of the basic TreeMutator (recall all + ** the "mutation primitives" are implemented NOP within the base class). So the actual + ** TreeMutator will be structured like an onion, where each layer cares for the sole + ** concrete aspect it was tied for by the supplied closure. For example, there might + ** be a decorator to handle setting of a "foobar" attribute. Thus, when the diff + ** dictates to mutate "foobar", the corresponding closure will be invoked. + ** + ** \par test dummy target + ** There is a special adapter binding to support writing unit tests. The corresponding + ** API is only declared (forward) by default. The TestMutationTarget is a helper class, + ** which can be attached through this binding and allows a unit test fixture to record + ** and verify all the mutation operations encountered. + ** ** @see tree-mutator-test.cpp ** @see DiffDetector ** @@ -73,6 +91,10 @@ namespace diff{ using std::function; using std::string; + + class TestMutationTarget; // for unit testing + + namespace { template struct Builder; @@ -100,7 +122,7 @@ namespace diff{ /* ==== operation API ==== */ virtual void - insertChild (ID id) + insertChild (GenNode const& n) { UNIMPLEMENTED("establish new child node at current position"); } @@ -133,7 +155,7 @@ namespace diff{ static Builder build(); }; - namespace { + namespace { // Mutator-Builder decorator components... /** * Type rebinding helper to pick up the actual argument type. @@ -181,6 +203,11 @@ namespace diff{ { } }; + + template + struct TestWireTap; + + template struct Builder : PAR @@ -192,6 +219,8 @@ namespace diff{ template using Change = ChangeOperation; + using WireTap = TestWireTap; + /* ==== binding API ==== */ @@ -201,9 +230,14 @@ namespace diff{ { return Change (attributeID, closure, *this); } + + Builder + attachDummy (TestMutationTarget& dummy); + }; - - } + + }//(END) Mutator-Builder decorator components... + Builder TreeMutator::build () diff --git a/tests/library/diff/tree-manipulation-binding-test.cpp b/tests/library/diff/tree-manipulation-binding-test.cpp index 77b4bffac..5c4808b8f 100644 --- a/tests/library/diff/tree-manipulation-binding-test.cpp +++ b/tests/library/diff/tree-manipulation-binding-test.cpp @@ -25,6 +25,7 @@ #include "lib/format-util.hpp" #include "lib/test/test-helper.hpp" #include "lib/diff/tree-mutator.hpp" +#include "lib/diff/test-mutation-target.hpp" #include "lib/time/timevalue.hpp" #include "lib/format-cout.hpp" #include "lib/util.hpp" @@ -34,6 +35,7 @@ //#include using util::isnil; +using lib::time::Time; using std::string; //using std::vector; //using std::swap; @@ -107,7 +109,7 @@ namespace test{ TestMutationTarget target; auto mutator = TreeMutator::build() - .attachDummy(target); + .attachDummy (target); CHECK (isnil (target)); diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 53b5c58e5..66e9e97dd 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -1517,7 +1517,8 @@ - + + @@ -1705,7 +1706,17 @@ - + + + + + + + + + + +