mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-23 21:13:35 +00:00
Merge pull request #8 from pese-git/refactor
Refactor code and add toInstanceAsync method
This commit is contained in:
@@ -30,7 +30,7 @@ Binding<String>().toProvide(() => "hello world");
|
||||
// Asynchronous lazy initialization
|
||||
Binding<String>().toProvideAsync(() async => "hello async world");
|
||||
|
||||
/ Asynchronous lazy initialization with dynamic parameters
|
||||
// Asynchronous lazy initialization with dynamic parameters
|
||||
Binding<String>().toProvideAsyncWithParams((params) async => "hello $params");
|
||||
|
||||
// Initialization with dynamic parameters
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
enum Mode { simple, instance, providerInstance, providerInstanceWithParams }
|
||||
|
||||
typedef Provider<T> = T? Function();
|
||||
|
||||
typedef ProviderWithParams<T> = T Function(dynamic params);
|
||||
|
||||
typedef AsyncProvider<T> = Future<T> Function();
|
||||
@@ -27,11 +29,13 @@ class Binding<T> {
|
||||
late Type _key;
|
||||
late String _name;
|
||||
T? _instance;
|
||||
T? Function()? _provider;
|
||||
Future<T>? _instanceAsync;
|
||||
Provider<T>? _provider;
|
||||
ProviderWithParams<T>? _providerWithParams;
|
||||
|
||||
AsyncProvider<T>? asyncProvider;
|
||||
AsyncProviderWithParams<T>? asyncProviderWithParams;
|
||||
|
||||
ProviderWithParams<T>? _providerWithParams;
|
||||
late bool _isSingleton = false;
|
||||
late bool _isNamed = false;
|
||||
|
||||
@@ -91,11 +95,22 @@ class Binding<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/// RU: Инициализация экземляпяра [value].
|
||||
/// ENG: Initialization instance [value].
|
||||
///
|
||||
/// return [Binding]
|
||||
Binding<T> toInstanceAsync(Future<T> value) {
|
||||
_mode = Mode.instance;
|
||||
_instanceAsync = value;
|
||||
_isSingleton = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// RU: Инициализация экземляпяра через провайдер [value].
|
||||
/// ENG: Initialization instance via provider [value].
|
||||
///
|
||||
/// return [Binding]
|
||||
Binding<T> toProvide(T Function() value) {
|
||||
Binding<T> toProvide(Provider<T> value) {
|
||||
_mode = Mode.providerInstance;
|
||||
_provider = value;
|
||||
return this;
|
||||
@@ -146,6 +161,12 @@ class Binding<T> {
|
||||
/// return [T]
|
||||
T? get instance => _instance;
|
||||
|
||||
/// RU: Поиск экземпляра.
|
||||
/// ENG: Resolve instance.
|
||||
///
|
||||
/// return [T]
|
||||
Future<T>? get instanceAsync => _instanceAsync;
|
||||
|
||||
/// RU: Поиск экземпляра.
|
||||
/// ENG: Resolve instance.
|
||||
///
|
||||
|
||||
@@ -160,11 +160,18 @@ class Scope {
|
||||
if (binding.key == T &&
|
||||
((!binding.isNamed && named == null) ||
|
||||
(binding.isNamed && named == binding.name))) {
|
||||
if (binding.instanceAsync != null) {
|
||||
return await binding.instanceAsync;
|
||||
}
|
||||
|
||||
if (binding.asyncProvider != null) {
|
||||
return await binding.asyncProvider?.call();
|
||||
}
|
||||
|
||||
if (binding.asyncProviderWithParams != null) {
|
||||
if (params == null) {
|
||||
throw StateError('Param is null. Maybe you forget pass it');
|
||||
}
|
||||
return await binding.asyncProviderWithParams!(params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,314 +2,270 @@ import 'package:cherrypick/src/binding.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('Check instance.', () {
|
||||
group('Without name.', () {
|
||||
test('Binding resolves null', () {
|
||||
// --- Instance binding (synchronous) ---
|
||||
group('Instance Binding (toInstance)', () {
|
||||
group('Without name', () {
|
||||
test('Returns null by default', () {
|
||||
final binding = Binding<int>();
|
||||
expect(binding.instance, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toInstance(expectedValue);
|
||||
|
||||
test('Sets mode to instance', () {
|
||||
final binding = Binding<int>().toInstance(5);
|
||||
expect(binding.mode, Mode.instance);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toInstance(expectedValue);
|
||||
|
||||
test('isSingleton is true', () {
|
||||
final binding = Binding<int>().toInstance(5);
|
||||
expect(binding.isSingleton, true);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toInstance(expectedValue);
|
||||
|
||||
expect(binding.instance, expectedValue);
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toInstance(expectedValue);
|
||||
expect(binding.instance, expectedValue);
|
||||
test('Stores value', () {
|
||||
final binding = Binding<int>().toInstance(5);
|
||||
expect(binding.instance, 5);
|
||||
});
|
||||
});
|
||||
|
||||
group('With name.', () {
|
||||
test('Binding resolves null', () {
|
||||
final binding = Binding<int>().withName('expectedValue');
|
||||
group('With name', () {
|
||||
test('Returns null by default', () {
|
||||
final binding = Binding<int>().withName('n');
|
||||
expect(binding.instance, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
|
||||
test('Sets mode to instance', () {
|
||||
final binding = Binding<int>().withName('n').toInstance(5);
|
||||
expect(binding.mode, Mode.instance);
|
||||
});
|
||||
|
||||
test('Binding check key', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
|
||||
test('Sets key', () {
|
||||
final binding = Binding<int>().withName('n').toInstance(5);
|
||||
expect(binding.key, int);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
|
||||
test('isSingleton is true', () {
|
||||
final binding = Binding<int>().withName('n').toInstance(5);
|
||||
expect(binding.isSingleton, true);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
|
||||
expect(binding.instance, expectedValue);
|
||||
test('Stores value', () {
|
||||
final binding = Binding<int>().withName('n').toInstance(5);
|
||||
expect(binding.instance, 5);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
|
||||
expect(binding.name, 'expectedValue');
|
||||
test('Sets name', () {
|
||||
final binding = Binding<int>().withName('n').toInstance(5);
|
||||
expect(binding.name, 'n');
|
||||
});
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().withName('expectedValue').toInstance(expectedValue);
|
||||
expect(binding.instance, expectedValue);
|
||||
});
|
||||
test('Multiple toInstance calls change value', () {
|
||||
final binding = Binding<int>().toInstance(1).toInstance(2);
|
||||
expect(binding.instance, 2);
|
||||
});
|
||||
});
|
||||
|
||||
group('Check provide.', () {
|
||||
group('Without name.', () {
|
||||
test('Binding resolves null', () {
|
||||
// --- Instance binding (asynchronous) ---
|
||||
group('Async Instance Binding (toInstanceAsync)', () {
|
||||
test('Resolves instanceAsync with expected value', () async {
|
||||
final binding = Binding<int>().toInstanceAsync(Future.value(42));
|
||||
expect(await binding.instanceAsync, 42);
|
||||
});
|
||||
|
||||
test('Does not affect instance', () {
|
||||
final binding = Binding<int>().toInstanceAsync(Future.value(5));
|
||||
expect(binding.instance, null);
|
||||
});
|
||||
|
||||
test('Sets mode to instance', () {
|
||||
final binding = Binding<int>().toInstanceAsync(Future.value(5));
|
||||
expect(binding.mode, Mode.instance);
|
||||
});
|
||||
|
||||
test('isSingleton is true after toInstanceAsync', () {
|
||||
final binding = Binding<int>().toInstanceAsync(Future.value(5));
|
||||
expect(binding.isSingleton, isTrue);
|
||||
});
|
||||
|
||||
test('Composes with withName', () async {
|
||||
final binding = Binding<int>()
|
||||
.withName('asyncValue')
|
||||
.toInstanceAsync(Future.value(7));
|
||||
expect(binding.isNamed, isTrue);
|
||||
expect(binding.name, 'asyncValue');
|
||||
expect(await binding.instanceAsync, 7);
|
||||
});
|
||||
|
||||
test('Keeps value after multiple awaits', () async {
|
||||
final binding = Binding<int>().toInstanceAsync(Future.value(123));
|
||||
final result1 = await binding.instanceAsync;
|
||||
final result2 = await binding.instanceAsync;
|
||||
expect(result1, equals(result2));
|
||||
});
|
||||
});
|
||||
|
||||
// --- Provider binding (synchronous) ---
|
||||
group('Provider Binding (toProvide)', () {
|
||||
group('Without name', () {
|
||||
test('Returns null by default', () {
|
||||
final binding = Binding<int>();
|
||||
expect(binding.provider, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvide(() => expectedValue);
|
||||
|
||||
test('Sets mode to providerInstance', () {
|
||||
final binding = Binding<int>().toProvide(() => 5);
|
||||
expect(binding.mode, Mode.providerInstance);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvide(() => expectedValue);
|
||||
|
||||
test('isSingleton is false by default', () {
|
||||
final binding = Binding<int>().toProvide(() => 5);
|
||||
expect(binding.isSingleton, false);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvide(() => expectedValue);
|
||||
|
||||
expect(binding.provider, expectedValue);
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvide(() => expectedValue);
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Returns provided value', () {
|
||||
final binding = Binding<int>().toProvide(() => 5);
|
||||
expect(binding.provider, 5);
|
||||
});
|
||||
});
|
||||
|
||||
group('With name.', () {
|
||||
test('Binding resolves null', () {
|
||||
final binding = Binding<int>().withName('expectedValue');
|
||||
group('With name', () {
|
||||
test('Returns null by default', () {
|
||||
final binding = Binding<int>().withName('n');
|
||||
expect(binding.provider, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
|
||||
test('Sets mode to providerInstance', () {
|
||||
final binding = Binding<int>().withName('n').toProvide(() => 5);
|
||||
expect(binding.mode, Mode.providerInstance);
|
||||
});
|
||||
|
||||
test('Binding check key', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
|
||||
test('Sets key', () {
|
||||
final binding = Binding<int>().withName('n').toProvide(() => 5);
|
||||
expect(binding.key, int);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
|
||||
test('isSingleton is false by default', () {
|
||||
final binding = Binding<int>().withName('n').toProvide(() => 5);
|
||||
expect(binding.isSingleton, false);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Returns provided value', () {
|
||||
final binding = Binding<int>().withName('n').toProvide(() => 5);
|
||||
expect(binding.provider, 5);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
|
||||
expect(binding.name, 'expectedValue');
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue);
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Sets name', () {
|
||||
final binding = Binding<int>().withName('n').toProvide(() => 5);
|
||||
expect(binding.name, 'n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('Check Async provider.', () {
|
||||
test('Binding resolves value asynchronously', () async {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvideAsync(() async => expectedValue);
|
||||
|
||||
final result = await binding.asyncProvider?.call();
|
||||
expect(result, expectedValue);
|
||||
// --- Async provider binding ---
|
||||
group('Async Provider Binding', () {
|
||||
test('Resolves asyncProvider value', () async {
|
||||
final binding = Binding<int>().toProvideAsync(() async => 5);
|
||||
expect(await binding.asyncProvider?.call(), 5);
|
||||
});
|
||||
|
||||
test('Binding resolves value asynchronously with params', () async {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>().toProvideAsyncWithParams(
|
||||
(param) async => expectedValue + (param as int));
|
||||
|
||||
final result = await binding.asyncProviderWithParams?.call(3);
|
||||
expect(result, expectedValue + 3);
|
||||
test('Resolves asyncProviderWithParams value', () async {
|
||||
final binding = Binding<int>()
|
||||
.toProvideAsyncWithParams((param) async => 5 + (param as int));
|
||||
expect(await binding.asyncProviderWithParams?.call(3), 8);
|
||||
});
|
||||
});
|
||||
|
||||
group('Check singleton provide.', () {
|
||||
group('Without name.', () {
|
||||
test('Binding resolves null', () {
|
||||
// --- Singleton provider binding ---
|
||||
group('Singleton Provider Binding', () {
|
||||
group('Without name', () {
|
||||
test('Returns null if no provider set', () {
|
||||
final binding = Binding<int>().singleton();
|
||||
expect(binding.provider, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().toProvide(() => expectedValue).singleton();
|
||||
|
||||
test('Sets mode to providerInstance', () {
|
||||
final binding = Binding<int>().toProvide(() => 5).singleton();
|
||||
expect(binding.mode, Mode.providerInstance);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().toProvide(() => expectedValue).singleton();
|
||||
|
||||
test('isSingleton is true', () {
|
||||
final binding = Binding<int>().toProvide(() => 5).singleton();
|
||||
expect(binding.isSingleton, true);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().toProvide(() => expectedValue).singleton();
|
||||
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Returns singleton value', () {
|
||||
final binding = Binding<int>().toProvide(() => 5).singleton();
|
||||
expect(binding.provider, 5);
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding =
|
||||
Binding<int>().toProvide(() => expectedValue).singleton();
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Returns same value each call and provider only called once', () {
|
||||
int counter = 0;
|
||||
final binding = Binding<int>().toProvide(() {
|
||||
counter++;
|
||||
return counter;
|
||||
}).singleton();
|
||||
|
||||
final first = binding.provider;
|
||||
final second = binding.provider;
|
||||
expect(first, equals(second));
|
||||
expect(counter, 1);
|
||||
});
|
||||
});
|
||||
|
||||
group('With name.', () {
|
||||
test('Binding resolves null', () {
|
||||
final binding = Binding<int>().withName('expectedValue').singleton();
|
||||
group('With name', () {
|
||||
test('Returns null if no provider set', () {
|
||||
final binding = Binding<int>().withName('n').singleton();
|
||||
expect(binding.provider, null);
|
||||
});
|
||||
|
||||
test('Binding check mode', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
|
||||
test('Sets mode to providerInstance', () {
|
||||
final binding =
|
||||
Binding<int>().withName('n').toProvide(() => 5).singleton();
|
||||
expect(binding.mode, Mode.providerInstance);
|
||||
});
|
||||
|
||||
test('Binding check key', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
|
||||
test('Sets key', () {
|
||||
final binding =
|
||||
Binding<int>().withName('n').toProvide(() => 5).singleton();
|
||||
expect(binding.key, int);
|
||||
});
|
||||
|
||||
test('Binding check singleton', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
|
||||
test('isSingleton is true', () {
|
||||
final binding =
|
||||
Binding<int>().withName('n').toProvide(() => 5).singleton();
|
||||
expect(binding.isSingleton, true);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
|
||||
expect(binding.provider, expectedValue);
|
||||
test('Returns singleton value', () {
|
||||
final binding =
|
||||
Binding<int>().withName('n').toProvide(() => 5).singleton();
|
||||
expect(binding.provider, 5);
|
||||
});
|
||||
|
||||
test('Binding check value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
|
||||
expect(binding.name, 'expectedValue');
|
||||
test('Sets name', () {
|
||||
final binding =
|
||||
Binding<int>().withName('n').toProvide(() => 5).singleton();
|
||||
expect(binding.name, 'n');
|
||||
});
|
||||
});
|
||||
|
||||
test('Binding resolves value', () {
|
||||
final expectedValue = 5;
|
||||
final binding = Binding<int>()
|
||||
.withName('expectedValue')
|
||||
.toProvide(() => expectedValue)
|
||||
.singleton();
|
||||
expect(binding.provider, expectedValue);
|
||||
});
|
||||
test('Chained withName and singleton preserves mode', () {
|
||||
final binding =
|
||||
Binding<int>().toProvide(() => 3).withName("named").singleton();
|
||||
expect(binding.mode, Mode.providerInstance);
|
||||
});
|
||||
});
|
||||
|
||||
// --- WithName / Named binding, isNamed, edge-cases ---
|
||||
group('Named binding & helpers', () {
|
||||
test('withName sets isNamed true and stores name', () {
|
||||
final binding = Binding<int>().withName('foo');
|
||||
expect(binding.isNamed, true);
|
||||
expect(binding.name, 'foo');
|
||||
});
|
||||
|
||||
test('providerWithParams returns null if not set', () {
|
||||
final binding = Binding<int>();
|
||||
expect(binding.providerWithParams(123), null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,46 +3,44 @@ import 'package:cherrypick/src/scope.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('Without parent scope.', () {
|
||||
test('Parent scope is null.', () {
|
||||
// --------------------------------------------------------------------------
|
||||
group('Scope & Subscope Management', () {
|
||||
test('Scope has no parent if constructed with null', () {
|
||||
final scope = Scope(null);
|
||||
expect(scope.parentScope, null);
|
||||
});
|
||||
|
||||
test('Open sub scope.', () {
|
||||
test('Can open and retrieve the same subScope by key', () {
|
||||
final scope = Scope(null);
|
||||
final subScope = scope.openSubScope('subScope');
|
||||
expect(scope.openSubScope('subScope'), subScope);
|
||||
});
|
||||
|
||||
test("Container throws state error if the value can't be resolved", () {
|
||||
test('closeSubScope removes subscope so next openSubScope returns new', () {
|
||||
final scope = Scope(null);
|
||||
final subScope = scope.openSubScope("child");
|
||||
expect(scope.openSubScope("child"), same(subScope));
|
||||
scope.closeSubScope("child");
|
||||
final newSubScope = scope.openSubScope("child");
|
||||
expect(newSubScope, isNot(same(subScope)));
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
group('Dependency Resolution (standard)', () {
|
||||
test("Throws StateError if value can't be resolved", () {
|
||||
final scope = Scope(null);
|
||||
expect(() => scope.resolve<String>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test('Container resolves value after adding a dependency', () {
|
||||
test('Resolves value after adding a dependency', () {
|
||||
final expectedValue = 'test string';
|
||||
final scope = Scope(null)
|
||||
.installModules([TestModule<String>(value: expectedValue)]);
|
||||
expect(scope.resolve<String>(), expectedValue);
|
||||
});
|
||||
});
|
||||
|
||||
group('With parent scope.', () {
|
||||
/*
|
||||
test(
|
||||
"Container bind() throws state error (if it's parent already has a resolver)",
|
||||
() {
|
||||
final parentScope = new Scope(null)
|
||||
.installModules([TestModule<String>(value: "string one")]);
|
||||
final scope = new Scope(parentScope);
|
||||
|
||||
expect(
|
||||
() => scope.installModules([TestModule<String>(value: "string two")]),
|
||||
throwsA(isA<StateError>()));
|
||||
});
|
||||
*/
|
||||
test('Container resolve() returns a value from parent container.', () {
|
||||
test('Returns a value from parent scope', () {
|
||||
final expectedValue = 5;
|
||||
final parentScope = Scope(null);
|
||||
final scope = Scope(parentScope);
|
||||
@@ -52,8 +50,7 @@ void main() {
|
||||
expect(scope.resolve<int>(), expectedValue);
|
||||
});
|
||||
|
||||
test('Container resolve() returns a several value from parent container.',
|
||||
() {
|
||||
test('Returns several values from parent container', () {
|
||||
final expectedIntValue = 5;
|
||||
final expectedStringValue = 'Hello world';
|
||||
final parentScope = Scope(null).installModules([
|
||||
@@ -66,15 +63,126 @@ void main() {
|
||||
expect(scope.resolve<String>(), expectedStringValue);
|
||||
});
|
||||
|
||||
test("Container resolve() throws a state error if parent hasn't value too.",
|
||||
() {
|
||||
test("Throws StateError if parent hasn't value too", () {
|
||||
final parentScope = Scope(null);
|
||||
final scope = Scope(parentScope);
|
||||
expect(() => scope.resolve<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test("After dropModules resolves fail", () {
|
||||
final scope = Scope(null)..installModules([TestModule<int>(value: 5)]);
|
||||
expect(scope.resolve<int>(), 5);
|
||||
scope.dropModules();
|
||||
expect(() => scope.resolve<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
group('Named Dependencies', () {
|
||||
test('Resolve named binding', () {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
TestModule<String>(value: "first"),
|
||||
TestModule<String>(value: "second", name: "special")
|
||||
]);
|
||||
expect(scope.resolve<String>(named: "special"), "second");
|
||||
expect(scope.resolve<String>(), "first");
|
||||
});
|
||||
|
||||
test('Named binding does not clash with unnamed', () {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
TestModule<String>(value: "foo", name: "bar"),
|
||||
]);
|
||||
expect(() => scope.resolve<String>(), throwsA(isA<StateError>()));
|
||||
expect(scope.resolve<String>(named: "bar"), "foo");
|
||||
});
|
||||
|
||||
test("tryResolve returns null for missing named", () {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
TestModule<String>(value: "foo"),
|
||||
]);
|
||||
expect(scope.tryResolve<String>(named: "bar"), isNull);
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
group('Provider with parameters', () {
|
||||
test('Resolve dependency using providerWithParams', () {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
_InlineModule((m, s) {
|
||||
m.bind<int>().toProvideWithParams((param) => (param as int) * 2);
|
||||
}),
|
||||
]);
|
||||
expect(scope.resolve<int>(params: 3), 6);
|
||||
expect(() => scope.resolve<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
group('Async Resolution', () {
|
||||
test('Resolve async instance', () async {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
_InlineModule((m, s) {
|
||||
m.bind<String>().toInstanceAsync(Future.value('async value'));
|
||||
}),
|
||||
]);
|
||||
expect(await scope.resolveAsync<String>(), "async value");
|
||||
});
|
||||
|
||||
test('Resolve async provider', () async {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
_InlineModule((m, s) {
|
||||
m.bind<int>().toProvideAsync(() async => 7);
|
||||
}),
|
||||
]);
|
||||
expect(await scope.resolveAsync<int>(), 7);
|
||||
});
|
||||
|
||||
test('Resolve async provider with param', () async {
|
||||
final scope = Scope(null)
|
||||
..installModules([
|
||||
_InlineModule((m, s) {
|
||||
m.bind<int>().toProvideAsyncWithParams((x) async => (x as int) * 3);
|
||||
}),
|
||||
]);
|
||||
expect(await scope.resolveAsync<int>(params: 2), 6);
|
||||
expect(() => scope.resolveAsync<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test('tryResolveAsync returns null for missing', () async {
|
||||
final scope = Scope(null);
|
||||
final result = await scope.tryResolveAsync<String>();
|
||||
expect(result, isNull);
|
||||
});
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
group('Optional resolution and error handling', () {
|
||||
test("tryResolve returns null for missing dependency", () {
|
||||
final scope = Scope(null);
|
||||
expect(scope.tryResolve<int>(), isNull);
|
||||
});
|
||||
|
||||
// Не реализован:
|
||||
// test("Container bind() throws state error (if it's parent already has a resolver)", () {
|
||||
// final parentScope = new Scope(null).installModules([TestModule<String>(value: "string one")]);
|
||||
// final scope = new Scope(parentScope);
|
||||
|
||||
// expect(
|
||||
// () => scope.installModules([TestModule<String>(value: "string two")]),
|
||||
// throwsA(isA<StateError>()));
|
||||
// });
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Вспомогательные модули
|
||||
|
||||
class TestModule<T> extends Module {
|
||||
final T value;
|
||||
final String? name;
|
||||
@@ -89,3 +197,12 @@ class TestModule<T> extends Module {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Вспомогательный модуль для подстановки builder'а через конструктор
|
||||
class _InlineModule extends Module {
|
||||
final void Function(Module, Scope) _builder;
|
||||
_InlineModule(this._builder);
|
||||
|
||||
@override
|
||||
void builder(Scope s) => _builder(this, s);
|
||||
}
|
||||
|
||||
@@ -28,18 +28,16 @@ packages:
|
||||
cherrypick:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cherrypick
|
||||
sha256: e1e2b4f3a70cbe7760e479e6ddb7dce2fc85a1bbb2fba6c398efe235ed111dfe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
path: "../../cherrypick"
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.1.0"
|
||||
cherrypick_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cherrypick_flutter
|
||||
sha256: ad63ae816b7d1147ffb0a82bcae5a1ea3d51e9d398a79459c619464391a43a79
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
path: "../../cherrypick_flutter"
|
||||
relative: true
|
||||
source: path
|
||||
version: "1.1.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
|
||||
@@ -153,11 +153,10 @@ packages:
|
||||
cherrypick:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cherrypick
|
||||
sha256: e1e2b4f3a70cbe7760e479e6ddb7dce2fc85a1bbb2fba6c398efe235ed111dfe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
path: "../../cherrypick"
|
||||
relative: true
|
||||
source: path
|
||||
version: "2.1.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
Reference in New Issue
Block a user