Lumiera  0.pre.03
»edit your freedom«
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) Lumiera.org
5  2017, 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 "steam/cmd.hpp"
31 #include "lib/format-string.hpp"
32 #include "lib/format-cout.hpp"
33 #include "lib/util.hpp"
34 
35 #include <string>
36 #include <regex>
37 
38 
39 namespace steam {
40 namespace cmd {
41 namespace test {
42 
43  using lib::Literal;
44  using std::string;
45  using std::regex;
46  using std::regex_replace;
47  using util::isnil;
48  using util::_Fmt;
49 
50 
51 
52 
53 
54  namespace { // Test fixture....
55 
57  string testString;
58 
59 
60  void
61  do_something_pointless (CommandDef&)
62  {
63  testString = "Ichthyostega wuz here";
64  }
65 
66 
67  void
68  operate (string search, string replace)
69  {
70  testString = regex_replace (testString, regex(search), replace);
71  }
72 
73  string
74  capture (string, string)
75  {
76  return testString;
77  }
78 
79  void
80  undoIt (string, string, string oldVal)
81  {
82  testString = oldVal;
83  }
84 
85 
86  /* ==== prepare a dummy command definition ==== */
87 
88  COMMAND_DEFINITION (test_CommandSetup_test)
89  {
90  def.operation(operate)
91  .captureUndo(capture)
92  .undoOperation(undoIt);
93  };
94  }
95 
96 
97 
98  /***********************************************************************/
106  class CommandSetup_test : public Test
107  {
108 
109  virtual void
110  run (Arg)
111  {
115  }
116 
117 
119  void
121  {
122  // can be created from arbitrary character literal
123  CommandSetup def_empty{"to be or not to be"};
124 
125  // at runtime it is nothing but a dressed-up C-string
126  Literal empty_text = def_empty;
127  CHECK (empty_text == "to be or not to be");
128  CHECK (sizeof(def_empty) == sizeof(Literal));
129  CHECK (sizeof(def_empty) == sizeof(char*));
130 
131  const char* actualContent = reinterpret_cast<char*&>(def_empty);
132  CHECK (actualContent == empty_text);
133 
134  // for convenience a string conversion is provided...
135  CHECK (string(def_empty) == string(empty_text));
136 
137  // can be equality compared based on sting (ID) content
138  CHECK (def_empty == CommandSetup("to be or not to be"));
139  CHECK (def_empty != CommandSetup("to pee or not to pee"));
140 
142 // def_empty = CommandSetup{"to peel whatever"};
143 
144 
145  // add actual definition closures...
146  CommandSetup def_0{"test.CommandSetup.def_0"};
147  CHECK (CommandSetup::pendingCnt() == 0);
148 
149  def_0 = do_something_pointless;
150  CHECK (CommandSetup::pendingCnt() == 1);
151 
152 
153  CommandSetup def_1 = CommandSetup{"test.CommandSetup.def_1"}
154  = [](CommandDef& def)
155  {
156  def.operation (operate)
157  .captureUndo (capture)
158  .undoOperation (undoIt);
159  };
160 
161  CommandSetup def_2 = CommandSetup{"test.CommandSetup.def_2"}
162  = [&](CommandDef& def) // NOTE: we capture context by reference
163  {
164  def.operation ([&](uint cnt)
165  {
166  testString += pattern % cnt; // NOTE: capture the field 'pattern' of the enclosing class
167  })
168  .captureUndo ([](uint) -> string
169  {
170  return testString;
171  })
172  .undoOperation ([](uint, string oldVal)
173  {
174  testString = oldVal;
175  });
176  };
177  }
178  _Fmt pattern{" %d times."};
179 
180 
181 
183  void
185  {
186  CHECK (isnil (testString));
187 
189  CHECK (CommandSetup::pendingCnt() == 0);
190  CHECK (testString == "Ichthyostega wuz here");
191 
192  // the closure for the first entry did "something pointless",
193  // but it actually did not define a command entry, thus...
194  CHECK (not Command::defined("test.CommandSetup.def_0"));
195 
196  // but the other two entries did indeed define commands
197  CHECK (Command::defined("test.CommandSetup.def_1"));
198  CHECK (Command::defined("test.CommandSetup.def_2"));
199 
200  // ...and they defined the commands as specified
201  Command com1{"test.CommandSetup.def_1"};
202  Command com2{"test.CommandSetup.def_2"};
203 
204  com1.bind (string{"^(\\w+)"}, string{"No $1"});
205  com2.bind (uint(42));
206 
207  CHECK (testString == "Ichthyostega wuz here");
208  com1();
209  CHECK (testString == "No Ichthyostega wuz here");
210 
211  com2();
212  CHECK (testString == "No Ichthyostega wuz here 42 times.");
213 
214  com1.undo();
215  CHECK (testString == "Ichthyostega wuz here");
216  }
217 
218 
235  void
237  {
238  Command{test_CommandSetup_test}
239  .storeDef("c1")
240  .storeDef("c2");
241 
242  Command c1{"c1"}, c2{"c2"};
243  CHECK (not c1.canExec());
244  CHECK (not c2.canExec());
245 
246  c1.bind (string{"wuz.*"}, string{"the Devonian"});
247  c2.bind (string{"\\s*\\w+$"}, string{""});
248  CHECK (c1.canExec());
249  CHECK (c2.canExec());
250  CHECK (not Command::canExec(test_CommandSetup_test));
251 
252  CHECK (testString == "Ichthyostega wuz here");
253 
254  c1();
255  CHECK (testString == "Ichthyostega the Devonian");
256 
257  c2();
258  CHECK (testString == "Ichthyostega the");
259 
260  c2();
261  CHECK (testString == "Ichthyostega");
262 
263  c2();
264  CHECK (testString == "");
265 
266  c1.undo();
267  CHECK (testString == "Ichthyostega wuz here");
268 
269  Command::remove("c1");
270  Command::remove("c2");
271 
272  CHECK (not Command::defined("c1"));
273  CHECK (not Command::defined("c2"));
274  CHECK (Command::defined(test_CommandSetup_test));
275  }
276  };
277 
278 
280  LAUNCHER (CommandSetup_test, "unit controller");
281 
282 
283 }}} // 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:49
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
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:192
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
Simple 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:124
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.