Lumiera  0.pre.03
»edit your freedom«
opaque-holder-test.cpp
Go to the documentation of this file.
1 /*
2  OpaqueHolder(Test) - check the inline type erasure helper
3 
4  Copyright (C)
5  2009, 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 #include "lib/util-foreach.hpp"
24 #include "lib/opaque-holder.hpp"
25 
26 #include <iostream>
27 #include <vector>
28 
29 
30 namespace lib {
31 namespace test{
32 
33  using ::Test;
34  using util::isnil;
35  using util::for_each;
36  using util::isSameObject;
37  using LERR_(BOTTOM_VALUE);
38  using LERR_(WRONG_TYPE);
39  using LERR_(ASSERTION);
40 
41  using std::vector;
42  using std::cout;
43  using std::endl;
44 
45  namespace { // test dummy hierarchy
46  // Note: common storage but no vtable
47 
48  long _checksum = 0;
49  uint _create_count = 0;
50 
51 
52  struct Base
53  {
54  uint id_;
55 
56  Base(uint i=0) : id_(i) { _checksum +=id_; ++_create_count; }
57  Base(Base const& o) : id_(o.id_) { _checksum +=id_; ++_create_count; }
58 
59  uint getIt() { return id_; }
60  };
61 
62 
63  template<uint ii>
64  struct DD : Base
65  {
66  DD() : Base(ii) { }
67  ~DD() { _checksum -= ii; } // doing the decrement here
68  }; // verifies the correct dtor is called
69 
70 
71  struct Special
72  : DD<7>
73  {
74  ulong myVal_;
75 
76  Special (uint val)
77  : myVal_(val)
78  { }
79 
80  explicit
81  operator bool() const
82  {
83  return myVal_ % 2;
84  }
85  };
86 
87 
92  const size_t _ALIGN_ = sizeof(size_t);
93 
94  }
95 
96  typedef OpaqueHolder<Base> Opaque;
97  typedef vector<Opaque> TestList;
98 
99 
100 
101  /******************************************************************************/
111  class OpaqueHolder_test : public Test
112  {
113 
114  virtual void
115  run (Arg)
116  {
117  _checksum = 0;
118  _create_count = 0;
119  {
120  TestList objs = createDummies ();
121  for_each (objs, reAccess);
122  checkHandling (objs);
123  checkSpecialSubclass ();
124  }
125  CHECK (0 == _checksum); // all dead
126  }
127 
128 
129  TestList
130  createDummies ()
131  {
132  TestList list;
133  list.push_back (DD<1>());
134  list.push_back (DD<3>());
135  list.push_back (DD<5>());
136  list.push_back (DD<7>());
137  return list;
138  } //note: copy
139 
140 
141  static void
142  reAccess (Opaque& elm)
143  {
144  cout << elm->getIt() << endl;
145  }
146 
147 
151  void
152  checkHandling (TestList& objs)
153  {
154  Opaque oo;
155  CHECK (!oo);
156  CHECK (isnil(oo));
157 
158  oo = objs[1];
159  CHECK (oo);
160  CHECK (!isnil(oo));
161 
162  typedef DD<3> D3;
163  typedef DD<5> D5;
164  D3 d3 (oo.get<D3>() );
165  CHECK (3 == oo->getIt()); // re-access through Base interface
166  CHECK (!isSameObject (d3, *oo));
167  VERIFY_ERROR (WRONG_TYPE, oo.get<D5>() );
168 
169  // direct assignment of target into Buffer
170  oo = D5();
171  CHECK (oo);
172  CHECK (5 == oo->getIt());
173  VERIFY_ERROR (WRONG_TYPE, oo.get<D3>() );
174 
175  // can get a direct reference to contained object
176  D5 &rd5 (oo.get<D5>());
177  CHECK (isSameObject (rd5, *oo));
178 
179  CHECK (!isnil(oo));
180  oo = objs[3]; // copy construction also works on non-empty object
181  CHECK (7 == oo->getIt());
182 
183  // WARNING: direct ref has been messed up through the backdoor!
184  CHECK (7 == rd5.getIt());
185  CHECK (isSameObject (rd5, *oo));
186 
187  uint cnt_before = _create_count;
188 
189  oo.clear();
190  CHECK (!oo);
191  oo = D5(); // direct assignment also works on empty object
192  CHECK (oo);
193  CHECK (5 == oo->getIt());
194  CHECK (_create_count == 2 + cnt_before);
195  // one within buff and one for the anonymous temporary D5()
196 
197 
198  // verify that self-assignment is properly detected...
199  cnt_before = _create_count;
200  oo = oo;
201  CHECK (oo);
202  CHECK (_create_count == cnt_before);
203  oo = oo.get<D5>();
204  CHECK (_create_count == cnt_before);
205  oo = *oo;
206  CHECK (_create_count == cnt_before);
207  CHECK (oo);
208 
209  oo.clear();
210  CHECK (!oo);
211  CHECK (isnil(oo));
212  VERIFY_ERROR (BOTTOM_VALUE, oo.get<D5>() );
213 #if false
214  VERIFY_ERROR (ASSERTION, oo->getIt() );
215 #endif
216  // can't access empty holder...
217 
218  Opaque o1 (oo);
219  CHECK (!o1);
220 
221  Opaque o2 (d3);
222  CHECK (!isSameObject (d3, *o2));
223  CHECK (3 == o2->getIt());
224 
225  CHECK (sizeof(Opaque) <= sizeof(Base) + sizeof(void*) + _ALIGN_);
226  }
227 
228 
240  void
242  {
243  typedef OpaqueHolder<Base, sizeof(Special)> SpecialOpaque;
244 
245  cout << showSizeof<Base>() << endl;
246  cout << showSizeof<Special>() << endl;
247  cout << showSizeof<Opaque>() << endl;
248  cout << showSizeof<SpecialOpaque>() << endl;
249 
250  CHECK (sizeof(Special) > sizeof(Base));
251  CHECK (sizeof(SpecialOpaque) > sizeof(Opaque));
252  CHECK (sizeof(SpecialOpaque) <= sizeof(Special) + sizeof(void*) + _ALIGN_);
253 
254  Special s1 (6);
255  Special s2 (3);
256  CHECK (!s1); // even value
257  CHECK (s2); // odd value
258  CHECK (7 == s1.getIt()); // indeed subclass of DD<7>
259  CHECK (7 == s2.getIt());
260 
261  SpecialOpaque ospe0;
262  SpecialOpaque ospe1 (s1);
263  SpecialOpaque ospe2 (s2);
264 
265  CHECK (!ospe0); // note: bool test (isValid)
266  CHECK (!ospe1); // also forwarded to contained object (myVal_==6 is even)
267  CHECK ( ospe2);
268  CHECK ( isnil(ospe0)); // while isnil just checks the empty state
269  CHECK (!isnil(ospe1));
270  CHECK (!isnil(ospe2));
271 
272  CHECK (7 == ospe1->getIt());
273  CHECK (6 == ospe1.get<Special>().myVal_);
274  CHECK (3 == ospe2.get<Special>().myVal_);
275 
276  ospe1 = DD<5>(); // but can be reassigned like any normal Opaque
277  CHECK (ospe1);
278  CHECK (5 == ospe1->getIt());
279  VERIFY_ERROR (WRONG_TYPE, ospe1.get<Special>() );
280 
281  Opaque normal = DD<5>();
282  CHECK (normal);
283  CHECK (5 == normal->getIt());
284 #if false
285  // Assertion protects against SEGV
286  VERIFY_ERROR (ASSERTION, normal = s1 );
287 #endif
288  }
289  };
290 
291 
292  LAUNCHER (OpaqueHolder_test, "unit common");
293 
294 
295 }} // namespace lib::test
296 
void checkHandling(TestList &objs)
Definition: run.hpp:40
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
const size_t _ALIGN_
maximum additional storage maybe wasted due to alignment of the contained object within OpaqueHolder&#39;...
Implementation namespace for support and library code.
Inline buffer to hold and own an object while concealing the concrete type.
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Helper allowing type erasure while holding the actual object inline.
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
A collection of frequently used helper functions to support unit testing.
SUB & get() const
re-accessing the concrete contained object.
Perform operations "for each element" of a collection.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee&#39;s memory identities. ...
Definition: util.hpp:421