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) 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 steam {
39 namespace control {
40 namespace test {
41 
42  using util::isSameObject;
43  using util::contains;
44  using LERR_(INVALID_COMMAND);
45  using LERR_(DUPLICATE_COMMAND);
46  using LERR_(UNBOUND_ARGUMENTS);
47  using LERR_(INVALID_ARGUMENTS);
48 
49 
50 
51 
52  /***********************************************************************/
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();
76  statePredicates();
77  definePrototype();
78  usePrototype();
79  preventDuplicates();
80  stringRepresentation();
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
90  allInOneStep()
91  {
92 
93  CommandDef ("test.command1.1")
94  .operation (command1::operate)
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
109  standardUse()
110  {
111  {
112  CommandDef ("test.command1.2")
113  .operation (command1::operate)
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
148  statePredicates()
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 
156  def.operation (command1::operate)
157  .captureUndo (command1::capture);
158  CHECK (!def); // undo functor still missing
159  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") );
160 
161  def.operation (command1::operate)
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
200  definePrototype()
201  {
202  CommandDef ("test.command1.3")
203  .operation (command1::operate)
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
214  usePrototype()
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 
238  c2();
239  CHECK (randVal + randVal == command1::check_);
240  CHECK (c2.canUndo());
241  CHECK (c1 != c2);
242 
243  c1.undo();
244  CHECK (0 == command1::check_);
245  c2.undo();
246  CHECK (randVal == command1::check_);
247 
248  c2.bind(23);
249  c2();
250  CHECK (randVal + 23 == command1::check_);
251 
252  // you should not use a command more than once (but it works...)
253  c1();
254  CHECK (randVal + 23 + randVal == command1::check_);
255  c1.undo();
256  CHECK (randVal + 23 == command1::check_);
257  // note we've overwritten the previous undo state
258  // and get the sate captured on the second invocation
259 
260  c2.undo();
261  CHECK (randVal == command1::check_);
262  c1.undo();
263  CHECK (randVal + 23 == command1::check_);
264 
265  // use the current sate of c2 as Prototype for new command definition
266  c2.storeDef ("test.command1.4");
267  Command c4 = Command::get("test.command1.4");
268  CHECK (c4);
269  CHECK (c4.canExec());
270  CHECK (c4.canUndo());
271  CHECK (not c4.isAnonymous());
272  CHECK ( c2.isAnonymous());
273  CHECK (c4 != c2); // note: it was stored as independent clone copy
274  CHECK (c4 != c1);
275  c4();
276  CHECK (c4 != c2); // now lives independently from the original
277  CHECK (randVal + 2*23 == command1::check_);
278 
279  c4.bind(int(-command1::check_)); // new command argument binding
280  c4();
281  CHECK (0 == command1::check_);
282  c2();
283  CHECK (23 == command1::check_);
284  c2.undo();
285  CHECK (0 == command1::check_);
286 
287  // remove argument bindings per instance and return to pristine state
288  c4.unbind();
289  CHECK (c2.canExec());
290  CHECK (c2.canUndo());
291  CHECK (not c4.canExec());
292  CHECK (not c4.canUndo());
293  }
294 
295 
296  void
297  preventDuplicates()
298  {
299  #define BUILD_NEW_COMMAND_DEF(_ID_) \
300  CommandDef (_ID_) \
301  .operation (command1::operate) \
302  .captureUndo (command1::capture) \
303  .undoOperation (command1::undoIt)
304 
305  CHECK (CommandDef ("test.command1.1"));
306  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.1") );
307  CHECK (CommandDef ("test.command1.2"));
308  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.2") );
309  CHECK (CommandDef ("test.command1.3"));
310  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.3") );
311  CHECK (CommandDef ("test.command1.4"));
312  VERIFY_ERROR (DUPLICATE_COMMAND, BUILD_NEW_COMMAND_DEF ("test.command1.4") );
313  }
314 
315 
316  void
317  stringRepresentation()
318  {
319  cout << Command::get("test.command1.1") << endl;
320  cout << Command::get("test.command1.2") << endl;
321  cout << Command::get("test.command1.3") << endl;
322  cout << Command::get("test.command1.4") << endl;
323  cout << Command() << endl;
324 
325  Command com
326  = CommandDef ("test.command1.5")
327  .operation (command1::operate)
328  .captureUndo (command1::capture)
329  .undoOperation (command1::undoIt);
330 
331  cout << com << endl;
332  com.bind(123);
333  cout << com << endl;
334  com();
335  cout << com << endl;
336  com.undo();
337  cout << com << endl;
338  }
339 
340 
341  void
342  undef()
343  {
344  CHECK (CommandDef ("test.command1.1"));
345  CHECK (CommandDef ("test.command1.2"));
346  CHECK (CommandDef ("test.command1.3"));
347  CHECK (CommandDef ("test.command1.4"));
348 
349  CHECK (Command::get("test.command1.1"));
350  CHECK (Command::get("test.command1.2"));
351  CHECK (Command::get("test.command1.3"));
352  CHECK (Command::get("test.command1.4"));
353 
354  VERIFY_ERROR (INVALID_COMMAND, Command::get("miracle"));
355  VERIFY_ERROR (INVALID_COMMAND, invoke ("miracle") (1,2,3));
356 
357  CommandDef unbelievable ("miracle");
358  CHECK (!unbelievable);
359 
360  Command miracle;
361  // but because the miracle isn't yet defined, any use throws
362  VERIFY_ERROR (INVALID_COMMAND, miracle.bind("abracadabra"));
363  VERIFY_ERROR (INVALID_COMMAND, miracle.execSync());
364  VERIFY_ERROR (INVALID_COMMAND, miracle.undo());
365  VERIFY_ERROR (INVALID_COMMAND, miracle());
366  CHECK (!miracle.canExec());
367  CHECK (!miracle.canUndo());
368  CHECK (!miracle);
369 
370  Command c5 (Command::get("test.command1.5"));
371 
372  CHECK (Command::remove("test.command1.1"));
373  CHECK (Command::remove("test.command1.2"));
374  CHECK (Command::remove("test.command1.3"));
375  CHECK (Command::remove("test.command1.4"));
376  CHECK (Command::remove("test.command1.5"));
377 
378  CHECK (!Command::remove("miracle")); // there is no such thing...
379 
380  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.1"));
381  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2"));
382  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.3"));
383  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.4"));
384  VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.5"));
385  VERIFY_ERROR (INVALID_COMMAND, Command::get("miracle"));
386 
387 
388  // note, removed the registered definitions,
389  // but existing instances remain valid...
390  // thus we're free to create new instances...
391  CHECK (c5.isValid());
392  CHECK (c5.canExec());
393  }
394  };
395 
396 
397 
399  LAUNCHER (CommandUse1_test, "function controller");
400 
401 
402 }}} // 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:298
Definition: run.hpp:49
Command newInstance() const
create independent (anonymous) clone copy of this command
Definition: command.cpp:209
#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:129
Steam-Layer implementation namespace root.
static size_t instance_count()
Definition: command.cpp:307
Command & unbind()
discard any argument data previously bound.
Definition: command.cpp:288
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.
ExecResult execSync()
invoke using a default "synchronous" execution pattern
Definition: command.cpp:459
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:124
RET bind()
Accept dummy binding (0 Arg)
bool isAnonymous() const
Definition: command.cpp:388
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, bypassing any custom comparison operators.
Definition: util.hpp:372