back to UI command invocation: basically implement a placeholder command
based on the previous experiments, this adds a fake operation
and a definition frame to hook this operation as pseudo Proc-Layer command
WIP: the invocation itself is not yet implemented.
We need to build a custom invocation pattern for that,
in order to be able to capture the instance-ID of the command
on invocation
NOTE: also, because of #989, we can not bind a time value for this test
This commit is contained in:
parent
297f986b5f
commit
eaa12499f3
7 changed files with 195 additions and 11 deletions
|
|
@ -146,7 +146,8 @@ namespace ctrl {
|
||||||
* the element. Thus, the default implementation is just to pass the
|
* the element. Thus, the default implementation is just to pass the
|
||||||
* given state mark "up", assuming that it will reach the hub
|
* given state mark "up", assuming that it will reach the hub
|
||||||
* eventually, which in turn knows hot to reach the element.
|
* eventually, which in turn knows hot to reach the element.
|
||||||
* @note messages to unreachable elements will be dropped silently.
|
* @return if the target was known and the mark operation dispatched.
|
||||||
|
* @note messages to unreachable elements will be dropped.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
BusTerm::mark (ID subject, GenNode const& mark)
|
BusTerm::mark (ID subject, GenNode const& mark)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ namespace ctrl{
|
||||||
/** route mark messages down to the individual Tangible.
|
/** route mark messages down to the individual Tangible.
|
||||||
* @note only messages to elements currently registered
|
* @note only messages to elements currently registered
|
||||||
* in the routing table are dispatched. All other
|
* in the routing table are dispatched. All other
|
||||||
* messages are dropped silently.
|
* messages are dropped without further effect.
|
||||||
*/
|
*/
|
||||||
virtual bool
|
virtual bool
|
||||||
mark (ID subject, GenNode const& mark) override
|
mark (ID subject, GenNode const& mark) override
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,21 @@ namespace idi {
|
||||||
return format::instance_format (namePrefix<TY>(), instanceCounter.inc<TY>());
|
return format::instance_format (namePrefix<TY>(), instanceCounter.inc<TY>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** build a long type based identifier, with running counter and custom prefix.
|
||||||
|
* @param prefix optional prefix to prepend to the generated ID
|
||||||
|
* @return a ID string based on the full type, followed by an instance number
|
||||||
|
* @warning for one, like \ref generateSymbolicID(), this operation is not really
|
||||||
|
* cheap. And then, since the type ID is slightly abbreviated and then
|
||||||
|
* mangled, there is still the possibility of occasional clashes.
|
||||||
|
*/
|
||||||
|
template<class TY>
|
||||||
|
inline string
|
||||||
|
generateExtendedID(string prefix ="")
|
||||||
|
{
|
||||||
|
static TypedCounter instanceCounter;
|
||||||
|
return format::instance_format (prefix + typeFullID<TY>(), instanceCounter.inc<TY>());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a standard hash value, based on the full (mangled) C++ type name
|
* @return a standard hash value, based on the full (mangled) C++ type name
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ namespace test {
|
||||||
commandInvocation ()
|
commandInvocation ()
|
||||||
{
|
{
|
||||||
MARK_TEST_FUN
|
MARK_TEST_FUN
|
||||||
auto cmd = gui::test::Nexus::prepareMockCmd<string, TimeSpan, HashVal>();
|
auto cmd = gui::test::Nexus::prepareMockCmd<string, HashVal>(); //TimeSpan /////////////TODO
|
||||||
|
|
||||||
MockElm mock("uiElm");
|
MockElm mock("uiElm");
|
||||||
|
|
||||||
|
|
@ -186,6 +186,12 @@ namespace test {
|
||||||
TimeSpan clip (Time(1,2,3), lib::test::randTime());
|
TimeSpan clip (Time(1,2,3), lib::test::randTime());
|
||||||
LuidH luid;
|
LuidH luid;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////TODO WIP
|
||||||
|
mock.issueCommand(cmd);
|
||||||
|
cout << "____Nexus-Log_________________\n"
|
||||||
|
<< util::join(gui::test::Nexus::getLog(), "\n")
|
||||||
|
<< "\n───╼━━━━━━━━━╾────────────────"<<endl;
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////TODO WIP
|
||||||
// we cannot invoke commands prior to binding arguments
|
// we cannot invoke commands prior to binding arguments
|
||||||
VERIFY_ERROR (UNBOUND_ARGUMENTS, mock.issueCommand(cmd) );
|
VERIFY_ERROR (UNBOUND_ARGUMENTS, mock.issueCommand(cmd) );
|
||||||
|
|
||||||
|
|
@ -196,19 +202,19 @@ namespace test {
|
||||||
CHECK (not gui::test::Nexus::canInvoke(cmd));
|
CHECK (not gui::test::Nexus::canInvoke(cmd));
|
||||||
|
|
||||||
|
|
||||||
mock.prepareCommand(cmd, Rec({text, clip, luid}));
|
mock.prepareCommand(cmd, Rec({text, luid})); ////////TODO clip,
|
||||||
|
|
||||||
CHECK (gui::test::Nexus::canInvoke(cmd));
|
CHECK (gui::test::Nexus::canInvoke(cmd));
|
||||||
CHECK (gui::test::Nexus::wasBound(cmd, text, clip, luid));
|
CHECK (gui::test::Nexus::wasBound(cmd, text, luid)); ////////TODO clip,
|
||||||
CHECK (not gui::test::Nexus::wasInvoked(cmd));
|
CHECK (not gui::test::Nexus::wasInvoked(cmd));
|
||||||
CHECK (not gui::test::Nexus::wasInvoked(cmd, text, clip, luid));
|
CHECK (not gui::test::Nexus::wasInvoked(cmd, text, luid)); ////////TODO clip,
|
||||||
CHECK (not gui::test::Nexus::wasBound(cmd, "lololo"));
|
CHECK (not gui::test::Nexus::wasBound(cmd, "lololo"));
|
||||||
|
|
||||||
|
|
||||||
mock.issueCommand(cmd);
|
mock.issueCommand(cmd);
|
||||||
|
|
||||||
CHECK (gui::test::Nexus::wasInvoked(cmd));
|
CHECK (gui::test::Nexus::wasInvoked(cmd));
|
||||||
CHECK (gui::test::Nexus::wasInvoked(cmd, text, clip, luid));
|
CHECK (gui::test::Nexus::wasInvoked(cmd, text, luid)); ////////TODO clip,
|
||||||
CHECK (not gui::test::Nexus::wasInvoked(cmd, " huh ", clip, luid));
|
CHECK (not gui::test::Nexus::wasInvoked(cmd, " huh ", clip, luid));
|
||||||
CHECK (not gui::test::Nexus::wasInvoked(cmd, text, clip));
|
CHECK (not gui::test::Nexus::wasInvoked(cmd, text, clip));
|
||||||
|
|
||||||
|
|
|
||||||
138
tests/gui/test/placeholder-command.hpp
Normal file
138
tests/gui/test/placeholder-command.hpp
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
PLACEHOLDER-COMMAND.hpp - fake operation to mock command invocation from UI
|
||||||
|
|
||||||
|
Copyright (C) Lumiera.org
|
||||||
|
2016, 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 placeholder-command.hpp
|
||||||
|
** Generate fake commands with stub operations and the ability to verify invocation.
|
||||||
|
** This helper for unit testing of UI interactions might serve as dummy placeholder,
|
||||||
|
** or be used to mock some operation expected to happen within Proc-Layer. The test::Nexus
|
||||||
|
** offers a convenience front-end to install such an placeholder operation and use it
|
||||||
|
** as counterpart for some tested elements connected to the UI-bus.
|
||||||
|
**
|
||||||
|
** The actual operation is void of any functionality, but might be installed to accept
|
||||||
|
** arbitrary predetermined argument bindings, and to verify invocation and passed arguments.
|
||||||
|
**
|
||||||
|
** @see BusTerm_test
|
||||||
|
** @see test::Nexus::prepareMockCmd
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GUI_TEST_PLACEHOLDER_COMMAND_H
|
||||||
|
#define GUI_TEST_PLACEHOLDER_COMMAND_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "lib/error.hpp"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
|
#include "lib/idi/genfunc.hpp"
|
||||||
|
#include "lib/test/event-log.hpp"
|
||||||
|
#include "proc/control/command-def.hpp"
|
||||||
|
#include "lib/format-util.hpp"
|
||||||
|
//#include "lib/diff/gen-node.hpp"
|
||||||
|
|
||||||
|
//#include <boost/noncopyable.hpp>
|
||||||
|
//#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gui {
|
||||||
|
namespace test{
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using lib::Symbol;
|
||||||
|
|
||||||
|
|
||||||
|
/** place the string persistently in memory.
|
||||||
|
* @internal used as workaround for creating command-IDs on the fly
|
||||||
|
* @todo temporary workaround, shall be replaced by lib::Symbol implementation ///////////////TICKET #157 maintain symbol table for interned strings
|
||||||
|
* @return a C-String marked as lib::Literal, pointing
|
||||||
|
* to the permanent location in heap memory.
|
||||||
|
* @see \ref test-nexus.cpp implementation
|
||||||
|
*/
|
||||||
|
Symbol internedString (string&& idString);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of stub command operations.
|
||||||
|
* This is a typed definition frame with some operations,
|
||||||
|
* suitably to be bound into a Proc-Layer command. The actual
|
||||||
|
* command "operation" just logs invocation into a statically
|
||||||
|
* obtained \ref EventLog Event-Log instance.
|
||||||
|
*/
|
||||||
|
template<typename...ARGS>
|
||||||
|
class PlaceholderCommand
|
||||||
|
{
|
||||||
|
static lib::test::EventLog log_;
|
||||||
|
|
||||||
|
/** @internal ID-string specific for the instance `ARGS` */
|
||||||
|
static string
|
||||||
|
thisTypeInstance()
|
||||||
|
{
|
||||||
|
return lib::idi::generateExtendedID<PlaceholderCommand>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** a dummy command "operation */
|
||||||
|
static void
|
||||||
|
operate (ARGS ...args)
|
||||||
|
{
|
||||||
|
log_.call(thisTypeInstance(), "operate", std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static string
|
||||||
|
capture (ARGS ...args)
|
||||||
|
{
|
||||||
|
using VecS = std::vector<string>;
|
||||||
|
return "Memento⧏" + util::join (util::stringify<VecS> (args...),"⧓") + "⧐";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
undo (ARGS ..., string memento)
|
||||||
|
{
|
||||||
|
log_.call(thisTypeInstance(), "undo", memento);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
static proc::control::Command
|
||||||
|
fabricateNewInstance (lib::test::EventLog const& invocationLog)
|
||||||
|
{
|
||||||
|
log_ = invocationLog;
|
||||||
|
return proc::control::CommandDef(internedString (thisTypeInstance()))
|
||||||
|
.operation(PlaceholderCommand::operate)
|
||||||
|
.captureUndo(PlaceholderCommand::capture)
|
||||||
|
.undoOperation(PlaceholderCommand::undo);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename...ARGS>
|
||||||
|
lib::test::EventLog PlaceholderCommand<ARGS...>::log_{"test-dummy-"+thisTypeInstance()};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace gui::test
|
||||||
|
#endif /*GUI_TEST_PLACEHOLDER_COMMAND_H*/
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
#include "test/test-nexus.hpp"
|
#include "test/test-nexus.hpp"
|
||||||
#include "lib/test/event-log.hpp"
|
#include "lib/test/event-log.hpp"
|
||||||
#include "gui/ctrl/nexus.hpp"
|
#include "gui/ctrl/nexus.hpp"
|
||||||
|
|
@ -56,9 +57,11 @@
|
||||||
//#include "lib/util.hpp"
|
//#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
using lib::Symbol;
|
||||||
using lib::Variant;
|
using lib::Variant;
|
||||||
using lib::diff::Rec;
|
using lib::diff::Rec;
|
||||||
using lib::diff::GenNode;
|
using lib::diff::GenNode;
|
||||||
|
|
@ -73,6 +76,20 @@ using util::_Fmt;
|
||||||
namespace gui {
|
namespace gui {
|
||||||
namespace test{
|
namespace test{
|
||||||
|
|
||||||
|
namespace { // quick-n-dirty string table implementation
|
||||||
|
|
||||||
|
/** @warning grows eternally, never shrinks */
|
||||||
|
std::deque<string> idStringBuffer; ////////////////////////////////TICKET #158 replace by symbol table
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol
|
||||||
|
internedString (string&& idString)
|
||||||
|
{
|
||||||
|
idStringBuffer.emplace_back (std::forward<string> (idString));
|
||||||
|
return Symbol (idStringBuffer.back().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace { // internal details
|
namespace { // internal details
|
||||||
|
|
||||||
using BusHub = gui::ctrl::Nexus;
|
using BusHub = gui::ctrl::Nexus;
|
||||||
|
|
@ -159,9 +176,15 @@ namespace test{
|
||||||
{
|
{
|
||||||
log_.call(this, "mark", subject, mark);
|
log_.call(this, "mark", subject, mark);
|
||||||
if (BusHub::mark (subject, mark))
|
if (BusHub::mark (subject, mark))
|
||||||
log_.event ("TestNexus", _Fmt("delivered mark to %s |%s") % subject % mark);
|
{
|
||||||
|
log_.event ("TestNexus", _Fmt("delivered mark to %s |%s") % subject % mark);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
log_.warn (_Fmt("discarding mark to unknown %s |%s") % subject % mark);
|
{
|
||||||
|
log_.warn (_Fmt("discarding mark to unknown %s |%s") % subject % mark);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual BusTerm&
|
virtual BusTerm&
|
||||||
|
|
@ -336,7 +359,7 @@ namespace test{
|
||||||
|
|
||||||
lib::Depend<ZombieNexus> zombieNexus;
|
lib::Depend<ZombieNexus> zombieNexus;
|
||||||
|
|
||||||
} // internal details
|
}//(End) internal details
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "gui/ctrl/bus-term.hpp"
|
#include "gui/ctrl/bus-term.hpp"
|
||||||
#include "gui/model/tangible.hpp"
|
#include "gui/model/tangible.hpp"
|
||||||
|
#include "test/placeholder-command.hpp"
|
||||||
#include "lib/test/event-log.hpp"
|
#include "lib/test/event-log.hpp"
|
||||||
#include "lib/diff/gen-node.hpp"
|
#include "lib/diff/gen-node.hpp"
|
||||||
|
|
||||||
|
|
@ -116,7 +117,7 @@ namespace test{
|
||||||
inline interact::InvocationTrail
|
inline interact::InvocationTrail
|
||||||
Nexus::prepareMockCmd()
|
Nexus::prepareMockCmd()
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED("pick up arbitrary types and fabricate a mock command accepting those types");
|
return Cmd {PlaceholderCommand<ARGS...>::fabricateNewInstance(getLog())};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename...ARGS>
|
template<typename...ARGS>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue