Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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"
22#include "lib/util.hpp"
23
24#include <string>
25
26using util::join;
27using util::isnil;
28
29using std::string;
30
31
32namespace lib {
33namespace test{
34namespace test{
35
36
37
38
39
40 /***********************************************************/
52 class EventLog_test : public Test
53 {
54 void
67
68
69 void
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
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
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
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
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
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
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
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
Helper to log and verify the occurrence of events.
EventLog & warn(string text)
Log a warning entry.
EventLog & destroy(string text)
Log the destruction of an object.
EventLog & event(string text)
log some text as event
EventMatch verify(string match) const
start a query to match for some substring.
EventLog & error(string text)
Log an error note.
EventLog & clear()
purge log contents while retaining just the original Header-ID
EventMatch verifyCall(string match) const
start a query to match especially a function call
EventMatch verifyEvent(string match) const
start a query to match for some event.
EventLog & joinInto(EventLog &otherLog)
Merge this log into another log, forming a combined log.
EventMatch verifyMatch(string regExp) const
start a query to match with a regular expression
EventLog & create(string text)
Log the creation of an object.
EventMatch ensureNot(string match) const
start a query to ensure the given expression does not match.
EventLog & note(ELMS const &...initialiser)
EventLog & call(string target, string function)
Log occurrence of a function call with no arguments.
EventLog & fatal(string text)
Log a fatal failure.
EventMatch & type(string typeID)
refine filter to additionally require a matching log entry type
EventMatch & beforeMatch(string regExp)
find a match with the given regular expression
EventMatch & id(string classifier)
refine filter to additionally match on the ID attribute
EventMatch & arg(ARGS const &...args)
refine filter to additionally require specific arguments
EventMatch & argMatch(ARGS const &...regExps)
refine filter to additionally cover all arguments with a series of regular expressions.
EventMatch & before(string match)
find a match (substring match) of the given text in an EventLog entry after the current position
EventMatch & beforeEvent(string match)
find a match for an "event" after the current point of reference
EventMatch & locate(string match)
basic search function: continue linear lookup over the elements of the EventLog to find a match (subs...
EventMatch & argPos(size_t idx, ARG const &arg)
refine filter to additionally require match on a specific positional argument
EventMatch & after(string match)
find a match (substring match) of the given text in an EventLog entry before the current position,...
EventMatch & attrib(string key, string valueMatch)
refine filter to additionally match on a specific attribute
EventMatch & on(string targetID)
refine filter to additionally match the ‘'this’` attribute
EventMatch & beforeCall(string match)
find a match for some function invocation after the current point of reference
EventMatch & afterMatch(string regExp)
Support for verifying the occurrence of events from unit tests.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
string instanceTypeID(const TY *const obj)
designation of an distinct object instance
Definition genfunc.hpp:116
Implementation namespace for support and library code.
Test runner and basic definitions for tests.
string join(COLL &&coll, string const &delim=", ")
enumerate a collection's contents, separated by delimiter.
bool isnil(lib::time::Duration const &dur)
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...