Index: third_party/pkg/di/test/main.dart |
diff --git a/third_party/pkg/di/test/main.dart b/third_party/pkg/di/test/main.dart |
index 0ebb3057ffe1077e4039dab28280342aa4474ffa..0626e930f4f123150e0438829454539d94a0d933 100644 |
--- a/third_party/pkg/di/test/main.dart |
+++ b/third_party/pkg/di/test/main.dart |
@@ -17,6 +17,7 @@ import 'package:di/dynamic_injector.dart'; |
import 'package:di/static_injector.dart'; |
import 'package:di/annotations.dart'; |
+import 'test_annotations.dart'; |
// Generated file. Run ../test_tf_gen.sh. |
import 'type_factories_gen.dart' as type_factories_gen; |
@@ -25,12 +26,12 @@ import 'type_factories_gen.dart' as type_factories_gen; |
* generated. For testing purposes not all classes are marked with this |
* annotation, some classes are included in @Injectables at the top. |
*/ |
-class Injectable { |
- const Injectable(); |
+class InjectableTest { |
+ const InjectableTest(); |
} |
// just some classes for testing |
-@Injectable() |
+@InjectableTest() |
class Engine { |
final String id = 'v8-id'; |
} |
@@ -40,7 +41,7 @@ class MockEngine implements Engine { |
final String id = 'mock-id'; |
} |
-@Injectable() |
+@InjectableTest() |
class MockEngine2 implements Engine { |
String id = 'mock-id-2'; |
} |
@@ -49,7 +50,17 @@ class HiddenConstructor { |
HiddenConstructor._(); |
} |
-@Injectable() |
+@InjectableTest() |
+class TurboEngine implements Engine { |
+ String id = 'turbo-engine-id'; |
+} |
+ |
+@InjectableTest() |
+class BrokenOldEngine implements Engine { |
+ String id = 'broken-old-engine-id'; |
+} |
+ |
+@InjectableTest() |
class Car { |
Engine engine; |
Injector injector; |
@@ -64,6 +75,14 @@ class Lemon { |
Lemon(this.engine, this.injector); |
} |
+@InjectableTest() |
+class Porsche { |
+ Engine engine; |
+ Injector injector; |
+ |
+ Porsche(@Turbo() this.engine, this.injector); |
+} |
+ |
class NumDependency { |
NumDependency(num value) {} |
} |
@@ -118,34 +137,51 @@ class ClassOne implements InterfaceOne { |
} |
} |
-@Injectable() |
+@InjectableTest() |
class ParameterizedType<T1, T2> { |
ParameterizedType(); |
} |
-@Injectable() |
+@InjectableTest() |
class ParameterizedDependency { |
final ParameterizedType<bool, int> _p; |
ParameterizedDependency(this._p); |
} |
-@Injectable() |
+@InjectableTest() |
class GenericParameterizedDependency { |
final ParameterizedType _p; |
GenericParameterizedDependency(this._p); |
} |
-@Injectable() |
+@InjectableTest() |
class Log { |
var log = []; |
add(String message) => log.add(message); |
} |
+@InjectableTest() |
+class AnnotatedPrimitiveDependency { |
+ String strValue; |
+ AnnotatedPrimitiveDependency(@Turbo() this.strValue); |
+} |
+ |
class EmulatedMockEngineFactory { |
call(Injector i) => new MockEngine(); |
} |
+bool throwOnceShouldThrow = true; |
+@InjectableTest() |
+class ThrowOnce { |
+ ThrowOnce() { |
+ if (throwOnceShouldThrow) { |
+ throwOnceShouldThrow = false; |
+ throw ["ThrowOnce"]; |
+ } |
+ } |
+} |
+ |
void main() { |
createInjectorSpec('DynamicInjector', |
(modules, [name]) => new DynamicInjector(modules: modules, name: name)); |
@@ -156,6 +192,7 @@ void main() { |
dynamicInjectorTest(); |
staticInjectorTest(); |
+ createKeySpec(); |
} |
typedef Injector InjectorFactory(List<Module> modules, [String name]); |
@@ -172,6 +209,17 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
expect(instance.id, toEqual('v8-id')); |
}); |
+ it('should instantiate an annotated type', () { |
+ var injector = injectorFactory([new Module() |
+ ..type(Engine, withAnnotation: Turbo, implementedBy: TurboEngine) |
+ ..value(Car, new Engine()) |
+ ]); |
+ var instance = injector.getByKey(new Key(Engine, Turbo)); |
+ |
+ expect(instance, instanceOf(TurboEngine)); |
+ expect(instance.id, toEqual('turbo-engine-id')); |
+ }); |
+ |
it('should fail if no binding is found', () { |
var injector = injectorFactory([]); |
expect(() { |
@@ -189,6 +237,28 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
expect(instance.engine.id, toEqual('v8-id')); |
}); |
+ it('should resolve complex dependencies', () { |
+ var injector = injectorFactory([new Module() |
+ ..type(Porsche) |
+ ..type(TurboEngine) |
+ ..type(Engine, withAnnotation: Turbo, implementedBy: TurboEngine) |
+ ]); |
+ var instance = injector.get(Porsche); |
+ |
+ expect(instance, instanceOf(Porsche)); |
+ expect(instance.engine.id, toEqual('turbo-engine-id')); |
+ }); |
+ |
+ it('should resolve annotated primitive type', () { |
+ var injector = injectorFactory([new Module() |
+ ..type(AnnotatedPrimitiveDependency) |
+ ..value(String, 'Worked!', withAnnotation: Turbo) |
+ ]); |
+ var instance = injector.get(AnnotatedPrimitiveDependency); |
+ |
+ expect(instance, instanceOf(AnnotatedPrimitiveDependency)); |
+ expect(instance.strValue, toEqual('Worked!')); |
+ }); |
it('should inject generic parameterized types', () { |
var injector = injectorFactory([new Module() |
@@ -321,13 +391,39 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
it('should throw an exception when circular dependency', () { |
- var injector = injectorFactory([new Module()..type(CircularA)..type(CircularB)]); |
+ var injector = injectorFactory([new Module()..type(CircularA) |
+ ..type(CircularB)]); |
+ |
+ expect(() { |
+ injector.get(CircularA); |
+ }, toThrow(CircularDependencyError, 'Cannot resolve a circular ' |
+ 'dependency! (resolving CircularA -> CircularB -> CircularA')); |
+ }); |
+ |
+ it('should throw an exception when circular dependency in factory', () { |
+ var injector = injectorFactory([new Module() |
+ ..factory(CircularA, (i) => i.get(CircularA)) |
+ ]); |
expect(() { |
injector.get(CircularA); |
- }, toThrow(CircularDependencyError, 'Cannot resolve a circular dependency! ' |
- '(resolving CircularA -> ' |
- 'CircularB -> CircularA)')); |
+ }, toThrow(CircularDependencyError, 'Cannot resolve a ' |
+ 'circular dependency! (resolving CircularA -> CircularA')); |
+ }); |
+ |
+ |
+ it('should recover from errors', () { |
+ var injector = injectorFactory([new Module()..type(ThrowOnce)]); |
+ throwOnceShouldThrow = true; |
+ |
+ var caught = false; |
+ try { |
+ injector.get(ThrowOnce); |
+ } catch (e, s) { |
+ caught = true; |
+ expect(injector.get(ThrowOnce), not(toEqual(null))); |
+ } |
+ expect(caught, toEqual(true)); |
}); |
@@ -383,8 +479,10 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
var parent = injectorFactory([new Module()..type(Engine)]); |
var child = parent.createChild([new Module()..type(MockEngine)]); |
- expect(parent.types, unorderedEquals(new Set.from([Engine, Injector]))); |
- expect(child.types, unorderedEquals(new Set.from([Engine, MockEngine, Injector]))); |
+ expect(parent.types, unorderedEquals(new Set.from( |
+ [Engine, Injector]))); |
+ expect(child.types, unorderedEquals(new Set.from( |
+ [Engine, MockEngine, Injector]))); |
}); |
@@ -425,7 +523,7 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
var parent = injectorFactory([new Module()..type(Engine)]); |
var abcAlreadyInParent = parent.get(Engine); |
- var child = parent.createChild([], forceNewInstances: [Engine]); |
+ var child = parent.createChild([], forceNewInstances: [new Key(Engine)]); |
var abcFromChild = child.get(Engine); |
expect(abcFromChild, not(toBe(abcAlreadyInParent))); |
@@ -437,7 +535,7 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
var grandParent = injectorFactory([module]); |
var parent = grandParent.createChild([]); |
- var child = parent.createChild([], forceNewInstances: [Engine]); |
+ var child = parent.createChild([], forceNewInstances: [new Key(Engine)]); |
var abcFromGrandParent = grandParent.get(Engine); |
var abcFromChild = child.get(Engine); |
@@ -469,7 +567,8 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
it('should instantiate class only once (Issue #18)', () { |
- var injector = injectorFactory([ |
+ var rootInjector = injectorFactory([]); |
+ var injector = rootInjector.createChild([ |
new Module() |
..type(Log) |
..type(ClassOne) |
@@ -481,46 +580,6 @@ createInjectorSpec(String injectorName, InjectorFactory injectorFactory) { |
}); |
- describe('creation strategy', () { |
- |
- it('should get called for instance creation', () { |
- |
- List creationLog = []; |
- dynamic creation(Injector requesting, Injector defining, factory) { |
- creationLog.add([requesting, defining]); |
- return factory(); |
- } |
- |
- var parentModule = new Module() |
- ..type(Engine, implementedBy: MockEngine, creation: creation) |
- ..type(Car, creation: creation); |
- |
- var parentInjector = injectorFactory([parentModule]); |
- var childInjector = parentInjector.createChild([]); |
- childInjector.get(Car); |
- expect(creationLog, [ |
- [childInjector, parentInjector], |
- [childInjector, parentInjector] |
- ]); |
- }); |
- |
- it('should be able to prevent instantiation', () { |
- |
- List creationLog = []; |
- dynamic creation(Injector requesting, Injector defining, factory) { |
- throw 'not allowing'; |
- } |
- |
- var module = new Module() |
- ..type(Engine, implementedBy: MockEngine, creation: creation); |
- var injector = injectorFactory([module]); |
- expect(() { |
- injector.get(Engine); |
- }, throwsA('not allowing')); |
- }); |
- }); |
- |
- |
describe('visiblity', () { |
it('should hide instances', () { |
@@ -584,6 +643,24 @@ void dynamicInjectorTest() { |
'default constructor.'))); |
}); |
+ it('should inject parameters into function and invoke it', () { |
+ var module = new Module() |
+ ..type(Engine); |
+ var id; |
+ var injector = new DynamicInjector(modules: [module]); |
+ injector.invoke((Engine e) => id = e.id); |
+ expect(id, equals('v8-id')); |
+ }); |
+ |
+ it('should inject annotated parameters into function and invoke it', () { |
+ var module = new Module() |
+ ..type(Engine, withAnnotation: Turbo, implementedBy: TurboEngine); |
+ var id; |
+ var injector = new DynamicInjector(modules: [module]); |
+ injector.invoke((@Turbo() Engine e) => id = e.id); |
+ expect(id, equals('turbo-engine-id')); |
+ }); |
+ |
}); |
} |
@@ -690,3 +767,43 @@ void staticInjectorTest() { |
}); |
} |
+ |
+createKeySpec() { |
+ describe('Key', () { |
+ it('should be equal to another key if type is the same', () { |
+ Key k1 = new Key(Car); |
+ Key k2 = new Key(Car); |
+ expect(k1, equals(k2)); |
+ expect(k1.hashCode, equals(k2.hashCode)); |
+ }); |
+ |
+ it('should be equal to another key if type and annotation are the same', () { |
+ Key k1 = new Key(Car, Turbo); |
+ Key k2 = new Key(Car, Turbo); |
+ expect(k1, equals(k2)); |
+ expect(k1.hashCode, equals(k2.hashCode)); |
+ }); |
+ |
+ it('should not be equal to another key if types are different', () { |
+ Key k1 = new Key(Car); |
+ Key k2 = new Key(Porsche); |
+ expect(k1, not(equals(k2))); |
+ expect(k1.hashCode, not(equals(k2.hashCode))); |
+ }); |
+ |
+ it('should not be equal to another key if annotations are different', () { |
+ Key k1 = new Key(Car, Turbo); |
+ Key k2 = new Key(Car, Old); |
+ expect(k1, not(equals(k2))); |
+ expect(k1.hashCode, not(equals(k2.hashCode))); |
+ }); |
+ |
+ it('should not be equal to another key if type is different and annotation' |
+ ' is same', () { |
+ Key k1 = new Key(Engine, Old); |
+ Key k2 = new Key(Car, Old); |
+ expect(k1, not(equals(k2))); |
+ expect(k1.hashCode, not(equals(k2.hashCode))); |
+ }); |
+ }); |
+} |