2009-06-19 05:57:06 +02:00
|
|
|
|
/*
|
2018-11-15 21:13:52 +01:00
|
|
|
|
CommandMutation(Test) - checking the functor and undo-functor used within Steam-commands
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2009, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** 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. See the file COPYING for further details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2017-02-22 01:54:20 +01:00
|
|
|
|
/** @file command-mutation-test.cpp
|
2017-02-22 03:17:18 +01:00
|
|
|
|
** unit test \ref CommandMutation_test
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
2009-08-10 01:30:59 +02:00
|
|
|
|
#include "lib/test/test-helper.hpp"
|
2018-11-15 23:42:43 +01:00
|
|
|
|
#include "steam/control/command-mutation.hpp"
|
|
|
|
|
|
#include "steam/control/command-simple-closure.hpp"
|
|
|
|
|
|
#include "steam/control/memento-tie.hpp"
|
2016-01-17 23:55:41 +01:00
|
|
|
|
#include "lib/meta/tuple-helper.hpp"
|
2009-06-19 19:11:33 +02:00
|
|
|
|
#include "lib/meta/typelist.hpp"
|
2016-01-07 03:58:29 +01:00
|
|
|
|
#include "lib/format-cout.hpp"
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
|
#include <functional>
|
2009-06-24 05:51:02 +02:00
|
|
|
|
#include <cstdlib>
|
2009-06-19 05:57:06 +02:00
|
|
|
|
#include <string>
|
|
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
|
using std::function;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
using std::string;
|
2009-06-24 05:51:02 +02:00
|
|
|
|
using std::rand;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
namespace steam {
|
2009-06-19 05:57:06 +02:00
|
|
|
|
namespace control {
|
|
|
|
|
|
namespace test {
|
2009-06-19 19:11:33 +02:00
|
|
|
|
|
2011-12-03 02:56:50 +01:00
|
|
|
|
using namespace lib::meta;
|
2009-06-19 19:11:33 +02:00
|
|
|
|
using control::CmdClosure;
|
2024-03-16 02:04:47 +01:00
|
|
|
|
using LERR_(MISSING_MEMENTO);
|
|
|
|
|
|
using LERR_(UNBOUND_ARGUMENTS);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
2009-07-10 19:04:01 +02:00
|
|
|
|
namespace { /* ======= test functions to bind ========= */
|
|
|
|
|
|
|
2009-06-20 07:13:20 +02:00
|
|
|
|
int testVal=0; ///< used to verify the effect of testFunc
|
2009-07-10 19:04:01 +02:00
|
|
|
|
|
2009-06-19 05:57:06 +02:00
|
|
|
|
void
|
2009-06-19 19:11:33 +02:00
|
|
|
|
testFunc (int val)
|
2009-06-19 05:57:06 +02:00
|
|
|
|
{
|
2009-06-19 19:11:33 +02:00
|
|
|
|
testVal += val;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2009-06-19 19:11:33 +02:00
|
|
|
|
int
|
|
|
|
|
|
capture ()
|
2009-06-19 05:57:06 +02:00
|
|
|
|
{
|
2009-06-19 19:11:33 +02:00
|
|
|
|
return testVal;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
|
/***********************************************************************//**
|
2009-06-19 05:57:06 +02:00
|
|
|
|
* Verify the behaviour of the type erased closure, which is used
|
2018-11-15 21:13:52 +01:00
|
|
|
|
* by Steam-Layer commands to implement the capturing and later
|
2009-06-19 05:57:06 +02:00
|
|
|
|
* re-invocation of a function.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @see control::Command
|
|
|
|
|
|
* @see control::CommandDef
|
|
|
|
|
|
* @see control::Mutation
|
|
|
|
|
|
* @see control::UndoMutation
|
|
|
|
|
|
* @see command-basic-test.hpp
|
|
|
|
|
|
*/
|
|
|
|
|
|
class CommandMutation_test : public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
2024-11-13 02:23:23 +01:00
|
|
|
|
seedRand();
|
|
|
|
|
|
|
2009-06-19 05:57:06 +02:00
|
|
|
|
checkMutation();
|
|
|
|
|
|
checkUndoMutation();
|
2009-07-10 19:04:01 +02:00
|
|
|
|
checkStateCapturingMechanism();
|
2009-06-19 05:57:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-02-07 01:41:40 +01:00
|
|
|
|
/** @test check the Mutation functor which is bound to our `testFunc(int)`.
|
2009-09-20 18:37:20 +02:00
|
|
|
|
* Then create a argument closure and use this to invoke the Mutation
|
|
|
|
|
|
* and verify actually \c testFunc(param) is executed.
|
2009-06-19 05:57:06 +02:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
checkMutation ()
|
|
|
|
|
|
{
|
2009-09-21 03:15:06 +02:00
|
|
|
|
typedef void SIG_fun(int);
|
|
|
|
|
|
function<SIG_fun> funky = testFunc;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
|
|
|
|
|
Mutation functor (funky);
|
|
|
|
|
|
|
2016-02-07 01:41:40 +01:00
|
|
|
|
SimpleClosure<SIG_fun> nullClosure;
|
|
|
|
|
|
CHECK (not nullClosure.isValid());
|
2009-09-20 18:37:20 +02:00
|
|
|
|
cout << "empty placeholder closure: " << nullClosure << endl;
|
|
|
|
|
|
VERIFY_ERROR (UNBOUND_ARGUMENTS, functor(nullClosure) );
|
|
|
|
|
|
|
|
|
|
|
|
// now create a real closure....
|
2025-06-07 18:04:59 +02:00
|
|
|
|
std::tuple<int> param = std::make_tuple(23);
|
2016-02-07 01:41:40 +01:00
|
|
|
|
SimpleClosure<void(int)> closed_over{param};
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2016-02-07 01:41:40 +01:00
|
|
|
|
CmdClosure& closure (closed_over);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (closure);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2009-09-20 18:37:20 +02:00
|
|
|
|
cout << "param values: " << closure << endl;
|
2009-06-24 05:51:02 +02:00
|
|
|
|
|
2009-06-19 05:57:06 +02:00
|
|
|
|
testVal = 0;
|
2009-09-20 18:37:20 +02:00
|
|
|
|
functor(closure);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 23);
|
2009-09-20 18:37:20 +02:00
|
|
|
|
functor(closure);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 2*23);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test check the special Mutation which is used to \em undo a command.
|
|
|
|
|
|
* This time, we use our \c testFunc(int) as implementation of the
|
|
|
|
|
|
* "undo" function; thus its parameter has now the meaning of an
|
|
|
|
|
|
* captured state value. Consequently this time the \em operation
|
|
|
|
|
|
* which is to be undone would have the signature \c void(void) .
|
2009-07-06 03:48:45 +02:00
|
|
|
|
* Obviously this is a rather silly "undo" function, but it is
|
2009-07-10 19:04:01 +02:00
|
|
|
|
* easy to check for unit testing. To carry out this test, we
|
|
|
|
|
|
* first have to trigger the state capturing mechanism; after that,
|
2009-07-06 03:48:45 +02:00
|
|
|
|
* invoking the UndoMutation will call the testFunc with the
|
|
|
|
|
|
* previously captured state.
|
|
|
|
|
|
* @note Mutation and UndoMutation are value objects, but they refer
|
|
|
|
|
|
* to a common command state, which for this test is modelled
|
|
|
|
|
|
* by local variables and which for the real commands is
|
2016-02-06 16:29:06 +01:00
|
|
|
|
* contained in a Command-StorageHolder
|
2009-06-19 05:57:06 +02:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
checkUndoMutation ()
|
|
|
|
|
|
{
|
2009-07-10 19:04:01 +02:00
|
|
|
|
function<void(int)> undo_func = testFunc;
|
|
|
|
|
|
function<int(void)> cap_func = capture;
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2009-07-08 05:36:02 +02:00
|
|
|
|
typedef MementoTie<void(),int> MemHolder;
|
|
|
|
|
|
|
|
|
|
|
|
MemHolder mementoHolder (undo_func,cap_func);
|
2009-07-06 03:48:45 +02:00
|
|
|
|
UndoMutation undoFunctor (mementoHolder);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (!mementoHolder);
|
2009-09-20 18:37:20 +02:00
|
|
|
|
|
2016-02-07 01:41:40 +01:00
|
|
|
|
SimpleClosure<void(void)> nullClosure;
|
2009-09-20 18:37:20 +02:00
|
|
|
|
VERIFY_ERROR (UNBOUND_ARGUMENTS, undoFunctor(nullClosure) );
|
|
|
|
|
|
VERIFY_ERROR (UNBOUND_ARGUMENTS, undoFunctor.captureState(nullClosure) );
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2025-06-07 18:04:59 +02:00
|
|
|
|
Tuple<Types<>> param;
|
2016-02-07 01:41:40 +01:00
|
|
|
|
SimpleClosure<void()> clo{param};
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (!mementoHolder);
|
2009-09-20 18:37:20 +02:00
|
|
|
|
VERIFY_ERROR (MISSING_MEMENTO, undoFunctor (clo) );
|
2009-07-08 05:36:02 +02:00
|
|
|
|
VERIFY_ERROR (MISSING_MEMENTO, mementoHolder.getState() );
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
|
|
|
|
|
testVal = 11;
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor.captureState(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (mementoHolder);
|
|
|
|
|
|
CHECK (testVal == 11);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
|
2009-07-06 03:48:45 +02:00
|
|
|
|
int mem = mementoHolder.getState();
|
2009-06-19 05:57:06 +02:00
|
|
|
|
cout << "saved state: " << mem << endl;
|
|
|
|
|
|
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 11 + 11);
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 11 + 11 + 11);
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor.captureState(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (33 == mementoHolder.getState());
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 33 + 33);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
testVal = 9;
|
2009-09-20 18:37:20 +02:00
|
|
|
|
undoFunctor(clo);
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 42);
|
2009-06-19 05:57:06 +02:00
|
|
|
|
}
|
2009-06-24 05:51:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
2009-07-10 19:04:01 +02:00
|
|
|
|
/** @test check the undo memento capturing mechanism in isolation
|
|
|
|
|
|
* @see memento-tie-test.cpp more in-depth coverage */
|
|
|
|
|
|
void
|
|
|
|
|
|
checkStateCapturingMechanism ()
|
|
|
|
|
|
{
|
|
|
|
|
|
typedef MementoTie<void(),int> MemHolder;
|
|
|
|
|
|
|
|
|
|
|
|
MemHolder mementoHolder (testFunc, capture);
|
|
|
|
|
|
|
|
|
|
|
|
function<void()> bound_undo_func = mementoHolder.tieUndoFunc();
|
|
|
|
|
|
function<void()> bound_cap_func = mementoHolder.tieCaptureFunc();
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-13 02:23:23 +01:00
|
|
|
|
int rr{rani (100)};
|
2009-07-10 19:04:01 +02:00
|
|
|
|
testVal = rr;
|
|
|
|
|
|
bound_cap_func(); // invoke state capturing
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (rr == mementoHolder.getState());
|
2009-07-10 19:04:01 +02:00
|
|
|
|
|
|
|
|
|
|
testVal = 10; // meanwhile "somehow" mutate the state
|
|
|
|
|
|
bound_undo_func(); // invoking the undo() feeds back the memento
|
2010-12-10 02:55:40 +01:00
|
|
|
|
CHECK (testVal == 10+rr);
|
2009-07-10 19:04:01 +02:00
|
|
|
|
}
|
2009-06-19 05:57:06 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
|
|
|
|
|
LAUNCHER (CommandMutation_test, "unit controller");
|
2009-07-10 19:04:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
}}} // namespace steam::control::test
|