all these tests are ported by drop-in replacement and should work afterwards exactly as before (and they do indeed) A minor twist was spotted though (nice to have more unit tests indeed!): Sometimes we want to pass a custom constructor *not* as modern-style lambda, but rather as direct function reference, function pointer or even member function pointer. However, we can not store those types into the closure for later lazy invocation. This is basically the same twist I run into yesterday, when modernising the thread-wrapper. And the solution is similar. Our traits class _Fun<FUN> has a new typedef Functor with a suitable functor type to be instantiated and copied. In case of the Lambda this is the (anonymous) lamda class itself, but in case of a function reference or pointer it is a std::function.
173 lines
4.3 KiB
C++
173 lines
4.3 KiB
C++
/*
|
|
SingletonTestMock(Test) - using Singleton for injecting Test-Mocks
|
|
|
|
Copyright (C) Lumiera.org
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
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-testmock-test.cpp
|
|
** unit test \ref SingletonTestMock_test
|
|
*/
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
#include "lib/depend-inject.hpp"
|
|
#include "lib/util.hpp"
|
|
|
|
#include "lib/format-cout.hpp"
|
|
#include "lib/format-string.hpp"
|
|
|
|
using util::_Fmt;
|
|
using util::isnil;
|
|
|
|
|
|
namespace lib {
|
|
namespace test{
|
|
|
|
|
|
/**
|
|
* Client Class normally to be instantiated as Singleton.
|
|
* But for tests, this class should be replaced by a Mock....
|
|
*/
|
|
class TestSingO
|
|
{
|
|
int callCnt_;
|
|
Symbol typid_;
|
|
_Fmt msg_;
|
|
|
|
public:
|
|
TestSingO(Symbol ty="TestSingO")
|
|
: callCnt_(0)
|
|
, typid_(ty)
|
|
, msg_("%s::doIt() call=%d\n")
|
|
{
|
|
TRACE (test, "ctor %s", typid_.c());
|
|
}
|
|
|
|
virtual
|
|
~TestSingO()
|
|
{
|
|
TRACE (test, "dtor %s", typid_.c());
|
|
}
|
|
|
|
void doIt ()
|
|
{
|
|
++callCnt_;
|
|
cout << msg_ % typid_ % callCnt_;
|
|
}
|
|
|
|
int getCnt ()
|
|
{
|
|
return callCnt_;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Mock-1 to replace the Client Class...
|
|
*/
|
|
struct Mock_1 : TestSingO
|
|
{
|
|
Mock_1() : TestSingO("Mock_1") { };
|
|
};
|
|
|
|
/**
|
|
* Mock-2 to replace the Client Class...
|
|
* @note no default ctor
|
|
*/
|
|
struct Mock_2 : TestSingO
|
|
{
|
|
int id;
|
|
|
|
Mock_2(Literal specialID, int i)
|
|
: TestSingO{Symbol (_Fmt{"%s_%d"} % specialID % i)}
|
|
, id{i}
|
|
{ };
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************//**
|
|
* @test inject a Mock object into the Singleton Factory,
|
|
* to be returned and used in place of the original object.
|
|
* This test covers the full usage cycle: first access the
|
|
* Client Object, then replace it by two different mocks,
|
|
* and finally restore the original Client Object.
|
|
* @see lib::Depend
|
|
* @see depend-inject.hpp
|
|
* @see DependencyFactory_test
|
|
*/
|
|
class SingletonTestMock_test : public Test
|
|
{
|
|
|
|
void
|
|
run (Arg)
|
|
{
|
|
Depend<TestSingO> sing;
|
|
|
|
sing().doIt();
|
|
sing().doIt();
|
|
CHECK (sing().getCnt() == 2);
|
|
|
|
{
|
|
// shadow by local Mock instance
|
|
DependInject<TestSingO>::Local<Mock_1> mock_1;
|
|
sing().doIt();
|
|
sing().doIt();
|
|
sing().doIt();
|
|
sing().doIt();
|
|
sing().doIt();
|
|
CHECK (sing().getCnt() == 5);
|
|
|
|
// shadow again by different local Mock, this time with special ctor call
|
|
int instanceID = 0;
|
|
DependInject<TestSingO>::Local<Mock_2> mock_2 ([&]{ return new Mock_2{"Mock", instanceID}; });
|
|
|
|
// NOTE: the ctor call for the Mock really happens delayed...
|
|
instanceID = rand() % 10;
|
|
sing().doIt(); // ctor invoked on first access
|
|
CHECK (sing().getCnt() == 1);
|
|
|
|
// can access the Mock for instrumentation
|
|
CHECK (instanceID == mock_2->id);
|
|
|
|
}// original instance automatically un-shadowed here
|
|
|
|
CHECK (sing().getCnt() == 2);
|
|
sing().doIt();
|
|
CHECK (sing().getCnt() == 3);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/** Register this test class... */
|
|
LAUNCHER (SingletonTestMock_test, "unit common");
|
|
|
|
|
|
|
|
}} // namespace lib::test
|