LUMIERA.clone/tests/core/steam/mobject/session/session-service-access-test.cpp
Ichthyostega 7aa1698a95 clean-up: prepare for variadic Type-Sequences (see #987)
Attempting to reduce the remaining pre-C++11 workarounds before upgrade to C++20...

As a first step: rename the old type-sequence implementation into `TyOLD`
to make it clearly distinguishable; a new variadic implementation `TySeq`
was already introduced as partial workaround, and the next steps
will be to switch over essential parts of the type-sequence library.
2025-06-02 03:24:44 +02:00

341 lines
8.2 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.

/*
SessionServiceAccess(Test) - accessing implementation level session services
Copyright (C)
2008, 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 session-service-access-test.cpp
** unit test \ref SessionServiceAccess_test
*/
#include "lib/test/run.hpp"
#include "steam/mobject/session.hpp"
#include "lib/meta/generator.hpp"
#include "lib/format-cout.hpp"
#include "lib/depend.hpp"
#include <boost/lexical_cast.hpp>
#include <memory>
#include <string>
namespace steam {
namespace mobject {
namespace session {
namespace test {
using lib::Depend;
using boost::lexical_cast;
using std::unique_ptr;
using std::string;
namespace { // what follows is a simulated (simplified) version
// of the complete Session + SessionManager setup.....
using lib::meta::TyOLD;
using lib::meta::InstantiateChained;
/* === Interface level === */ //----------------corresponding-to-session.hpp
struct TSessManager;
typedef TSessManager& PSess;
struct TSession
{
virtual ~TSession () { }
static TSessManager& current;
virtual void externalOperation () =0;
};
struct TSessManager
{
/** access to the current session */
virtual TSession* operator-> () =0;
virtual void reset () =0;
virtual ~TSessManager() { };
};
/* === Service level API === */ //----------------internal-API-definition-headers
struct InternalAPI_1
{
virtual ~InternalAPI_1() {}
virtual uint getMagic() =0;
static InternalAPI_1& access();
};
struct InternalAPI_2
{
static void invokeImplementationService();
};
/* === Implementation level === */ //----------------corresponding-to-session-impl.hpp
struct TSessionImpl : TSession
{
static uint magic_;
/* ==== Session API ==== */
void externalOperation() ;
/* ==== Implementation level API ==== */
void implementationService() ;
/* ==== internals ==== */
TSessionImpl();
operator string() const;
};
template<class API, class IMPL>
struct TServiceAccessPoint;
template<class IMPL>
struct TServiceAccessPoint<InternalAPI_1, IMPL>
: IMPL
, InternalAPI_1
{
uint
getMagic ()
{
return IMPL::magic_;
}
};
template<class IMPL>
struct TServiceAccessPoint<InternalAPI_2, IMPL>
: IMPL
{
void
forwardServiceInvocation()
{
IMPL::implementationService();
}
};
template< typename IMPS
, class FRONT
, class SESS
>
class TSessionServices
: public InstantiateChained<typename IMPS::List, TServiceAccessPoint, SESS>
{
public:
static FRONT& current;
template<class API>
API&
get()
{
return *this;
}
};
/* === storage and basic session manager configuration === */
struct TSessManagerImpl;
typedef TSessionServices< TyOLD<InternalAPI_1,InternalAPI_2>
, TSessManagerImpl
, TSessionImpl
> SessionImplAPI;
struct TSessManagerImpl : TSessManager
{
unique_ptr<SessionImplAPI> pImpl_;
TSessManagerImpl()
: pImpl_{}
{ }
SessionImplAPI*
operator-> ()
{
if (!pImpl_)
this->reset();
return pImpl_.get();
}
/* ==== Manager API ==== */
void
reset ()
{
unique_ptr<SessionImplAPI> tmpS {new SessionImplAPI};
pImpl_.swap (tmpS);
}
};
uint TSessionImpl::magic_;
TSessManager& TSession::current = Depend<TSessManagerImpl>()();
//note: already during static initialisation
template<>
TSessManagerImpl& SessionImplAPI::current = static_cast<TSessManagerImpl&> (TSession::current);
/* === Implementation of service access === */ //----------------corresponding-to-session-services.cpp
InternalAPI_1&
InternalAPI_1::access()
{
return SessionImplAPI::current->get<InternalAPI_1>();
}
void
InternalAPI_2::invokeImplementationService()
{
SessionImplAPI::current->forwardServiceInvocation();
}
/* === Implementation of Session internals === */ //----------------corresponding-to-session-impl.cpp
TSessionImpl::operator string() const
{
return string("Session-Impl(")
+ lexical_cast<string>(magic_)
+ ")";
}
TSessionImpl::TSessionImpl()
{
++magic_;
cout << "creating new Session " << magic_ << endl;
}
void
TSessionImpl::externalOperation()
{
cout << this << "::externalOperation()" << endl;
}
/* ==== Implementation level API ==== */
inline void
TSessionImpl::implementationService()
{
cout << this << "::implementationService()" << endl;
}
} // (END) simulated session management
/***************************************************************************//**
* Verify the access mechanism both to the pubic session API and
* to implementation level APIs used by Steam-Layer internals.
*
* Actually, this test uses a simulated setup of the real session,
* complete with interfaces, implementation and session manager frontend.
*
* @see session-impl.hpp the real thing
* @see SessionServices;
*/
class SessionServiceAccess_test : public Test
{
virtual void
run (Arg)
{
access_defaultSession();
make_newSession();
invoke_implServices();
}
/** @test accessing an non-existing session
* causes creation of a new TSessionImpl instance.
* After that, the public API function gets invoked.
*/
void
access_defaultSession ()
{
cout << "Session not yet used...." << endl;
TSession::current->externalOperation();
}
/** @test invoking the management API to close the session.
* The next public API invocation will create
* a new TSessionImpl instance.
*/
void
make_newSession ()
{
TSession::current.reset();
TSession::current->externalOperation();
}
/** example of an one-liner, as it might be used
* internally by implementation code within Steam-Layer */
uint magic() { return InternalAPI_1::access().getMagic(); }
/** @test accessing implementation-level APIs */
void
invoke_implServices ()
{
cout << "current Session-Impl-ID = " << magic() << endl;
InternalAPI_2::invokeImplementationService();
cout << "now resetting this session." << endl;
TSession::current.reset();
InternalAPI_2::invokeImplementationService(); // invocation creates new session as side effect
cout << "current Session-Impl-ID = " << magic() << endl;
}
};
/** Register this test class... */
LAUNCHER (SessionServiceAccess_test, "function session");
}}}} // namespace steam::mobject::session::test