WIP injecting a test-mock instead of a singleton
This commit is contained in:
parent
7585c5c358
commit
eef591f873
12 changed files with 496 additions and 32 deletions
|
|
@ -26,7 +26,9 @@
|
|||
namespace backend_interface
|
||||
{
|
||||
|
||||
/** */
|
||||
/** storage for the SingletonFactory
|
||||
* (actually a cinelerra::test::MockInjector) */
|
||||
Singleton<MediaAccessFacade> MediaAccessFacade::instance;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef CINELERRA_MULTITHREAD_H
|
||||
#define CINELERRA_MULTITHREAD_H
|
||||
|
||||
#include "nobugcfg.h"
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
|
|
|
|||
52
src/common/singleton.hpp
Normal file
52
src/common/singleton.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
SINGLETON.hpp - configuration header for singleton factory
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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 singleton.hpp
|
||||
** Factory for creating Singleton instances.
|
||||
** This configuration header just pulls in some other implementation headers in
|
||||
** the right order. The basic class template for creating singletons resides in
|
||||
** singletonfactory.hpp, besides we need policy classes defining how to create
|
||||
** the singleton objects, how to manage lifecycle and multithreading. Finally,
|
||||
** we want to preconfigure singleton factories for some important facilities;
|
||||
** e.g. sometimes we want to include a hook for injecting Test Mock instances.
|
||||
**
|
||||
** You'll find the default Policies in singletonfactory.hpp and the default
|
||||
** definition of type cinelerra::singleton in singletonpreconfigure.hpp
|
||||
**
|
||||
** @see SingletonFactory
|
||||
** @see singleton::StaticCreate
|
||||
** @see singleton::AutoDestroy
|
||||
** @see singletontest.hpp
|
||||
** @see singletontestmocktest.hpp
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CINELERRA_SINGLETON_H
|
||||
#define CINELERRA_SINGLETON_H
|
||||
|
||||
|
||||
#include "common/singletonpolicies.hpp"
|
||||
#include "common/singletonfactory.hpp"
|
||||
#include "common/singletonpreconfigure.hpp"
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -54,8 +54,8 @@ namespace cinelerra
|
|||
*/
|
||||
template
|
||||
< class SI, // the class to make Singleton
|
||||
template <class> class Create = singleton::Static, // how to create/destroy the instance
|
||||
template <class> class Life = singleton::Automatic, // how to manage Singleton Lifecycle
|
||||
template <class> class Create = singleton::StaticCreate, // how to create/destroy the instance
|
||||
template <class> class Life = singleton::AutoDestroy, // how to manage Singleton Lifecycle
|
||||
template <class> class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!!
|
||||
>
|
||||
class SingletonFactory
|
||||
|
|
@ -99,6 +99,8 @@ namespace cinelerra
|
|||
*/
|
||||
static void destroy()
|
||||
{
|
||||
TRACE (singleton, "Singleton: triggering destruction");
|
||||
|
||||
REQUIRE (!isDead_);
|
||||
Create<SI>::destroy (pInstance_);
|
||||
pInstance_ = 0;
|
||||
|
|
@ -131,7 +133,9 @@ namespace cinelerra
|
|||
///// is tricky because of invoking the destructors. If we rely on instance vars,
|
||||
///// the object may already have been released when the runtime system calls the
|
||||
///// destructors of static objects at shutdown.
|
||||
|
||||
///// It seems this would either cost us much of the flexibility or get complicated
|
||||
///// to a point where we could as well implement our own Depenency Injection Manager.
|
||||
|
||||
/** @internal used to link together the Create policy and Life policy.
|
||||
* @return a functor object for invoking this->destroy() */
|
||||
/* SingletonFactory::DelFunc getDeleter()
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ namespace cinelerra
|
|||
* Policy for creating the Singleton instance statically
|
||||
*/
|
||||
template<class S>
|
||||
struct Static
|
||||
struct StaticCreate
|
||||
{
|
||||
static S* create ()
|
||||
{
|
||||
|
|
@ -72,29 +72,13 @@ namespace cinelerra
|
|||
* Policy for creating the Singleton instance heap allocated
|
||||
*/
|
||||
template<class S>
|
||||
struct Heap
|
||||
struct HeapCreate
|
||||
{
|
||||
static S* create () { return new S; }
|
||||
static void destroy (S* pS) { delete pS; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Policy for creating dynamic Singleton instance, with
|
||||
* additional facility to support Mock testing. When injecting
|
||||
* a Mock instance (typically a subclass of the product), the
|
||||
* main Singleton instance is temporarily shaddowed.
|
||||
*/
|
||||
template<class S>
|
||||
struct DynamicMockTestable
|
||||
{
|
||||
static S* create () { return new S; }
|
||||
static void destroy (S* pS) { delete pS; }
|
||||
};
|
||||
void injectSubclass (SI* mock)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -105,7 +89,7 @@ namespace cinelerra
|
|||
* Policy relying on the compiler/runtime system for Singleton Lifecycle
|
||||
*/
|
||||
template<class S>
|
||||
struct Automatic
|
||||
struct AutoDestroy
|
||||
{
|
||||
/** implements the Singleton removal by calling
|
||||
* the provided deleter function(s) at application shutdown,
|
||||
|
|
|
|||
112
src/common/singletonpreconfigure.hpp
Normal file
112
src/common/singletonpreconfigure.hpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
SINGLETONPRECONFIGURE - declare the configuration of some Singleton types in advance
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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 singletonpreconfigure.hpp
|
||||
** Preconfiguration of some Singleton types, done by template specialisation.
|
||||
** Typically the client code just includes singleton.h and uses the Singleton
|
||||
** type. But in some cases, we want to configure specific (dependency injection)
|
||||
** behaviour at a central location. At some point, we may well have a full blown
|
||||
** Dependency Manager, but for the moment using just some specialized Singleton
|
||||
** type for some instances seems sufficient.
|
||||
**
|
||||
** One Reason why one wants special Singleton behaviour is Testing: Without
|
||||
** altering the executable, for running some Tests we need to inject a Test Mock
|
||||
** in place of some Service Object, so we can verify the behaviour of the code
|
||||
** <i>using</i> this Service. For this, we mix cinelerra::test::MockInjector
|
||||
** into the actual Singleton type.
|
||||
**
|
||||
** @note we declare the specialisations into the target namespace
|
||||
**
|
||||
** @see SingletonFactory
|
||||
** @see singletontestmocktest.hpp
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CINELERRA_SINGLETONPRECONFIGURE_H
|
||||
#define CINELERRA_SINGLETONPRECONFIGURE_H
|
||||
|
||||
#include "common/test/mockinjector.hpp"
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
/**
|
||||
* Default Singleton configuration
|
||||
* @note all Policy template parameters taking default values
|
||||
*/
|
||||
template <class SI>
|
||||
class Singleton
|
||||
: public SingletonFactory<SI>
|
||||
{ }
|
||||
;
|
||||
|
||||
|
||||
/* ********************************************************************** */
|
||||
/* Forward declarations of all Classes we want to specialize the template */
|
||||
/* ********************************************************************** */
|
||||
|
||||
namespace test
|
||||
{
|
||||
class TargetObj;
|
||||
using cinelerra::Singleton;
|
||||
|
||||
} // namespace test
|
||||
} // namespace cinelerra
|
||||
|
||||
namespace backend_interface
|
||||
{
|
||||
class MediaAccessFacade;
|
||||
using cinelerra::Singleton;
|
||||
|
||||
} // namespace backend_interface
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ************************** */
|
||||
/* Specialisation Definitions */
|
||||
/* ************************** */
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
|
||||
using test::MockInjector;
|
||||
|
||||
|
||||
template<>
|
||||
class Singleton<test::TargetObj>
|
||||
: public MockInjector<test::TargetObj>
|
||||
{ };
|
||||
|
||||
|
||||
template<>
|
||||
class Singleton<backend_interface::MediaAccessFacade>
|
||||
: public MockInjector<backend_interface::MediaAccessFacade>
|
||||
{ };
|
||||
|
||||
} // namespace cinelerra
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
94
src/common/test/mockinjector.hpp
Normal file
94
src/common/test/mockinjector.hpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
MOCKINJECTOR.hpp - replacement singleton factory for injecting Test-Mock objects
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CINELERRA_TEST_MOCKINJECTOR_H
|
||||
#define CINELERRA_TEST_MOCKINJECTOR_H
|
||||
|
||||
|
||||
#include "common/singletonfactory.hpp"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
using boost::scoped_ptr;
|
||||
|
||||
/**
|
||||
* Special SingletonFactory allowing to inject some instance of the Singleton
|
||||
* class, thus shaddowing "the" (default) Singleton instance temporarily.
|
||||
* This allows installing a Mock Subclass of the Singleton for running tests,
|
||||
* while the Singleton can be used as usual in production code.
|
||||
* @note we use the default policies or SingletonFactory
|
||||
*/
|
||||
template<class SI>
|
||||
class MockInjector : public SingletonFactory<SI>
|
||||
{
|
||||
scoped_ptr<SI> mock_;
|
||||
|
||||
public:
|
||||
/** Overwriting the normal Singleton creation Interface
|
||||
* to return some mock if defined, falling back to the
|
||||
* default Singleton creation behaviour else.
|
||||
*/
|
||||
SI& operator() ()
|
||||
{
|
||||
if (mock_)
|
||||
return *mock_;
|
||||
else
|
||||
return SingletonFactory<SI>::operator() ();
|
||||
}
|
||||
|
||||
void injectSubclass (SI* mockobj)
|
||||
{
|
||||
TRACE_IF (mockobj, singleton, "Singleton: installing Mock object");
|
||||
TRACE_IF (!mockobj, singleton, "Singleton: removing Mock object");
|
||||
mock_.reset (mockobj);
|
||||
}
|
||||
|
||||
|
||||
MockInjector () {};
|
||||
|
||||
/** @note MockInjector singleton factory objects can be copied,
|
||||
* but the copy will start out with clean internal state,
|
||||
* i.e. exhibiting normal SingletonFactory behaviour
|
||||
* without mock object.
|
||||
*/
|
||||
MockInjector (const MockInjector& other)
|
||||
: SingletonFactory<SI>(other), mock_(0) { }
|
||||
|
||||
MockInjector<SI>& operator= (const MockInjector<SI>& other)
|
||||
{
|
||||
return SingletonFactory<SI>::operator= (other);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace cinelerra
|
||||
#endif
|
||||
|
|
@ -50,6 +50,7 @@
|
|||
/* declare flags used throughout the code base... */
|
||||
NOBUG_DECLARE_FLAG(config);
|
||||
NOBUG_DECLARE_FLAG(test);
|
||||
NOBUG_DECLARE_FLAG(singleton);
|
||||
NOBUG_DECLARE_FLAG(assetmem);
|
||||
NOBUG_DECLARE_FLAG(mobjectmem);
|
||||
|
||||
|
|
@ -76,7 +77,8 @@
|
|||
/* flags used throughout the code base... */
|
||||
NOBUG_CPP_DEFINE_FLAG(config);
|
||||
NOBUG_CPP_DEFINE_FLAG(test);
|
||||
NOBUG_CPP_DEFINE_FLAG_LIMIT(assetmem, LOG_WARNING);
|
||||
NOBUG_CPP_DEFINE_FLAG_LIMIT(singleton, LOG_WARNING);
|
||||
NOBUG_CPP_DEFINE_FLAG_LIMIT(assetmem, LOG_WARNING);
|
||||
NOBUG_CPP_DEFINE_FLAG_LIMIT(mobjectmem, LOG_WARNING);
|
||||
|
||||
#include "common/error.hpp"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ namespace asset
|
|||
DB () : table() {}
|
||||
~DB () {}
|
||||
|
||||
friend class cinelerra::singleton::Static<DB>;
|
||||
friend class cinelerra::singleton::StaticCreate<DB>;
|
||||
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ namespace asset
|
|||
|
||||
AssetManager ();
|
||||
|
||||
friend class cinelerra::singleton::Static<AssetManager>;
|
||||
friend class cinelerra::singleton::StaticCreate<AssetManager>;
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ namespace cinelerra
|
|||
protected:
|
||||
TargetObj () : TestTargetObj(cnt) {}
|
||||
|
||||
friend class singleton::Static<TargetObj>;
|
||||
friend class singleton::Heap<TargetObj>;
|
||||
friend class singleton::StaticCreate<TargetObj>;
|
||||
friend class singleton::HeapCreate<TargetObj>;
|
||||
};
|
||||
|
||||
int TargetObj::cnt = 0;
|
||||
|
|
@ -74,8 +74,8 @@ namespace cinelerra
|
|||
* @test implement a Singleton class using our Singleton Template.
|
||||
* Expected results: no memory leaks.
|
||||
* @see cinelerra::Singleton
|
||||
* @see cinelerra::singleton::Static
|
||||
* @see cinelerra::singleton::Heap
|
||||
* @see cinelerra::singleton::StaticCreate
|
||||
* @see cinelerra::singleton::HeapCreate
|
||||
*/
|
||||
class Singleton_test : public Test
|
||||
{
|
||||
|
|
@ -96,7 +96,7 @@ namespace cinelerra
|
|||
*/
|
||||
void testStaticallyAllocatedSingleton (uint num)
|
||||
{
|
||||
Singleton<TargetObj> single;
|
||||
SingletonFactory<TargetObj> single;
|
||||
instance = single;
|
||||
useInstance (num, "statically allocated");
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ namespace cinelerra
|
|||
*/
|
||||
void testHeapAllocatedSingleton (uint num)
|
||||
{
|
||||
Singleton<TargetObj,singleton::Heap> single;
|
||||
SingletonFactory<TargetObj,singleton::HeapCreate> single;
|
||||
instance = single;
|
||||
useInstance (num, "heap allocated");
|
||||
}
|
||||
|
|
|
|||
213
tests/components/common/singletontestmocktest.cpp
Normal file
213
tests/components/common/singletontestmocktest.cpp
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
SingletonTestMock(Test) - using Singleton for injecting Test-Mocks
|
||||
|
||||
Copyright (C) CinelerraCV
|
||||
2007, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
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 "common/test/run.hpp"
|
||||
#include "common/singleton.hpp"
|
||||
#include "common/util.hpp"
|
||||
#include "nobugcfg.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::lexical_cast;
|
||||
using boost::format;
|
||||
using util::isnil;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
|
||||
|
||||
namespace cinelerra
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Client Class normally to be instantiated as Singleton.
|
||||
* But for tests, this class should be replaced by a Mock....
|
||||
*/
|
||||
class TargetObj
|
||||
{
|
||||
int callCnt;
|
||||
char* typid;
|
||||
format msg;
|
||||
|
||||
public:
|
||||
TargetObj(char* ty="TargetObj")
|
||||
: callCnt (0), typid(ty), msg ("%s::doIt() call=%d\n")
|
||||
{
|
||||
TRACE (singleton, "ctor %s", typid);
|
||||
}
|
||||
virtual ~TargetObj()
|
||||
{
|
||||
TRACE (singleton, "dtor %s", typid);
|
||||
}
|
||||
|
||||
void doIt ()
|
||||
{
|
||||
++callCnt;
|
||||
cout << msg % typid % callCnt;
|
||||
}
|
||||
int getCnt () {return callCnt; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mock-1 to replace the Client Class...
|
||||
*/
|
||||
struct Mock_1 : TargetObj
|
||||
{
|
||||
Mock_1() : TargetObj("Mock_1") {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock-2 to replace the Client Class...
|
||||
*/
|
||||
struct Mock_2 : TargetObj
|
||||
{
|
||||
Mock_2() : TargetObj("Mock_2") {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* @test inject a Mock object into the Singleton Factory,
|
||||
* to be returned and used in place of the original object.
|
||||
* Expected results: Mock(s) called, no memory leaks.
|
||||
* @see cinelerra::Singleton
|
||||
* @see cinelerra::singleton::Static
|
||||
*/
|
||||
class SingletonTestMock_test : public Test
|
||||
{
|
||||
Singleton<TargetObj> instance;
|
||||
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
string scenario = isnil(arg)? "default" : arg[1];
|
||||
|
||||
if (scenario == "default")
|
||||
injectBoth();
|
||||
else
|
||||
if (scenario == "noMock")
|
||||
noMock();
|
||||
else
|
||||
if (scenario == "onlyMock")
|
||||
onlyMock();
|
||||
else
|
||||
if (scenario == "firstMock")
|
||||
firstMock();
|
||||
}
|
||||
|
||||
|
||||
/** @test complete use sequence: first access the Client Object,
|
||||
* then replace it by two different mocks, and finally
|
||||
* restore the original Client Object
|
||||
*/
|
||||
void injectBoth ()
|
||||
{
|
||||
TargetObj* tartar = &instance();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 2);
|
||||
|
||||
instance.injectSubclass (new Mock_1);
|
||||
tartar = &instance();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 5);
|
||||
|
||||
instance.injectSubclass (new Mock_2);
|
||||
tartar = &instance();
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 1);
|
||||
|
||||
instance.injectSubclass (0); // unshaddowing original instance
|
||||
tartar = &instance();
|
||||
ASSERT (tartar->getCnt() == 2);
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 3);
|
||||
}
|
||||
|
||||
|
||||
/** @test just use Singleton Factory normally without any Mock.
|
||||
*/
|
||||
void noMock ()
|
||||
{
|
||||
TargetObj& tartar = instance();
|
||||
tartar.doIt();
|
||||
}
|
||||
|
||||
|
||||
/** @test inject the Mock prior to using the Singleton Factory,
|
||||
* thus the original Client Object shouldn't be created.
|
||||
*/
|
||||
void onlyMock ()
|
||||
{
|
||||
instance.injectSubclass (new Mock_1);
|
||||
TargetObj& tartar = instance();
|
||||
tartar.doIt();
|
||||
}
|
||||
|
||||
|
||||
/** @test inject the Mock prior to using the Singleton Factory,
|
||||
* but then reset the Mock, so following calls should
|
||||
* create the original Client Object.
|
||||
*/
|
||||
void firstMock ()
|
||||
{
|
||||
instance.injectSubclass (new Mock_1);
|
||||
TargetObj* tartar = &instance();
|
||||
tartar->doIt();
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 2);
|
||||
|
||||
instance.injectSubclass (0);
|
||||
tartar = &instance();
|
||||
tartar->doIt();
|
||||
ASSERT (tartar->getCnt() == 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SingletonTestMock_test, "unit common");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace cinelerra
|
||||
Loading…
Reference in a new issue