Lumiera  0.pre.03
»edit your freedom«
scoped-collection-test.cpp
Go to the documentation of this file.
1 /*
2  ScopedCollection(Test) - holding and owning a fixed collection of noncopyable objects
3 
4  Copyright (C)
5  2012, 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"
21 #include "lib/test/test-helper.hpp"
22 #include "lib/util.hpp"
23 
26 
27 
28 namespace lib {
29 namespace test{
30 
31  namespace error = lumiera::error;
32 
33 
34  namespace { // our explosive special Dummy
35 
36  LUMIERA_ERROR_DEFINE(SUBVERSIVE, "undercover action");
37 
38  class SubDummy
39  : public Dummy
40  {
41  int trigger_;
42 
46  virtual long
47  calc (int i)
48  {
49  if (!i)
50  return getVal() + trigger_;
51  else
52  return Dummy::calc(i);
53  }
54 
55  public:
56  SubDummy (int id, int trigger)
57  : Dummy(id)
58  , trigger_(trigger)
59  {
60  if (trigger == getVal())
61  throw error::Fatal ("Subversive Bomb", LUMIERA_ERROR_SUBVERSIVE);
62  }
63 
64  SubDummy()
65  : Dummy()
66  , trigger_(-1)
67  { }
68  };
69 
70 
71  inline uint
72  sum (uint n)
73  {
74  return n*(n+1) / 2;
75  }
76 
77  }//(End) subversive test data
78 
79 
80 
81 
82  using util::isnil;
83  using LERR_(ITER_EXHAUST);
84 
86 
87 
88  /****************************************************************/
95  class ScopedCollection_test : public Test
96  {
97 
98  virtual void
99  run (Arg)
100  {
101  seedRand();
102  simpleUsage();
103  building_RAII_Style();
104  building_StackStyle();
105  iterating();
106  verify_defaultPopulator();
107  verify_iteratorPopulator();
108  verify_embeddedCollection();
109  }
110 
111 
112  void
113  simpleUsage()
114  {
115  CHECK (0 == Dummy::checksum());
116  {
117  CollD container(5);
118  CHECK (isnil (container));
119  CHECK (0 == container.size());
120  CHECK (0 == Dummy::checksum());
121 
122  container.populate();
123  CHECK (!isnil (container));
124  CHECK (5 == container.size());
125  CHECK (0 != Dummy::checksum());
126 
127  container.clear();
128  CHECK (isnil (container));
129  CHECK (0 == container.size());
130  CHECK (0 == Dummy::checksum());
131 
132  container.populate();
133  CHECK (Dummy::checksum() == container[0].getVal()
134  + container[1].getVal()
135  + container[2].getVal()
136  + container[3].getVal()
137  + container[4].getVal());
138  }
139  CHECK (0 == Dummy::checksum());
140  }
141 
142 
143  void
144  iterating()
145  {
146  CHECK (0 == Dummy::checksum());
147  {
148  CollD coll(50);
149  for (uint i=0; i<coll.capacity(); ++i)
150  coll.emplace<Dummy>(i);
151 
152  int check=0;
153  CollD::iterator ii = coll.begin();
154  while (ii)
155  {
156  CHECK (check == ii->getVal());
157  CHECK (check == ii->calc(+5) - 5);
158  ++check;
159  ++ii;
160  }
161 
162 
163  // Test the const iterator
164  CollD const& const_coll (coll);
165  check = 0;
166  CollD::const_iterator cii = const_coll.begin();
167  while (cii)
168  {
169  CHECK (check == cii->getVal());
170  ++check;
171  ++cii;
172  }
173 
174 
175  // Test c++11 foreach iteration
176  check = 0;
177  for (auto& entry : coll)
178  {
179  CHECK (check == entry.getVal());
180  ++check;
181  }
182  check = 0;
183  for (auto const& entry : const_coll)
184  {
185  CHECK (check == entry.getVal());
186  ++check;
187  }
188 
189 
190  // Verify correct behaviour of iteration end
191  CHECK (! (coll.end()));
192  CHECK (isnil (coll.end()));
193 
194  VERIFY_ERROR (ITER_EXHAUST, *coll.end() );
195  VERIFY_ERROR (ITER_EXHAUST, ++coll.end() );
196 
197  CHECK (ii == coll.end());
198  CHECK (cii == coll.end());
199  VERIFY_ERROR (ITER_EXHAUST, ++ii );
200  VERIFY_ERROR (ITER_EXHAUST, ++cii );
201 
202  }
203  CHECK (0 == Dummy::checksum());
204  }
205 
206 
216  void
218  {
219  CHECK (0 == Dummy::checksum());
220  {
221 
222  int rr = rani(100);
223 
224  CollD coll(3);
225  CHECK (0 == coll.size());
226  CHECK (0 == Dummy::checksum());
227 
228  Dummy& d0 = coll.emplaceElement();
229  CHECK (1 == coll.size());
230 
231  Dummy& d1 = coll.emplace<Dummy> (rr);
232  CHECK (2 == coll.size());
233 
234  int sum = Dummy::checksum();
235 
236  // trigger the bomb
237  VERIFY_ERROR (SUBVERSIVE, coll.emplace<SubDummy>(rr,rr) );
238 
239  CHECK ( 2 == coll.size()); // the other objects survived
240  CHECK (sum == Dummy::checksum());
241 
242  Dummy& d2 = coll.emplace<SubDummy> (rr, rr+1);
243  CHECK (3 == coll.size());
244 
245  CHECK (sum + rr == Dummy::checksum());
246 
247  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
248  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
249  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
250 
251  CHECK (3 == coll.size());
252  CHECK (sum + rr == Dummy::checksum());
253 
254 
255  CHECK (d0.calc(11) == coll[0].getVal() + 11 );
256  CHECK (d1.calc(22) == rr + 22);
257  CHECK (d2.calc(33) == rr + 33);
258  CHECK (d2.calc(0) == rr + (rr+1) ); // SubDummy's special implementation of the acc()-function
259  // returns the trigger value, when the argument is zero
260 
261  coll.clear();
262  coll.emplace<SubDummy> (11,22);
263 
264  CHECK ( 1 == coll.size());
265  CHECK (11 == Dummy::checksum());
266 
267  // NOTE DANGEROUS:
268  // The previously obtained references just point into the object storage.
269  // Thus we're now accessing a different object, even a different type!
270  CHECK (d0.calc(0) == 11 + 22);
271 
272  // The others even point into obsoleted storage holding zombie objects
273  CHECK (d1.calc(44) == rr + 44);
274 
275  }
276  CHECK (0 == Dummy::checksum());
277  }
278 
279 
296  void
298  {
299  CHECK (0 == Dummy::checksum());
300  {
301  int rr = rani(100);
302  int trigger = 100 + 5 + 1; // prevents the bomb from exploding (since rr < 100)
303 
304  CollD coll (6, Populator(rr, trigger));
305 
306  CHECK (!isnil (coll));
307  CHECK (6 == coll.size());
308  CHECK (0 != Dummy::checksum());
309 
310  CHECK (coll[0].calc(0) == 0 + rr);
311  CHECK (coll[1].calc(0) == 1 + rr + trigger);
312  CHECK (coll[2].calc(0) == 2 + rr);
313  CHECK (coll[3].calc(0) == 3 + rr + trigger);
314  CHECK (coll[4].calc(0) == 4 + rr);
315  CHECK (coll[5].calc(0) == 5 + rr + trigger);
316  // what does this check prove?
317  // - the container was indeed populated with DubDummy objects
318  // since the overridden version of Dummy::acc() did run and
319  // reveal the trigger value
320  // - the population was indeed done with the anonymous Populator
321  // instance fed to the ctor, since this object was "marked" with
322  // the random value rr, and adds this mark to the built values.
323 
324  coll.clear();
325  CHECK (0 == Dummy::checksum());
326 
327  // Verify Error handling while in creation:
328  // SubDummy explodes on equal ctor parameters
329  // which here happens for i==7
330  VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0, 7)) );
331 
332  // any already created object was properly destroyed
333  CHECK (0 == Dummy::checksum());
334 
335  }
336  CHECK (0 == Dummy::checksum());
337  }
338 
340  class Populator
341  {
342  uint i_;
343  int off_;
344  int trigg_;
345 
346  public:
347  Populator (int baseOffset, int triggerCode)
348  : i_(0)
349  , off_(baseOffset)
350  , trigg_(triggerCode)
351  { }
352 
353  void
354  operator() (CollD::ElementHolder& storage)
355  {
356  switch (i_ % 2)
357  {
358  case 0:
359  storage.create<Dummy> (i_+off_);
360  break;
361 
362  case 1:
363  storage.create<SubDummy> (i_+off_, trigg_);
364  break;
365  }
366  ++i_;
367  }
368  };
369 
370 
371 
377  void
379  {
380  CHECK (0 == Dummy::checksum());
381 
382  CollD coll (25, CollD::FillAll() );
383 
384  CHECK (!isnil (coll));
385  CHECK (25 == coll.size());
386  CHECK (0 != Dummy::checksum());
387 
388  for (CollD::iterator ii = coll.begin(); ii; ++ii)
389  {
390  CHECK ( INSTANCEOF (Dummy, & (*ii)));
391  CHECK (!INSTANCEOF (SubDummy, & (*ii)));
392  }
393  }
394 
395 
396  void
397  verify_subclassPopulator()
398  {
399  CHECK (0 == Dummy::checksum());
400 
401  CollD coll (25, CollD::FillWith<SubDummy>() );
402 
403  CHECK (!isnil (coll));
404  CHECK (25 == coll.size());
405  CHECK (0 != Dummy::checksum());
406 
407  for (CollD::iterator ii = coll.begin(); ii; ++ii)
408  CHECK (INSTANCEOF (SubDummy, & (*ii)));
409  }
410 
411 
412  void
413  verify_iteratorPopulator()
414  {
415  typedef ScopedCollection<uint> CollI;
416 
417  CollI source (25);
418  for (uint i=0; i < source.capacity(); ++i)
419  source.emplace<uint>(i); // holding the numbers 0..24
420 
421  CollI coll (20, CollI::pull(source.begin()));
422  // this immediately pulls in the first 20 elements
423  CHECK (!isnil (coll));
424  CHECK (20 == coll.size());
425  CHECK (25 == source.size());
426 
427  for (uint i=0; i < coll.size(); ++i)
428  {
429  CHECK (coll[i] == i );
430  CHECK (coll[i] == source[i]);
431  }
432 
433  // note: the iterator is assumed to deliver a sufficient amount of elements
434  VERIFY_ERROR (ITER_EXHAUST, CollI (50, CollI::pull (source.begin())));
435  }
436 
437 
445  void
447  {
448  ManagerDemo object_with_embedded_Collection(50);
449  CHECK (sum(50) == object_with_embedded_Collection.useMyNumbers());
450  }
451 
453  {
455 
456  uint memberVar_;
457  const CollI my_own_Numbers_;
458 
459  void
460  buildNumbers (CollI::ElementHolder& storage)
461  {
462  storage.create<uint>(memberVar_);
463  --memberVar_;
464  }
465 
466  public:
467  ManagerDemo(uint cnt)
468  : memberVar_(cnt)
469  , my_own_Numbers_(cnt, &ManagerDemo::buildNumbers, this)
470  {
471  CHECK (0 == memberVar_);
472  CHECK (cnt == my_own_Numbers_.size());
473  }
474 
475  uint
476  useMyNumbers()
477  {
478  uint sum(0);
479  for (CollI::const_iterator ii = my_own_Numbers_.begin(); ii; ++ii)
480  sum += *ii;
481  return sum;
482  }
483  };
484  };
485 
486 
487 
488  LAUNCHER (ScopedCollection_test, "unit common");
489 
490 
491 }} // namespace lib::test
492 
A fixed collection of non-copyable polymorphic objects.
TY & create(ARGS &&...args)
place object of type TY, forwarding ctor arguments
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Definition: run.hpp:40
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
int rani(uint bound=_iBOUND())
Definition: random.hpp:135
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
TY & emplace(ARGS &&...args)
push new entry at the end of this container and build object of type TY in place there ...
virtual long calc(int i)
a dummy API operation
Implementation namespace for support and library code.
Managing a collection of non-copyable polymorphic objects in compact storage.
Storage Frame to hold one Child object.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
unittest helper code: test dummy objects to track instances.
A collection of frequently used helper functions to support unit testing.
A Dummy object for tests.
void populate()
init all elements default constructed
fills the ScopedCollection with default constructed I-instances
I & emplaceElement()
push a new element of default type to the end of this container
virtual long calc(int i)
special variant of the dummy API operation:
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
Definition: error.h:71