Lumiera  0.pre.03
»edit your freedom«
diagnostic-context-test.cpp
Go to the documentation of this file.
1 /*
2  DiagnosticContext(Test) - verify thread local stack for collecting diagnostics
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 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
30 
32 #include "lib/iter-explorer.hpp"
33 #include "lib/thread.hpp"
34 
35 #include <vector>
36 #include <chrono>
37 #include <array>
38 
39 using std::this_thread::sleep_for;
40 using std::chrono_literals::operator ""us;
41 
42 
43 
44 
45 namespace lib {
46 namespace test{
47 
48  namespace error = lumiera::error;
49 
50  namespace { // private test setup...
51 
52  /* WARNING: memory hungry */
53  const uint NUM_THREADS = 75;
54  const uint MAX_RAND = 100*1000;
55 
56  auto isOdd = [](auto val) { return bool (val % 2); };
57 
58  } // (End) test setup....
59 
60  using lib::ThreadJoinable;
61  using error::LERR_(LOGIC);
62  using std::rand;
63 
64 
70 
71  typedef std::vector<uint> VecI;
72 
73 
74 
75 
76 
77  /******************************************************************************/
88  class DiagnosticContext_test : public Test
89  {
90 
91  virtual void
92  run (Arg)
93  {
94  verify_simpleAccess();
95  verify_heavilyParallelUsage();
96  }
97 
98 
99 
104  void
106  {
107  VERIFY_ERROR (LOGIC, Marker::access());
108 
109  VecI loggedValues;
110 
111  Marker zero(0);
112  CHECK (0 == zero);
113  CHECK (0 == Marker::access());
114 
115  { // nested scope
116  CHECK (0 == Marker::access());
117 
118  Marker one(1);
119  CHECK (1 == Marker::access());
120  CHECK (1 == one);
121  CHECK (0 == zero);
122 
123  { // nested scope
124  CHECK (1 == Marker::access());
125 
126  Marker two(2);
127  CHECK (2 == Marker::access());
128  CHECK (2 == two);
129  CHECK (1 == one);
130  CHECK (0 == zero);
131 
132  loggedValues = Marker::extractStack();
133  }
134  CHECK (1 == Marker::access());
135  }
136  CHECK (0 == Marker::access());
137 
138  CHECK (3 == loggedValues.size());
139  CHECK (2 == loggedValues[0]);
140  CHECK (1 == loggedValues[1]);
141  CHECK (0 == loggedValues[2]);
142  }
143 
144 
145 
146 
162  void
164  {
165  auto verifyResult = [](VecI sequence)
166  {
167  uint prev = 0;
168  for (uint val : sequence)
169  {
170  CHECK (isOdd(val) and val > prev);
171  prev = val;
172  }
173  };
174 
175  std::array<TestThread, NUM_THREADS> testcases;
176 
177  auto results = lib::explore(testcases)
178  .transform([](TestThread& t){ return t.join(); })
179  .effuse();
180 
181  for (auto& res : results)
182  verifyResult (res);
183  }
184 
185 
187  struct TestThread
188  : ThreadJoinable<VecI>
189  {
190  TestThread()
191  : ThreadJoinable("test context stack"
192  ,&verifyDiagnosticStack)
193  { }
194  };
195 
196 
201  static VecI
203  {
204  uint seed (1 + rand() % MAX_RAND);
205  return descend (seed);
206  }
207 
208  static VecI
209  descend (uint current)
210  {
211  if (current < 2)
212  return Marker::extractStack();
213 
214  sleep_for (500us);
215 
216  if (isOdd(current))
217  {
218  Marker remember(current);
219  return descend (current+1);
220  }
221  else
222  return descend (current/2);
223  }
224  };
225 
226 
227 
229  LAUNCHER (DiagnosticContext_test, "function common");
230 
231 
232 
233 }} // namespace vault::test
Variant of the standard case, requiring to wait and join() on the termination of this thread...
Definition: thread.hpp:674
build a call stack within separate thread and capture diagnostics
static VecI verifyDiagnosticStack()
the actual test operation running in a separate thread produces a descending number sequence...
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
Definition: run.hpp:49
Facility for collecting diagnostic context information explicitly.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify a statement indeed raises an exception.
Implementation namespace for support and library code.
ThreadJoinable(string const &, FUN &&, ARGS &&...) -> ThreadJoinable< std::invoke_result_t< FUN, ARGS... >>
deduction guide: find out about result value to capture from a generic callable.
Simple test class runner.
lib::Result< RES > join()
put the caller into a blocking wait until this thread has terminated
Definition: thread.hpp:691
Convenience front-end to simplify and codify basic thread handling.
A collection of frequently used helper functions to support unit testing.
Diagnostic data frame to collect specific information concerning a scope.
ExampleStrategy::Qualifier two(string additionalArg)
definition of another qualifier two(arg), accepting an additional argument
static DiagnosticContext & access()
accessing the innermost diagnostic context created
Building tree expanding and backtracking evaluations within hierarchical scopes.
ExampleStrategy::Qualifier one()
definition of a qualifier one()
static ValSequence extractStack()
snapshot of the current stack of diagnostic frames