Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
command-instance-manager-test.cpp
Go to the documentation of this file.
1/*
2 CommandInstanceManager(Test) - verify helper for setup of actual command definitions
3
4 Copyright (C)
5 2017, 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"
22#include "lib/format-string.hpp"
23#include "lib/format-cout.hpp"
24#include "lib/iter-stack.hpp"
25#include "lib/util.hpp"
26
27#include <algorithm>
28#include <utility>
29#include <string>
30#include <deque>
31
32
33namespace steam {
34namespace control {
35namespace test {
36
37 using lib::Literal;
38 using std::string;
39 using util::_Fmt;
40 using std::move;
41
42 using LERR_(LIFECYCLE);
43 using LERR_(INVALID_COMMAND);
44 using LERR_(DUPLICATE_COMMAND);
45 using LERR_(UNBOUND_ARGUMENTS);
46
47
48 namespace { // Test fixture....
49
51 const string INVOCATION_ID = "CommandInstanceManager_test";
52
53 class Fixture
54 : public CommandDispatch
55 {
56 std::deque<Command> queue_;
57
58
59 /* == Interface: CommandDispatch == */
60
61 void
62 clear() override
63 {
64 queue_.clear();
65 }
66
67 void
68 enqueue (Command&& cmd) override
69 {
70 queue_.emplace_front (move (cmd));
71 }
72
73 public:
74 bool
75 contains (Command const& ref)
76 {
77 return queue_.end()!= std::find_if (queue_.begin()
78 ,queue_.end()
79 ,[=](Command const& elm)
80 {
81 return elm == ref;
82 });
83 }
84
85 void
87 {
88 for (Command& cmd : queue_)
89 cmd();
90 clear();
91 }
92 };
93 }
94
95
96
97 /***********************************************************************/
105 class CommandInstanceManager_test : public Test
106 {
107
108 virtual void
109 run (Arg)
110 {
111 seedRand();
118 }
119
120
131 void
133 {
134 Fixture fixture;
136 CHECK (not iManager.contains (COMMAND_PROTOTYPE));
137
138 int r1{rani(1000)}, r2{rani(2000)};
139 command1::check_ = 0; // commands will add to this on invocation
140
141 iManager.bindAndDispatch (COMMAND_PROTOTYPE, Rec{r1});
142 CHECK (not iManager.contains (COMMAND_PROTOTYPE));
143
144 Command com{COMMAND_PROTOTYPE};
145 com.bind(r2);
146 CHECK (com.canExec());
147
148 iManager.dispatch (COMMAND_PROTOTYPE);
149 CHECK (not iManager.contains (COMMAND_PROTOTYPE));
150
151 // an anonymous clone instance was dispatched,
152 // thus re-binding the arguments won't interfere with execution
153 com.bind(-1);
154
155 CHECK (command1::check_ == 0); // nothing invoked yet
156 fixture.invokeAll();
157 CHECK (command1::check_ == r1 + r2); // both instances were invoked with their specific arguments
158
159 // clean-up: we have bound arguments on the global prototype
160 com.unbind();
161 }
162
163
165 void
167 {
168 Fixture fixture;
170 Symbol instanceID = iManager.newInstance (COMMAND_PROTOTYPE, INVOCATION_ID);
171 CHECK (iManager.contains (instanceID));
172
173 Command cmd = iManager.getInstance (instanceID);
174 CHECK (cmd);
175 CHECK (not cmd.canExec());
176
177 cmd.bind(42);
178 CHECK (cmd.canExec());
179
180 iManager.dispatch (instanceID);
181 CHECK (fixture.contains (cmd));
182 CHECK (not iManager.contains (instanceID));
183 VERIFY_ERROR (LIFECYCLE, iManager.getInstance (instanceID));
184
186 fixture.invokeAll();
187 CHECK (command1::check_ == 42); // the dispatched instance was executed
188 }
189
190
191
209 void
211 {
212 Fixture fixture;
214 Symbol i1 = iManager.newInstance (COMMAND_PROTOTYPE, "i1");
215 Symbol i2 = iManager.newInstance (COMMAND_PROTOTYPE, "i2");
216
217 Command c11 = iManager.getInstance (i1);
218 Command c12 = iManager.getInstance (i1);
219 CHECK (c11 == c12);
220 CHECK (c11.isValid());
221 CHECK (not c11.canExec());
222
223 int r1{rani(100)}, r2{rani(200)}, r3{rani(300)};
224 command1::check_ = 0; // commands will add to this on invocation
225
226 c11.bind (r1);
227 CHECK (c12.canExec());
228 CHECK (c11.canExec());
229
230 Command c2 = iManager.getInstance (i2);
231 CHECK (c2 != c11);
232 CHECK (c2 != c12);
233 c2.bind (r2);
234
235 CHECK (iManager.contains (i1));
236 CHECK (iManager.contains (i2));
237 CHECK (not fixture.contains (c11));
238 CHECK (not fixture.contains (c12));
239 CHECK (not fixture.contains (c2));
240
241 iManager.dispatch (i1);
242 CHECK (not iManager.contains (i1));
243 CHECK ( iManager.contains (i2));
244 CHECK ( fixture.contains (c11));
245 CHECK ( fixture.contains (c12));
246 CHECK (not fixture.contains (c2));
247
248 CHECK (command1::check_ == 0);
249
250 Symbol i11 = iManager.newInstance (COMMAND_PROTOTYPE, "i1");
251 CHECK (i11 == i1);
252 CHECK (CStr(i11) == CStr(i1));
253
254 // but the instances themselves are disjoint
255 Command c13 = iManager.getInstance (i1);
256 CHECK (c13 != c11);
257 CHECK (c13 != c12);
258 CHECK (c11.canExec());
259 CHECK (not c13.canExec());
260
261 c13.bind (r3);
262 CHECK (c13.canExec());
263
264 CHECK (command1::check_ == 0);
265 c12();
267
268 // even a command still in instance manager can be invoked
269 c2();
271
272 CHECK ( iManager.contains (i1));
273 CHECK ( iManager.contains (i2));
274 CHECK ( fixture.contains (c11));
275 CHECK ( fixture.contains (c12));
276 CHECK (not fixture.contains (c2));
277
278 iManager.dispatch (i2);
279 iManager.dispatch (i11);
280 CHECK (not iManager.contains (i1));
281 CHECK (not iManager.contains (i2));
282 CHECK ( fixture.contains (c11));
283 CHECK ( fixture.contains (c12));
284 CHECK ( fixture.contains (c13));
285 CHECK ( fixture.contains (c2));
286
287 // if we continue to hold onto an instance,
288 // we can do anything with it. Like re-binding arguments.
289 c2.bind (47);
290 c2();
291 c13();
292 c13();
293 CHECK (command1::check_ == 0+r1+r2+47+r3+r3);
294
295 c11.undo();
296 CHECK (command1::check_ == 0);
297 c2.undo();
298 CHECK (command1::check_ == 0+r1+r2); // undo() restores the value captured before second invocation of c2()
299 c12.undo(); // c11 and c12 refer to the same instance, which was invoked first
300 CHECK (command1::check_ == 0);
301 }
302
303
310 void
312 {
313 Fixture fixture;
315 Symbol i1 = iManager.newInstance (COMMAND_PROTOTYPE, "i1");
316 Symbol i2 = iManager.newInstance (COMMAND_PROTOTYPE, "i2");
317
318 VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i1"));
319 VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i2"));
320
321 iManager.bindAndDispatch (i1, {-1}); // bind and dispatch i1, thus i1 is ready for new cycle
322
323 iManager.newInstance (COMMAND_PROTOTYPE, "i1"); // open new cycle for i1
324 VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i2"));
325
326 CHECK (iManager.getInstance (i1));
327 CHECK (iManager.getInstance (i2));
328 }
329
330
338 void
340 {
341 Fixture fixture;
343
344 // a manually constructed ID is unknown of course
345 Symbol instanceID{COMMAND_PROTOTYPE, INVOCATION_ID};
346 VERIFY_ERROR (INVALID_COMMAND, iManager.getInstance (instanceID));
347 VERIFY_ERROR (INVALID_COMMAND, iManager.dispatch (instanceID));
348
349 Symbol i2 = iManager.newInstance (COMMAND_PROTOTYPE, INVOCATION_ID);
350 CHECK (i2 == instanceID);
351 CHECK (iManager.getInstance (instanceID));
352
353
354 Command cmd = iManager.getInstance (instanceID);
355 CHECK (cmd);
356 CHECK (not cmd.canExec());
357
358 VERIFY_ERROR (UNBOUND_ARGUMENTS, iManager.dispatch (instanceID));
359 VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, INVOCATION_ID));
360 CHECK (iManager.contains (instanceID)); // errors have not messed up anything
361
362 cmd.bind(23);
363 CHECK (cmd.canExec());
364 iManager.dispatch (instanceID);
365
366 CHECK (not iManager.contains (instanceID));
367 VERIFY_ERROR (LIFECYCLE, iManager.getInstance (instanceID));
368 VERIFY_ERROR (LIFECYCLE, iManager.dispatch (instanceID));
369 CHECK (instanceID == iManager.newInstance (COMMAND_PROTOTYPE, INVOCATION_ID));
370 }
371
372
375 void
377 {
378 Fixture fixture;
380
381 CHECK (not iManager.contains (COMMAND_PROTOTYPE));
382 Command cmd = iManager.getInstance (COMMAND_PROTOTYPE);
383
384 CHECK (cmd.isValid());
385 CHECK (not cmd.isAnonymous());
386 CHECK (cmd == Command::get(COMMAND_PROTOTYPE));
387 CHECK (cmd == Command{COMMAND_PROTOTYPE});
388
389 cmd.bind(-12);
390 CHECK (cmd.canExec());
391 CHECK (not fixture.contains(cmd));
392
393 iManager.dispatch (COMMAND_PROTOTYPE);
394 CHECK (fixture.contains(cmd)); // an equivalent clone was enqueued
395
397 fixture.invokeAll();
398 CHECK (command1::check_ == -12); // the clone copy was executed
399
400 // clean-up: we have bound arguments on the global prototype
401 cmd.unbind();
402 }
403 };
404
405
408
409
410}}} // namespace steam::control::test
Inline string literal.
Definition symbol.hpp:78
Token or Atom with distinct identity.
Definition symbol.hpp:120
Interface of a service to perform Commands on the session.
Maintain a current command instance for parametrisation.
Handle object representing a single Command instance to be used by client code.
Definition command.hpp:120
static Command get(Symbol cmdID)
Access existing command for use.
Definition command.cpp:120
A front-end for using printf-style formatting.
Service to support forming and invocation of command instances for use by the UI.
#define LERR_(_NAME_)
Definition error.hpp:45
const char * CStr
Definition error.hpp:42
Automatically use custom string conversion in C++ stream output.
Front-end for printf-style string template interpolation.
Conveniently iterable stack and queue containers.
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
int64_t check_
< test command just adding a given value
CommandSetup test_Dummy_command1
test dummy command to add the argument to a global variable
Steam-Layer implementation namespace root.
Test runner and basic definitions for tests.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Some dummy command functions used for building unit test cases.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...