LUMIERA.clone/tests/core/steam/control/command-argument-test.cpp
Ichthyostega afa7ca2e4d Upgrade: switch to C++23 (see #1245)
The Lumiera »Reference Platform« is now upgraded to Debian/Buster, which provides GCC-14 and Clang-20.
Thus the compiler support for C++20 language features seems solid enough, and C++23,
while still in ''experimental stage'' can be seen as a complement and addendum.

This changeset
 * upgrades the compile switches for the build system
 * provides all the necessary adjustments to keep the code base compilable

Notable changes:
 * λ-capture by value now requires explicit qualification how to handle `this`
 * comparison operators are now handled transparently by the core language,
   largely obsoleting boost::operators. This change incurs several changes
   to implicit handling rules and causes lots of ambiguities — which typically
   pinpoint some long standing design issues, especially related to MObjects
   and the ''time entities''. Most tweaks done here can be ''considered preliminary''
 * unfortunately the upgraded standard ''fails'' to handle **tuple-like** entities
   in a satisfactory way — rather an ''exposition-only'' concept is introduced,
   which applies solely to some containers from the STL, thereby breaking some
   very crucial code in the render entities, which was built upon the notion of
   ''tuple-like'' entities and the ''tuple protocol''. The solution is to
   abandon the STL in this respect and **provide an alternative implementation**
   of the `apply` function and related elements.
2025-06-19 01:52:55 +02:00

349 lines
10 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
CommandArgument(Test) - checking storage of specifically typed command arguments
Copyright (C)
2009, Hermann Vosseler <Ichthyostega@web.de>
  **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.
* *****************************************************************/
/** @file command-argument-test.cpp
** unit test \ref CommandArgument_test
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "steam/control/command-storage-holder.hpp"
#include "lib/scoped-ptrvect.hpp"
#include "lib/format-string.hpp"
#include "lib/format-cout.hpp"
#include "lib/util-foreach.hpp"
#include "lib/util.hpp"
#include <functional>
#include <sstream>
#include <cstdlib>
#include <string>
#include <tuple>
#include <array>
using util::_Fmt;
using util::isnil;
using util::for_each;
using lib::time::Time;
using lib::time::TimeVar;
using lib::time::TimeValue;
using std::string;
using std::ostringstream;
using std::make_tuple;
using std::rand;
namespace steam {
namespace control {
namespace test {
using lib::test::showSizeof;
using lib::test::randTime;
using namespace lib::meta;
using LERR_(MISSING_MEMENTO);
namespace { // test helpers
ostringstream protocol; ///< used to verify the test function calls
/**
* watching the instance creation
* of some parameter values
*/
template<typename TY>
struct Tracker
{
TY element_;
static int instanceCnt;
Tracker (TY init = TY()) : element_(init) { ++instanceCnt; }
Tracker (Tracker const& otr) : element_(otr.element_) { ++instanceCnt; }
~Tracker() { --instanceCnt; }
Tracker& operator= (Tracker const&) = default;
TY&
operator* ()
{
return element_;
}
operator string() const { return util::toString(element_); }
friend bool
operator== (Tracker const& tra1, Tracker const& tra2)
{
return tra1.element_ == tra2.element_;
}
};
template<typename TY>
int Tracker<TY>::instanceCnt (0);
/** Dummy custom memento datatype
* @note memento needs to be equality comparable
*/
struct Sint5
{
std::array<int,5> i5i;
friend bool
operator== (Sint5 const& i1, Sint5 const& i2)
{
return i1.i5i == i2.i5i;
}
};
/* === functions to implement test-"operation" & UNDO === */
void
doIt (Tracker<TimeVar> time, Tracker<string> str, int rand)
{
static _Fmt fmt ("doIt( Time=%s \"%s\" rand=%2d )");
cout << "invoke operation..." << endl;
protocol << fmt % *time % *str % rand;
}
Tracker<string>
captureState (Tracker<TimeVar>, Tracker<string> xstr, int)
{
cout << "capture state..." << endl;
return protocol.str() + *xstr;
}
void
undoIt (Tracker<TimeVar> time, Tracker<string>, int, Tracker<string> memento)
{
cout << "undo... memento=" << memento << endl;
protocol << "undoIt(time="<<time<<")----memento-:"<< *memento;
}
/// another dummy-UNDO function
void dummyU (int,int,int) { }
int dummyC (int u,int o) { return u + rani(o-u+1); }
void
showIt (CmdClosure& clo)
{
cout << clo << endl;
}
void
checkSerialisation (CmdClosure& clo)
{
TODO ("implement serialisation/de-serialisation-Check");
cout << "would be serialised....." << clo << endl;
// serialise, then de-serialise into a new instance and compare both
}
int
twoRandomDigits()
{
return 10 + rani(90);
}
} // test-helper implementation
typedef lib::ScopedPtrVect<CmdClosure> ArgTuples;
/***********************************************************************//**
* @test Check storage handling of the command parameters and state memento.
*
* @see control::CommandStorageHolder
* @see command-basic-test.hpp
*/
class CommandArgument_test : public Test
{
virtual void
run (Arg)
{
seedRand();
ArgTuples testTuples;
Tracker<TimeVar>::instanceCnt = 0;
Tracker<string>::instanceCnt = 0;
createTuples (testTuples);
serialiseArgTuples (testTuples);
testTuples.clear();
simulateCmdLifecycle();
// verify all dtors properly called...
CHECK (0 == Tracker<TimeVar>::instanceCnt);
CHECK (0 == Tracker<string>::instanceCnt);
}
typedef Tracker<TimeVar> TTime;
typedef Tracker<string> Tstr;
/** @test create various argument tuples and re-access their contents */
void
createTuples (ArgTuples& tup)
{
typedef StorageHolder<void(), bool> A1;
typedef StorageHolder<void(int), void*> A2;
typedef StorageHolder<void(int,TimeVar), int> A3;
typedef StorageHolder<void(int,TimeVar), Sint5> A4;
typedef StorageHolder<void(TTime,Tstr,int), Tstr> A5;
A1* arg1 = new A1(); tup.manage (arg1);
A2* arg2 = new A2(); tup.manage (arg2);
A3* arg3 = new A3(); tup.manage (arg3);
A4* arg4 = new A4(); tup.manage (arg4);
A5* arg5 = new A5(); tup.manage (arg5);
CHECK (isnil (*arg1));
CHECK (isnil (*arg2));
CHECK (isnil (*arg3));
CHECK (isnil (*arg4));
CHECK (isnil (*arg5));
for_each (tup, showIt);
arg1->storeTuple (std::tuple<>());
arg2->storeTuple (make_tuple (rani(10)));
arg3->storeTuple (make_tuple (rani(10), TimeVar(randTime())));
arg4->storeTuple (make_tuple (rani(10), TimeVar(randTime())));
arg5->storeTuple (make_tuple (TTime (randTime()), Tstr("glorious"), twoRandomDigits() ));
CHECK (!arg5->canUndo());
arg5->tie(undoIt, captureState)
.tieCaptureFunc() // bind capturing function to memento storage,
(TTime(), Tstr("destruction"), 11); // then invoke the bound capturing mechanism
CHECK (arg5->canUndo());
CHECK (*arg5->memento() == "destruction");
VERIFY_ERROR(MISSING_MEMENTO, arg4->memento().i5i[3] = 513 );
for_each (tup, showIt);
}
/** @test serialise and de-serialise each tuple and check validity
* @todo unimplemented, waiting on Serialiser
*/
void
serialiseArgTuples (ArgTuples& tup)
{
for_each (tup, checkSerialisation);
}
/** @test simulate a complete command lifecycle with regards to the
* storage handling of the command parameters and state memento.
*/
void
simulateCmdLifecycle()
{
typedef void SIG_do(Tracker<TimeVar>, Tracker<string>, int);
using Args = StorageHolder<SIG_do, Tracker<string>>;
using MemHolder = MementoTie<SIG_do, Tracker<string>>;
Args args;
CHECK (isnil (args));
cout << showSizeof(args) << endl;
// store a set of parameter values, later to be used on invocation
args.storeTuple (
make_tuple (TTime(randTime()), Tstr("Lumiera rocks"), twoRandomDigits() ));
CHECK (!isnil (args));
cout << args << endl;
CHECK (!args.canUndo());
VERIFY_ERROR(MISSING_MEMENTO, args.memento() );
MemHolder& memHolder = args.tie(undoIt,captureState);
CHECK (!memHolder); // no stored memento....
CHECK (!args.canUndo());
function<SIG_do> doItFun = doIt;
function<SIG_do> undoFun = memHolder.tieUndoFunc();
function<SIG_do> captFun = memHolder.tieCaptureFunc();
typedef function<void()> OpFun;
// now close all the functions with the stored parameter values...
OpFun bound_doItFun = std::bind (&CmdClosure::invoke, args, CmdFunctor(doItFun));
OpFun bound_undoFun = std::bind (&CmdClosure::invoke, args, CmdFunctor(undoFun));
OpFun bound_captFun = std::bind (&CmdClosure::invoke, args, CmdFunctor(captFun));
protocol.seekp(0);
protocol << "START...";
bound_captFun();
cout << "captured state: " << args.memento() << endl;
CHECK (memHolder);
CHECK (!isnil (*args.memento()));
CHECK (args.canUndo());
cout << args << endl;
bound_doItFun();
cout << protocol.str() << endl;
bound_undoFun();
cout << protocol.str() << endl;
// Commands can serve as prototype to be copied....
Args argsCopy (args);
bound_captFun();
protocol.seekp(0);
protocol << "RESET...";
args.storeTuple (
make_tuple (TTime(TimeValue(123456)), Tstr("unbelievable"), twoRandomDigits() ));
cout << "modified: " << args << endl;
cout << "copied : " << argsCopy << endl; // holds still the old params & memento
bound_undoFun();
cout << protocol.str() << endl;
}
};
/** Register this test class... */
LAUNCHER (CommandArgument_test, "unit controller");
}}} // namespace steam::control::test