Lumiera  0.pre.03
»edit your freedom«
event-log-test.cpp
Go to the documentation of this file.
1 /*
2  EventLog(Test) - helper for event registration and verification
3 
4  Copyright (C) Lumiera.org
5  2015, 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/format-util.hpp"
30 #include "lib/test/event-log.hpp"
31 #include "lib/util.hpp"
32 
33 #include <string>
34 
35 using util::join;
36 using util::isnil;
37 
38 using std::string;
39 
40 
41 namespace lib {
42 namespace test{
43 namespace test{
44 
45 
46 
47 
48 
49  /***********************************************************/
61  class EventLog_test : public Test
62  {
63  void
64  run (Arg)
65  {
66  verify_simpleUsage();
67  verify_backwardMatch();
68  verify_negatedMatch();
70  verify_callLogging();
71  verify_eventLogging();
72  verify_genericLogging();
73  verify_regExpMatch();
74  verify_logPurging();
75  }
76 
77 
78  void
79  verify_simpleUsage ()
80  {
81  EventLog log(this);
82  CHECK (isnil (log));
83 
84  log.event("α");
85  log.event("β");
86  CHECK (!isnil(log));
87 
88  CHECK (log.verify("α"));
89  CHECK (log.verify("β"));
90  CHECK (not log.verify("γ"));
91 
92  CHECK (log.verify("α").before("β"));
93  CHECK (not log.verify("β").before("α"));
94 
95  CHECK (join(log) == "Rec(EventLogHeader| this = "+idi::instanceTypeID(this)+" ), "
96  + "Rec(event|{α}), "
97  + "Rec(event|{β})");
98  }
99 
100 
101  void
102  verify_backwardMatch ()
103  {
104  EventLog log("baked beans");
105  log.event("spam");
106  log.event("ham");
107 
108  CHECK (log.verify("ham").after("spam").after("beans"));
109  CHECK (log.verify("ham").after("beans").before("spam").before("ham"));
110  CHECK (not log.verify("spam").after("beans").after("ham"));
111 
112  log.event("beans");
113  CHECK (log.verify("beans").after("spam")); // Note: Backtracking! The first match on beans fails,
114  // only the match on second beans succeeds.
115 
116  // consecutive matches always move by at least one step
117  CHECK ( log.verify("beans").after("ham").after("spam") .after("baked"));
118  CHECK (not log.verify("beans").after("ham").after("spam").after("spam").after("baked"));
119  CHECK ( log.verify("beans").after("ham").after("spam").locate("spam").locate("spam").after("baked"));
120  } // ^^^^^^ locate re-applies at current pos without moving
121 
122 
123  void
124  verify_negatedMatch ()
125  {
126  EventLog log("eggs");
127  log.event("spam");
128  log.event("ham");
129  log.event("spam");
130 
131  CHECK (log.ensureNot("baked beans"));
132  CHECK (log.ensureNot("ham").before("eggs"));
133  CHECK (log.ensureNot("spam").after("spam").before("eggs"));
134  CHECK (not log.ensureNot("spam").before("spam").after("eggs").before("ham"));
135  }
136 
137 
149  void
151  {
152  EventLog log1("spam");
153  EventLog log2("ham");
154 
155  log1.event("baked beans");
156  log2.event("eggs");
157 
158  CHECK (log1.verify("spam").before("baked beans"));
159  CHECK (log2.verify("ham").before("eggs"));
160 
161  CHECK (log1.ensureNot("ham"));
162  CHECK (log1.ensureNot("eggs"));
163  CHECK (log2.ensureNot("spam"));
164  CHECK (log2.ensureNot("baked beans"));
165 
166  EventLog copy(log2);
167  copy.event("bacon");
168  CHECK (copy.verify("ham").before("eggs").before("bacon"));
169  CHECK (log2.verify("ham").before("eggs").before("bacon"));
170  CHECK (log1.ensureNot("bacon"));
171 
172  CHECK (log1 != log2);
173  CHECK (copy == log2);
174 
175  log2.joinInto(log1);
176 
177  CHECK (log1 == log2);
178  CHECK (copy != log2);
179 
180  CHECK (log1.verify("logJoin|{ham}").after("baked beans"));
181  CHECK (log1.verify("logJoin|{ham}").after("EventLogHeader| this = ham").before("eggs").before("bacon").before("logJoin"));
182 
183  log2.event("sausage");
184  CHECK (log1.verify("sausage").after("logJoin").after("spam"));
185 
186  CHECK (copy.ensureNot("logJoin"));
187  CHECK (copy.ensureNot("sausage"));
188  CHECK (copy.verify("joined|{spam}").after("EventLogHeader"));
189 
190  copy.event("spam tomato");
191  CHECK (log1.ensureNot("spam tomato"));
192  CHECK (log2.ensureNot("spam tomato"));
193  CHECK (copy.verify("joined|{spam}").before("spam tomato"));
194 
195 
196  CHECK (join(log1) == string(
197  "Rec(EventLogHeader| this = spam ), "
198  "Rec(event|{baked beans}), "
199  "Rec(EventLogHeader| this = ham ), "
200  "Rec(event|{eggs}), "
201  "Rec(event|{bacon}), "
202  "Rec(logJoin|{ham}), "
203  "Rec(event|{sausage})"));
204 
205  CHECK (join(copy) == string(
206  "Rec(EventLogHeader| this = ham ), "
207  "Rec(joined|{spam}), "
208  "Rec(event|{spam tomato})"));
209  }
210 
211 
212  void
213  verify_callLogging ()
214  {
215  EventLog log("funCall");
216  log.call (this, "fun1");
217  log.call ("some", "fun2");
218  log.call ("more", "fun3", "facts", 3.2,1);
219 
220  CHECK(log.verify("fun1").before("fun2").before("fun3"));
221 
222  CHECK (join(log) == string(
223  "Rec(EventLogHeader| this = funCall ), "
224  "Rec(call| fun = fun1, this = "+idi::instanceTypeID(this)+" ), "
225  "Rec(call| fun = fun2, this = some ), "
226  "Rec(call| fun = fun3, this = more |{facts, 3.2, 1})"));
227 
228  CHECK (log.verifyCall("fun1"));
229  CHECK (log.verifyCall("fun2"));
230  CHECK (log.verifyCall("fun3"));
231 
232  CHECK (log.verifyCall("fun"));
233  CHECK (log.verifyCall("fun").after("fun").after("fun"));
234  CHECK (log.ensureNot("fun").after("fun").after("fun2"));
235 
236  CHECK (log.verifyCall("fun3").arg("facts", 3.2, 1));
237  CHECK (log.verifyCall("fun3").arg(string("facts"), 3.2f, int64_t(1)));
238  CHECK (log.verifyCall("fun3").arg("facts", "3.2", "1"));
239  CHECK (log.verifyCall("fun3").argPos(0, "facts"));
240  CHECK (log.verifyCall("fun3").argPos(0, "act"));
241  CHECK (log.verifyCall("fun3").argPos(1, ".2"));
242  CHECK (log.verifyCall("fun3").argPos(1, 3.2));
243  CHECK (log.verifyCall("fun3").argPos(2, 1u));
244 
245  CHECK (log.ensureNot("fun").arg(" facts ","3.2", "1")); // the match is on the exact textual representation...
246  CHECK (log.ensureNot("fun").arg("facts", "3.20","1"));
247  CHECK (log.ensureNot("fun").arg("facts", "3.2", "1L"));
248  CHECK (log.ensureNot("fun").argPos(1, "anything")); // matches first invocation, which has no arguments
249  CHECK (log.ensureNot("fun3").argPos(3, 5555)); // the "fun3" invocation has only 3 arguments
250  CHECK (log.ensureNot("fun3").argPos(1, 3.3)); // the second argument is 2.3, not 3.3
251  CHECK (log.ensureNot("fun3").argPos(2, 5)); // the last argument is 1, not 5
252 
253  CHECK (log.verifyCall("fun1").arg());
254  CHECK (log.verifyCall("fun2").arg());
255 
256  CHECK (log.verify("fun").arg().before("fun").arg("facts", 3.2, 1));
257 
258  CHECK (log.verify("fun").on(this));
259  CHECK (log.verify("fun").on("some"));
260  CHECK (log.verify("fun").on("more"));
261  CHECK (log.verify("fun").on("more").on("more"));
262  CHECK (log.ensureNot("fun").on("some").on("more"));
263 
264  CHECK (log.verify("fun").on("some").arg());
265  CHECK (log.ensureNot("fun").arg().on("more"));
266  CHECK (log.ensureNot("fun").on("some").arg("facts", "3.2", "1"));
267  CHECK (log.verifyCall("fun").arg("facts", "3.2", "1").on("more"));
268  }
269 
270 
271  void
272  verify_eventLogging ()
273  {
274  EventLog log("event trace");
275  log.event("no","fun");
276  log.call("some","fun");
277 
278  CHECK (log.verify("fun").before("fun"));
279  CHECK (log.verify("no").before("some"));
280 
281  CHECK (log.verifyEvent("fun").beforeCall("fun").on("some"));
282  CHECK (!log.verifyEvent("fun").after("some"));
283 
284  CHECK (log.verifyEvent("no","fun"));
285  CHECK (log.verifyEvent("fun").id("no"));
286  CHECK (log.verify("no").arg("fun"));
287 
288  CHECK (join(log) == string(
289  "Rec(EventLogHeader| this = event trace ), "
290  "Rec(event| ID = no |{fun}), "
291  "Rec(call| fun = fun, this = some )"));
292  }
293 
294 
295  void
296  verify_genericLogging ()
297  {
298  EventLog log("theHog");
299  log.note ("type=some","ID=weird","stuff");
300  log.warn ("danger");
301  log.error ("horrible");
302  log.fatal ("destiny");
303  log.create ("something");
304  log.destroy ("everything");
305 
306  CHECK (log.verify("theHog")
307  .before("stuff")
308  .before("danger")
309  .before("horrible")
310  .before("destiny")
311  .before("something")
312  .before("everything"));
313  CHECK (log.verify("this").type("EventLogHeader")
314  .before("weird").type("some")
315  .before("danger").type("warn")
316  .before("horrible").type("error")
317  .before("destiny").type("fatal")
318  .before("something").type("create")
319  .before("everything").type("destroy"));
320 
321  CHECK (log.verify("some").attrib("ID","weird").arg("stuff"));
322 
323  // NOTE: there is some built-in leeway in event-matching...
324  CHECK (log.verifyEvent("horrible").beforeEvent("something").beforeEvent("everything"));
325  CHECK (!log.verifyEvent("stuff")); // not every entry type is an event by default
326  CHECK (!log.verifyEvent("danger")); // warning is not an event by default
327  CHECK (log.verifyEvent("some","stuff")); // but the classifier-param matches on the type
328  CHECK (log.verifyEvent("weird","stuff"));
329  CHECK (log.verifyEvent("warn","danger"));
330  CHECK (log.verifyEvent("fatal","destiny"));
331  CHECK (log.verifyEvent("destroy","everything"));
332 
333  CHECK (join(log) == string(
334  "Rec(EventLogHeader| this = theHog ), "
335  "Rec(some| ID = weird |{stuff}), "
336  "Rec(warn|{danger}), "
337  "Rec(error|{horrible}), "
338  "Rec(fatal|{destiny}), "
339  "Rec(create|{something}), "
340  "Rec(destroy|{everything})"));
341  }
342 
343 
344  void
345  verify_regExpMatch ()
346  {
347  EventLog log("Lovely spam!");
348  log.note ("type=spam", "egg and bacon"
349  , "egg sausage and bacon"
350  , "egg and spam"
351  , "egg bacon and spam"
352  , "egg bacon sausage and spam"
353  , "spam bacon sausage and spam"
354  , "spam egg spam spam bacon and spam"
355  , "spam sausage spam spam bacon spam tomato and spam");
356  log.fatal("Lobster Thermidor a Crevette with a mornay sauce served in a Provencale manner "
357  "with shallots and aubergines garnished with truffle pate, brandy and with a fried egg on top and spam");
358 
359  CHECK (log.verify("spam").before("(spam|").before("egg on top and spam"));
360  CHECK (log.verify("and spam").after("(spam|").after("spam!").before("bacon"));
361  CHECK (log.ensureNot("and spam").after("(spam|").after("spam!").after("bacon"));
362 
363  // RegExp on full String representation
364  CHECK (log.verifyMatch("spam.+spam"));
365  CHECK (log.verifyMatch("spam.+spam").beforeMatch("spam(?!.+spam)"));
366  CHECK (log.verifyEvent("fatal","spam").afterMatch("(spam.*){15}"));
367 
368  // Cover all arguments with sequence of regular expressions
369  CHECK (log.verify("spam").argMatch("^egg ", "^spam .+spam$"));
370  CHECK (log.verifyMatch("Rec.+fatal").afterMatch("\\{.+\\}").argMatch("bacon$","and spam$"));
371 
372  // argument match must cover all arguments...
373  CHECK (log.ensureNot("spam").argMatch("bacon|^spam"));
374  }
375 
376 
377  void
378  verify_logPurging ()
379  {
380  EventLog log("obnoxious");
381  log.create("spam").create("spam").create("spam");
382  CHECK (log.verify("spam").after("obnoxious"));
383 
384  log.clear();
385  CHECK (log.ensureNot("spam"));
386  CHECK (log.verify("obnoxious").type("EventLogHeader").on("obnoxious"));
387 
388  log.warn("eggs");
389  log.clear("unbearable");
390  CHECK (log.ensureNot("eggs"));
391  CHECK (log.ensureNot("obnoxious"));
392  CHECK (log.verify("unbearable").type("EventLogHeader").on("unbearable"));
393  }
394  };
395 
396  LAUNCHER (EventLog_test, "unit common");
397 
398 
399 }}} // namespace lib::test::test
400 
EventMatch & type(string typeID)
refine filter to additionally require a matching log entry type
Definition: event-log.cpp:548
EventLog & event(string text)
log some text as event
Definition: event-log.cpp:685
EventLog & warn(string text)
Log a warning entry.
Definition: event-log.cpp:719
Support for verifying the occurrence of events from unit tests.
Definition: run.hpp:49
EventMatch & beforeCall(string match)
find a match for some function invocation after the current point of reference
Definition: event-log.cpp:447
Helper to log and verify the occurrence of events.
Definition: event-log.hpp:284
EventMatch & beforeMatch(string regExp)
find a match with the given regular expression
Definition: event-log.cpp:404
EventLog & create(string text)
Log the creation of an object.
Definition: event-log.cpp:742
EventMatch & after(string match)
find a match (substring match) of the given text in an EventLog entry before the current position...
Definition: event-log.cpp:463
EventMatch & arg(ARGS const &...args)
refine filter to additionally require specific arguments
Definition: event-log.hpp:207
EventMatch verifyEvent(string match) const
start a query to match for some event.
Definition: event-log.cpp:779
Implementation namespace for support and library code.
EventMatch & attrib(string key, string valueMatch)
refine filter to additionally match on a specific attribute
Definition: event-log.cpp:570
EventMatch verifyCall(string match) const
start a query to match especially a function call
Definition: event-log.cpp:797
EventMatch ensureNot(string match) const
start a query to ensure the given expression does not match.
Definition: event-log.cpp:814
EventMatch & beforeEvent(string match)
find a match for an "event" after the current point of reference
Definition: event-log.cpp:426
EventLog & clear()
purge log contents while retaining just the original Header-ID
Definition: event-log.cpp:652
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
EventLog & call(string target, string function)
Log occurrence of a function call with no arguments.
Definition: event-log.cpp:699
EventLog & joinInto(EventLog &otherLog)
Merge this log into another log, forming a combined log.
Definition: event-log.cpp:634
EventMatch & argPos(size_t idx, ARG const &arg)
refine filter to additionally require match on a specific positional argument
Definition: event-log.hpp:236
EventMatch & argMatch(ARGS const &...regExps)
refine filter to additionally cover all arguments with a series of regular expressions.
Definition: event-log.hpp:226
EventMatch & id(string classifier)
refine filter to additionally match on the ID attribute
Definition: event-log.cpp:581
string instanceTypeID(const TY *const obj)
designation of an distinct object instance
Definition: genfunc.hpp:125
EventMatch & locate(string match)
basic search function: continue linear lookup over the elements of the EventLog to find a match (subs...
Definition: event-log.cpp:330
EventLog & fatal(string text)
Log a fatal failure.
Definition: event-log.cpp:733
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
EventMatch verify(string match) const
start a query to match for some substring.
Definition: event-log.cpp:761
EventLog & destroy(string text)
Log the destruction of an object.
Definition: event-log.cpp:749
EventMatch verifyMatch(string regExp) const
start a query to match with a regular expression
Definition: event-log.cpp:770
EventMatch & on(string targetID)
refine filter to additionally match the &#39;this&#39; attribute
Definition: event-log.cpp:592
EventMatch & before(string match)
find a match (substring match) of the given text in an EventLog entry after the current position ...
Definition: event-log.cpp:393
EventLog & error(string text)
Log an error note.
Definition: event-log.cpp:726