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) Lumiera.org
5  2018, 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 
32 #include "lib/test/run.hpp"
33 #include "lib/format-cout.hpp"
34 #include "lib/test/test-helper.hpp"
35 #include "lib/util.hpp"
36 
37 #include "lib/depend.hpp"
38 #include "lib/depend-inject.hpp"
39 
40 
41 
42 namespace lib {
43 namespace test{
44 
45  using ::Test;
46  using util::isSameObject;
47 
48  namespace {
49 
50  struct Dum
52  {
53  virtual ~Dum() { }
54  virtual int probe() =0;
55  };
56 
57 
58  int checksum = 0;
59 
60  template<int N>
61  struct Dummy
62  : Dum
63  {
64  Dummy() { checksum += N; }
65  ~Dummy() { checksum -= N; }
66 
67  virtual int
68  probe() override
69  {
70  return N * checksum;
71  }
72  };
73  }
74 
75  using LERR_(LIFECYCLE);
76  using LERR_(FATAL);
77 
78 
79 
80 
81 
82  /***************************************************************************/
98  : public Test
99  {
100 
101 
102  virtual void
103  run (Arg)
104  {
105  checksum = 0;
106 
107  verify_Singleton();
108  verify_SubclassSingleton();
109  verify_expose_Service_with_Lifecycle();
110  verify_automaticReplacement();
111  verify_customFactory();
112 
113  CHECK (9+7+5+1 == checksum); // singletons stay alive until application shutdown
114  }
115 
116 
118  void
120  {
121  Depend<Dummy<1>> dep11;
122  Depend<Dummy<5>> dep5;
123  Depend<Dummy<1>> dep12;
124 
125  CHECK (1 == sizeof(dep11));
126  CHECK (1 == sizeof(dep12));
127  CHECK (1 == sizeof(dep5));
128 
129  // no singleton instance created yet
130  CHECK ( 0 == checksum );
131 
132  CHECK ( 1*1 == dep11().probe() );
133  CHECK ( 1 == checksum );
134  CHECK ((1+5)*5 == dep5().probe() );
135  CHECK ((1+5) == checksum );
136  CHECK ((1+5)*1 == dep12().probe() );
137  CHECK ((1+5) == checksum );
138 
139  CHECK (not isSameObject (dep11, dep12));
140  CHECK ( isSameObject (dep11(), dep12()));
141  }
142 
143 
145  void
147  {
148  // unable to create singleton instance of abstract baseclass
149  VERIFY_ERROR (FATAL, Depend<Dum>{}() );
150 
151  CHECK ((1+5) == checksum );
152 
153  Depend<Dum> dumm;
155  CHECK ((1+5) == checksum );
156 
157  CHECK ((1+5+7)*7 == dumm().probe() );
158  CHECK ((1+5+7) == checksum );
159 
161  CHECK ((1+5+7)*7 == Depend<Dum>{}().probe() );
162  CHECK ((1+5+7)*7 == dumm().probe() );
163  CHECK ((1+5+7) == checksum );
164  }
165 
166 
168  void
170  {
171  CHECK ((1+5+7) == checksum );
172 
173  struct SubDummy
174  : Dummy<3>
175  {
176  virtual int
177  probe() override
178  {
179  return offset - checksum;
180  }
181 
182  int offset = 0;
183  };
184 
185  Depend<Dummy<3>> dep3;
186  CHECK ((1+5+7) == checksum );
187  {
188  DependInject<Dummy<3>>::ServiceInstance<SubDummy> service{};
189  CHECK (service);
190  CHECK ((1+5+7+3) == checksum );
191  CHECK (-(1+5+7+3) == dep3().probe() );
192  CHECK ((1+5+7+3) == checksum );
193  service->offset = (1+5+7);
194  CHECK ( -3 == dep3().probe() );
195  CHECK ((1+5+7+3) == checksum );
196  }
197  CHECK ((1+5+7) == checksum );
198  VERIFY_ERROR (LIFECYCLE, dep3().probe() );
200  CHECK ((1+5+7) == checksum );
201  }
202 
203 
204 
206  void
208  {
209  Depend<Dum> dumm;
210  Depend<Dummy<3>> depp;
211  CHECK ((1+5+7) == checksum );
212  CHECK ((1+5+7)*7 == dumm().probe() );
213  VERIFY_ERROR (LIFECYCLE, depp().probe() );
214 
215  struct Mock
216  : Dummy<3>
217  {
218  virtual int
219  probe() override
220  {
221  return response;
222  }
223 
224  int response = -1;
225  };
226 
227  {
228  DependInject<Dum>::Local<Mock> mockDumm;
229  DependInject<Dummy<3>>::Local<Mock> mockDummy3;
230  CHECK ((1+5+7) == checksum );
231 
232  CHECK (!mockDumm);
233  CHECK (!mockDummy3);
234  CHECK (-1 == dumm().probe() ); // NOTE: now returning the response from the mock instance
235  CHECK ( mockDumm);
236  CHECK (!mockDummy3);
237  CHECK ((1+5+7+3) == checksum );
238  CHECK (-1 == mockDumm->probe() );
239  CHECK ((1+5+7+3) == checksum );
240 
241  mockDumm->response = 11;
242  CHECK (11 == dumm().probe() ); // NOTE: now returning the response changed on the mock instance
243 
244  CHECK (!mockDummy3); // the second mock is still in not yet created state...
245  CHECK ((1+5+7+3) == checksum );
246  CHECK (-1 == depp().probe() );
247  CHECK ((1+5+7+3+3) == checksum ); // ...and now we got a second mock instance!
248  CHECK ( mockDummy3);
249  CHECK (-1 == mockDummy3->probe() );
250  CHECK ((1+5+7+3+3) == checksum );
251  mockDummy3->response = 22;
252  CHECK (22 == depp().probe() );
253  mockDumm->response = 12;
254  CHECK (22 == depp().probe() ); // these are really two distinct instances
255  CHECK (12 == dumm().probe() );
256  CHECK ((1+5+7+3+3) == checksum );
257  }
258 
259  // Back to normal: the Mocks are gone, original behaviour uncovered
260  CHECK ((1+5+7) == checksum );
261  CHECK ((1+5+7)*7 == dumm().probe() );
262  VERIFY_ERROR (LIFECYCLE, depp().probe() );
263  CHECK ((1+5+7) == checksum );
264 
265  {
266  DependInject<Dummy<3>>::ServiceInstance<Mock> service{};
267  CHECK ((1+5+7+3) == checksum ); // NOTE: we got a new Dummy<3> service instance
268  CHECK (-1 == depp().probe() ); // ..... which returns the pristine mock response
269  service->response = 33;
270  CHECK (33 == depp().probe() );
271  CHECK ((1+5+7+3) == checksum );
272 
273  {
274  DependInject<Dummy<3>>::Local<Mock> mockDummy31;
275  CHECK (!mockDummy31);
276  CHECK ((1+5+7+3) == checksum ); // ...while SerivceInstance is created eagerly
277  CHECK (-1 == depp().probe() ); // the Local mock instance is only created on-demand
278  CHECK ((1+5+7+3+3) == checksum );
279  mockDummy31->response = 44;
280  CHECK (44 == depp().probe() );
281  CHECK (44 == mockDummy31->probe() );
282  CHECK (33 == service->probe() );
283  CHECK (mockDummy31->response != service->response);
284  service->response = 34;
285  CHECK (44 == depp().probe() ); // NOTE: remains shadowed by the mockDummy
286  CHECK (44 == mockDummy31->probe() );
287  CHECK (34 == service->probe() );
288  CHECK ((1+5+7+3+3) == checksum );
289  }
290 
291  // Now the mock is gone and the service instance becomes uncovered
292  CHECK ((1+5+7+3) == checksum );
293  CHECK (34 == depp().probe() ); // now reveals the response changed from within the nested test scope
294  CHECK ((1+5+7+3) == checksum );
295  }
296 
297  // Back to normal: Mocks is gone, Service is shutdown, original behaviour uncovered
298  CHECK ((1+5+7) == checksum );
299  VERIFY_ERROR (LIFECYCLE, depp().probe() );
300  CHECK ((1+5+7)*7 == dumm().probe() );
301  CHECK ((1+5+7) == checksum );
302  }
303 
304 
305 
315  void
317  {
318  CHECK ((1+5+7) == checksum );
319 
320  struct Veryspecial
321  : Dummy<9>
322  {
323  Veryspecial(int& ref)
324  : magic_{ref}
325  { }
326 
327  int& magic_;
328 
329  virtual int
330  probe() override
331  {
332  return magic_++;
333  }
334  };
335 
336  // NOTE: the following is rejected due to missing default ctor
337  DependInject<Dummy<9>>::useSingleton<Veryspecial>();
338  VERIFY_ERROR (FATAL, Depend<Dummy<9>>{}() );
339 
340 
341  int backdoor = 22;
342 
343  DependInject<Dummy<9>>::useSingleton ([&]{ return new Veryspecial{backdoor}; });
344 
345  CHECK ((1+5+7) == checksum );
346  CHECK ( 22 == backdoor );
347 
348  Depend<Dummy<9>> tricky;
349  CHECK ((1+5+7) == checksum );
350  CHECK (22 == backdoor );
351 
352  CHECK (22 == tricky().probe());
353  CHECK (23 == backdoor );
354  CHECK ((1+5+7+9) == checksum ); // Veryspecial Dummy<9> subclass was created on the heap
355  // and will continue to live there until the testsuite terminates
356  backdoor = 41;
357  CHECK (41 == tricky().probe());
358  CHECK (42 == backdoor );
359 
360 
361  Depend<Dum> dumm;
362  CHECK ((1+5+7+9)*7 == dumm().probe() );
363 
364  {
365 
367 // // since Veryspecial has no default ctor...
368 // //
369 // DependInject<Dum>::Local<Dum> impossible;
370 
371  DependInject<Dum>::Local<Dum> insidious ([&]{ return new Veryspecial{backdoor}; });
372 
373  CHECK ((1+5+7+9) == checksum );
374  CHECK (not insidious);
375 
376  CHECK (42 == dumm().probe() );
377  CHECK (43 == backdoor );
378  CHECK ((1+5+7+9+9) == checksum );
379 
380  CHECK (isSameObject (dumm(), *insidious));
381 
382  CHECK (43 == tricky().probe());
383  CHECK (44 == backdoor );
384 
385  backdoor = -1;
386  CHECK (-1 == dumm().probe() );
387  CHECK ( 0 == backdoor );
388 
389  CHECK ((1+5+7+9+9) == checksum );
390  }
391 
392  CHECK ((1+5+7+9) == checksum );
393  CHECK ((1+5+7+9)*7 == dumm().probe() );
394  CHECK ( 0 == tricky().probe());
395  CHECK (+1 == backdoor );
396  } // NOTE: Veryspecial holds a dangling reference into stack memory from now on!
397  };
398 
399 
400 
401  LAUNCHER (DependencyConfiguration_test, "unit common");
402 
403 
404 }} // namespace lib::test
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:49
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
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:289
Implementation namespace for support and library code.
This framework allows to (re)configure the lib::Depend front-end for dependency-injection.
Simple 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.
Definition: testdummy.hpp:50
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, bypassing any custom comparison operators.
Definition: util.hpp:372