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:
Fischlurch 2016-01-22 12:19:25 +01:00
parent 297f986b5f
commit eaa12499f3
7 changed files with 195 additions and 11 deletions

View file

@ -146,7 +146,8 @@ namespace ctrl {
* the element. Thus, the default implementation is just to pass the
* given state mark "up", assuming that it will reach the hub
* 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
BusTerm::mark (ID subject, GenNode const& mark)

View file

@ -88,7 +88,7 @@ namespace ctrl{
/** route mark messages down to the individual Tangible.
* @note only messages to elements currently registered
* in the routing table are dispatched. All other
* messages are dropped silently.
* messages are dropped without further effect.
*/
virtual bool
mark (ID subject, GenNode const& mark) override

View file

@ -145,6 +145,21 @@ namespace idi {
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
*/

View file

@ -177,7 +177,7 @@ namespace test {
commandInvocation ()
{
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");
@ -186,6 +186,12 @@ namespace test {
TimeSpan clip (Time(1,2,3), lib::test::randTime());
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
VERIFY_ERROR (UNBOUND_ARGUMENTS, mock.issueCommand(cmd) );
@ -196,19 +202,19 @@ namespace test {
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::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, text, clip, luid));
CHECK (not gui::test::Nexus::wasInvoked(cmd, text, luid)); ////////TODO clip,
CHECK (not gui::test::Nexus::wasBound(cmd, "lololo"));
mock.issueCommand(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, text, clip));

View 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*/

View file

@ -44,6 +44,7 @@
#include "lib/error.hpp"
#include "lib/symbol.hpp"
#include "test/test-nexus.hpp"
#include "lib/test/event-log.hpp"
#include "gui/ctrl/nexus.hpp"
@ -56,9 +57,11 @@
//#include "lib/util.hpp"
#include <string>
#include <deque>
using std::string;
using lib::Symbol;
using lib::Variant;
using lib::diff::Rec;
using lib::diff::GenNode;
@ -73,6 +76,20 @@ using util::_Fmt;
namespace gui {
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
using BusHub = gui::ctrl::Nexus;
@ -159,9 +176,15 @@ namespace test{
{
log_.call(this, "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
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&
@ -336,7 +359,7 @@ namespace test{
lib::Depend<ZombieNexus> zombieNexus;
} // internal details
}//(End) internal details

View file

@ -48,6 +48,7 @@
#include "lib/error.hpp"
#include "gui/ctrl/bus-term.hpp"
#include "gui/model/tangible.hpp"
#include "test/placeholder-command.hpp"
#include "lib/test/event-log.hpp"
#include "lib/diff/gen-node.hpp"
@ -116,7 +117,7 @@ namespace test{
inline interact::InvocationTrail
Nexus::prepareMockCmd()
{
UNIMPLEMENTED("pick up arbitrary types and fabricate a mock command accepting those types");
return Cmd {PlaceholderCommand<ARGS...>::fabricateNewInstance(getLog())};
}
template<typename...ARGS>