Lumiera  0.pre.03
»edit your freedom«
diff-tree-application-test.cpp
Go to the documentation of this file.
1 /*
2  DiffTreeApplication(Test) - demonstrate the main features of tree diff representation
3 
4  Copyright (C)
5  2015, 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 
24 #include "lib/test/run.hpp"
25 #include "lib/format-util.hpp"
27 #include "lib/iter-adapter-stl.hpp"
28 #include "lib/time/timevalue.hpp"
29 #include "lib/format-util.hpp"
30 #include "lib/util.hpp"
31 
32 #include <string>
33 #include <vector>
34 
36 using util::isnil;
37 using util::join;
38 using std::string;
39 using std::vector;
40 using lib::time::Time;
41 
42 
43 namespace lib {
44 namespace diff{
45 namespace test{
46 
47  namespace {//Test fixture....
48 
49  // define some GenNode elements
50  // to act as templates within the concrete diff
51  // NOTE: everything in this diff language is by-value
52  const GenNode ATTRIB1("α", 1), // attribute α = 1
53  ATTRIB2("β", int64_t(2)), // attribute α = 2L (int64_t)
54  ATTRIB3("γ", 3.45), // attribute γ = 3.45 (double)
55  TYPE_X("type", "X"), // a "magic" type attribute "X"
56  TYPE_Y("type", "Y"), //
57  CHILD_A("a"), // unnamed string child node
58  CHILD_B('b'), // unnamed char child node
59  CHILD_T(Time(12,34,56,78)), // unnamed time value child
60  SUB_NODE = MakeRec().genNode(), // empty anonymous node used to open a sub scope
61  ATTRIB_NODE = MakeRec().genNode("δ"), // empty named node to be attached as attribute δ
62  CHILD_NODE = SUB_NODE; // yet another child node, same ID as SUB_NODE (!)
63 
64  }//(End)Test fixture
65 
66 
67 
68 
69 
70 
71 
72 
73 
74  /***********************************************************************/
105  : public Test
107  {
109 
110  DiffSeq
111  populationDiff()
112  {
113  return snapshot({ins(TYPE_X)
114  , ins(ATTRIB1)
115  , ins(ATTRIB2)
116  , ins(ATTRIB3)
117  , ins(CHILD_A)
118  , ins(CHILD_T)
119  , ins(CHILD_T)
120  , ins(SUB_NODE)
121  , mut(SUB_NODE)
122  , ins(CHILD_B)
123  , ins(CHILD_A)
124  , emu(SUB_NODE)
125  });
126  }
127 
128 
129  DiffSeq
130  mutationDiff()
131  {
132  // prepare for direct assignment of new value
133  // NOTE: the target ID will be reconstructed, including hash
134  GenNode childA_upper(CHILD_A.idi.getSym(), "A");
135 
136  return snapshot({after(Ref::ATTRIBS) // fast forward to the first child
137  , find(CHILD_T)
138  , pick(CHILD_A)
139  , skip(CHILD_T)
140  , del(CHILD_T)
141  , after(Ref::END) // accept anything beyond as-is
142  , mut(SUB_NODE)
143  , ins(ATTRIB3)
144  , ins(ATTRIB_NODE) // attributes can also be nested objects
145  , find(CHILD_A)
146  , del(CHILD_B)
147  , ins(CHILD_NODE)
148  , ins(CHILD_T)
149  , skip(CHILD_A)
150  , mut(CHILD_NODE)
151  , ins(TYPE_Y)
152  , ins(ATTRIB2)
153  , emu(CHILD_NODE)
154  , set(childA_upper) // direct assignment, target found by ID (out of order)
155  , mut(ATTRIB_NODE) // mutation can be out-of order, target found by ID
156  , ins(CHILD_A)
157  , ins(CHILD_A)
158  , ins(CHILD_A)
159  , emu(ATTRIB_NODE)
160  , emu(SUB_NODE)
161  });
162  }
163 
164 
165  virtual void
166  run (Arg)
167  {
168  Rec::Mutator target;
169  Rec& subject = target;
170  DiffApplicator<Rec::Mutator> application(target);
171 
172  // Part I : apply diff to populate
173  application.consume (populationDiff());
174 
175  CHECK (!isnil (subject)); // nonempty -- content has been added
176  CHECK ("X" == subject.getType()); // type was set to "X"
177  CHECK (1 == subject.get("α").data.get<int>()); // has gotten our int attribute "α"
178  CHECK (2L == subject.get("β").data.get<int64_t>()); // ... the long attribute "β"
179  CHECK (3.45 == subject.get("γ").data.get<double>()); // ... and double attribute "γ"
180  auto scope = subject.scope(); // look into the scope contents...
181  CHECK ( *scope == CHILD_A); // there is CHILD_A
182  CHECK (*++scope == CHILD_T); // followed by a copy of CHILD_T
183  CHECK (*++scope == CHILD_T); // and another copy of CHILD_T
184  CHECK (*++scope == MakeRec().appendChild(CHILD_B) // and there is a nested Record
185  .appendChild(CHILD_A) // with CHILD_B
186  .genNode(SUB_NODE.idi.getSym())); // and CHILD_A
187  CHECK (isnil(++scope)); // thats all -- no more children
188 
189  // Part II : apply the second diff
190  application.consume (mutationDiff());
191  CHECK (join (subject.keys()) == "α, β, γ"); // the attributes weren't altered
192  scope = subject.scope(); // but the scope was reordered
193  CHECK ( *scope == CHILD_T); // CHILD_T
194  CHECK (*++scope == CHILD_A); // CHILD_A
195  Rec nested = (++scope)->data.get<Rec>(); // and our nested Record, which too has been altered:
196  CHECK (nested.get("γ").data.get<double>() == 3.45); // it carries now an attribute "δ", which is again
197  CHECK (nested.get("δ") == MakeRec().appendChild(CHILD_A) // a nested Record with three children CHILD_A
198  .appendChild(CHILD_A) //
199  .appendChild(CHILD_A) //
200  .genNode("δ")); //
201  auto subScope = nested.scope(); // and within the nested sub-scope we find
202  CHECK ( *subScope != CHILD_A); // CHILD_A has been altered by assignment
203  CHECK (CHILD_A.idi == subScope->idi); // ...: same ID as CHILD_A
204  CHECK ("A" == subScope->data.get<string>()); // ...: but mutated payload
205  CHECK (*++subScope == MakeRec().type("Y") // a yet-again nested sub-Record of type "Y"
206  .set("β", int64_t(2)) // with just an attribute "β" == 2L
207  .genNode(CHILD_NODE.idi.getSym())); // (and an empty child scope)
208  CHECK (*++subScope == CHILD_T); // followed by another copy of CHILD_T
209  CHECK (isnil (++subScope)); //
210  CHECK (isnil (++scope)); // and nothing beyond that.
211  }
212  };
213 
214 
216  LAUNCHER (DiffTreeApplication_test, "unit common");
217 
218 
219 
220 }}} // namespace lib::diff::test
Concrete implementation to apply structural changes to hierarchical data structures.
Definition: run.hpp:40
iter_stl::IterSnapshot< VAL > snapshot(std::initializer_list< VAL > const &&ili)
Take a snapshot of the given std::initializer_list.
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
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...
static const Ref ATTRIBS
symbolic ID ref "_ATTRIBS_"
Definition: gen-node.hpp:865
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
materialised iterator contents.
Preconfigured adapters for some STL container standard usage situations.
a family of time value like entities and their relationships.
object-like record of data.
Definition: record.hpp:141
generic data element node within a tree
Definition: gen-node.hpp:222
generic builder to apply a diff description to a given target data structure.