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) Lumiera.org
5  2009, 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 #include "lib/util-foreach.hpp"
33 #include "lib/opaque-holder.hpp"
34 
35 #include <iostream>
36 #include <vector>
37 
38 
39 namespace lib {
40 namespace test{
41 
42  using ::Test;
43  using util::isnil;
44  using util::for_each;
45  using util::isSameObject;
46  using LERR_(BOTTOM_VALUE);
47  using LERR_(WRONG_TYPE);
48  using LERR_(ASSERTION);
49 
50  using std::vector;
51  using std::cout;
52  using std::endl;
53 
54  namespace { // test dummy hierarchy
55  // Note: common storage but no vtable
56 
57  long _checksum = 0;
58  uint _create_count = 0;
59 
60 
61  struct Base
62  {
63  uint id_;
64 
65  Base(uint i=0) : id_(i) { _checksum +=id_; ++_create_count; }
66  Base(Base const& o) : id_(o.id_) { _checksum +=id_; ++_create_count; }
67 
68  uint getIt() { return id_; }
69  };
70 
71 
72  template<uint ii>
73  struct DD : Base
74  {
75  DD() : Base(ii) { }
76  ~DD() { _checksum -= ii; } // doing the decrement here
77  }; // verifies the correct dtor is called
78 
79 
80  struct Special
81  : DD<7>
82  {
83  ulong myVal_;
84 
85  Special (uint val)
86  : myVal_(val)
87  { }
88 
89  explicit
90  operator bool() const
91  {
92  return myVal_ % 2;
93  }
94  };
95 
96 
101  const size_t _ALIGN_ = sizeof(size_t);
102 
103  }
104 
105  typedef OpaqueHolder<Base> Opaque;
106  typedef vector<Opaque> TestList;
107 
108 
109 
110  /******************************************************************************/
120  class OpaqueHolder_test : public Test
121  {
122 
123  virtual void
124  run (Arg)
125  {
126  _checksum = 0;
127  _create_count = 0;
128  {
129  TestList objs = createDummies ();
130  for_each (objs, reAccess);
131  checkHandling (objs);
132  checkSpecialSubclass ();
133  }
134  CHECK (0 == _checksum); // all dead
135  }
136 
137 
138  TestList
139  createDummies ()
140  {
141  TestList list;
142  list.push_back (DD<1>());
143  list.push_back (DD<3>());
144  list.push_back (DD<5>());
145  list.push_back (DD<7>());
146  return list;
147  } //note: copy
148 
149 
150  static void
151  reAccess (Opaque& elm)
152  {
153  cout << elm->getIt() << endl;
154  }
155 
156 
160  void
161  checkHandling (TestList& objs)
162  {
163  Opaque oo;
164  CHECK (!oo);
165  CHECK (isnil(oo));
166 
167  oo = objs[1];
168  CHECK (oo);
169  CHECK (!isnil(oo));
170 
171  typedef DD<3> D3;
172  typedef DD<5> D5;
173  D3 d3 (oo.get<D3>() );
174  CHECK (3 == oo->getIt()); // re-access through Base interface
175  CHECK (!isSameObject (d3, *oo));
176  VERIFY_ERROR (WRONG_TYPE, oo.get<D5>() );
177 
178  // direct assignment of target into Buffer
179  oo = D5();
180  CHECK (oo);
181  CHECK (5 == oo->getIt());
182  VERIFY_ERROR (WRONG_TYPE, oo.get<D3>() );
183 
184  // can get a direct reference to contained object
185  D5 &rd5 (oo.get<D5>());
186  CHECK (isSameObject (rd5, *oo));
187 
188  CHECK (!isnil(oo));
189  oo = objs[3]; // copy construction also works on non-empty object
190  CHECK (7 == oo->getIt());
191 
192  // WARNING: direct ref has been messed up through the backdoor!
193  CHECK (7 == rd5.getIt());
194  CHECK (isSameObject (rd5, *oo));
195 
196  uint cnt_before = _create_count;
197 
198  oo.clear();
199  CHECK (!oo);
200  oo = D5(); // direct assignment also works on empty object
201  CHECK (oo);
202  CHECK (5 == oo->getIt());
203  CHECK (_create_count == 2 + cnt_before);
204  // one within buff and one for the anonymous temporary D5()
205 
206 
207  // verify that self-assignment is properly detected...
208  cnt_before = _create_count;
209  oo = oo;
210  CHECK (oo);
211  CHECK (_create_count == cnt_before);
212  oo = oo.get<D5>();
213  CHECK (_create_count == cnt_before);
214  oo = *oo;
215  CHECK (_create_count == cnt_before);
216  CHECK (oo);
217 
218  oo.clear();
219  CHECK (!oo);
220  CHECK (isnil(oo));
221  VERIFY_ERROR (BOTTOM_VALUE, oo.get<D5>() );
222 #if false
223  VERIFY_ERROR (ASSERTION, oo->getIt() );
224 #endif
225  // can't access empty holder...
226 
227  Opaque o1 (oo);
228  CHECK (!o1);
229 
230  Opaque o2 (d3);
231  CHECK (!isSameObject (d3, *o2));
232  CHECK (3 == o2->getIt());
233 
234  CHECK (sizeof(Opaque) <= sizeof(Base) + sizeof(void*) + _ALIGN_);
235  }
236 
237 
249  void
251  {
252  typedef OpaqueHolder<Base, sizeof(Special)> SpecialOpaque;
253 
254  cout << showSizeof<Base>() << endl;
255  cout << showSizeof<Special>() << endl;
256  cout << showSizeof<Opaque>() << endl;
257  cout << showSizeof<SpecialOpaque>() << endl;
258 
259  CHECK (sizeof(Special) > sizeof(Base));
260  CHECK (sizeof(SpecialOpaque) > sizeof(Opaque));
261  CHECK (sizeof(SpecialOpaque) <= sizeof(Special) + sizeof(void*) + _ALIGN_);
262 
263  Special s1 (6);
264  Special s2 (3);
265  CHECK (!s1); // even value
266  CHECK (s2); // odd value
267  CHECK (7 == s1.getIt()); // indeed subclass of DD<7>
268  CHECK (7 == s2.getIt());
269 
270  SpecialOpaque ospe0;
271  SpecialOpaque ospe1 (s1);
272  SpecialOpaque ospe2 (s2);
273 
274  CHECK (!ospe0); // note: bool test (isValid)
275  CHECK (!ospe1); // also forwarded to contained object (myVal_==6 is even)
276  CHECK ( ospe2);
277  CHECK ( isnil(ospe0)); // while isnil just checks the empty state
278  CHECK (!isnil(ospe1));
279  CHECK (!isnil(ospe2));
280 
281  CHECK (7 == ospe1->getIt());
282  CHECK (6 == ospe1.get<Special>().myVal_);
283  CHECK (3 == ospe2.get<Special>().myVal_);
284 
285  ospe1 = DD<5>(); // but can be reassigned like any normal Opaque
286  CHECK (ospe1);
287  CHECK (5 == ospe1->getIt());
288  VERIFY_ERROR (WRONG_TYPE, ospe1.get<Special>() );
289 
290  Opaque normal = DD<5>();
291  CHECK (normal);
292  CHECK (5 == normal->getIt());
293 #if false
294  // Assertion protects against SEGV
295  VERIFY_ERROR (ASSERTION, normal = s1 );
296 #endif
297  }
298  };
299 
300 
301  LAUNCHER (OpaqueHolder_test, "unit common");
302 
303 
304 }} // namespace lib::test
305 
void checkHandling(TestList &objs)
Definition: run.hpp:49
#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.
Simple 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, bypassing any custom comparison operators.
Definition: util.hpp:372