Lumiera  0.pre.03
»edit your freedom«
generic-record-test.cpp
Go to the documentation of this file.
1 /*
2  GenericRecord(Test) - introspective representation of object-like data
3 
4  Copyright (C) Lumiera.org
5  2015, 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 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
30 #include "lib/format-cout.hpp"
31 #include "lib/format-util.hpp"
32 #include "lib/diff/record.hpp"
33 #include "lib/itertools.hpp"
34 
35 #include <string>
36 #include <vector>
37 
38 using std::string;
39 using util::isSameObject;
40 using util::isnil;
41 using util::join;
42 using std::vector;
43 using std::swap;
44 
45 
46 namespace lib {
47 namespace diff{
48 namespace test{
49 
50  using LERR_(INVALID);
51  using LERR_(INDEX_BOUNDS);
52  using LERR_(BOTTOM_VALUE);
53 
54  namespace {//Test fixture....
55 
56  using Seq = vector<string>;
57  using RecS = Record<string>;
58 
59  template<class IT>
60  inline Seq
61  contents (IT const& it)
62  {
63  Seq collected;
64  append_all (it, collected);
65  return collected;
66  }
67 
68  inline Seq
69  contents (RecS const& rec_of_strings)
70  {
71  return contents (rec_of_strings.begin());
72  }
73 
74  template<class X>
75  inline Seq
76  strings (std::initializer_list<X> const& con)
77  {
78  Seq collected;
79  for (auto elm : con)
80  collected.push_back(elm);
81  return collected;
82  }
83 
84 
85  }//(End)Test fixture
86 
87 
88 
89 
90 
91 
92 
93  /*************************************************************************************/
127  class GenericRecord_test : public Test
128  {
129 
130  virtual void
131  run (Arg)
132  {
133  simpleUsage();
134  verifyCreation();
135  verifyMutations();
136  copy_and_move();
137  equality();
138  wrapRef();
139  }
140 
141 
142  void
143  simpleUsage()
144  {
145  RecS enterprise("starship"
146  , strings ({"Name = USS Enterprise"
147  ,"Registry = NCC-1701-D"
148  ,"Class = Galaxy"
149  ,"Owner = United Federation of Planets"
150  ,"Operator= Starfleet"
151  ,"built=2363"
152  })
153  , strings ({"Picard", "Riker", "Data", "Troi", "Worf", "Crusher", "La Forge"})
154  );
155 
156  CHECK (enterprise.getType() == "starship");
157  CHECK (enterprise.get("Registry") == "NCC-1701-D");
158  CHECK (enterprise.child(0) == "Picard");
159  CHECK (enterprise.child(2) == "Data");
160 
161  CHECK (enterprise.hasAttribute("Owner"));
162  CHECK (!enterprise.hasAttribute("owner"));
163  CHECK (!enterprise.hasAttribute("Owner ")); // no normalisation
164 
165  CHECK (enterprise.contains("Data"));
166  CHECK (!enterprise.contains("Woof")); // it is /Worf/, madam
167  CHECK (util::contains (enterprise, "Worf"));
168 
169  VERIFY_ERROR (INVALID, enterprise.get("warp10"));
170  VERIFY_ERROR (INDEX_BOUNDS, enterprise.child(12));
171 
172  cout << "enterprise = "
173  << enterprise <<endl;
174  for (string elm : enterprise)
175  cout << elm <<endl;
176  cout << "--Attributes--"<<endl;
177  for (string att : enterprise.attribs())
178  cout << att <<endl;
179  cout << "--Keys--->" << join (enterprise.keys(), "<->")<<endl;
180  cout << "--Vals--->" << join (enterprise.vals(), "<->")<<endl;
181  cout << "--Crew--->" << join (enterprise.scope()," | ")<<endl;
182  }
183 
184 
185  void
186  verifyCreation()
187  {
188  RecS nil;
189  CHECK (isnil(nil));
190  CHECK ("NIL" == nil.getType());
191  CHECK (RecS::TYPE_NIL == nil.getType());
192 
193  CHECK (!nil.begin());
194  CHECK (nil.begin() == nil.end());
195 
196 
197  RecS untyped({"x"});
198  CHECK (!isnil(untyped));
199  CHECK ("NIL" == untyped.getType());
200  CHECK (Seq{"x"} == contents(untyped));
201  CHECK (Seq{"x"} == contents(untyped.scope()));
202  CHECK (isnil (untyped.attribs()));
203 
204  RecS untyped2({"x=y", "z"});
205  CHECK (!isnil(untyped2));
206  CHECK ("NIL" == untyped2.getType());
207  CHECK (Seq({"x=y", "z"}) == contents(untyped2));
208  CHECK (Seq{"x"} == contents (untyped2.keys()));
209  CHECK (Seq{"y"} == contents (untyped2.vals()));
210  CHECK (Seq{"z"} == contents (untyped2.scope()));
211 
212 
213  RecS something({"a=1", "type=thing", "b=2", "c", "d"});
214  CHECK (!isnil(something));
215  CHECK ("thing" == something.getType());
216  CHECK (Seq({"a=1", "b=2", "c", "d"}) == contents(something));
217  CHECK (Seq({"a", "b"}) == contents (something.keys()));
218  CHECK (Seq({"1", "2"}) == contents (something.vals()));
219  CHECK (Seq({"c", "d"}) == contents (something.scope()));
220  }
221 
222 
223  void
224  copy_and_move()
225  {
226  RecS a({"a=1", "b=2", "c", "d"});
227  RecS b(a);
228  CHECK (a.getType() == b.getType());
229  CHECK (contents(a) == contents(b));
230  CHECK (contents(a.attribs()) == contents(b.attribs()));
231 
232  CHECK (!isSameObject (a.get("a"), b.get("a")));
233  CHECK (!isSameObject (*a.scope(), *b.scope()));
234 
235  string const& c = *b.scope();
236  CHECK ("c" == c);
237 
238  RecS bb;
239  CHECK (isnil(bb));
240  bb = move(b);
241  CHECK ("2" == bb.get("b"));
242  CHECK (isSameObject(c, *bb.scope()));
243 
244  swap (a, bb);
245  CHECK (!isSameObject(c, *bb.scope()));
246  CHECK ( isSameObject(c, *a.scope()));
247 
248  CHECK (isnil (b));
249  b = bb;
250  CHECK (!isnil (b));
251  CHECK (!isSameObject(b.get("a"), bb.get("a")));
252  CHECK (!isSameObject(*b.scope(), *bb.scope()));
253  }
254 
255 
256  void
257  equality()
258  {
259  RecS a({"a"});
260  RecS aa({"a","aa"});
261  RecS aaa({"a","a"});
262  RecS ax({"type=a","a"});
263  RecS ay({"a=a","a"});
264  RecS az({"a =a","a"});
265 
266  CHECK (a != aa); CHECK (aa != a);
267  CHECK (aa != aaa); CHECK (aaa != aa);
268  CHECK (a != aaa); CHECK (aaa != a);
269  CHECK (a != ax); CHECK (ax != a);
270  CHECK (a != ay); CHECK (ay != a);
271  CHECK (ax != ay); CHECK (ay != ax);
272  CHECK (aaa != ay); CHECK (ay != aaa);
273  CHECK (ay != az); CHECK (az != ay); // NOTE: attributes are *not* normalised,
274  // rather, they are used as-is,
275  // thus "a=a" != "a =a"
276  RecS a2({"a","aa"});
277  CHECK (aa == a2); CHECK (a2 == aa);
278 
279  RecS o1("oo", strings({"a=α", "b=β"}), strings({"γ", "δ", "ε"}));
280  RecS o2({"type=oo", "a=α", "b=β", "γ", "δ", "ε"});
281  RecS o3({"type=oO", "a=α", "b=β", "γ", "δ", "ε"});
282  RecS o4({"type=oo", "a=α", "b=β", "c=γ", "δ", "ε"});
283  RecS o5({"type=oo", "a=α", "b=β", "γ", "ε", "δ"});
284  RecS o6({"type=oo", "a=α", "b=β", "γ", "δ"});
285 
286  CHECK (o1 == o2); CHECK (o2 == o1);
287  CHECK (o2 != o3); CHECK (o3 != o2);
288  CHECK (o3 != o4); CHECK (o4 != o3);
289  CHECK (o4 != o5); CHECK (o5 != o4);
290  CHECK (o5 != o6); CHECK (o6 != o5);
291  CHECK (o1 != o3); CHECK (o3 != o1);
292  CHECK (o1 != o4); CHECK (o4 != o1);
293  CHECK (o1 != o5); CHECK (o5 != o1);
294  CHECK (o1 != o6); CHECK (o6 != o1);
295  CHECK (o2 != o4); CHECK (o4 != o2);
296  CHECK (o2 != o5); CHECK (o5 != o2);
297  CHECK (o2 != o6); CHECK (o6 != o2);
298  CHECK (o3 != o5); CHECK (o5 != o3);
299  CHECK (o3 != o6); CHECK (o6 != o3);
300  CHECK (o4 != o6); CHECK (o6 != o4);
301 
302  RecS o7({"type=oo", "b = β", "a = α", "γ", "δ", "ε"});
303  CHECK (o2 != o7); CHECK (o7 != o2);
304  // ideally, they would be equal, but this would require
305  // a way more expensive implementation
306  }
307 
308 
309  void
310  verifyMutations()
311  {
312  RecS a;
313  CHECK (isnil (a));
314  CHECK ("NIL" == a.getType());
315 
316  RecS::Mutator mut(a);
317  mut.setType("u");
318  mut.appendChild("a");
319  mut.set("a", "1");
320 
321  RecS aa(mut);
322  CHECK (a != aa);
323  CHECK ("u" == aa.getType());
324  CHECK (Seq({"a = 1", "a"}) == contents(aa));
325  CHECK (Seq({"a"}) == contents (aa.keys()));
326  CHECK (Seq({"1"}) == contents (aa.vals()));
327  CHECK (Seq({"a"}) == contents (aa.scope()));
328 
329  CHECK (mut == aa);
330 
331  mut.prependChild("⟂");
332  mut.set("b", "β");
333  mut.set("a", "α");
334 
335  CHECK (mut != aa);
336 
337  mut.swap (a);
338  CHECK (isnil (mut));
339  CHECK (Seq({"a = α", "b = β", "⟂", "a"}) == contents(a));
340  CHECK (Seq({"a = 1", "a"}) == contents(aa));
341  }
342 
343 
344  void
345  wrapRef()
346  {
347  RecS oo({"type = 🌰", "☿ = mercury", "♀ = venus", "♁ = earth", "♂ = mars", "♃ = jupiter", "♄ = saturn"});
348 
349  RecordRef<string> empty;
350  CHECK (bool(empty) == false);
351  CHECK (nullptr == empty.get());
352  VERIFY_ERROR (BOTTOM_VALUE, empty.operator RecS&() );
353 
354  RecordRef<string> ref(oo);
355  CHECK (ref);
356  CHECK (ref.get() == &oo);
357 
358  RecS& oor = ref;
359  CHECK ("🌰" == oor.getType());
360  CHECK (oor.get("♄") == "saturn");
361 
362  // are copyable but not reassignable
363  RecordRef<string> r2 = ref;
364  CHECK (r2);
365  CHECK (r2.get() == ref.get());
366  CHECK (!isSameObject (r2, ref));
367 
368  // but references are move-assignable
369  empty = std::move(r2);
370  CHECK (empty);
371  CHECK (!r2);
372  CHECK (nullptr == r2.get());
373  }
374  };
375 
376 
378  LAUNCHER (GenericRecord_test, "unit common");
379 
380 
381 
382 }}} // namespace lib::diff::test
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:49
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
iterator begin() const
default iteration exposes all data within this "object", starting with the attributes ...
Definition: record.hpp:318
Implementation namespace for support and library code.
Special collection to represent object-like data.
Simple test class runner.
wrapped record reference.
Definition: record.hpp:620
A collection of frequently used helper functions to support unit testing.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Helpers for working with iterators based on the pipeline model.
object-like record of data.
Definition: record.hpp:150
bool isSameObject(A const &a, B const &b)
compare plain object identity, bypassing any custom comparison operators.
Definition: util.hpp:372