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) Lumiera.org
5  2019, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
29 #include "lib/test/run.hpp"
32 #include "lib/format-util.hpp"
33 #include "lib/util.hpp"
34 
35 #include <boost/algorithm/string.hpp>
36 #include <string>
37 #include <vector>
38 
39 using util::isnil;
40 using std::string;
41 using std::vector;
42 
43 
44 namespace lib {
45 namespace diff{
46 namespace test{
47 
48  namespace {//Test fixture....
49 
50  // some symbolic values to be used within the diff
51  const GenNode VAL_A{"a"},
52  VAL_B{"b"},
53  VAL_C{"c"},
54  VAL_D{"d"},
55 
56  VAL_C_UPPER{"C"},
57  VAL_D_UPPER{"D"};
58 
59  string
60  contents (vector<string> const& strings)
61  {
62  return util::join (strings);
63  }
64 
65  string
66  lowerCase (string src)
67  {
68  return boost::algorithm::to_lower_copy(src); //WARNING: only works for ASCII
69  }
70 
71  bool
72  caseInsensitiveEqual (string a, string b)
73  {
74  return lowerCase (a) == lowerCase (b);
75  }
76  }//(End)Test fixture
77 
78 
79 
80 
81 
82 
83 
84 
85 
86  /****************************************************************************/
115  : public Test
116  , public DiffMutable
118  {
119  std::vector<string> subject_;
120  int structChanges_ = 0;
121  int localChanges_ = 0;
122 
129  void
131  {
132  buff.emplace (
134  .attach (collection (subject_)
135  .matchElement ([](GenNode const& spec, string const& elm) -> bool
136  { // »Matcher« : what target string "matches" a diff spec?
137  return caseInsensitiveEqual(elm, spec.data.get<string>());
138  })
139  .assignElement ([](string& target, GenNode const& spec) -> bool
140  { // »Setter« : how to assign the value from the spec to the target
141  target = spec.data.get<string>();
142  return true;
143  }))
144  .onSeqChange ([&]()
145  {
146  ++structChanges_; // Note: these lambdas are the key point for this test
147  })
148  .onLocalChange ([&]()
149  {
150  ++localChanges_;
151  })
152  );
153  }
154 
155 
156  virtual void
157  run (Arg)
158  {
159  CHECK (isnil (subject_));
160  CHECK (0 == structChanges_);
161  CHECK (0 == localChanges_);
162 
164 
165  applicator.consume (MutationMessage{{ins (VAL_A)
166  , ins (VAL_C)
167  , ins (VAL_D)
168  , ins (VAL_C)
169  }});
170  CHECK ("a, c, d, c" == contents(subject_));
171  CHECK (1 == structChanges_);
172  CHECK (1 == localChanges_);
173 
174  applicator.consume (MutationMessage{{after(Ref::END)
175  , set (VAL_C_UPPER) // Note: the current element is tried first, which happens to match
176  , set (VAL_D_UPPER) // ...while in this case, a linear search finds the "d"
177  }});
178  CHECK ("a, c, D, C" == contents(subject_));
179  CHECK (1 == structChanges_); // Note: the listener has not fired, since this counts as value change.
180  CHECK (2 == localChanges_);
181 
182  applicator.consume (MutationMessage{{pick(VAL_A)
183  , ins (VAL_B)
184  , find(VAL_D)
185  , pick(VAL_C)
186  , skip(VAL_D)
187  , del (VAL_C)
188  }});
189  CHECK ("a, b, D, c" == contents(subject_));
190  CHECK (2 == structChanges_); // Note: this obviously is a structure change, so both listeners fired.
191  CHECK (3 == localChanges_);
192 
193  applicator.consume (MutationMessage{{after(Ref::END)
194  }});
195  CHECK ("a, b, D, c" == contents(subject_));
196  CHECK (2 == structChanges_); // Note: contents confirmed as-is, none of the listeners is invoked.
197  CHECK (3 == localChanges_);
198  }
199  };
200 
201 
203  LAUNCHER (DiffTreeMutationListener_test, "unit common");
204 
205 
206 
207 }}} // 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:49
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:113
static const Ref END
symbolic ID ref "_END_"
Definition: gen-node.hpp:871
Simple 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:231
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.