Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
mock-elm.hpp
Go to the documentation of this file.
1/*
2 MOCK-ELM.hpp - generic mock UI element for unit testing
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
14
50#ifndef STAGE_TEST_MOCK_ELM_H
51#define STAGE_TEST_MOCK_ELM_H
52
53
54#include "lib/error.hpp"
58#include "lib/diff/record.hpp"
59#include "lib/idi/genfunc.hpp"
60#include "test/test-nexus.hpp"
62#include "lib/format-cout.hpp"
63#include "lib/symbol.hpp"
64#include "lib/util.hpp"
65
66#include <string>
67#include <memory>
68#include <vector>
69#include <map>
70
71
72namespace stage {
75
76namespace test{
77
78
80 using util::isnil;
81 using lib::Symbol;
82 using std::string;
83
84 class MockElm;
85 using PMockElm = std::unique_ptr<MockElm>;
86
87
99 class MockElm
101 {
103
105
106 bool virgin_{true};
107 bool expanded_{false};
108
109 string message_;
110 string error_;
111
112
113
114 /* ==== Tangible interface ==== */
115
116 virtual bool
117 doReset() override
118 {
119 log_.call(this->identify(), string{MARK_reset});
120 if (virgin_)
121 return false; // there was nothing to reset
122
123 error_ = "";
124 message_ = "";
125 expanded_ = false;
126 virgin_ = true;
127 log_.event(string{MARK_reset});
128 return true; // we did indeed reset something
129 } // and thus a state mark should be captured
130
131 virtual bool
132 doExpand (bool yes) override
133 {
134 log_.call(this->identify(), string{MARK_expand}, yes);
135 return Tangible::doExpand (yes);
136 }
137
138 virtual void
139 doReveal() override
140 {
141 log_.call(this->identify(), string{MARK_reveal});
142 Tangible::doReveal(); // NOTE: without specific configuration this is NOP
143 }
144
145 virtual bool
146 doMsg (string text) override
147 {
148 log_.call (this->identify(), "doMsg", text);
149 cout << this->identify() << " <-- Message(\""<<text<<"\")" <<endl;
150 message_ = text;
151 virgin_ = false;
152 log_.note ("type=mark", "ID=Message", text);
153
154 return false; // messages not sticky for this mock implementation
155 }
156
157 virtual bool
158 doClearMsg () override
159 {
160 log_.call (this->identify(), "doClearMsg");
161 if (isnil (message_))
162 return false;
163
164 message_ = "";
165 log_.note ("type=mark", "ID=Message", "Message notification cleared");
166 return true;
167 }
168
169 virtual bool
170 doErr (string text) override
171 {
172 log_.call (this->identify(), "doErr", text);
173 cerr << this->identify() << " <-- Error(\""<<text<<"\")" <<endl;
174 error_ = text;
175 virgin_ = false;
176 log_.note ("type=mark", "ID=Error", text);
177
178 return true; // error states are sticky for this mock implementation
179 }
180
181 virtual bool
182 doClearErr () override
183 {
184 log_.call (this->identify(), "doClearErr");
185 if (not isError())
186 return false;
187
188 error_ = "";
189 log_.note ("type=mark", "ID=Error", "Error state cleared");
190 return true;
191 }
192
193 virtual void
194 doFlash() override
195 {
196 log_.call (this->identify(), "doFlash");
197 cout << this->identify() << " <-- Flash!" <<endl;
198 log_.note ("type=mark", "ID=Flash");
199 }
200
201 virtual void
202 doMark (GenNode const& mark) override
203 {
204 log_.call (this->identify(), "doMark", mark);
205 cout << this->identify() << " <-- state-mark = "<< mark <<endl;
206 log_.note ("type=mark", "ID="+mark.idi.getSym(), mark);
207
208 this->virgin_ = false; // assume state change....
209
210 // forward to default handler
211 Tangible::doMark (mark);
212 }
213
214 virtual void
216 {
217 using Attrib = std::pair<const string,string>;
218 using lib::diff::collection;
219 using lib::diff::render;
220
221 log_.call (this->identify(), "buildMutator");
222 cout << this->identify() << " <-- DIFF" <<endl;
223
224 buffer.emplace(
226 .attach (collection(scope)
227 .isApplicableIf ([&](GenNode const& spec) -> bool
228 {
229 return spec.data.isNested(); // »Selector« : require object-like sub scope
230 })
231 .matchElement ([&](GenNode const& spec, PMockElm const& elm) -> bool
232 {
233 return spec.idi == elm->getID();
234 })
235 .constructFrom ([&](GenNode const& spec) -> PMockElm
236 {
237 log_.event("diff", "create child \""+spec.idi.getSym()+"\"");
238 PMockElm child = std::make_unique<MockElm>(spec.idi, this->uiBus_);
239 child->joinLog(*this); // create a child element wired via this Element's BusTerm
240 return child;
241 })
242 .buildChildMutator ([&](PMockElm& target, GenNode::ID const& subID, TreeMutator::Handle buff) -> bool
243 {
244 if (target->getID() != subID) return false; //require match on already existing child object
245 target->buildMutator (buff); // delegate to child to build nested TreeMutator
246 log_.event("diff", ">>Scope>> "+subID.getSym());
247 return true;
248 }))
249 .attach (collection(attrib)
250 .isApplicableIf ([&](GenNode const& spec) -> bool
251 {
252 return spec.isNamed() // »Selector« : accept attribute-like values
253 and not spec.data.isNested(); // but no nested objects
254 })
255 .matchElement ([&](GenNode const& spec, Attrib const& elm) -> bool
256 {
257 return elm.first == spec.idi.getSym();
258 })
259 .constructFrom ([&](GenNode const& spec) -> Attrib
260 {
261 string key{spec.idi.getSym()},
262 val{render(spec.data)};
263 log_.event("diff", "++Attrib++ "+key+" = "+val);
264 return {key, val};
265 })
266 .assignElement ([&](Attrib& target, GenNode const& spec) -> bool
267 {
268 string key{spec.idi.getSym()},
269 newVal{render (spec.data)};
270 log_.event("diff", "set Attrib "+key+" <-"+newVal);
271 target.second = newVal;
272 return true;
273 })));
274
275 log_.event ("diff", getID().getSym() +" accepts mutation...");
276 }
277
278
279 protected:
280 string
281 identify() const
282 {
283 return getID().getSym() +"."+ lib::idi::instanceTypeID(this);
284 }
285
286
287 public:
288 explicit
289 MockElm(string id)
290 : MockElm(lib::idi::EntryID<MockElm>(id))
291 { }
292
293 explicit
295 : stage::model::Tangible(identity, nexus)
296 {
297 log_.call (this->identify(), "ctor", identity, string(nexus));
298 log_.create (getID().getSym());
299 installExpander ([&](){ return this->expanded_; }
300 ,[&](bool yes)
301 {
302 virgin_ = false;
303 expanded_ = yes;
304 log_.event (expanded_? "expanded" : "collapsed");
305 });
306 }
307
308
311 {
312 try {
313 log_.call (this->identify(), "dtor");
314 log_.destroy (getID().getSym());
315 }
316 catch(...)
317 {
318 CStr errID = lumiera_error();
319 if (errID)
320 cerr << "Error while logging shutdown of Mock-UI-Element: " << errID <<endl;
321 else
322 cerr << "Unknown Error while logging shutdown of Mock-UI-Element." <<endl;
323 }
324 }
325
326
327
328
329 /* ==== special operations API ==== */
330
339 void
341 {
342 log_.call (this->identify(), "kill");
343 log_.destroy (getID().getSym());
344
346 log_.event (string(getID()) + " successfully connected to zombie bus");
347 }
348
349
350
351
352 /* ==== Attributes and mock children ==== */
353
354 std::map<string, string> attrib;
355 std::vector<PMockElm> scope;
356
357
358 /* ==== Query/Verification API ==== */
359
360 ID getID() const
361 {
362 return uiBus_.getID();
363 }
364
365 bool
366 isTouched() const
367 {
368 return not virgin_;
369 }
370
371 bool
373 {
374 return expanded_;
375 }
376
377 bool
378 isError() const
379 {
380 return not isnil(error_);
381 }
382
383 string
385 {
386 return message_;
387 }
388
389 string
390 getError() const
391 {
392 return error_;
393 }
394
395
396
398 verify (string match) const
399 {
400 return getLog().verify(match);
401 }
402
404 verifyMatch (string regExp) const
405 {
406 return getLog().verifyMatch(regExp);
407 }
408
410 verifyEvent (string match) const
411 {
412 return getLog().verifyEvent(match);
413 }
414
416 verifyEvent (string classifier, string match) const
417 {
418 return getLog().verifyEvent (classifier,match);
419 }
420
422 verifyCall (string match) const
423 {
424 return getLog().verifyCall(match);
425 }
426
428 ensureNot (string match) const
429 {
430 return getLog().ensureNot(match);
431 }
432
435 verifyMark (string id) const
436 {
437 return getLog().verify(id).type("mark").id(id);
438 }
439
445 verifyMark (string id, string payloadMatch) const
446 {
447 return getLog().verifyEvent("mark", payloadMatch).type("mark").id(id);
448 }
449
450 template<typename X>
452 verifyMark (string id, X const& something) const
453 {
454 return getLog().verifyEvent("mark", something).type("mark").id(id);
455 }
456
457
458 EventLog const&
459 getLog() const
460 {
461 return log_;
462 }
463
464 EventLog&
465 joinLog (MockElm& otherMock)
466 {
467 log_.joinInto (otherMock.log_);
468 return log_;
469 }
470
471 EventLog&
472 joinLog (EventLog& otherLog)
473 {
474 log_.joinInto (otherLog);
475 return log_;
476 }
477 };
478
479
480
481}} // namespace stage::test
482#endif /*STAGE_TEST_MOCK_ELM_H*/
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
Token or Atom with distinct identity.
Definition symbol.hpp:120
bool isNested() const
determine if payload constitutes a nested scope ("object")
Definition gen-node.hpp:769
Customisable intermediary to abstract mutating operations on arbitrary, hierarchical object-like data...
static Builder< TreeMutator > build()
DSL: start building a custom adapted tree mutator, where the operations are tied by closures or wrapp...
string const & getSym() const
Definition entry-id.hpp:169
Helper to log and verify the occurrence of events.
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.
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.
EventMatch & type(string typeID)
refine filter to additionally require a matching log entry type
EventMatch & id(string classifier)
refine filter to additionally match on the ID attribute
connection point at the UI-Bus.
Definition bus-term.hpp:98
Interface common to all UI elements of relevance for the Lumiera application.
Definition tangible.hpp:160
Tangible(ID identity, ctrl::BusTerm &nexus)
Definition tangible.hpp:174
void installExpander(Expander::ProbeFun, Expander::ChangeFun)
Configure the (optional) functionality to expand or collapse the UI-Element.
Definition tangible.hpp:273
ctrl::BusTerm::ID ID
Definition tangible.hpp:162
void mark(GenNode const &)
generic handler for all incoming "state mark" messages
Definition tangible.cpp:251
ctrl::BusTerm uiBus_
Definition tangible.hpp:168
Mock UI element or controller.
Definition mock-elm.hpp:101
bool isError() const
Definition mock-elm.hpp:378
virtual bool doClearErr() override
Definition mock-elm.hpp:182
virtual bool doReset() override
Definition mock-elm.hpp:117
virtual bool doMsg(string text) override
Definition mock-elm.hpp:146
virtual void doReveal() override
generic default implementation of the "reveal" functionality.
Definition mock-elm.hpp:139
virtual void doMark(GenNode const &mark) override
default implementation and catch-all handler for receiving »state mark« messages.
Definition mock-elm.hpp:202
string identify() const
Definition mock-elm.hpp:281
string getMessage() const
Definition mock-elm.hpp:384
virtual void doFlash() override
Definition mock-elm.hpp:194
EventMatch verifyEvent(string classifier, string match) const
Definition mock-elm.hpp:416
MockElm(ID identity, ctrl::BusTerm &nexus=Nexus::testUI())
Definition mock-elm.hpp:294
string getError() const
Definition mock-elm.hpp:390
EventMatch verifyMark(string id) const
special verification match on a "state mark" message to this element
Definition mock-elm.hpp:435
EventMatch verifyMark(string id, string payloadMatch) const
verification match on a specific "state mark" message
Definition mock-elm.hpp:445
~MockElm()
document our death in the diagnostic log.
Definition mock-elm.hpp:310
EventLog const & getLog() const
Definition mock-elm.hpp:459
virtual bool doExpand(bool yes) override
generic default implementation of the expand/collapse functionality.
Definition mock-elm.hpp:132
EventMatch verify(string match) const
Definition mock-elm.hpp:398
bool isExpanded() const
Definition mock-elm.hpp:372
virtual void buildMutator(TreeMutator::Handle buffer) override
build a custom implementation of the TreeMutator interface, suitably wired to cause appropriate chang...
Definition mock-elm.hpp:215
std::map< string, string > attrib
Definition mock-elm.hpp:354
std::vector< PMockElm > scope
Definition mock-elm.hpp:355
void kill()
commit suicide.
Definition mock-elm.hpp:340
EventMatch verifyCall(string match) const
Definition mock-elm.hpp:422
EventMatch verifyEvent(string match) const
Definition mock-elm.hpp:410
virtual bool doClearMsg() override
Definition mock-elm.hpp:158
EventMatch verifyMatch(string regExp) const
Definition mock-elm.hpp:404
EventLog & joinLog(EventLog &otherLog)
Definition mock-elm.hpp:472
bool isTouched() const
Definition mock-elm.hpp:366
EventMatch verifyMark(string id, X const &something) const
Definition mock-elm.hpp:452
EventMatch ensureNot(string match) const
Definition mock-elm.hpp:428
EventLog & joinLog(MockElm &otherMock)
Definition mock-elm.hpp:465
virtual bool doErr(string text) override
Definition mock-elm.hpp:170
static ctrl::BusTerm & testUI()
get a connection point to a UI backbone faked for test
static void zombificate(ctrl::BusTerm &)
kill the given [BusTerm] and implant a dead terminal in place
lumiera_err lumiera_error(void)
Get and clear current error state.
Lumiera error handling (C++ interface).
const char * CStr
Definition error.hpp:42
Support for verifying the occurrence of events from unit tests.
Automatically use custom string conversion in C++ stream output.
Generic functions to build identification schemes.
string instanceTypeID(const TY *const obj)
designation of an distinct object instance
Definition genfunc.hpp:116
Implementation namespace for support and library code.
std::unique_ptr< MockElm > PMockElm
Definition mock-elm.hpp:85
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
const Symbol MARK_reset
const Symbol MARK_expand
const Symbol MARK_reveal
Test runner and basic definitions for tests.
bool isnil(lib::time::Duration const &dur)
Special collection to represent object-like data.
generic data element node within a tree
Definition gen-node.hpp:224
bool isNamed() const
Definition gen-node.hpp:337
Marker types to indicate a literal string and a Symbol.
Abstraction: a tangible element of the User Interface.
Diagnostic helper for unit tests regarding mutation of custom data.
A fake UI backbone for investigations and unit testing.
Hard wired key constants and basic definitions for communication with the GUI.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...