Lumiera  0.pre.03
»edit your freedom«
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
command-setup-test.cpp
Go to the documentation of this file.
1 /*
2  CommandSetup(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"
20 #include "steam/cmd.hpp"
22 #include "lib/format-string.hpp"
23 #include "lib/format-cout.hpp"
24 #include "lib/util.hpp"
25 
26 #include <string>
27 #include <regex>
28 
29 
30 namespace steam {
31 namespace cmd {
32 namespace test {
33 
34  using lib::Literal;
35  using std::string;
36  using std::regex;
37  using std::regex_replace;
38  using util::isnil;
39  using util::_Fmt;
40 
41 
42 
43 
44 
45  namespace { // Test fixture....
46 
48  string testString;
49 
50 
51  void
52  do_something_pointless (CommandDef&)
53  {
54  testString = "Ichthyostega wuz here";
55  }
56 
57 
58  void
59  operate (string search, string replace)
60  {
61  testString = regex_replace (testString, regex(search), replace);
62  }
63 
64  string
65  capture (string, string)
66  {
67  return testString;
68  }
69 
70  void
71  undoIt (string, string, string oldVal)
72  {
73  testString = oldVal;
74  }
75 
76 
77  /* ==== prepare a dummy command definition ==== */
78 
79  COMMAND_DEFINITION (test_CommandSetup_test)
80  {
81  def.operation(operate)
82  .captureUndo(capture)
83  .undoOperation(undoIt);
84  };
85  }
86 
87 
88 
89  /***********************************************************************/
97  class CommandSetup_test : public Test
98  {
99 
100  virtual void
101  run (Arg)
102  {
106  }
107 
108 
110  void
112  {
113  // can be created from arbitrary character literal
114  CommandSetup def_empty{"to be or not to be"};
115 
116  // at runtime it is nothing but a dressed-up C-string
117  Literal empty_text = def_empty;
118  CHECK (empty_text == "to be or not to be");
119  CHECK (sizeof(def_empty) == sizeof(Literal));
120  CHECK (sizeof(def_empty) == sizeof(char*));
121 
122  const char* actualContent = reinterpret_cast<char*&>(def_empty);
123  CHECK (actualContent == empty_text);
124 
125  // for convenience a string conversion is provided...
126  CHECK (string(def_empty) == string(empty_text));
127 
128  // can be equality compared based on sting (ID) content
129  CHECK (def_empty == CommandSetup("to be or not to be"));
130  CHECK (def_empty != CommandSetup("to pee or not to pee"));
131 
133 // def_empty = CommandSetup{"to peel whatever"};
134 
135 
136  // add actual definition closures...
137  CommandSetup def_0{"test.CommandSetup.def_0"};
138  CHECK (CommandSetup::pendingCnt() == 0);
139 
140  def_0 = do_something_pointless;
141  CHECK (CommandSetup::pendingCnt() == 1);
142 
143 
144  CommandSetup def_1 = CommandSetup{"test.CommandSetup.def_1"}
145  = [](CommandDef& def)
146  {
147  def.operation (operate)
148  .captureUndo (capture)
149  .undoOperation (undoIt);
150  };
151 
152  CommandSetup def_2 = CommandSetup{"test.CommandSetup.def_2"}
153  = [&](CommandDef& def) // NOTE: we capture context by reference
154  {
155  def.operation ([&](uint cnt)
156  {
157  testString += pattern % cnt; // NOTE: capture the field 'pattern' of the enclosing class
158  })
159  .captureUndo ([](uint) -> string
160  {
161  return testString;
162  })
163  .undoOperation ([](uint, string oldVal)
164  {
165  testString = oldVal;
166  });
167  };
168  }
169  _Fmt pattern{" %d times."};
170 
171 
172 
174  void
176  {
177  CHECK (isnil (testString));
178 
180  CHECK (CommandSetup::pendingCnt() == 0);
181  CHECK (testString == "Ichthyostega wuz here");
182 
183  // the closure for the first entry did "something pointless",
184  // but it actually did not define a command entry, thus...
185  CHECK (not Command::defined("test.CommandSetup.def_0"));
186 
187  // but the other two entries did indeed define commands
188  CHECK (Command::defined("test.CommandSetup.def_1"));
189  CHECK (Command::defined("test.CommandSetup.def_2"));
190 
191  // ...and they defined the commands as specified
192  Command com1{"test.CommandSetup.def_1"};
193  Command com2{"test.CommandSetup.def_2"};
194 
195  com1.bind (string{"^(\\w+)"}, string{"No $1"});
196  com2.bind (uint(42));
197 
198  CHECK (testString == "Ichthyostega wuz here");
199  com1();
200  CHECK (testString == "No Ichthyostega wuz here");
201 
202  com2();
203  CHECK (testString == "No Ichthyostega wuz here 42 times.");
204 
205  com1.undo();
206  CHECK (testString == "Ichthyostega wuz here");
207  }
208 
209 
226  void
228  {
229  Command{test_CommandSetup_test}
230  .storeDef("c1")
231  .storeDef("c2");
232 
233  Command c1{"c1"}, c2{"c2"};
234  CHECK (not c1.canExec());
235  CHECK (not c2.canExec());
236 
237  c1.bind (string{"wuz.*"}, string{"the Devonian"});
238  c2.bind (string{"\\s*\\w+$"}, string{""});
239  CHECK (c1.canExec());
240  CHECK (c2.canExec());
241  CHECK (not Command::canExec(test_CommandSetup_test));
242 
243  CHECK (testString == "Ichthyostega wuz here");
244 
245  c1();
246  CHECK (testString == "Ichthyostega the Devonian");
247 
248  c2();
249  CHECK (testString == "Ichthyostega the");
250 
251  c2();
252  CHECK (testString == "Ichthyostega");
253 
254  c2();
255  CHECK (testString == "");
256 
257  c1.undo();
258  CHECK (testString == "Ichthyostega wuz here");
259 
260  Command::remove("c1");
261  Command::remove("c2");
262 
263  CHECK (not Command::defined("c1"));
264  CHECK (not Command::defined("c2"));
265  CHECK (Command::defined(test_CommandSetup_test));
266  }
267  };
268 
269 
271  LAUNCHER (CommandSetup_test, "unit controller");
272 
273 
274 }}} // namespace steam::cmd::test
Helper class used solely for defining a Command-Object.
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:40
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
Front-end for printf-style string template interpolation.
#define COMMAND_DEFINITION(_NAME_)
Macro to write command definitions in a compact form.
Common ID definitions for Steam-Layer commands.
Command storeDef(Symbol newCmdID) const
create a clone definition
Definition: command.cpp:183
Steam-Layer implementation namespace root.
A front-end for using printf-style formatting.
Marker and Helper for writing Steam-Layer Command definitions.
static size_t pendingCnt()
diagnostics / test
Simplistic test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
static void invokeDefinitionClosures()
Handle object representing a single Command instance to be used by client code.
Definition: command.hpp:115
RET bind()
Accept dummy binding (0 Arg)
string testString
will be manipulated by the commands we define
Actually defining a command and binding it to execution parameters.