Lumiera  0.pre.03
»edit your freedom«
multifact-test.cpp
Go to the documentation of this file.
1 /*
2  MultiFact(Test) - cover the configurable object-family creating factory
3 
4  Copyright (C)
5  2014, 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 
19 #include "lib/test/run.hpp"
20 #include "lib/test/test-helper.hpp"
21 #include "lib/multifact.hpp"
22 #include "lib/util.hpp"
23 
24 #include <boost/lexical_cast.hpp>
25 #include <functional>
26 #include <memory>
27 #include <string>
28 
29 
30 
31 namespace lib {
32 namespace test{
33 
34  using boost::lexical_cast;
35  using util::isSameObject;
36  using util::isnil;
37 
38  using std::shared_ptr;
39  using std::function;
40  using std::string;
41  using std::bind;
42 
43  using lumiera::error::LUMIERA_ERROR_INVALID;
44 
45 
46  namespace { // hierarchy of test dummy objects
47 
48  struct Interface
49  {
50  virtual ~Interface() {};
51  virtual operator string () =0;
52  };
53 
54 
55 
56  enum theID
57  { ONE = 1
58  , TWO
59  , THR
60  , FOU
61  };
62 
63 
64 
65  template<theID ii>
67  : public Interface
68  {
69  string instanceID_;
70 
71  operator string()
72  {
73  return instanceID_ + lexical_cast<string> (ii);
74  }
75 
76  public:
77  Implementation(string id = "Impl-")
78  : instanceID_(id)
79  { }
80  };
81 
82 
83 
84  template<typename X>
85  string
86  buildSome (X rawVal)
87  {
88  return lexical_cast<string> (rawVal);
89  }
90 
91  string
92  buildOne()
93  {
94  return buildSome(ONE);
95  }
96  }
97 
98 
99 
100 
101 
102  /******************************************************************************/
114  class MultiFact_test : public Test
115  {
116  void
117  run (Arg)
118  {
119  produce_simple_values();
120  produce_smart_pointers();
121  pass_additional_arguments();
122  fed_a_custom_finishing_functor();
123  }
124 
125  string
126  callMe (string val)
127  {
128  ++invocations_;
129  return val;
130  }
131  uint invocations_ = 0;
132 
133 
134  void
135  produce_simple_values()
136  {
138 
140 
141  // the first "production line" is wired to a free function
142  theFact.defineProduction (ONE, buildOne);
143 
144  // second "production line" uses a explicit partial closure
145  theFact.defineProduction (TWO, bind (buildSome<theID>, TWO));
146 
147  // for the third "production line" we set up a function object
148  auto memberFunction = bind (&MultiFact_test::callMe, this, "lalü");
149  theFact.defineProduction (THR, memberFunction);
150 
151  // and the fourth "production line" uses a lambda, closed with a local reference
152  string backdoor("backdoor");
153  theFact.defineProduction (FOU, [&] {
154  return backdoor;
155  });
156 
157  CHECK (!isnil (theFact));
158  CHECK (theFact(ONE) == "1");
159  CHECK (theFact(TWO) == "2");
160 
161  CHECK (theFact(THR) == "lalü");
162  CHECK (invocations_ == 1);
163 
164  CHECK (theFact(FOU) == "backdoor");
165  backdoor = "I am " + backdoor.substr(0,4);
166  CHECK (theFact(FOU) == "I am back");
167 
168 
169  TestFactory anotherFact;
170  CHECK (isnil (anotherFact));
171  VERIFY_ERROR (INVALID, anotherFact(ONE) );
172 
173  anotherFact.defineProduction (ONE, memberFunction);
174  CHECK (anotherFact(ONE) == "lalü");
175  CHECK (invocations_ == 2);
176 
177  CHECK (theFact(THR) == "lalü");
178  CHECK (invocations_ == 3);
179 
180 
181  CHECK ( theFact.contains (FOU));
182  CHECK (!anotherFact.contains (FOU));
183 
184  anotherFact = theFact;
185  CHECK (anotherFact.contains (FOU));
186  CHECK (!isSameObject(theFact, anotherFact));
187 
188  CHECK (anotherFact(ONE) == "1");
189  CHECK (anotherFact(TWO) == "2");
190  CHECK (anotherFact(THR) == "lalü");
191  CHECK (anotherFact(FOU) == "I am back");
192  CHECK (invocations_ == 4);
193  }
194 
195 
196  void
197  produce_smart_pointers()
198  {
200  using PIfa = shared_ptr<Interface>;
201 
203 
204  // set up the "production lines" by lambda
205  theFact.defineProduction (ONE, [] { return new Implementation<ONE>; });
206  theFact.defineProduction (TWO, [] { return new Implementation<TWO>; });
207  theFact.defineProduction (THR, [] { return new Implementation<THR>; });
208  theFact.defineProduction (FOU, [] { return new Implementation<FOU>; });
209  CHECK (!isnil (theFact));
210 
211  PIfa p1 = theFact(ONE);
212  PIfa p2 = theFact(TWO);
213  PIfa p3 = theFact(THR);
214  PIfa p4 = theFact(FOU);
215 
216  PIfa p11 = theFact(ONE);
217 
218  CHECK ("Impl-1" == string(*p1));
219  CHECK ("Impl-2" == string(*p2));
220  CHECK ("Impl-3" == string(*p3));
221  CHECK ("Impl-4" == string(*p4));
222 
223  CHECK ("Impl-1" == string(*p11));
224  CHECK (!isSameObject(*p1, *p11));
225 
226  PIfa p12(p11);
227  CHECK (isSameObject(*p11, *p12));
228  CHECK ("Impl-1" == string(*p12));
229  CHECK (1 == p1.use_count());
230  CHECK (2 == p11.use_count());
231  CHECK (2 == p12.use_count());
232  }
233 
234 
235  void
236  pass_additional_arguments()
237  {
239 
241 
242  // set up the "production lines"
243  theFact.defineProduction (ONE, [](string ) { return new Implementation<ONE>; });
244  theFact.defineProduction (TWO, [](string ) { return new Implementation<TWO>("X"); });
245  theFact.defineProduction (THR, [](string id) { return new Implementation<THR>(id); });
246  theFact.defineProduction (FOU, [](string id) { return new Implementation<FOU>("Z"+id);});
247 
248  Interface *p1 = theFact(ONE, "irrelevant"),
249  *p2 = theFact(TWO, "ignored"),
250  *p3 = theFact(THR, "idiocy"),
251  *p4 = theFact(FOU, "omg"),
252  *p5 = theFact(FOU, "z");
253 
254  // does not compile...
255  // theFact(ONE);
256  // theFact(ONE, "foo", bar);
257 
258  CHECK ("Impl-1" == string(*p1));
259  CHECK ("X2" == string(*p2));
260  CHECK ("idiocy3"== string(*p3));
261  CHECK ("Zomg4" == string(*p4));
262  CHECK ("Zz4" == string(*p5));
263 
264  CHECK (!isSameObject(*p4, *p5));
265  CHECK (INSTANCEOF(Implementation<ONE>, p1));
266  CHECK (INSTANCEOF(Implementation<TWO>, p2));
267  CHECK (INSTANCEOF(Implementation<THR>, p3));
268  CHECK (INSTANCEOF(Implementation<FOU>, p4));
269  CHECK (INSTANCEOF(Implementation<FOU>, p5));
270 
271  delete p1;
272  delete p2;
273  delete p3;
274  delete p4;
275  delete p5;
276  }
277 
278 
279  void
280  fed_a_custom_finishing_functor()
281  {
283 
285 
286  // Setup(1): each "production line" does a distinct calculation
287  theFact.defineProduction (ONE, [](int par) { return par; });
288  theFact.defineProduction (TWO, [](int par) { return 2 * par; });
289  theFact.defineProduction (THR, [](int par) { return par*par; });
290  theFact.defineProduction (FOU, [](int par) { return 1 << par;});
291 
292  // Setup(2): and a common "wrapper functor" finishes
293  // the output of the chosen "production line"
294  theFact.defineFinalWrapper([](int raw) { return raw + 1; });
295 
296  CHECK (long(1 + 1) == theFact(ONE, 1));
297  CHECK (long(1 + 2) == theFact(ONE, 2));
298  CHECK (long(1 + 3) == theFact(ONE, 3));
299 
300  CHECK (long(1 + 2) == theFact(TWO, 1));
301  CHECK (long(1 + 4) == theFact(TWO, 2));
302  CHECK (long(1 + 6) == theFact(TWO, 3));
303 
304  CHECK (long(1 + 1) == theFact(THR, 1));
305  CHECK (long(1 + 4) == theFact(THR, 2));
306  CHECK (long(1 + 9) == theFact(THR, 3));
307 
308  CHECK (long(1 + 2) == theFact(FOU, 1));
309  CHECK (long(1 + 4) == theFact(FOU, 2));
310  CHECK (long(1 + 8) == theFact(FOU, 3));
311  }
312  };
313 
314 
316  LAUNCHER (MultiFact_test, "unit common");
317 
318 
319 
320 }} // namespace lib::test
factory::MultiFact< Num(int), prodID, factory::BuildRefcountPtr > TestFactory
the factory instantiation used for this test
Definition: run.hpp:40
Framework for building a configurable factory, to generate families of related objects.
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Implementation namespace for support and library code.
Factory for creating a family of objects by ID.
Definition: multifact.hpp:253
Target object to be instantiated as Singleton Allocates a variable amount of additional heap memory a...
Simplistic 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.
void defineProduction(ID id, FUNC &&fun)
to set up a production line, associated with a specific ID
Definition: multifact.hpp:311
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