Lumiera  0.pre.03
»edit your freedom«
diff-tree-mutation-listener-test.cpp
Go to the documentation of this file.
1 /*
2  DiffTreeMutationListener(Test) - verify notification on structural changes
3 
4  Copyright (C)
5  2019, 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 
20 #include "lib/test/run.hpp"
23 #include "lib/format-util.hpp"
24 #include "lib/util.hpp"
25 
26 #include <boost/algorithm/string.hpp>
27 #include <string>
28 #include <vector>
29 
30 using util::isnil;
31 using std::string;
32 using std::vector;
33 
34 
35 namespace lib {
36 namespace diff{
37 namespace test{
38 
39  namespace {//Test fixture....
40 
41  // some symbolic values to be used within the diff
42  const GenNode VAL_A{"a"},
43  VAL_B{"b"},
44  VAL_C{"c"},
45  VAL_D{"d"},
46 
47  VAL_C_UPPER{"C"},
48  VAL_D_UPPER{"D"};
49 
50  string
51  contents (vector<string> const& strings)
52  {
53  return util::join (strings);
54  }
55 
56  string
57  lowerCase (string src)
58  {
59  return boost::algorithm::to_lower_copy(src); //WARNING: only works for ASCII
60  }
61 
62  bool
63  caseInsensitiveEqual (string a, string b)
64  {
65  return lowerCase (a) == lowerCase (b);
66  }
67  }//(End)Test fixture
68 
69 
70 
71 
72 
73 
74 
75 
76 
77  /****************************************************************************/
106  : public Test
107  , public DiffMutable
109  {
110  std::vector<string> subject_;
111  int structChanges_ = 0;
112  int localChanges_ = 0;
113 
120  void
122  {
123  buff.emplace (
125  .attach (collection (subject_)
126  .matchElement ([](GenNode const& spec, string const& elm) -> bool
127  { // »Matcher« : what target string "matches" a diff spec?
128  return caseInsensitiveEqual(elm, spec.data.get<string>());
129  })
130  .assignElement ([](string& target, GenNode const& spec) -> bool
131  { // »Setter« : how to assign the value from the spec to the target
132  target = spec.data.get<string>();
133  return true;
134  }))
135  .onSeqChange ([&]()
136  {
137  ++structChanges_; // Note: these lambdas are the key point for this test
138  })
139  .onLocalChange ([&]()
140  {
141  ++localChanges_;
142  })
143  );
144  }
145 
146 
147  virtual void
148  run (Arg)
149  {
150  CHECK (isnil (subject_));
151  CHECK (0 == structChanges_);
152  CHECK (0 == localChanges_);
153 
155 
156  applicator.consume (MutationMessage{{ins (VAL_A)
157  , ins (VAL_C)
158  , ins (VAL_D)
159  , ins (VAL_C)
160  }});
161  CHECK ("a, c, d, c" == contents(subject_));
162  CHECK (1 == structChanges_);
163  CHECK (1 == localChanges_);
164 
165  applicator.consume (MutationMessage{{after(Ref::END)
166  , set (VAL_C_UPPER) // Note: the current element is tried first, which happens to match
167  , set (VAL_D_UPPER) // ...while in this case, a linear search finds the "d"
168  }});
169  CHECK ("a, c, D, C" == contents(subject_));
170  CHECK (1 == structChanges_); // Note: the listener has not fired, since this counts as value change.
171  CHECK (2 == localChanges_);
172 
173  applicator.consume (MutationMessage{{pick(VAL_A)
174  , ins (VAL_B)
175  , find(VAL_D)
176  , pick(VAL_C)
177  , skip(VAL_D)
178  , del (VAL_C)
179  }});
180  CHECK ("a, b, D, c" == contents(subject_));
181  CHECK (2 == structChanges_); // Note: this obviously is a structure change, so both listeners fired.
182  CHECK (3 == localChanges_);
183 
184  applicator.consume (MutationMessage{{after(Ref::END)
185  }});
186  CHECK ("a, b, D, c" == contents(subject_));
187  CHECK (2 == structChanges_); // Note: contents confirmed as-is, none of the listeners is invoked.
188  CHECK (3 == localChanges_);
189  }
190  };
191 
192 
194  LAUNCHER (DiffTreeMutationListener_test, "unit common");
195 
196 
197 
198 }}} // namespace lib::diff::test
Concrete implementation to apply structural changes to hierarchical data structures.
Generic Message with an embedded diff, to describe changes to model elements.
Definition: run.hpp:40
void buildMutator(TreeMutator::Handle buff) override
rig the test class itself to receive a diff mutation.
Opaque message to effect a structural change on a target, which is likewise only known in an abstract...
Implementation namespace for support and library code.
static Builder< TreeMutator > build()
DSL: start building a custom adapted tree mutator, where the operations are tied by closures or wrapp...
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:104
static const Ref END
symbolic ID ref "_END_"
Definition: gen-node.hpp:862
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
auto collection(COLL &coll)
Entry point to a nested DSL for setup and configuration of a collection binding.
generic data element node within a tree
Definition: gen-node.hpp:222
Marker or capability interface: an otherwise not further disclosed data structure, which can be transformed through "tree diff messages".
generic builder to apply a diff description to a given target data structure.