LUMIERA.clone/tests/gui/test/mock-elm.hpp

291 lines
7.5 KiB
C++
Raw Normal View History

/*
MOCK-ELM.hpp - generic mock UI element for unit testing
Copyright (C) Lumiera.org
2015, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file mock-elm.hpp
** A generic interface element instrumented for unit testing.
** All relevant building blocks within the Lumiera GTK UI are based on
** gui::model::Tangible, meaning that any generic effect of interface interactions
** can be expressed in terms of this interface contract. As far as the UI participates
** in interactions with the lower layers, like e.g. command invocation, structure updates
** and state notifications, these processes can be modelled and verified with the help
** of a specially prepared Tangible instance. This gui::test::MockElm provides the
** necessary instrumentation to observe what has been invoked and received.
**
** @todo initial draft and WIP-WIP-WIP as of 11/2015
**
** @see abstract-tangible-test.cpp
**
*/
#ifndef GUI_TEST_MOCK_ELM_H
#define GUI_TEST_MOCK_ELM_H
#include "lib/error.hpp"
//#include "lib/idi/entry-id.hpp"
//#include "lib/util.hpp"
#include "lib/test/event-log.hpp"
#include "gui/model/tangible.hpp"
#include "lib/diff/record.hpp"
#include "lib/idi/genfunc.hpp"
#include "test/test-nexus.hpp"
#include "lib/symbol.hpp"
#include <iostream>
#include <string>
namespace gui {
2015-11-28 21:43:09 +01:00
namespace error = lumiera::error;
using error::LUMIERA_ERROR_ASSERTION;
using lib::test::EventLog;
using lib::test::EventMatch;
2015-11-28 21:43:09 +01:00
namespace test{
2015-11-28 21:43:09 +01:00
// using lib::HashVal;
// using util::isnil;
// using lib::idi::EntryID;
// using lib::diff::Record;
using lib::Symbol;
using std::string;
using std::cout;
using std::cerr;
using std::endl;
/**
* Mock UI element or controller.
* Within Lumiera, all interface components of relevance are based
* on the [Tangible] interface, which we mock here for unit testing.
* This special implementation is instrumented to [log][lib::test::EventLog]
* any invocation and any messages sent or received through the UI Backbone,
* which is formed by the [UiBus].
*
* @todo some usage details
* @see abstract-tangible-test.cpp
*/
class MockElm
: public gui::model::Tangible
{
using _Par = gui::model::Tangible;
EventLog log_{this};
bool virgin_{true};
bool expanded_{false};
/* ==== Tangible interface ==== */
virtual void
doReset() override
2015-11-28 21:43:09 +01:00
{
log_.call(this->identify(), "reset");
expanded_ = false;
virgin_ = true;
log_.event("reset");
2015-11-28 21:43:09 +01:00
}
virtual bool
doExpand (bool yes) override
{
log_.call(this->identify(), "expand", yes);
virgin_ = false;
expanded_ = yes;
log_.event (expanded_? "expanded" : "collapsed");
return true;
}
virtual void
doReveal (ID child) override
2015-11-28 21:43:09 +01:00
{
UNIMPLEMENTED ("mock doReveal");
}
virtual void
doRevealYourself() override
{
UNIMPLEMENTED ("mock doRevealYourself");
}
virtual void
doMsg (string text) override
2015-11-28 21:43:09 +01:00
{
log_.call (this->identify(), "doMsg", text);
cout << this->identify() << " <-- Message(\""<<text<<"\")" <<endl;
log_.note ("type=mark", "ID=Message", text);
2015-11-28 21:43:09 +01:00
}
virtual void
doErr (string text) override
2015-11-28 21:43:09 +01:00
{
log_.call (this->identify(), "doErr", text);
cerr << this->identify() << " <-- Error(\""<<text<<"\")" <<endl;
log_.note ("type=mark", "ID=Error", text);
2015-11-28 21:43:09 +01:00
}
virtual void
doFlash() override
2015-11-28 21:43:09 +01:00
{
log_.call (this->identify(), "doFlash");
cout << this->identify() << " <-- Flash!" <<endl;
log_.note ("type=mark", "ID=Flash");
2015-11-28 21:43:09 +01:00
}
virtual void
doMark (GenNode const& mark) override
2015-11-28 21:43:09 +01:00
{
log_.call (this->identify(), "doMark");
cout << this->identify() << " <-- state-mark = "<< string(mark) <<endl;
log_.note ("type=mark", "ID="+mark.idi.getSym(), mark);
2015-11-28 21:43:09 +01:00
}
protected:
string
identify() const
{
return getID().getSym() +"."+ lib::idi::instanceTypeID(this);
}
public:
explicit
MockElm(string id)
: MockElm(lib::idi::EntryID<MockElm>(id))
{ }
explicit
2015-11-28 21:43:09 +01:00
MockElm(ID identity, ctrl::BusTerm& nexus =Nexus::testUI())
: gui::model::Tangible(identity, nexus)
{
log_.call(this->identify(), "ctor", identity, string(nexus));
log_.create(getID().getSym());
}
/* ==== special operations API ==== */
void
kill()
{
UNIMPLEMENTED ("suicide");
}
/* ==== Query/Verification API ==== */
ID getID() const
{
return uiBus_.getID();
}
bool
isTouched() const
{
return not virgin_;
}
bool
isExpanded() const
{
return expanded_;
}
EventMatch
verify (string match) const
{
return getLog().verify(match);
}
EventMatch
verifyMatch (string regExp) const
{
return getLog().verifyMatch(regExp);
}
EventMatch
verifyEvent (string match) const
{
return getLog().verifyEvent(match);
}
EventMatch
verifyEvent (string classifier, string match) const
{
return getLog().verifyEvent (classifier,match);
}
EventMatch
verifyCall (string match) const
{
return getLog().verifyCall(match);
}
EventMatch
ensureNot (string match) const
{
return getLog().ensureNot(match);
}
/** special verification match on a "state mark" message to this element */
EventMatch
verifyMark (string msgContentMatch) const
{
return getLog().verifyEvent("mark", msgContentMatch);
}
/** verification match on a specific "state mark" message
* @param id the ID-symbol used, identifying the kind of notification message
* @param payloadMatch to be applied to the payload of the message solely
*/
EventMatch
verifyMark (string id, string payloadMatch) const
{
return getLog().verifyEvent("mark", payloadMatch).type("mark").id(id);
}
EventLog const&
getLog() const
{
return log_;
}
EventLog&
joinLog (MockElm& otherMock)
{
log_.joinInto (otherMock.log_);
return log_;
}
};
}} // namespace gui::test
#endif /*GUI_TEST_MOCK_ELM_H*/