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) Lumiera.org
5  2012, 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"
30 #include "lib/test/test-helper.hpp"
31 #include "lib/util.hpp"
32 
34 #include "lib/test/testdummy.hpp"
35 
36 #include <cstdlib>
37 
38 
39 namespace lib {
40 namespace test{
41 
42  namespace error = lumiera::error;
43 
44 
45  namespace { // our explosive special Dummy
46 
47  LUMIERA_ERROR_DEFINE(SUBVERSIVE, "undercover action");
48 
49  class SubDummy
50  : public Dummy
51  {
52  int trigger_;
53 
57  virtual long
58  acc (int i)
59  {
60  if (!i)
61  return getVal() + trigger_;
62  else
63  return Dummy::acc(i);
64  }
65 
66  public:
67  SubDummy (int id, int trigger)
68  : Dummy(id)
69  , trigger_(trigger)
70  {
71  if (trigger == getVal())
72  throw error::Fatal ("Subversive Bomb", LUMIERA_ERROR_SUBVERSIVE);
73  }
74 
75  SubDummy()
76  : Dummy()
77  , trigger_(-1)
78  { }
79  };
80 
81 
82  inline uint
83  sum (uint n)
84  {
85  return n*(n+1) / 2;
86  }
87 
88  }//(End) subversive test data
89 
90 
91 
92 
93  using util::isnil;
94  using LERR_(ITER_EXHAUST);
95 
97 
98 
99  /****************************************************************/
106  class ScopedCollection_test : public Test
107  {
108 
109  virtual void
110  run (Arg)
111  {
112  simpleUsage();
113  building_RAII_Style();
114  building_StackStyle();
115  iterating();
116  verify_defaultPopulator();
117  verify_iteratorPopulator();
118  verify_embeddedCollection();
119  }
120 
121 
122  void
123  simpleUsage()
124  {
125  CHECK (0 == Dummy::checksum());
126  {
127  CollD container(5);
128  CHECK (isnil (container));
129  CHECK (0 == container.size());
130  CHECK (0 == Dummy::checksum());
131 
132  container.populate();
133  CHECK (!isnil (container));
134  CHECK (5 == container.size());
135  CHECK (0 != Dummy::checksum());
136 
137  container.clear();
138  CHECK (isnil (container));
139  CHECK (0 == container.size());
140  CHECK (0 == Dummy::checksum());
141 
142  container.populate();
143  CHECK (Dummy::checksum() == container[0].getVal()
144  + container[1].getVal()
145  + container[2].getVal()
146  + container[3].getVal()
147  + container[4].getVal());
148  }
149  CHECK (0 == Dummy::checksum());
150  }
151 
152 
153  void
154  iterating()
155  {
156  CHECK (0 == Dummy::checksum());
157  {
158  CollD coll(50);
159  for (uint i=0; i<coll.capacity(); ++i)
160  coll.emplace<Dummy>(i);
161 
162  int check=0;
163  CollD::iterator ii = coll.begin();
164  while (ii)
165  {
166  CHECK (check == ii->getVal());
167  CHECK (check == ii->acc(+5) - 5);
168  ++check;
169  ++ii;
170  }
171 
172 
173  // Test the const iterator
174  CollD const& const_coll (coll);
175  check = 0;
176  CollD::const_iterator cii = const_coll.begin();
177  while (cii)
178  {
179  CHECK (check == cii->getVal());
180  ++check;
181  ++cii;
182  }
183 
184 
185  // Test c++11 foreach iteration
186  check = 0;
187  for (auto& entry : coll)
188  {
189  CHECK (check == entry.getVal());
190  ++check;
191  }
192  check = 0;
193  for (auto const& entry : const_coll)
194  {
195  CHECK (check == entry.getVal());
196  ++check;
197  }
198 
199 
200  // Verify correct behaviour of iteration end
201  CHECK (! (coll.end()));
202  CHECK (isnil (coll.end()));
203 
204  VERIFY_ERROR (ITER_EXHAUST, *coll.end() );
205  VERIFY_ERROR (ITER_EXHAUST, ++coll.end() );
206 
207  CHECK (ii == coll.end());
208  CHECK (cii == coll.end());
209  VERIFY_ERROR (ITER_EXHAUST, ++ii );
210  VERIFY_ERROR (ITER_EXHAUST, ++cii );
211 
212  }
213  CHECK (0 == Dummy::checksum());
214  }
215 
216 
226  void
228  {
229  CHECK (0 == Dummy::checksum());
230  {
231 
232  int rr = rand() % 100;
233 
234  CollD coll(3);
235  CHECK (0 == coll.size());
236  CHECK (0 == Dummy::checksum());
237 
238  Dummy& d0 = coll.emplaceElement();
239  CHECK (1 == coll.size());
240 
241  Dummy& d1 = coll.emplace<Dummy> (rr);
242  CHECK (2 == coll.size());
243 
244  int sum = Dummy::checksum();
245 
246  // trigger the bomb
247  VERIFY_ERROR (SUBVERSIVE, coll.emplace<SubDummy>(rr,rr) );
248 
249  CHECK ( 2 == coll.size()); // the other objects survived
250  CHECK (sum == Dummy::checksum());
251 
252  Dummy& d2 = coll.emplace<SubDummy> (rr, rr+1);
253  CHECK (3 == coll.size());
254 
255  CHECK (sum + rr == Dummy::checksum());
256 
257  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
258  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
259  VERIFY_ERROR (CAPACITY, coll.emplaceElement());
260 
261  CHECK (3 == coll.size());
262  CHECK (sum + rr == Dummy::checksum());
263 
264 
265  CHECK (d0.acc(11) == coll[0].getVal() + 11 );
266  CHECK (d1.acc(22) == rr + 22);
267  CHECK (d2.acc(33) == rr + 33);
268  CHECK (d2.acc(0) == rr + (rr+1) ); // SubDummy's special implementation of the acc()-function
269  // returns the trigger value, when the argument is zero
270 
271  coll.clear();
272  coll.emplace<SubDummy> (11,22);
273 
274  CHECK ( 1 == coll.size());
275  CHECK (11 == Dummy::checksum());
276 
277  // NOTE DANGEROUS:
278  // The previously obtained references just point into the object storage.
279  // Thus we're now accessing a different object, even a different type!
280  CHECK (d0.acc(0) == 11 + 22);
281 
282  // The others even point into obsoleted storage holding zombie objects
283  CHECK (d1.acc(44) == rr + 44);
284 
285  }
286  CHECK (0 == Dummy::checksum());
287  }
288 
289 
306  void
308  {
309  CHECK (0 == Dummy::checksum());
310  {
311  int rr = rand() % 100;
312  int trigger = 100 + 5 + 1; // prevents the bomb from exploding (since rr < 100)
313 
314  CollD coll (6, Populator(rr, trigger));
315 
316  CHECK (!isnil (coll));
317  CHECK (6 == coll.size());
318  CHECK (0 != Dummy::checksum());
319 
320  CHECK (coll[0].acc(0) == 0 + rr);
321  CHECK (coll[1].acc(0) == 1 + rr + trigger);
322  CHECK (coll[2].acc(0) == 2 + rr);
323  CHECK (coll[3].acc(0) == 3 + rr + trigger);
324  CHECK (coll[4].acc(0) == 4 + rr);
325  CHECK (coll[5].acc(0) == 5 + rr + trigger);
326  // what does this check prove?
327  // - the container was indeed populated with DubDummy objects
328  // since the overridden version of Dummy::acc() did run and
329  // reveal the trigger value
330  // - the population was indeed done with the anonymous Populator
331  // instance fed to the ctor, since this object was "marked" with
332  // the random value rr, and adds this mark to the built values.
333 
334  coll.clear();
335  CHECK (0 == Dummy::checksum());
336 
337  // Verify Error handling while in creation:
338  // SubDummy explodes on equal ctor parameters
339  // which here happens for i==7
340  VERIFY_ERROR (SUBVERSIVE, CollD(10, Populator(0, 7)) );
341 
342  // any already created object was properly destroyed
343  CHECK (0 == Dummy::checksum());
344 
345  }
346  CHECK (0 == Dummy::checksum());
347  }
348 
350  class Populator
351  {
352  uint i_;
353  int off_;
354  int trigg_;
355 
356  public:
357  Populator (int baseOffset, int triggerCode)
358  : i_(0)
359  , off_(baseOffset)
360  , trigg_(triggerCode)
361  { }
362 
363  void
364  operator() (CollD::ElementHolder& storage)
365  {
366  switch (i_ % 2)
367  {
368  case 0:
369  storage.create<Dummy> (i_+off_);
370  break;
371 
372  case 1:
373  storage.create<SubDummy> (i_+off_, trigg_);
374  break;
375  }
376  ++i_;
377  }
378  };
379 
380 
381 
387  void
389  {
390  CHECK (0 == Dummy::checksum());
391 
392  CollD coll (25, CollD::FillAll() );
393 
394  CHECK (!isnil (coll));
395  CHECK (25 == coll.size());
396  CHECK (0 != Dummy::checksum());
397 
398  for (CollD::iterator ii = coll.begin(); ii; ++ii)
399  {
400  CHECK ( INSTANCEOF (Dummy, & (*ii)));
401  CHECK (!INSTANCEOF (SubDummy, & (*ii)));
402  }
403  }
404 
405 
406  void
407  verify_subclassPopulator()
408  {
409  CHECK (0 == Dummy::checksum());
410 
411  CollD coll (25, CollD::FillWith<SubDummy>() );
412 
413  CHECK (!isnil (coll));
414  CHECK (25 == coll.size());
415  CHECK (0 != Dummy::checksum());
416 
417  for (CollD::iterator ii = coll.begin(); ii; ++ii)
418  CHECK (INSTANCEOF (SubDummy, & (*ii)));
419  }
420 
421 
422  void
423  verify_iteratorPopulator()
424  {
425  typedef ScopedCollection<uint> CollI;
426 
427  CollI source (25);
428  for (uint i=0; i < source.capacity(); ++i)
429  source.emplace<uint>(i); // holding the numbers 0..24
430 
431  CollI coll (20, CollI::pull(source.begin()));
432  // this immediately pulls in the first 20 elements
433  CHECK (!isnil (coll));
434  CHECK (20 == coll.size());
435  CHECK (25 == source.size());
436 
437  for (uint i=0; i < coll.size(); ++i)
438  {
439  CHECK (coll[i] == i );
440  CHECK (coll[i] == source[i]);
441  }
442 
443  // note: the iterator is assumed to deliver a sufficient amount of elements
444  VERIFY_ERROR (ITER_EXHAUST, CollI (50, CollI::pull (source.begin())));
445  }
446 
447 
455  void
457  {
458  ManagerDemo object_with_embedded_Collection(50);
459  CHECK (sum(50) == object_with_embedded_Collection.useMyNumbers());
460  }
461 
463  {
465 
466  uint memberVar_;
467  const CollI my_own_Numbers_;
468 
469  void
470  buildNumbers (CollI::ElementHolder& storage)
471  {
472  storage.create<uint>(memberVar_);
473  --memberVar_;
474  }
475 
476  public:
477  ManagerDemo(uint cnt)
478  : memberVar_(cnt)
479  , my_own_Numbers_(cnt, &ManagerDemo::buildNumbers, this)
480  {
481  CHECK (0 == memberVar_);
482  CHECK (cnt == my_own_Numbers_.size());
483  }
484 
485  uint
486  useMyNumbers()
487  {
488  uint sum(0);
489  for (CollI::const_iterator ii = my_own_Numbers_.begin(); ii; ++ii)
490  sum += *ii;
491  return sum;
492  }
493  };
494  };
495 
496 
497 
498  LAUNCHER (ScopedCollection_test, "unit common");
499 
500 
501 }} // namespace lib::test
502 
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:49
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:492
virtual long acc(int i)
a dummy API operation
Definition: testdummy.hpp:90
#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 ...
Implementation namespace for support and library code.
unittest helper code: test dummy objects to track instances.
Managing a collection of non-copyable polymorphic objects in compact storage.
Storage Frame to hold one Child object.
virtual long acc(int i)
special variant of the dummy API operation:
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A collection of frequently used helper functions to support unit testing.
A Dummy object for tests.
Definition: testdummy.hpp:50
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
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:80