Lumiera  0.pre.03
»edit your freedom«
polymorphic-value-test.cpp
Go to the documentation of this file.
1 /*
2  PolymorphicValue(Test) - verify handling of opaque polymorphic values
3 
4  Copyright (C) Lumiera.org
5  2011, 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-foreach.hpp"
32 
34 
35 #include <vector>
36 
37 
38 namespace lib {
39 namespace test{
40 
41  using ::Test;
42  using util::for_each;
43  using util::unConst;
44  using util::isSameObject;
45  using lumiera::error::LUMIERA_ERROR_ASSERTION;
46 
47 
48  namespace { // test dummy hierarchy
49  // Note: largely varying space requirements
50  // correct function depending on concrete class
51 
52 
53  struct Interface
54  {
55  virtual ~Interface() {}
56  virtual long apiFunc() =0;
57 
58  virtual long& localSum() =0;
59 
60  bool
61  operator== (Interface const& o) const
62  {
63  return unConst(this)->localSum()
64  == unConst(o).localSum();
65  }
66  };
67 
68 
69  const uint MAX_RAND = 1000;
70  const uint MAX_ELM = 111;
71  const uint MAX_SIZ = sizeof(long[MAX_ELM]);
72 
73  /* Checksums to verify proper ctor-dtor calls and copy operations */
74  long _checkSum = 0;
75  long _callSum = 0;
76  uint _created = 0;
77 
78 
85  template<uint ii, class BASE=Interface>
86  struct Imp : BASE
87  {
88  long localData_[ii];
89 
90  ~Imp()
91  {
92  mark (-1 * localSum());
93  CHECK (0 == localSum());
94  }
95 
96  Imp()
97  {
98  REQUIRE (0 < ii);
99  localSum() = 0;
100  mark(ii);
101  ++ _created;
102  }
103 
104  Imp (Imp const& o)
105  {
106  ++ _created;
107  copyData (o);
108  _checkSum += localSum();
109  }// adjust, because we've gotten two identical instances
110 
111  Imp&
112  operator= (Imp const& o)
113  {
114  _checkSum -= localSum();
115  copyData (o);
116  _checkSum += localSum();
117  return *this;
118  }
119 
120  private:
121  virtual long
122  apiFunc()
123  {
124  long rr = ii * (1 + rand() % MAX_RAND);
125  mark (rr);
126  _callSum += rr;
127  return rr;
128  }
129 
130  long&
131  localSum()
132  {
133  return localData_[ii-1];
134  }
135 
136  void
137  mark (long markerValue)
138  {
139  localSum() += markerValue;
140  _checkSum += markerValue;
141  }
142 
143  void
144  copyData (Imp const& o)
145  {
146  for (uint i=0; i<ii; ++i)
147  localData_[i] = o.localData_[i];
148  }
149  };
150 
151 
156  const size_t _ALIGN_ = sizeof(size_t);
157 
158  }
159 
161  using TestList = std::vector<PolyVal> ;
162 
163 
164 
165 
166 
167 
168  /******************************************************************************/
174  class PolymorphicValue_test : public Test
175  {
176 
177  virtual void
178  run (Arg)
179  {
180  _checkSum = 0;
181  _callSum = 0;
182  _created = 0;
183 
184  verifyBasics();
185 
186  {
187  TestList objs = createOpaqueValues ();
188  for_each (objs, operate);
189  }
190  CHECK (0 == _checkSum); // all dead
191 
192  verifyOverrunProtection();
193  verifyCopySupportDetectionMetafunctions();
194  }
195 
196 
197  TestList
198  createOpaqueValues ()
199  {
200  TestList list;
201  list.push_back (PolyVal::build<Imp<1>> () );
202  list.push_back (PolyVal::build<Imp<11>> () );
203  list.push_back (PolyVal::build<Imp<111>>() );
204  list.push_back (PolyVal::build<Imp<23>> () );
205  list.push_back (PolyVal::build<Imp<5>> () );
206  return list;
207  } //note: copy
208 
209 
210  static void
211  operate (PolyVal& elm)
212  {
213  PolyVal myLocalVal(elm);
214  CHECK (elm == myLocalVal);
215 
216  long prevSum = _callSum;
217  long randVal = myLocalVal->apiFunc();
218  CHECK (prevSum + randVal == _callSum);
219  CHECK (elm != myLocalVal);
220 
221  elm = myLocalVal;
222  CHECK (elm == myLocalVal);
223  CHECK (!isSameObject (elm, myLocalVal));
224 
225  CHECK (sizeof(myLocalVal) <= MAX_SIZ + polyvalue::Trait<Interface>::ADMIN_OVERHEAD + _ALIGN_);
226  }
227 
228 
229  void
230  verifyBasics()
231  {
232  typedef Imp<MAX_ELM> MaximumSizedImp;
233 
234  // Standard case: no copy support by client objects
235  verifyCreation_and_Copy<PolyVal, MaximumSizedImp>();
236 
237  // Special case: client objects expose extension point for copy support
238  using CopySupportAPI = polyvalue::CopySupport<Interface>; // Copy support API declared as sub-interface
239  using CopySupportingImp = Imp<MAX_ELM,CopySupportAPI>; // insert this sub-interface between public API and Implementation
240  using OptimalPolyVal = PolymorphicValue<Interface, MAX_SIZ, CopySupportAPI>; // Make the Holder use this special attachment point
241  CHECK (sizeof(OptimalPolyVal) < sizeof(PolyVal)); // results in smaller Holder and less implementation overhead
242 
243  verifyCreation_and_Copy<OptimalPolyVal, CopySupportingImp>();
244  }
245 
246 
247  template<class PV,class IMP>
248  void
249  verifyCreation_and_Copy()
250  {
251  using Holder = PV;
252  using ImpType = IMP;
253  using Api = typename PV::Interface ;
254 
255  long prevSum = _checkSum;
256  uint prevCnt = _created;
257 
258  Holder val = Holder::template build<ImpType>();
259  CHECK (prevSum+111 == _checkSum); // We got one primary ctor call
260  CHECK (prevCnt+1 <= _created); // Note: usually, the compiler optimises
261  CHECK (prevCnt+2 >= _created); // and skips the spurious copy-operation
262  CHECK (sizeof(Holder) >= sizeof(ImpType));
263  Api& api = val;
264  CHECK (isSameObject(api,val));
265  CHECK (INSTANCEOF(ImpType, &api));
266 
267  prevCnt = _created;
268  Holder val2(val); // invoke copy ctor without knowing the implementation type
269  api.apiFunc();
270  CHECK (val != val2); // invoking the API function had an sideeffect on the state
271  val = val2; // assignment of copy back to the original...
272  CHECK (val == val2); // cancels the side effect
273 
274  CHECK (prevCnt+1 == _created); // one new embedded instance was created by copy ctor
275  }
276 
277 
278  void
279  verifyOverrunProtection()
280  {
281  typedef Imp<MAX_ELM+1> OversizedImp;
282  CHECK (MAX_SIZ < sizeof(OversizedImp));
283 #if false
284  VERIFY_ERROR (ASSERTION, PolyVal::build<OversizedImp>() );
285 #endif
286  }
287 
288 
298  void
300  {
301  typedef polyvalue::CopySupport<Interface> CopySupportAPI;
302  typedef polyvalue::CloneValueSupport<Interface> CloneOnlyAPI;
303 
307 
310  }
311  };
312 
313 
314  LAUNCHER (PolymorphicValue_test, "unit common");
315 
316 
317 }} // namespace lib::test
const size_t _ALIGN_
maximum additional storage maybe wasted due to alignment of the contained object within the embedded ...
Definition: run.hpp:49
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:492
A variation for limited copy support.
helper to detect presence of a function to support clone operations
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
A mechanism to allow for opaque polymorphic value objects.
trait template to deal with different ways to support copy operations.
Implementation namespace for support and library code.
Template to generate concrete implementation classes.
Simple test class runner.
Template to build polymorphic value objects.
helper to detect if the API supports only copy construction, but no assignment
void for_each(CON const &elements, FUN function, P1 &&bind1, ARGS &&...args)
Accept binding for arbitrary function arguments.
Interface for active support of copy operations by the embedded client objects.
A collection of frequently used helper functions to support unit testing.
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