Lumiera  0.pre.03
»edit your freedom«
command-use1-test.cpp
Go to the documentation of this file.
1 /*
2  CommandUse1(Test) - usage aspects I
3 
4  Copyright (C)
5  2009, 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"
23 #include "lib/format-cout.hpp"
24 #include "lib/util.hpp"
25 
27 
28 
29 namespace steam {
30 namespace control {
31 namespace test {
32 
33  using util::isSameObject;
34  using util::contains;
35  using LERR_(INVALID_COMMAND);
36  using LERR_(DUPLICATE_COMMAND);
37  using LERR_(UNBOUND_ARGUMENTS);
38  using LERR_(INVALID_ARGUMENTS);
39 
40 
41 
42 
43  /***********************************************************************/
50  class CommandUse1_test : public Test
51  {
52 
53  int randVal;
54  int random() { return randVal = 10 + rani(40); }
55 
56 
57 
58  virtual void
59  run (Arg)
60  {
61  seedRand();
62  command1::check_ = 0;
63  uint cnt_defs = Command::definition_count();
64  uint cnt_inst = Command::instance_count();
65 
66  allInOneStep();
67  standardUse();
68  statePredicates();
69  definePrototype();
70  usePrototype();
71  preventDuplicates();
72  stringRepresentation();
73  undef();
74 
75  CHECK (0 == command1::check_);
76  CHECK (cnt_defs == Command::definition_count());
77  CHECK (cnt_inst == Command::instance_count());
78  }
79 
80 
81  void
82  allInOneStep()
83  {
84 
85  CommandDef ("test.command1.1")
86  .operation (command1::operate)
87  .captureUndo (command1::capture)
88  .undoOperation (command1::undoIt)
89  .bind (random())
90  .execSync()
91  ;
92 
93  CHECK (randVal == command1::check_);
94 
95  Command::get("test.command1.1").undo();
96  CHECK ( 0 == command1::check_);
97  }
98 
99 
100  void
101  standardUse()
102  {
103  {
104  CommandDef ("test.command1.2")
105  .operation (command1::operate)
106  .captureUndo (command1::capture)
107  .undoOperation (command1::undoIt)
108  ;
109  }
110  CHECK (CommandDef("test.command1.2"));
111 
112  Command com ("test.command1.2");
113  CHECK (com);
114  CHECK (com == Command::get("test.command1.2"));
115  CHECK (contains (string(com), "test.command1.2"));
116  CHECK (contains (string(com), "{def}"));
117  CHECK (!com.canExec());
118  VERIFY_ERROR (UNBOUND_ARGUMENTS, com() );
119  CHECK ( 0 == command1::check_);
120 
121  VERIFY_ERROR (INVALID_ARGUMENTS, com.bind ("foo") );
122  com.bind (random()); // note: run-time type check only
123  CHECK ( com.canExec());
124  CHECK (!com.canUndo());
125  com();
126  CHECK (randVal == command1::check_);
127  com.undo();
128  CHECK ( 0 == command1::check_);
129 
130  // the following shortcut does the same:
131  invoke ("test.command1.2") (1234);
132  CHECK ( 1234 == command1::check_);
133 
134  com.undo();
135  CHECK ( 0 == command1::check_);
136  }
137 
138 
139  void
140  statePredicates()
141  {
142  Command::remove("test.command1.2");
143  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") );
144 
145  CommandDef def ("test.command1.2");
146  CHECK (!def);
147 
148  def.operation (command1::operate)
149  .captureUndo (command1::capture);
150  CHECK (!def); // undo functor still missing
151  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") );
152 
153  def.operation (command1::operate)
154  .captureUndo (command1::capture)
155  .undoOperation (command1::undoIt);
156  CHECK (def);
157  CHECK (CommandDef("test.command1.2"));
158  CHECK (Command::get("test.command1.2"));
159 
160  CHECK ( Command::defined("test.command1.2"));
161  CHECK (!Command::canExec("test.command1.2"));
162  CHECK (!Command::canUndo("test.command1.2"));
163 
164  Command com = Command::get("test.command1.2");
165  CHECK (com);
166  CHECK (!com.canExec());
167  CHECK (!com.canUndo());
168 
169  com.bind (11111);
170  CHECK ( Command::defined("test.command1.2"));
171  CHECK ( Command::canExec("test.command1.2"));
172  CHECK (!Command::canUndo("test.command1.2"));
173 
174  com();
175  CHECK ( Command::defined("test.command1.2"));
176  CHECK ( Command::canExec("test.command1.2"));
177  CHECK ( Command::canUndo("test.command1.2"));
178 
179  com.undo();
180  CHECK ( Command::defined("test.command1.2"));
181  CHECK ( Command::canExec("test.command1.2"));
182  CHECK ( Command::canUndo("test.command1.2"));
183 
184  com.unbind(); // revert to pristine state
185  CHECK ( Command::defined("test.command1.2"));
186  CHECK (!Command::canExec("test.command1.2"));
187  CHECK (!Command::canUndo("test.command1.2"));
188  }
189 
190 
191  void
192  definePrototype()
193  {
194  CommandDef ("test.command1.3")
195  .operation (command1::operate)
196  .captureUndo (command1::capture)
197  .undoOperation (command1::undoIt)
198  .bind (random())
199  ;
200 
201  CHECK (Command::get("test.command1.3").canExec());
202  }
203 
204 
205  void
206  usePrototype()
207  {
208  Command c1 = Command::get("test.command1.3");
209  CHECK (c1);
210  CHECK (c1.canExec());
211  CHECK (!c1.canUndo());
212 
213  Command c2 = c1.newInstance();
214  CHECK (c2);
215  CHECK (c2.canExec());
216  CHECK (!c2.canUndo());
217  CHECK (c2.isAnonymous());
218 
219  CHECK (c1 != c2);
220  CHECK (!isSameObject(c1, c2));
221 
222  CHECK (0 == command1::check_);
223 
224  c1();
225 
226  CHECK (randVal == command1::check_);
227  CHECK ( c1.canUndo());
228  CHECK (!c2.canUndo());
229 
230  c2();
231  CHECK (randVal + randVal == command1::check_);
232  CHECK (c2.canUndo());
233  CHECK (c1 != c2);
234 
235  c1.undo();
236  CHECK (0 == command1::check_);
237  c2.undo();
238  CHECK (randVal == command1::check_);
239 
240  c2.bind(23);
241  c2();
242  CHECK (randVal + 23 == command1::check_);
243 
244  // you should not use a command more than once (but it works...)
245  c1();
246  CHECK (randVal + 23 + randVal == command1::check_);
247  c1.undo();
248  CHECK (randVal + 23 == command1::check_);
249  // note we've overwritten the previous undo state
250  // and get the sate captured on the second invocation
251 
252  c2.undo();
253  CHECK (randVal == command1::check_);
254  c1.undo();
255  CHECK (randVal + 23 == command1::check_);
256 
257  // use the current sate of c2 as Prototype for new command definition
258  c2.storeDef ("test.command1.4");
259  Command c4 = Command::get("test.command1.4");
260  CHECK (c4);
261  CHECK (c4.canExec());
262  CHECK (c4.canUndo());
263  CHECK (not c4.isAnonymous());
264  CHECK ( c2.isAnonymous());
265  CHECK (c4 != c2); // note: it was stored as independent clone copy
266  CHECK (c4 != c1);
267  c4();
268  CHECK (c4 != c2); // now lives independently from the original
269  CHECK (randVal + 2*23 == command1::check_);
270 
271  c4.bind(int(-command1::check_)); // new command argument binding
272  c4();
273  CHECK (0 == command1::check_);
274  c2();
275  CHECK (23 == command1::check_);
276  c2.undo();
277  CHECK (0 == command1::check_);
278 
279  // remove argument bindings per instance and return to pristine state
280  c4.unbind();
281  CHECK (c2.canExec());
282  CHECK (c2.canUndo());
283  CHECK (not c4.canExec());
284  CHECK (not c4.canUndo());
285  }
286 
287 
288  void
289  preventDuplicates()
290  {
291  #define BUILD_NEW_COMMAND_DEF(_ID_) \
292  CommandDef (_ID_) \
293  .operation (command1::operate) \
294  .captureUndo (command1::capture) \
295  .undoOperation (command1::undoIt)
296 
297  CHECK (CommandDef ("test.command1.1"));
298  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.1") );
299  CHECK (CommandDef ("test.command1.2"));
300  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.2") );
301  CHECK (CommandDef ("test.command1.3"));
302  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.3") );
303  CHECK (CommandDef ("test.command1.4"));
304  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.4") );
305  }
306 
307 
308  void
309  stringRepresentation()
310  {
311  cout << Command::get("test.command1.1") << endl;
312  cout << Command::get("test.command1.2") << endl;
313  cout << Command::get("test.command1.3") << endl;
314  cout << Command::get("test.command1.4") << endl;
315  cout << Command() << endl;
316 
317  Command com
318  = CommandDef ("test.command1.5")
319  .operation (command1::operate)
320  .captureUndo (command1::capture)
321  .undoOperation (command1::undoIt);
322 
323  cout << com << endl;
324  com.bind(123);
325  cout << com << endl;
326  com();
327  cout << com << endl;
328  com.undo();
329  cout << com << endl;
330  }
331 
332 
333  void
334  undef()
335  {
336  CHECK (CommandDef ("test.command1.1"));
337  CHECK (CommandDef ("test.command1.2"));
338  CHECK (CommandDef ("test.command1.3"));
339  CHECK (CommandDef ("test.command1.4"));
340 
341  CHECK (Command::get("test.command1.1"));
342  CHECK (Command::get("test.command1.2"));
343  CHECK (Command::get("test.command1.3"));
344  CHECK (Command::get("test.command1.4"));
345 
346  VERIFY_ERROR (INVALID_COMMAND, Command::get("miracle"));
347  VERIFY_ERROR (INVALID_COMMAND, invoke ("miracle") (1,2,3));
348 
349  CommandDef unbelievable ("miracle");
350  CHECK (!unbelievable);
351 
352  Command miracle;
353  // but because the miracle isn't yet defined, any use throws
354  VERIFY_ERROR (INVALID_COMMAND, miracle.bind("abracadabra"));
355  VERIFY_ERROR (INVALID_COMMAND, miracle.execSync());
356  VERIFY_ERROR (INVALID_COMMAND, miracle.undo());
357  VERIFY_ERROR (INVALID_COMMAND, miracle());
358  CHECK (!miracle.canExec());
359  CHECK (!miracle.canUndo());
360  CHECK (!miracle);
361 
362  Command c5 (Command::get("test.command1.5"));
363 
364  CHECK (Command::remove("test.command1.1"));
365  CHECK (Command::remove("test.command1.2"));
366  CHECK (Command::remove("test.command1.3"));
367  CHECK (Command::remove("test.command1.4"));
368  CHECK (Command::remove("test.command1.5"));
369 
370  CHECK (!Command::remove("miracle")); // there is no such thing...
371 
372  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.1"));
373  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2"));
374  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.3"));
375  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.4"));
376  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.5"));
377  VERIFY_ERROR (INVALID_COMMAND, Command::get("miracle"));
378 
379 
380  // note, removed the registered definitions,
381  // but existing instances remain valid...
382  // thus we're free to create new instances...
383  CHECK (c5.isValid());
384  CHECK (c5.canExec());
385  }
386  };
387 
388 
389 
391  LAUNCHER (CommandUse1_test, "function controller");
392 
393 
394 }}} // namespace steam::control::test
Some additional helpers and convenience shortcuts to ease command invocation.
Helper class used solely for defining a Command-Object.
Automatically use custom string conversion in C++ stream output.
static size_t definition_count()
Definition: command.cpp:289
Definition: run.hpp:40
int rani(uint bound=_iBOUND())
Definition: random.hpp:135
Command newInstance() const
create independent (anonymous) clone copy of this command
Definition: command.cpp:200
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
static Command get(Symbol cmdID)
Access existing command for use.
Definition: command.cpp:120
Steam-Layer implementation namespace root.
static size_t instance_count()
Definition: command.cpp:298
Command & unbind()
discard any argument data previously bound.
Definition: command.cpp:279
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.
ExecResult execSync()
invoke using a default "synchronous" execution pattern
Definition: command.cpp:450
Some dummy command functions used for building unit test cases.
Handle object representing a single Command instance to be used by client code.
Definition: command.hpp:115
RET bind()
Accept dummy binding (0 Arg)
bool isAnonymous() const
Definition: command.cpp:379
Actually defining a command and binding it to execution parameters.
bool contains(SEQ const &cont, typename SEQ::const_reference val)
shortcut for brute-force containment test in any sequential container
Definition: util.hpp:255
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