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