DI: draft implementation for testmock support

This commit is contained in:
Fischlurch 2018-03-18 00:05:02 +01:00
parent 786f051132
commit f0c8928301
2 changed files with 168 additions and 15 deletions

View file

@ -182,6 +182,14 @@ class DependInject
{
using Factory = typename Depend<SRV>::Factory;
public:
template<class SUB>
static void
__assert_compatible()
{
static_assert (std::is_base_of<SRV,SUB>::value,
"Installed implementation class must be compatible to the interface.");
}
static void
installFactory (Factory&& otherFac)
{
@ -193,6 +201,24 @@ class DependInject
Depend<SRV>::factory = move (otherFac);
}
static void
temporarilyInstallAlternateFactory (SRV*& stashInstance, Factory& stashFac, Factory&& newFac)
{
ClassLock<SRV> guard;
stashFac = move(Depend<SRV>::factory);
stashInstance = Depend<SRV>::instance;
Depend<SRV>::factory = move(newFac);
Depend<SRV>::instance = nullptr;
}
static void
restoreOriginalFactory (SRV*& stashInstance, Factory& stashFac)
{
ClassLock<SRV> guard;
Depend<SRV>::factory = move(stashFac);
Depend<SRV>::instance = stashInstance;
}
static void
disableFactory()
{
@ -225,6 +251,7 @@ class DependInject
static void
useSingleton()
{
__assert_compatible<SUB>();
static InstanceHolder<SUB> singleton;
installFactory ([&]()
{
@ -243,6 +270,7 @@ class DependInject
ServiceInstance()
: instance_(new IMP{})
{
__assert_compatible<IMP>();
activateServiceAccess (*instance_);
}
@ -251,6 +279,10 @@ class DependInject
deactivateServiceAccess();
}
ServiceInstance (ServiceInstance&&) = default;
ServiceInstance (ServiceInstance const&) = delete;
ServiceInstance& operator= (ServiceInstance&&) = delete;
explicit
operator bool() const
{
@ -272,13 +304,54 @@ class DependInject
}
};
template<class IMP>
template<class MOC>
class Local
{
std::unique_ptr<MOC> mock_;
SRV* origInstance_;
Factory origFactory_;
public:
Local()
{
__assert_compatible<MOC>();
temporarilyInstallAlternateFactory (origInstance_, origFactory_
,[this]()
{
disableFactory();
mock_.reset(new MOC{});
return mock_.get();
});
}
~Local()
{
restoreOriginalFactory (origInstance_, origFactory_);
}
Local (Local&&) = default;
Local (Local const&) = delete;
Local& operator= (Local&&) = delete;
explicit
operator bool() const
{
return bool(mock_);
}
MOC&
operator* () const
{
ENSURE (mock_);
return *mock_;
}
MOC*
operator-> () const
{
ENSURE (mock_);
return mock_.get();
}
};
};
@ -367,6 +440,69 @@ main (int, char**)
VERIFY_ERROR (LIFECYCLE, DependInject<Dum>::ServiceInstance<SubDummy>{} );
SHOW_EXPR( checksum );
{
DependInject<Dum>::Local<SubDummy> mockDum;
DependInject<Dummy<3>>::Local<SubDummy> mockDummy3;
CHECK (!mockDum);
CHECK (!mockDummy3);
SHOW_EXPR( dumm().probe() );
CHECK ( mockDum);
CHECK (!mockDummy3);
SHOW_EXPR( checksum );
SHOW_EXPR( mockDum->probe() );
SHOW_EXPR( checksum );
mockDum->offset = 20;
SHOW_EXPR( dumm().probe() );
VERIFY_ERROR (LIFECYCLE, mockDummy3->probe() );
SHOW_EXPR( checksum );
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( checksum );
CHECK ( mockDummy3);
SHOW_EXPR( mockDummy3->probe() );
SHOW_EXPR( checksum );
mockDummy3->offset = 10;
SHOW_EXPR( dep3().probe() );
mockDum->offset = 50;
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( dumm().probe() );
SHOW_EXPR( checksum );
}
SHOW_EXPR( checksum );
SHOW_EXPR( dumm().probe() );
VERIFY_ERROR (LIFECYCLE, dep3().probe() );
SHOW_EXPR( checksum );
{
DependInject<Dummy<3>>::ServiceInstance<SubDummy> service{};
SHOW_EXPR( checksum );
SHOW_EXPR( dep3().probe() );
service->offset = 5;
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( checksum );
{
DependInject<Dummy<3>>::Local<SubDummy> mockDummy31;
CHECK (!mockDummy31);
SHOW_EXPR( checksum );
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( checksum );
mockDummy31->offset = 10;
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( mockDummy31->probe() );
SHOW_EXPR( service->probe() );
CHECK (mockDummy31->offset != service->offset);
service->offset = 35;
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( mockDummy31->probe() );
SHOW_EXPR( service->probe() );
SHOW_EXPR( checksum );
}
SHOW_EXPR( checksum );
SHOW_EXPR( dep3().probe() );
SHOW_EXPR( checksum );
}
SHOW_EXPR( checksum );
VERIFY_ERROR (LIFECYCLE, dep3().probe() );
SHOW_EXPR( checksum );
cout << "\n.gulp.\n";

View file

@ -26839,21 +26839,38 @@
<node CREATED="1521208339124" ID="ID_1092066450" MODIFIED="1521387948246" TEXT="(optional)Closure &#xfc;ber konkreten Ctor"/>
</node>
<node CREATED="1521208261887" ID="ID_384054163" MODIFIED="1521208264827" TEXT="Local">
<node CREATED="1521209044203" ID="ID_1994153994" MODIFIED="1521209058181" TEXT="Closure &#xfc;ber konkreten Ctor"/>
<node CREATED="1521209708336" ID="ID_1870723126" MODIFIED="1521209734757" TEXT="Storage f&#xfc;r UnterBla-Instanz bereitstellen"/>
<node CREATED="1521209447572" ID="ID_1106858165" MODIFIED="1521209693387" TEXT="bestehenden Service-Zugang aus Depend&lt;Bla&gt; beiseite speichern"/>
<node CREATED="1521209547606" ID="ID_1693604174" MODIFIED="1521209881556" TEXT="tempor&#xe4;r neuen Service-Zugang in Depend&lt;Bla&gt; installieren, an erzeugte Closure delegierend"/>
<node CREATED="1521209759585" ID="ID_267047467" MODIFIED="1521209766124" TEXT="Lebenszyklus-Koppelung">
<node CREATED="1521209811802" ID="ID_1712617923" MODIFIED="1521209827180" TEXT="f&#xfc;r die UnterBla-Instanz"/>
<node CREATED="1521209827775" ID="ID_280216675" MODIFIED="1521209850760" TEXT="f&#xfc;r den tempor&#xe4;r installierten Service-Zugang"/>
<node CREATED="1521209044203" ID="ID_1994153994" MODIFIED="1521409010023" TEXT="(optional)Closure mit speziellen Argumenten "/>
<node COLOR="#338800" CREATED="1521209708336" ID="ID_1870723126" MODIFIED="1521411844636" TEXT="Storage f&#xfc;r UnterBla-Instanz bereitstellen">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1521208724943" ID="ID_221402501" MODIFIED="1521208881882" TEXT="smart-ptr-artiger Zugriff auf die Service-Impl"/>
<node CREATED="1521209904013" ID="ID_1098048607" MODIFIED="1521209918615" TEXT="debug/Kontroll-API">
<node CREATED="1521209958014" ID="ID_1638584681" MODIFIED="1521210043546" TEXT="Lebenszustand"/>
<node CREATED="1521209945287" ID="ID_42798820" MODIFIED="1521210049471" TEXT="Erzeugen/Zerst&#xf6;ren der Instanz">
<icon BUILTIN="help"/>
<node COLOR="#338800" CREATED="1521209447572" ID="ID_1106858165" MODIFIED="1521411847148" TEXT="bestehenden Service-Zugang aus Depend&lt;Bla&gt; beiseite speichern">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1521210051457" ID="ID_1794637059" MODIFIED="1521210070534" TEXT="explizites Deinstallieren">
<node COLOR="#338800" CREATED="1521209547606" ID="ID_1693604174" MODIFIED="1521411853636" TEXT="tempor&#xe4;r neuen Service-Zugang in Depend&lt;Bla&gt; installieren, an erzeugte Closure delegierend">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1521209759585" ID="ID_267047467" MODIFIED="1521411859346" TEXT="Lebenszyklus-Koppelung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1521209811802" ID="ID_1712617923" MODIFIED="1521411860363" TEXT="f&#xfc;r die UnterBla-Instanz">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1521209827775" ID="ID_280216675" MODIFIED="1521411861265" TEXT="f&#xfc;r den tempor&#xe4;r installierten Service-Zugang">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1521208724943" ID="ID_221402501" MODIFIED="1521411863017" TEXT="smart-ptr-artiger Zugriff auf die Service-Impl">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1521209904013" ID="ID_1098048607" MODIFIED="1521411940211" STYLE="fork" TEXT="debug/Kontroll-API">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1521209958014" ID="ID_1638584681" MODIFIED="1521411938195" TEXT="Lebenszustand">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1521209945287" ID="ID_42798820" MODIFIED="1521411938195" TEXT="Erzeugen/Zerst&#xf6;ren der Instanz">
<icon BUILTIN="button_cancel"/>
<node CREATED="1521411917770" ID="ID_50731939" MODIFIED="1521411938195" TEXT="YAGNI"/>
</node>
<node CREATED="1521210051457" ID="ID_1794637059" MODIFIED="1521411938195" TEXT="explizites Deinstallieren">
<icon BUILTIN="button_cancel"/>
</node>
</node>