Lumiera  0.pre.03
»edit your freedom«
dependency-configuration-test.cpp
Go to the documentation of this file.
1 /*
2  DependencyConfiguration(Test) - verify configuration for injecting dependencies
3 
4  Copyright (C)
5  2018, 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 
23 #include "lib/test/run.hpp"
24 #include "lib/format-cout.hpp"
25 #include "lib/test/test-helper.hpp"
26 #include "lib/util.hpp"
27 
28 #include "lib/depend.hpp"
29 #include "lib/depend-inject.hpp"
30 
31 
32 
33 namespace lib {
34 namespace test{
35 
36  using ::Test;
37  using util::isSameObject;
38 
39  namespace {
40 
41  struct Dum
43  {
44  virtual ~Dum() { }
45  virtual int probe() =0;
46  };
47 
48 
49  int checksum = 0;
50 
51  template<int N>
52  struct Dummy
53  : Dum
54  {
55  Dummy() { checksum += N; }
56  ~Dummy() { checksum -= N; }
57 
58  virtual int
59  probe() override
60  {
61  return N * checksum;
62  }
63  };
64  }
65 
66  using LERR_(LIFECYCLE);
67  using LERR_(FATAL);
68 
69 
70 
71 
72 
73  /***************************************************************************/
89  : public Test
90  {
91 
92 
93  virtual void
94  run (Arg)
95  {
96  checksum = 0;
97 
98  verify_Singleton();
99  verify_SubclassSingleton();
100  verify_expose_Service_with_Lifecycle();
101  verify_automaticReplacement();
102  verify_customFactory();
103 
104  CHECK (9+7+5+1 == checksum); // singletons stay alive until application shutdown
105  }
106 
107 
109  void
111  {
112  Depend<Dummy<1>> dep11;
113  Depend<Dummy<5>> dep5;
114  Depend<Dummy<1>> dep12;
115 
116  CHECK (1 == sizeof(dep11));
117  CHECK (1 == sizeof(dep12));
118  CHECK (1 == sizeof(dep5));
119 
120  // no singleton instance created yet
121  CHECK ( 0 == checksum );
122 
123  CHECK ( 1*1 == dep11().probe() );
124  CHECK ( 1 == checksum );
125  CHECK ((1+5)*5 == dep5().probe() );
126  CHECK ((1+5) == checksum );
127  CHECK ((1+5)*1 == dep12().probe() );
128  CHECK ((1+5) == checksum );
129 
130  CHECK (not isSameObject (dep11, dep12));
131  CHECK ( isSameObject (dep11(), dep12()));
132  }
133 
134 
136  void
138  {
139  // unable to create singleton instance of abstract baseclass
140  VERIFY_ERROR (FATAL, Depend<Dum>{}() );
141 
142  CHECK ((1+5) == checksum );
143 
144  Depend<Dum> dumm;
146  CHECK ((1+5) == checksum );
147 
148  CHECK ((1+5+7)*7 == dumm().probe() );
149  CHECK ((1+5+7) == checksum );
150 
152  CHECK ((1+5+7)*7 == Depend<Dum>{}().probe() );
153  CHECK ((1+5+7)*7 == dumm().probe() );
154  CHECK ((1+5+7) == checksum );
155  }
156 
157 
159  void
161  {
162  CHECK ((1+5+7) == checksum );
163 
164  struct SubDummy
165  : Dummy<3>
166  {
167  virtual int
168  probe() override
169  {
170  return offset - checksum;
171  }
172 
173  int offset = 0;
174  };
175 
176  Depend<Dummy<3>> dep3;
177  CHECK ((1+5+7) == checksum );
178  {
179  DependInject<Dummy<3>>::ServiceInstance<SubDummy> service{};
180  CHECK (service);
181  CHECK ((1+5+7+3) == checksum );
182  CHECK (-(1+5+7+3) == dep3().probe() );
183  CHECK ((1+5+7+3) == checksum );
184  service->offset = (1+5+7);
185  CHECK ( -3 == dep3().probe() );
186  CHECK ((1+5+7+3) == checksum );
187  }
188  CHECK ((1+5+7) == checksum );
189  VERIFY_ERROR (LIFECYCLE, dep3().probe() );
191  CHECK ((1+5+7) == checksum );
192  }
193 
194 
195 
197  void
199  {
200  Depend<Dum> dumm;
201  Depend<Dummy<3>> depp;
202  CHECK ((1+5+7) == checksum );
203  CHECK ((1+5+7)*7 == dumm().probe() );
204  VERIFY_ERROR (LIFECYCLE, depp().probe() );
205 
206  struct Mock
207  : Dummy<3>
208  {
209  virtual int
210  probe() override
211  {
212  return response;
213  }
214 
215  int response = -1;
216  };
217 
218  {
219  DependInject<Dum>::Local<Mock> mockDumm;
220  DependInject<Dummy<3>>::Local<Mock> mockDummy3;
221  CHECK ((1+5+7) == checksum );
222 
223  CHECK (!mockDumm);
224  CHECK (!mockDummy3);
225  CHECK (-1 == dumm().probe() ); // NOTE: now returning the response from the mock instance
226  CHECK ( mockDumm);
227  CHECK (!mockDummy3);
228  CHECK ((1+5+7+3) == checksum );
229  CHECK (-1 == mockDumm->probe() );
230  CHECK ((1+5+7+3) == checksum );
231 
232  mockDumm->response = 11;
233  CHECK (11 == dumm().probe() ); // NOTE: now returning the response changed on the mock instance
234 
235  CHECK (!mockDummy3); // the second mock is still in not yet created state...
236  CHECK ((1+5+7+3) == checksum );
237  CHECK (-1 == depp().probe() );
238  CHECK ((1+5+7+3+3) == checksum ); // ...and now we got a second mock instance!
239  CHECK ( mockDummy3);
240  CHECK (-1 == mockDummy3->probe() );
241  CHECK ((1+5+7+3+3) == checksum );
242  mockDummy3->response = 22;
243  CHECK (22 == depp().probe() );
244  mockDumm->response = 12;
245  CHECK (22 == depp().probe() ); // these are really two distinct instances
246  CHECK (12 == dumm().probe() );
247  CHECK ((1+5+7+3+3) == checksum );
248  }
249 
250  // Back to normal: the Mocks are gone, original behaviour uncovered
251  CHECK ((1+5+7) == checksum );
252  CHECK ((1+5+7)*7 == dumm().probe() );
253  VERIFY_ERROR (LIFECYCLE, depp().probe() );
254  CHECK ((1+5+7) == checksum );
255 
256  {
257  DependInject<Dummy<3>>::ServiceInstance<Mock> service{};
258  CHECK ((1+5+7+3) == checksum ); // NOTE: we got a new Dummy<3> service instance
259  CHECK (-1 == depp().probe() ); // ..... which returns the pristine mock response
260  service->response = 33;
261  CHECK (33 == depp().probe() );
262  CHECK ((1+5+7+3) == checksum );
263 
264  {
265  DependInject<Dummy<3>>::Local<Mock> mockDummy31;
266  CHECK (!mockDummy31);
267  CHECK ((1+5+7+3) == checksum ); // ...while SerivceInstance is created eagerly
268  CHECK (-1 == depp().probe() ); // the Local mock instance is only created on-demand
269  CHECK ((1+5+7+3+3) == checksum );
270  mockDummy31->response = 44;
271  CHECK (44 == depp().probe() );
272  CHECK (44 == mockDummy31->probe() );
273  CHECK (33 == service->probe() );
274  CHECK (mockDummy31->response != service->response);
275  service->response = 34;
276  CHECK (44 == depp().probe() ); // NOTE: remains shadowed by the mockDummy
277  CHECK (44 == mockDummy31->probe() );
278  CHECK (34 == service->probe() );
279  CHECK ((1+5+7+3+3) == checksum );
280  }
281 
282  // Now the mock is gone and the service instance becomes uncovered
283  CHECK ((1+5+7+3) == checksum );
284  CHECK (34 == depp().probe() ); // now reveals the response changed from within the nested test scope
285  CHECK ((1+5+7+3) == checksum );
286  }
287 
288  // Back to normal: Mocks is gone, Service is shutdown, original behaviour uncovered
289  CHECK ((1+5+7) == checksum );
290  VERIFY_ERROR (LIFECYCLE, depp().probe() );
291  CHECK ((1+5+7)*7 == dumm().probe() );
292  CHECK ((1+5+7) == checksum );
293  }
294 
295 
296 
306  void
308  {
309  CHECK ((1+5+7) == checksum );
310 
311  struct Veryspecial
312  : Dummy<9>
313  {
314  Veryspecial(int& ref)
315  : magic_{ref}
316  { }
317 
318  int& magic_;
319 
320  virtual int
321  probe() override
322  {
323  return magic_++;
324  }
325  };
326 
327  // NOTE: the following is rejected due to missing default ctor
328  DependInject<Dummy<9>>::useSingleton<Veryspecial>();
329  VERIFY_ERROR (FATAL, Depend<Dummy<9>>{}() );
330 
331 
332  int backdoor = 22;
333 
334  DependInject<Dummy<9>>::useSingleton ([&]{ return new Veryspecial{backdoor}; });
335 
336  CHECK ((1+5+7) == checksum );
337  CHECK ( 22 == backdoor );
338 
339  Depend<Dummy<9>> tricky;
340  CHECK ((1+5+7) == checksum );
341  CHECK (22 == backdoor );
342 
343  CHECK (22 == tricky().probe());
344  CHECK (23 == backdoor );
345  CHECK ((1+5+7+9) == checksum ); // Veryspecial Dummy<9> subclass was created on the heap
346  // and will continue to live there until the testsuite terminates
347  backdoor = 41;
348  CHECK (41 == tricky().probe());
349  CHECK (42 == backdoor );
350 
351 
352  Depend<Dum> dumm;
353  CHECK ((1+5+7+9)*7 == dumm().probe() );
354 
355  {
356 
358 // // since Veryspecial has no default ctor...
359 // //
360 // DependInject<Dum>::Local<Dum> impossible;
361 
362  DependInject<Dum>::Local<Dum> insidious ([&]{ return new Veryspecial{backdoor}; });
363 
364  CHECK ((1+5+7+9) == checksum );
365  CHECK (not insidious);
366 
367  CHECK (42 == dumm().probe() );
368  CHECK (43 == backdoor );
369  CHECK ((1+5+7+9+9) == checksum );
370 
371  CHECK (isSameObject (dumm(), *insidious));
372 
373  CHECK (43 == tricky().probe());
374  CHECK (44 == backdoor );
375 
376  backdoor = -1;
377  CHECK (-1 == dumm().probe() );
378  CHECK ( 0 == backdoor );
379 
380  CHECK ((1+5+7+9+9) == checksum );
381  }
382 
383  CHECK ((1+5+7+9) == checksum );
384  CHECK ((1+5+7+9)*7 == dumm().probe() );
385  CHECK ( 0 == tricky().probe());
386  CHECK (+1 == backdoor );
387  } // NOTE: Veryspecial holds a dangling reference into stack memory from now on!
388  };
389 
390 
391 
392  LAUNCHER (DependencyConfiguration_test, "unit common");
393 
394 
395 }} // namespace lib::test
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:40
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
Per type specific configuration of instances created as service dependencies.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
Implementation namespace for support and library code.
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
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.
A Dummy object for tests.
Singleton services and Dependency Injection.
Configuration handle for temporarily shadowing a dependency by a test mock instance.
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