diff --git a/src/proc/control/command-argument-holder.hpp b/src/proc/control/command-argument-holder.hpp new file mode 100644 index 000000000..4a981588e --- /dev/null +++ b/src/proc/control/command-argument-holder.hpp @@ -0,0 +1,100 @@ +/* + COMMAND-ARGUMENT-HOLDER.hpp - specifically typed container for storage of command arguments + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + 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 command-argument-holder.hpp + ** A simple container record holding the actual command arguments. + ** While all command objects themselves have a common type (type erasure), + ** the actual argument tuple and the state memento for undo can't. Especially, + ** the size of arguments and memento will depend on their respective types. + ** Thus, to manage somehow the storage of this data, we create a common holder, + ** to be managed by a custom allocator. + ** + ** @todo doing just plain heap allocation for now :-P + ** + ** @see Command + ** @see UndoMutation + ** @see MementoTie + ** @see command-argument-test.cpp + ** + */ + + + +#ifndef CONTROL_COMMAND_ARGUMENT_HOLDER_H +#define CONTROL_COMMAND_ARGUMENT_HOLDER_H + +//#include "pre.hpp" +//#include "lib/error.hpp" + +//#include +//#include +//#include +#include +#include + + + +namespace control { + +// using lumiera::Symbol; +// using std::tr1::shared_ptr; +// using boost::scoped_ptr; +// using std::tr1::function; + using std::ostream; + using std::string; + + + + /** + * @todo Type-comment + */ + class CommandArgumentHolder + { + + public: + virtual ~CommandArgumentHolder() { }; + virtual operator string() const =0; + }; + + + inline ostream& operator<< (ostream& os, CommandArgumentHolder const& arg) { return os << string(arg); } + + + + + /** specifically typed subclass used for actual storage */ + template + class ArgumentHolder + : public CommandArgumentHolder + { + + operator string() const { return "bääääh!"; } /////////////////TODO + + }; + ////////////////TODO currently just fleshing out the API.... + + + + +} // namespace control +#endif diff --git a/src/proc/control/command-def.hpp b/src/proc/control/command-def.hpp index 5002e9452..ebfc7906b 100644 --- a/src/proc/control/command-def.hpp +++ b/src/proc/control/command-def.hpp @@ -50,6 +50,7 @@ //#include "pre.hpp" #include "include/symbol.hpp" #include "proc/control/command.hpp" +#include "proc/control/command-signature.hpp" #include "proc/control/command-mutation.hpp" #include "proc/control/command-closure.hpp" #include "lib/meta/function.hpp" @@ -74,65 +75,6 @@ namespace control { using lumiera::typelist::Types; //using lumiera::typelist::NullType; using lumiera::typelist::Tuple; - using lumiera::typelist::Append; - using lumiera::typelist::SplitLast; - - - - - /** - * Type analysis helper template. - * Used for dissecting a given type signature to derive - * the related basic operation signature, the signature of a possible Undo-function - * and the signature necessary for capturing undo information. The implementation - * relies on re-binding an embedded type defining template, based on the actual - * case, as identified by the structure of the given parameter signature. - */ - template - struct UndoSignature - { - private: - typedef typename FunctionSignature< function >::Args Args; - typedef typename FunctionSignature< function >::Ret Ret; - - /** Case1: defining the Undo-Capture function */ - template - struct Case - { - typedef RET Memento; - typedef typename Append::List ExtendedArglist; - typedef typename Tuple::Type ExtendedArgs; - - typedef typename FunctionTypedef::Sig OperateSig; - typedef typename FunctionTypedef::Sig CaptureSig; - typedef typename FunctionTypedef::Sig UndoOp_Sig; - }; - /** Case2: defining the actual Undo function */ - template - struct Case - { - typedef typename ARG::List Args; - - typedef typename SplitLast::Type Memento; - typedef typename SplitLast::List OperationArglist; - typedef typename Tuple::Type OperationArgs; - - typedef typename FunctionTypedef::Sig OperateSig; - typedef typename FunctionTypedef::Sig CaptureSig; - typedef typename FunctionTypedef::Sig UndoOp_Sig; - }; - - public: - typedef typename Case::CaptureSig CaptureSig; - typedef typename Case::UndoOp_Sig UndoOp_Sig; - typedef typename Case::OperateSig OperateSig; - typedef typename Case::Memento Memento; - }; - - - - - diff --git a/src/proc/control/command-mutation.hpp b/src/proc/control/command-mutation.hpp index f0f77d704..cf745b778 100644 --- a/src/proc/control/command-mutation.hpp +++ b/src/proc/control/command-mutation.hpp @@ -38,7 +38,7 @@ //#include "pre.hpp" #include "lib/error.hpp" #include "proc/control/command-closure.hpp" -#include "proc/control/memento-closure.hpp" +#include "proc/control/memento-tie.hpp" //#include #include @@ -135,7 +135,7 @@ namespace control { }; - inline ostream& operator<< (ostream& os, const Mutation& muta) { return os << string(muta); } + inline ostream& operator<< (ostream& os, Mutation const& muta) { return os << string(muta); } @@ -146,17 +146,17 @@ namespace control { class UndoMutation : public Mutation { - CmdFunctor captureFunc_; - scoped_ptr memento_; + Mutation memento_; public: template UndoMutation (function const& undoFunc, function const& captureFunc) : Mutation (undoFunc) - , captureFunc_(captureFunc) + , memento_(captureFunc) { } - + +#if false /////////////////////////////////////////////////TODO: remove after refactoring UndoMutation (UndoMutation const& o) : Mutation (*this) , captureFunc_(o.captureFunc_) @@ -180,16 +180,17 @@ namespace control { REQUIRE (captureFunc_, "Param error: not bound to a valid function"); // create a special state closure, which can later on store the captured undo state (memento) - scoped_ptr stateClosure (new MementoClosure (captureFunc_)); - CmdFunctor closedCaptureFunc = stateClosure->bindArguments(captureFunc_); + scoped_ptr stateClosure (new MementoClosure (captureFunc_)); + CmdFunctor closedCaptureFunc = cmdClosure.bindArguments(captureFunc_); // the undoFunc (within parent class) will retrieve an argument tuple extended by the memento -// Mutation::close (stateClosure->decorate (cmdClosure)); + Mutation::close (stateClosure->decorate (cmdClosure)); captureFunc_ = closedCaptureFunc; - memento_.swap(stateClosure); +// memento_.swap(stateClosure); return *this; } +#endif Mutation& captureState () @@ -198,7 +199,7 @@ namespace control { throw lumiera::error::State ("need to bind function arguments prior to capturing undo state", LUMIERA_ERROR_UNBOUND_ARGUMENTS); - invoke(captureFunc_); + memento_(); return *this; } @@ -206,14 +207,14 @@ namespace control { getMemento() { ASSERT (memento_, "Lifecycle error: need to close first"); - return *memento_; +// return *memento_; } private: virtual bool isValid () const { - return Mutation::isValid() && captureFunc_ && memento_; +// return Mutation::isValid() && captureFunc_ && memento_; } diff --git a/src/proc/control/command-signature.hpp b/src/proc/control/command-signature.hpp new file mode 100644 index 000000000..503a212f2 --- /dev/null +++ b/src/proc/control/command-signature.hpp @@ -0,0 +1,153 @@ +/* + COMMAND-SIGNATURE.hpp - deriving suitable command function signatures + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + 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 command-signature.hpp + ** Metaprogramming helpers for deriving the precise function signatures + ** necessary to implement a given command. Basically, commands can be implemented + ** by arbitrary functions, but the signatures of the operation function, the + ** undo function and the undo state capturing function are required to obey + ** fixed relationships. Thus, at various stages of the command definition, + ** we need to accept functor objects with a very specific and predetermined + ** signature, thus allowing for strict type checking by the compiler. + ** + ** \par Relation of function signatures + ** - operation: void(P1,..PN) + ** - captureUndo: MEM(P1,..PN) + ** - undoOperation void(P1,..PN,MEM) + ** - bind takes the arguments:(P1,..PN) + ** + ** @see Command + ** @see CommandDef + ** + */ + + + +#ifndef CONTROL_COMMAND_SIGNATURE_H +#define CONTROL_COMMAND_SIGNATURE_H + +//#include "pre.hpp" +//#include "include/symbol.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/typelist.hpp" +#include "lib/meta/typelistutil.hpp" +#include "lib/meta/tuple.hpp" + +//#include +#include + + + + +namespace control { + +// using lumiera::Symbol; +// using std::tr1::shared_ptr; + using std::tr1::function; + + using lumiera::typelist::FunctionSignature; + using lumiera::typelist::FunctionTypedef; + using lumiera::typelist::Types; +//using lumiera::typelist::NullType; + using lumiera::typelist::Tuple; + using lumiera::typelist::Append; + using lumiera::typelist::SplitLast; + + + /** + * Metaprogramming helper for building Command function signatures. + * The complete definition context of any command is templated to the signature + * of the actual command operation and to the memento type. The typedefs embedded + * within CommandSignature allows accepting suitable typed functions + * to implement the command in question. + */ + template + class CommandSignature + { + typedef typename FunctionSignature< function >::Args Args; + + typedef typename Append::List ExtendedArglist; + typedef typename Tuple::Type ExtendedArgs; + + public: + typedef typename FunctionTypedef::Sig OperateSig; + typedef typename FunctionTypedef::Sig CaptureSig; + typedef typename FunctionTypedef::Sig UndoOp_Sig; + typedef MEM Memento; + }; + + + + + /** + * Type analysis helper template. + * Used for dissecting a given type signature to derive + * the related basic operation signature, the signature of a possible Undo-function + * and the signature necessary for capturing undo information. The implementation + * relies on re-binding an embedded type defining template, based on the actual + * case, as identified by the structure of the given parameter signature. + */ + template + class UndoSignature + { + typedef typename FunctionSignature< function >::Args Args; + typedef typename FunctionSignature< function >::Ret Ret; + + /** Case1: defining the Undo-Capture function */ + template + struct Case + { + typedef RET Memento; + typedef typename Append::List ExtendedArglist; + typedef typename Tuple::Type ExtendedArgs; + + typedef typename FunctionTypedef::Sig OperateSig; + typedef typename FunctionTypedef::Sig CaptureSig; + typedef typename FunctionTypedef::Sig UndoOp_Sig; + }; + /** Case2: defining the actual Undo function */ + template + struct Case + { + typedef typename ARG::List Args; + + typedef typename SplitLast::Type Memento; + typedef typename SplitLast::List OperationArglist; + typedef typename Tuple::Type OperationArgs; + + typedef typename FunctionTypedef::Sig OperateSig; + typedef typename FunctionTypedef::Sig CaptureSig; + typedef typename FunctionTypedef::Sig UndoOp_Sig; + }; + + public: + typedef typename Case::CaptureSig CaptureSig; + typedef typename Case::UndoOp_Sig UndoOp_Sig; + typedef typename Case::OperateSig OperateSig; + typedef typename Case::Memento Memento; + }; + + + +} // namespace control +#endif diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index fca9a6a8e..0b72a511e 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -51,12 +51,6 @@ namespace control { UNIMPLEMENTED ("fetch an existing command from the internal cmd registry"); } - - MementoClosure::MementoClosure (CmdFunctor&) - { - - } - diff --git a/src/proc/control/memento-closure.hpp b/src/proc/control/memento-closure.hpp deleted file mode 100644 index 14741bca8..000000000 --- a/src/proc/control/memento-closure.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - MEMENTO-CLOSURE.hpp - capturing and providing state for undoing commands - - Copyright (C) Lumiera.org - 2009, Hermann Vosseler - - 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 memento-closure.hpp - ** Extension to the CmdClosure for storing and retrieving a state memento. - ** //TODO - ** - ** @see CmdClosure - ** @see UndoMutation - ** @see memento-closure-test.cpp - ** - */ - - - -#ifndef CONTROL_MEMENTO_CLOSURE_H -#define CONTROL_MEMENTO_CLOSURE_H - -//#include "pre.hpp" -//#include "lib/meta/typelist.hpp" ////////////////TODO include these?? -//#include "lib/meta/function.hpp" -//#include "lib/meta/function-closure.hpp" -//#include "lib/meta/function-erasure.hpp" -//#include "lib/meta/tuple.hpp" -#include "proc/control/command-closure.hpp" -#include "lib/util.hpp" - -//#include -//#include -//#include -//#include - - -#include "lib/test/test-helper.hpp" /////////////////TODO remove this -using lib::test::showSizeof; - -using std::cout; //////////////////////////////////TODO remove this -using std::endl; - - -namespace control { - -// using lumiera::Symbol; -// using std::tr1::shared_ptr; -// using util::unConst; - using std::string; -// using std::ostream; -// using std::tr1::function; -// using lumiera::typelist::FunctionSignature; -// using lumiera::typelist::Tuple; -// using lumiera::typelist::BuildTupleAccessor; -// using lumiera::typelist::TupleApplicator; -// using lumiera::typelist::FunErasure; -// using lumiera::typelist::StoreFunction; - -// using lumiera::typelist::NullType; - - - - /** - * Special kind of Closure, which \em decorates an existing Closure - * and provides a captured state memento as additional parameter on invocation. - * - * @todo concept isn't clear yet. Multiple MementoClosurese are to decorate a single Closure; - * they have to match and extract the concrete type of the Closure and the provided Memento, - * but the latter needs to be erased immediately. Basically, MementoClosure must be able - * to stand-in for an simple parameter closure. - */ - class MementoClosure - : public CmdClosure ///////////TODO hierararchy? - { - public: - - virtual PClosure clone() const - { - return PClosure (new MementoClosure (*this)); - } - - virtual operator string() const - { - return "TODO"; - } - - virtual CmdFunctor bindArguments (CmdFunctor&) - { - UNIMPLEMENTED ("binding operation"); - } - - - ////////////TODO how to give access to the following dedicated API? - MementoClosure (CmdFunctor&); - - - CmdClosure& decorate (CmdClosure& core) - { - return *this; // TODO would be nice, but probably won't be thus simple ;-) - } - }; - - ////////////////TODO currently just fleshing out the API.... - - - - -} // namespace control -#endif diff --git a/src/proc/control/memento-tie.hpp b/src/proc/control/memento-tie.hpp new file mode 100644 index 000000000..14fc45a90 --- /dev/null +++ b/src/proc/control/memento-tie.hpp @@ -0,0 +1,146 @@ +/* + MEMENTO-TIE.hpp - capturing and providing state for undoing commands + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + 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 memento-tie.hpp + ** A special binding used by Proc-Layer commands for capturing UNDO state information. + ** The UndoMutation, which is the functor object created and configured by the Command + ** for handling UNDO, utilises a MementoTie (as ctor parameter) for binding together + ** the "undo capture function" and the actual "undo function", by retrieving the + ** memento data or memento object from the former and feeding it to the latter + ** as an additional parameter, when the undo operation is invoked. + ** //TODO + ** + ** @see CmdClosure + ** @see UndoMutation + ** @see memento-tie-test.cpp + ** + */ + + + +#ifndef CONTROL_MEMENTO_TIE_H +#define CONTROL_MEMENTO_TIE_H + +//#include "pre.hpp" +//#include "lib/meta/typelist.hpp" ////////////////TODO include these?? +//#include "lib/meta/function.hpp" +//#include "lib/meta/function-closure.hpp" +//#include "lib/meta/function-erasure.hpp" +//#include "lib/meta/tuple.hpp" +#include "proc/control/command-signature.hpp" +#include "proc/control/command-closure.hpp" ////////TODO really?? +#include "lib/util.hpp" + +//#include +//#include +//#include +//#include + + +#include "lib/test/test-helper.hpp" /////////////////TODO remove this +using lib::test::showSizeof; + +using std::cout; //////////////////////////////////TODO remove this +using std::endl; + + +namespace control { + +// using lumiera::Symbol; +// using std::tr1::shared_ptr; +// using util::unConst; + using std::string; +// using std::ostream; +// using std::tr1::function; +// using lumiera::typelist::FunctionSignature; +// using lumiera::typelist::Tuple; +// using lumiera::typelist::BuildTupleAccessor; +// using lumiera::typelist::TupleApplicator; +// using lumiera::typelist::FunErasure; +// using lumiera::typelist::StoreFunction; + +// using lumiera::typelist::NullType; + + + + /** + * Binding together state capturing and execution of the undo operation. + * MementoTie itself is passive container object with a very specific type, + * depending on the type of the operation arguments and the type of the memento. + * It is to be allocated within the ArgumentHolder of the command, thereby wrapping + * or decorating the undo and capture function, setting up the necessary bindings and + * closures, allowing them to cooperate behind the scenes to carry out the UNDO functionality. + * Through a reference to the MementoTie, the UndoMutation functor gets access to the prepared + * functions, storing them into generic containers (type erasure) for later invocation. + * + * More specifically, the \c captureFunction, which is expected to run immediately prior + * to the actual command operation, returns a \b memento value object (of unspecific type), + * which needs to be stored within the MementoTie. On UNDO, the undo-operation functor needs + * to be provided with a reference to this stored memento value through an additional + * parameter (which by convention is always the last argument of the undo function). + * + */ + template + class MementoTie + { + typedef typename CommandSignature::CaptureSig SIG_cap; + typedef typename CommandSignature::UndoOp_Sig SIG_undo; + + /** storage holding the captured state for undo */ + MEM memento_; + + function undo_; + function capture_; + + + function + buildFun() + { +// PlaceholderTuple tup; +// return tupleApplicator(tup).bind(origFun); + } + + void capture () + { + memento_ = capture(); + } + + public: + /** creates an execution context tying together the provided functions. + * Bound copies of these functors may be pulled from the MementoTie, + * in order to build the closures (with the concrete operation arguments) + * to be invoked later on command execution. + */ + MementoTie (function const& undoFunc, + function const& captureFunc) + { } + + }; + + ////////////////TODO currently just fleshing out the API.... + + + + +} // namespace control +#endif diff --git a/tests/45controller.tests b/tests/45controller.tests index 761354de1..7c5fd6d31 100644 --- a/tests/45controller.tests +++ b/tests/45controller.tests @@ -7,9 +7,13 @@ PLANNED "CommandBasic_test" CommandBasic_test < + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +//#include "proc/asset/media.hpp" +//#include "proc/mobject/session.hpp" +//#include "proc/mobject/session/edl.hpp" +//#include "proc/mobject/session/testclip.hpp" +//#include "proc/mobject/test-dummy-mobject.hpp" +//#include "lib/p.hpp" +//#include "proc/mobject/placement.hpp" +//#include "proc/mobject/placement-index.hpp" +//#include "proc/mobject/explicitplacement.hpp" +#include "proc/control/command-argument-holder.hpp" +//#include "lib/meta/typelist.hpp" +//#include "lib/meta/tuple.hpp" +//#include "lib/util.hpp" + +//#include +//#include +#include +//#include +#include + +//using std::tr1::bind; +//using std::tr1::placeholders::_1; +//using std::tr1::placeholders::_2; +//using std::tr1::function; +//using boost::format; +//using lumiera::Time; +//using util::contains; +using std::string; +//using std::rand; +using std::cout; +using std::endl; + + +namespace control { +namespace test { + + using lib::test::showSizeof; + +// using session::test::TestClip; +// using lumiera::P; +// using namespace lumiera::typelist; +// using lumiera::typelist::Tuple; + +// using control::CmdClosure; + + + + + + + namespace { + + int testVal=0; ///< used to verify the effect of testFunc ////////////////////TODO + + } + + + + /*************************************************************************** + * Verify the behaviour of the type erased closure, which is used + * by Proc-Layer commands to implement the capturing and later + * re-invocation of a function. + * + * @see control::Command + * @see control::CommandDef + * @see control::Mutation + * @see control::UndoMutation + * @see command-basic-test.hpp + */ + class CommandArgument_test : public Test + { + + virtual void + run (Arg) + { + UNIMPLEMENTED ("create various argument tuples and re-access their contents"); + } + }; + + + /** Register this test class... */ + LAUNCHER (CommandArgument_test, "unit controller"); + + +}} // namespace control::test diff --git a/tests/components/proc/control/memento-closure-test.cpp b/tests/components/proc/control/memento-tie-test.cpp similarity index 95% rename from tests/components/proc/control/memento-closure-test.cpp rename to tests/components/proc/control/memento-tie-test.cpp index 62598dc85..938033e5e 100644 --- a/tests/components/proc/control/memento-closure-test.cpp +++ b/tests/components/proc/control/memento-tie-test.cpp @@ -1,5 +1,5 @@ /* - MementoClosure(Test) - check the mechanism for capturing and providing undo-state + MementoTie(Test) - check the mechanism for capturing and providing undo-state Copyright (C) Lumiera.org 2009, Hermann Vosseler @@ -32,7 +32,7 @@ //#include "proc/mobject/placement.hpp" //#include "proc/mobject/placement-index.hpp" //#include "proc/mobject/explicitplacement.hpp" -#include "proc/control/memento-closure.hpp" +#include "proc/control/memento-tie.hpp" //#include "lib/meta/typelist.hpp" #include "lib/meta/tuple.hpp" //#include "lib/lumitime.hpp" @@ -103,7 +103,7 @@ namespace test { * @see control::UndoMutation * @see command-mutation-test.hpp */ - class MementoClosure_test : public Test + class MementoTie_test : public Test { virtual void @@ -169,7 +169,7 @@ namespace test { /** Register this test class... */ - LAUNCHER (MementoClosure_test, "unit controller"); + LAUNCHER (MementoTie_test, "unit controller"); }} // namespace control::test