mirror of
https://github.com/mbierlee/poodinis.git
synced 2024-11-15 04:04:01 +01:00
Reintroduce module container
This commit is contained in:
parent
a73b2b9b8b
commit
1d74064c15
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
module poodinis.autowire;
|
module poodinis.autowire;
|
||||||
|
|
||||||
public import poodinis.dependency;
|
public import poodinis.container;
|
||||||
|
|
||||||
import std.typetuple;
|
import std.typetuple;
|
||||||
|
|
||||||
|
@ -26,13 +26,13 @@ alias Autowired = Autowire;
|
||||||
|
|
||||||
public void autowire(Type)(DependencyContainer container, Type instance) {
|
public void autowire(Type)(DependencyContainer container, Type instance) {
|
||||||
// For the love of god, refactor this!
|
// For the love of god, refactor this!
|
||||||
|
|
||||||
debug(poodinisVerbose) {
|
debug(poodinisVerbose) {
|
||||||
auto instanceType = typeid(Type);
|
auto instanceType = typeid(Type);
|
||||||
auto instanceAddress = &instance;
|
auto instanceAddress = &instance;
|
||||||
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
|
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (member ; __traits(allMembers, Type)) {
|
foreach (member ; __traits(allMembers, Type)) {
|
||||||
static if(__traits(compiles, __traits(getMember, Type, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, Type, member)))) {
|
static if(__traits(compiles, __traits(getMember, Type, member)) && __traits(compiles, __traits(getAttributes, __traits(getMember, Type, member)))) {
|
||||||
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, Type, member))) {
|
foreach(autowireAttribute; __traits(getAttributes, __traits(getMember, Type, member))) {
|
||||||
|
@ -40,11 +40,11 @@ public void autowire(Type)(DependencyContainer container, Type instance) {
|
||||||
if (__traits(getMember, instance, member) is null) {
|
if (__traits(getMember, instance, member) is null) {
|
||||||
alias memberReference = TypeTuple!(__traits(getMember, instance, member));
|
alias memberReference = TypeTuple!(__traits(getMember, instance, member));
|
||||||
alias MemberType = typeof(memberReference)[0];
|
alias MemberType = typeof(memberReference)[0];
|
||||||
|
|
||||||
debug(poodinisVerbose) {
|
debug(poodinisVerbose) {
|
||||||
string qualifiedInstanceTypeString = typeid(MemberType).toString;
|
string qualifiedInstanceTypeString = typeid(MemberType).toString;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberType qualifiedInstance;
|
MemberType qualifiedInstance;
|
||||||
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
|
static if (is(autowireAttribute == Autowire!T, T) && !is(autowireAttribute.qualifier == UseMemberType)) {
|
||||||
alias QualifierType = typeof(autowireAttribute.qualifier);
|
alias QualifierType = typeof(autowireAttribute.qualifier);
|
||||||
|
@ -55,15 +55,15 @@ public void autowire(Type)(DependencyContainer container, Type instance) {
|
||||||
} else {
|
} else {
|
||||||
qualifiedInstance = container.resolve!(typeof(memberReference));
|
qualifiedInstance = container.resolve!(typeof(memberReference));
|
||||||
}
|
}
|
||||||
|
|
||||||
__traits(getMember, instance, member) = qualifiedInstance;
|
__traits(getMember, instance, member) = qualifiedInstance;
|
||||||
|
|
||||||
debug(poodinisVerbose) {
|
debug(poodinisVerbose) {
|
||||||
auto qualifiedInstanceAddress = &qualifiedInstance;
|
auto qualifiedInstanceAddress = &qualifiedInstance;
|
||||||
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", qualifiedInstanceTypeString, qualifiedInstanceAddress, instanceType, instanceAddress, member));
|
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", qualifiedInstanceTypeString, qualifiedInstanceAddress, instanceType, instanceAddress, member));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,4 +80,4 @@ mixin template AutowireConstructor() {
|
||||||
|
|
||||||
public void globalAutowire(Type)(Type instance) {
|
public void globalAutowire(Type)(Type instance) {
|
||||||
DependencyContainer.getInstance().autowire(instance);
|
DependencyContainer.getInstance().autowire(instance);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,136 @@
|
||||||
/**
|
/**
|
||||||
* Poodinis Dependency Injection Framework
|
* Poodinis Dependency Injection Framework
|
||||||
* Copyright 2014 Mike Bierlee
|
* Copyright 2014 Mike Bierlee
|
||||||
* This software is licensed under the terms of the MIT license.
|
* This software is licensed under the terms of the MIT license.
|
||||||
* The full terms of the license can be found in the LICENSE file.
|
* The full terms of the license can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module poodinis.container;
|
module poodinis.container;
|
||||||
|
|
||||||
pragma(msg, "Module \"container\" has been renamed to \"dependency\". The use of the \"container\" module is deprecated");
|
import std.string;
|
||||||
|
import std.array;
|
||||||
public import poodinis.dependency;
|
import std.algorithm;
|
||||||
|
|
||||||
|
debug {
|
||||||
|
import std.stdio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public import poodinis.registration;
|
||||||
|
public import poodinis.autowire;
|
||||||
|
|
||||||
|
class RegistrationException : Exception {
|
||||||
|
this(string message, TypeInfo registeredType, TypeInfo_Class concreteType) {
|
||||||
|
super(format("Exception while registering type %s to %s: %s", registeredType.toString(), concreteType.name, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResolveException : Exception {
|
||||||
|
this(string message, TypeInfo resolveType) {
|
||||||
|
super(format("Exception while resolving type %s: %s", resolveType.toString(), message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecated("Container has been renamed to DependencyContainer")
|
||||||
|
alias Container = DependencyContainer;
|
||||||
|
|
||||||
|
class DependencyContainer {
|
||||||
|
|
||||||
|
private static DependencyContainer instance;
|
||||||
|
|
||||||
|
private Registration[][TypeInfo] registrations;
|
||||||
|
|
||||||
|
private Registration[] autowireStack;
|
||||||
|
|
||||||
|
public Registration register(ConcreteType)() {
|
||||||
|
return register!(ConcreteType, ConcreteType)();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registration register(InterfaceType, ConcreteType : InterfaceType)() {
|
||||||
|
TypeInfo registeredType = typeid(InterfaceType);
|
||||||
|
TypeInfo_Class concreteType = typeid(ConcreteType);
|
||||||
|
|
||||||
|
debug(poodinisVerbose) {
|
||||||
|
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto existingCandidates = registeredType in registrations;
|
||||||
|
if (existingCandidates) {
|
||||||
|
auto existingRegistration = getRegistration(*existingCandidates, concreteType);
|
||||||
|
if (existingRegistration) {
|
||||||
|
return existingRegistration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration newRegistration = new Registration(registeredType, concreteType);
|
||||||
|
newRegistration.singleInstance();
|
||||||
|
registrations[registeredType] ~= newRegistration;
|
||||||
|
return newRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
|
||||||
|
foreach(existingRegistration ; candidates) {
|
||||||
|
if (existingRegistration.instantiatableType == concreteType) {
|
||||||
|
return existingRegistration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistrationType resolve(RegistrationType)() {
|
||||||
|
return resolve!(RegistrationType, RegistrationType)();
|
||||||
|
}
|
||||||
|
|
||||||
|
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)() {
|
||||||
|
TypeInfo resolveType = typeid(RegistrationType);
|
||||||
|
TypeInfo qualifierType = typeid(QualifierType);
|
||||||
|
|
||||||
|
debug(poodinisVerbose) {
|
||||||
|
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto candidates = resolveType in registrations;
|
||||||
|
if (!candidates) {
|
||||||
|
throw new ResolveException("Type not registered.", resolveType);
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates);
|
||||||
|
QualifierType instance = cast(QualifierType) registration.getInstance();
|
||||||
|
|
||||||
|
if (!autowireStack.canFind(registration)) {
|
||||||
|
autowireStack ~= registration;
|
||||||
|
this.autowire!(QualifierType)(instance);
|
||||||
|
autowireStack.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) {
|
||||||
|
if (resolveType == qualifierType) {
|
||||||
|
if (candidates.length > 1) {
|
||||||
|
string candidateList = candidates.toConcreteTypeListString();
|
||||||
|
throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.", resolveType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRegistration(candidates, qualifierType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAllRegistrations() {
|
||||||
|
registrations.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRegistration(RegistrationType)() {
|
||||||
|
registrations.remove(typeid(RegistrationType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DependencyContainer getInstance() {
|
||||||
|
if (instance is null) {
|
||||||
|
instance = new DependencyContainer();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
/**
|
|
||||||
* Poodinis Dependency Injection Framework
|
|
||||||
* Copyright 2014 Mike Bierlee
|
|
||||||
* This software is licensed under the terms of the MIT license.
|
|
||||||
* The full terms of the license can be found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
module poodinis.dependency;
|
|
||||||
|
|
||||||
import std.string;
|
|
||||||
import std.array;
|
|
||||||
import std.algorithm;
|
|
||||||
|
|
||||||
debug {
|
|
||||||
import std.stdio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public import poodinis.registration;
|
|
||||||
public import poodinis.autowire;
|
|
||||||
|
|
||||||
class RegistrationException : Exception {
|
|
||||||
this(string message, TypeInfo registeredType, TypeInfo_Class concreteType) {
|
|
||||||
super(format("Exception while registering type %s to %s: %s", registeredType.toString(), concreteType.name, message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ResolveException : Exception {
|
|
||||||
this(string message, TypeInfo resolveType) {
|
|
||||||
super(format("Exception while resolving type %s: %s", resolveType.toString(), message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deprecated("Container has been renamed to DependencyContainer")
|
|
||||||
alias Container = DependencyContainer;
|
|
||||||
|
|
||||||
class DependencyContainer {
|
|
||||||
|
|
||||||
private static DependencyContainer instance;
|
|
||||||
|
|
||||||
private Registration[][TypeInfo] registrations;
|
|
||||||
|
|
||||||
private Registration[] autowireStack;
|
|
||||||
|
|
||||||
public Registration register(ConcreteType)() {
|
|
||||||
return register!(ConcreteType, ConcreteType)();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Registration register(InterfaceType, ConcreteType : InterfaceType)() {
|
|
||||||
TypeInfo registeredType = typeid(InterfaceType);
|
|
||||||
TypeInfo_Class concreteType = typeid(ConcreteType);
|
|
||||||
|
|
||||||
debug(poodinisVerbose) {
|
|
||||||
writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto existingCandidates = registeredType in registrations;
|
|
||||||
if (existingCandidates) {
|
|
||||||
auto existingRegistration = getRegistration(*existingCandidates, concreteType);
|
|
||||||
if (existingRegistration) {
|
|
||||||
return existingRegistration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Registration newRegistration = new Registration(registeredType, concreteType);
|
|
||||||
newRegistration.singleInstance();
|
|
||||||
registrations[registeredType] ~= newRegistration;
|
|
||||||
return newRegistration;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
|
|
||||||
foreach(existingRegistration ; candidates) {
|
|
||||||
if (existingRegistration.instantiatableType == concreteType) {
|
|
||||||
return existingRegistration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegistrationType resolve(RegistrationType)() {
|
|
||||||
return resolve!(RegistrationType, RegistrationType)();
|
|
||||||
}
|
|
||||||
|
|
||||||
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)() {
|
|
||||||
TypeInfo resolveType = typeid(RegistrationType);
|
|
||||||
TypeInfo qualifierType = typeid(QualifierType);
|
|
||||||
|
|
||||||
debug(poodinisVerbose) {
|
|
||||||
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto candidates = resolveType in registrations;
|
|
||||||
if (!candidates) {
|
|
||||||
throw new ResolveException("Type not registered.", resolveType);
|
|
||||||
}
|
|
||||||
|
|
||||||
Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates);
|
|
||||||
QualifierType instance = cast(QualifierType) registration.getInstance();
|
|
||||||
|
|
||||||
if (!autowireStack.canFind(registration)) {
|
|
||||||
autowireStack ~= registration;
|
|
||||||
this.autowire!(QualifierType)(instance);
|
|
||||||
autowireStack.popBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) {
|
|
||||||
if (resolveType == qualifierType) {
|
|
||||||
if (candidates.length > 1) {
|
|
||||||
string candidateList = candidates.toConcreteTypeListString();
|
|
||||||
throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.", resolveType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return candidates[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRegistration(candidates, qualifierType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearAllRegistrations() {
|
|
||||||
registrations.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeRegistration(RegistrationType)() {
|
|
||||||
registrations.remove(typeid(RegistrationType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DependencyContainer getInstance() {
|
|
||||||
if (instance is null) {
|
|
||||||
instance = new DependencyContainer();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,98 +5,98 @@
|
||||||
* The full terms of the license can be found in the LICENSE file.
|
* The full terms of the license can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import poodinis.dependency;
|
import poodinis.container;
|
||||||
|
|
||||||
import std.exception;
|
import std.exception;
|
||||||
|
|
||||||
version(unittest) {
|
version(unittest) {
|
||||||
interface TestInterface {
|
interface TestInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestClass : TestInterface {
|
class TestClass : TestInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnrelatedClass{
|
class UnrelatedClass{
|
||||||
}
|
}
|
||||||
|
|
||||||
class FailOnCreationClass {
|
class FailOnCreationClass {
|
||||||
this() {
|
this() {
|
||||||
throw new Exception("This class should not be instantiated");
|
throw new Exception("This class should not be instantiated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AutowiredClass {
|
class AutowiredClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentClass {
|
class ComponentClass {
|
||||||
@Autowire
|
@Autowire
|
||||||
public AutowiredClass autowiredClass;
|
public AutowiredClass autowiredClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentCat {
|
class ComponentCat {
|
||||||
@Autowire
|
@Autowire
|
||||||
public ComponentMouse mouse;
|
public ComponentMouse mouse;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentMouse {
|
class ComponentMouse {
|
||||||
@Autowire
|
@Autowire
|
||||||
public ComponentCat cat;
|
public ComponentCat cat;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Eenie {
|
class Eenie {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Meenie meenie;
|
public Meenie meenie;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Meenie {
|
class Meenie {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Moe moe;
|
public Moe moe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Moe {
|
class Moe {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Eenie eenie;
|
public Eenie eenie;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Ittie {
|
class Ittie {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Bittie bittie;
|
public Bittie bittie;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Bittie {
|
class Bittie {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Banana banana;
|
public Banana banana;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Banana {
|
class Banana {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Bittie bittie;
|
public Bittie bittie;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SuperInterface {
|
interface SuperInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SuperImplementation : SuperInterface {
|
class SuperImplementation : SuperInterface {
|
||||||
@Autowire
|
@Autowire
|
||||||
public Banana banana;
|
public Banana banana;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Color {
|
interface Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Blue : Color {
|
class Blue : Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Red : Color {
|
class Red : Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test register concrete type
|
// Test register concrete type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
auto registration = container.register!(TestClass)();
|
auto registration = container.register!(TestClass)();
|
||||||
assert(registration.registeredType == typeid(TestClass), "Type of registered type not the same");
|
assert(registration.registeredType == typeid(TestClass), "Type of registered type not the same");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve registered type
|
// Test resolve registered type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -105,7 +105,7 @@ version(unittest) {
|
||||||
assert(actualInstance !is null, "Resolved type is null");
|
assert(actualInstance !is null, "Resolved type is null");
|
||||||
assert(cast(TestClass) actualInstance, "Resolved class is not the same type as expected");
|
assert(cast(TestClass) actualInstance, "Resolved class is not the same type as expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test register interface
|
// Test register interface
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -114,13 +114,13 @@ version(unittest) {
|
||||||
assert(actualInstance !is null, "Resolved type is null");
|
assert(actualInstance !is null, "Resolved type is null");
|
||||||
assert(cast(TestInterface) actualInstance, "Resolved class is not the same type as expected");
|
assert(cast(TestInterface) actualInstance, "Resolved class is not the same type as expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve non-registered type
|
// Test resolve non-registered type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving non-registered type does not fail");
|
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving non-registered type does not fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test clear registrations
|
// Test clear registrations
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -128,14 +128,14 @@ version(unittest) {
|
||||||
container.clearAllRegistrations();
|
container.clearAllRegistrations();
|
||||||
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving cleared type does not fail");
|
assertThrown!ResolveException(container.resolve!(TestClass)(), "Resolving cleared type does not fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test get singleton of container
|
// Test get singleton of container
|
||||||
unittest {
|
unittest {
|
||||||
auto instance1 = DependencyContainer.getInstance();
|
auto instance1 = DependencyContainer.getInstance();
|
||||||
auto instance2 = DependencyContainer.getInstance();
|
auto instance2 = DependencyContainer.getInstance();
|
||||||
assert(instance1 is instance2, "getInstance does not return the same instance");
|
assert(instance1 is instance2, "getInstance does not return the same instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve single instance for type
|
// Test resolve single instance for type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -144,7 +144,7 @@ version(unittest) {
|
||||||
auto instance2 = container.resolve!(TestClass);
|
auto instance2 = container.resolve!(TestClass);
|
||||||
assert(instance1 is instance2, "Resolved instance from single instance scope is not the each time it is resolved");
|
assert(instance1 is instance2, "Resolved instance from single instance scope is not the each time it is resolved");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve new instance for type
|
// Test resolve new instance for type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -153,7 +153,7 @@ version(unittest) {
|
||||||
auto instance2 = container.resolve!(TestClass);
|
auto instance2 = container.resolve!(TestClass);
|
||||||
assert(instance1 !is instance2, "Resolved instance from new instance scope is the same each time it is resolved");
|
assert(instance1 !is instance2, "Resolved instance from new instance scope is the same each time it is resolved");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve existing instance for type
|
// Test resolve existing instance for type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -162,7 +162,7 @@ version(unittest) {
|
||||||
auto actualInstance = container.resolve!(TestClass);
|
auto actualInstance = container.resolve!(TestClass);
|
||||||
assert(expectedInstance is actualInstance, "Resolved instance from existing instance scope is not the same as the registered instance");
|
assert(expectedInstance is actualInstance, "Resolved instance from existing instance scope is not the same as the registered instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowire resolved instances
|
// Test autowire resolved instances
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -172,7 +172,7 @@ version(unittest) {
|
||||||
auto autowiredInstance = container.resolve!AutowiredClass;
|
auto autowiredInstance = container.resolve!AutowiredClass;
|
||||||
assert(componentInstance.autowiredClass is autowiredInstance, "Member is not autowired upon resolving");
|
assert(componentInstance.autowiredClass is autowiredInstance, "Member is not autowired upon resolving");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test circular autowiring
|
// Test circular autowiring
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -182,7 +182,7 @@ version(unittest) {
|
||||||
auto cat = container.resolve!ComponentCat;
|
auto cat = container.resolve!ComponentCat;
|
||||||
assert(mouse.cat is cat && cat.mouse is mouse && mouse !is cat, "Circular dependencies should be autowirable");
|
assert(mouse.cat is cat && cat.mouse is mouse && mouse !is cat, "Circular dependencies should be autowirable");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test remove registration
|
// Test remove registration
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -190,69 +190,69 @@ version(unittest) {
|
||||||
container.removeRegistration!TestClass;
|
container.removeRegistration!TestClass;
|
||||||
assertThrown!ResolveException(container.resolve!TestClass);
|
assertThrown!ResolveException(container.resolve!TestClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowiring does not autowire member where instance is non-null
|
// Test autowiring does not autowire member where instance is non-null
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
auto existingA = new AutowiredClass();
|
auto existingA = new AutowiredClass();
|
||||||
auto existingB = new ComponentClass();
|
auto existingB = new ComponentClass();
|
||||||
existingB.autowiredClass = existingA;
|
existingB.autowiredClass = existingA;
|
||||||
|
|
||||||
container.register!AutowiredClass;
|
container.register!AutowiredClass;
|
||||||
container.register!(ComponentClass).existingInstance(existingB);
|
container.register!(ComponentClass).existingInstance(existingB);
|
||||||
auto resolvedA = container.resolve!AutowiredClass;
|
auto resolvedA = container.resolve!AutowiredClass;
|
||||||
auto resolvedB = container.resolve!ComponentClass;
|
auto resolvedB = container.resolve!ComponentClass;
|
||||||
|
|
||||||
assert(resolvedB.autowiredClass is existingA && resolvedA !is existingA, "Autowiring shouldn't rewire member when it is already wired to an instance");
|
assert(resolvedB.autowiredClass is existingA && resolvedA !is existingA, "Autowiring shouldn't rewire member when it is already wired to an instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowiring circular dependency by third-degree
|
// Test autowiring circular dependency by third-degree
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
container.register!Eenie;
|
container.register!Eenie;
|
||||||
container.register!Meenie;
|
container.register!Meenie;
|
||||||
container.register!Moe;
|
container.register!Moe;
|
||||||
|
|
||||||
auto eenie = container.resolve!Eenie;
|
auto eenie = container.resolve!Eenie;
|
||||||
|
|
||||||
assert(eenie.meenie.moe.eenie is eenie, "Autowiring third-degree circular dependency failed");
|
assert(eenie.meenie.moe.eenie is eenie, "Autowiring third-degree circular dependency failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowiring deep circular dependencies
|
// Test autowiring deep circular dependencies
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
container.register!Ittie;
|
container.register!Ittie;
|
||||||
container.register!Bittie;
|
container.register!Bittie;
|
||||||
container.register!Banana;
|
container.register!Banana;
|
||||||
|
|
||||||
auto ittie = container.resolve!Ittie;
|
auto ittie = container.resolve!Ittie;
|
||||||
|
|
||||||
assert(ittie.bittie is ittie.bittie.banana.bittie, "Autowiring deep dependencies failed.");
|
assert(ittie.bittie is ittie.bittie.banana.bittie, "Autowiring deep dependencies failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time
|
// Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
container.register!(Ittie).newInstance();
|
container.register!(Ittie).newInstance();
|
||||||
container.register!(Bittie).newInstance();
|
container.register!(Bittie).newInstance();
|
||||||
container.register!(Banana).newInstance();
|
container.register!(Banana).newInstance();
|
||||||
|
|
||||||
auto ittie = container.resolve!Ittie;
|
auto ittie = container.resolve!Ittie;
|
||||||
|
|
||||||
assert(ittie.bittie.banana.bittie.banana is null, "Autowiring deep dependencies with newInstance scope autowired a reoccuring type.");
|
assert(ittie.bittie.banana.bittie.banana is null, "Autowiring deep dependencies with newInstance scope autowired a reoccuring type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test autowiring type registered by interface fails (BUG test case)
|
// Test autowiring type registered by interface fails (BUG test case)
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
container.register!Banana;
|
container.register!Banana;
|
||||||
container.register!(SuperInterface, SuperImplementation);
|
container.register!(SuperInterface, SuperImplementation);
|
||||||
|
|
||||||
SuperImplementation superInstance = cast(SuperImplementation) container.resolve!SuperInterface;
|
SuperImplementation superInstance = cast(SuperImplementation) container.resolve!SuperInterface;
|
||||||
|
|
||||||
assert(superInstance.banana is null, "Autowire instance which was resolved by interface type, which was not expected to be possible");
|
assert(superInstance.banana is null, "Autowire instance which was resolved by interface type, which was not expected to be possible");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test reusing a container after clearing all registrations
|
// Test reusing a container after clearing all registrations
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -266,14 +266,14 @@ version(unittest) {
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test register multiple concrete classess to same interface type
|
// Test register multiple concrete classess to same interface type
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
container.register!(Color, Blue);
|
container.register!(Color, Blue);
|
||||||
container.register!(Color, Red);
|
container.register!(Color, Red);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test removing all registrations for type with multiple registrations.
|
// Test removing all registrations for type with multiple registrations.
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -281,16 +281,16 @@ version(unittest) {
|
||||||
container.register!(Color, Red);
|
container.register!(Color, Red);
|
||||||
container.removeRegistration!Color;
|
container.removeRegistration!Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test registering same registration again
|
// Test registering same registration again
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
auto firstRegistration = container.register!(Color, Blue);
|
auto firstRegistration = container.register!(Color, Blue);
|
||||||
auto secondRegistration = container.register!(Color, Blue);
|
auto secondRegistration = container.register!(Color, Blue);
|
||||||
|
|
||||||
assert(firstRegistration is secondRegistration, "First registration is not the same as the second of equal types");
|
assert(firstRegistration is secondRegistration, "First registration is not the same as the second of equal types");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve registration with multiple qualifiers
|
// Test resolve registration with multiple qualifiers
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -303,7 +303,7 @@ version(unittest) {
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test resolve registration with multiple qualifiers using a qualifier
|
// Test resolve registration with multiple qualifiers using a qualifier
|
||||||
unittest {
|
unittest {
|
||||||
auto container = new DependencyContainer();
|
auto container = new DependencyContainer();
|
||||||
|
@ -311,9 +311,9 @@ version(unittest) {
|
||||||
container.register!(Color, Red);
|
container.register!(Color, Red);
|
||||||
auto blueInstance = container.resolve!(Color, Blue);
|
auto blueInstance = container.resolve!(Color, Blue);
|
||||||
auto redInstance = container.resolve!(Color, Red);
|
auto redInstance = container.resolve!(Color, Red);
|
||||||
|
|
||||||
assert(blueInstance !is redInstance, "Resolving type with multiple, different registrations yielded the same instance");
|
assert(blueInstance !is redInstance, "Resolving type with multiple, different registrations yielded the same instance");
|
||||||
assert(blueInstance !is null, "Resolved blue instance to null");
|
assert(blueInstance !is null, "Resolved blue instance to null");
|
||||||
assert(redInstance !is null, "Resolved red instance to null");
|
assert(redInstance !is null, "Resolved red instance to null");
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue