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