after all the relevant library components do support both kinds of type sequences transparently, any usages in core code can now be switched over to the new, variadic type sequences.
341 lines
8.2 KiB
C++
341 lines
8.2 KiB
C++
/*
|
||
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::TySeq;
|
||
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;
|
||
|
||
using SessionImplAPI = TSessionServices< TySeq<InternalAPI_1,InternalAPI_2>
|
||
, TSessManagerImpl
|
||
, TSessionImpl
|
||
>;
|
||
|
||
|
||
|
||
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
|