From e91987c635b64842763a910b726b4f961de1d75f Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Mon, 19 May 2025 11:14:59 +0300 Subject: [PATCH] update tests --- cherrypick/test/src/binding_test.dart | 533 ++++++++++---------------- cherrypick/test/src/scope_test.dart | 110 +++--- 2 files changed, 257 insertions(+), 386 deletions(-) diff --git a/cherrypick/test/src/binding_test.dart b/cherrypick/test/src/binding_test.dart index 134257c..4d3ce11 100644 --- a/cherrypick/test/src/binding_test.dart +++ b/cherrypick/test/src/binding_test.dart @@ -2,380 +2,91 @@ 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(); expect(binding.instance, null); }); - test('Binding check mode', () { - final expectedValue = 5; - final binding = Binding().toInstance(expectedValue); - + test('Sets mode to instance', () { + final binding = Binding().toInstance(5); expect(binding.mode, Mode.instance); }); - test('Binding check singleton', () { - final expectedValue = 5; - final binding = Binding().toInstance(expectedValue); - + test('isSingleton is true', () { + final binding = Binding().toInstance(5); expect(binding.isSingleton, true); }); - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding().toInstance(expectedValue); - - expect(binding.instance, expectedValue); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = Binding().toInstance(expectedValue); - expect(binding.instance, expectedValue); + test('Stores value', () { + final binding = Binding().toInstance(5); + expect(binding.instance, 5); }); }); - group('With name.', () { - test('Binding resolves null', () { - final binding = Binding().withName('expectedValue'); + group('With name', () { + test('Returns null by default', () { + final binding = Binding().withName('n'); expect(binding.instance, null); }); - test('Binding check mode', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - + test('Sets mode to instance', () { + final binding = Binding().withName('n').toInstance(5); expect(binding.mode, Mode.instance); }); - test('Binding check key', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - + test('Sets key', () { + final binding = Binding().withName('n').toInstance(5); expect(binding.key, int); }); - test('Binding check singleton', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - + test('isSingleton is true', () { + final binding = Binding().withName('n').toInstance(5); expect(binding.isSingleton, true); }); - test('Binding check value', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - - expect(binding.instance, expectedValue); + test('Stores value', () { + final binding = Binding().withName('n').toInstance(5); + expect(binding.instance, 5); }); - test('Binding check value', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - - expect(binding.name, 'expectedValue'); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = - Binding().withName('expectedValue').toInstance(expectedValue); - expect(binding.instance, expectedValue); - }); - }); - }); - - group('Check provide.', () { - group('Without name.', () { - test('Binding resolves null', () { - final binding = Binding(); - expect(binding.provider, null); - }); - - test('Binding check mode', () { - final expectedValue = 5; - final binding = Binding().toProvide(() => expectedValue); - - expect(binding.mode, Mode.providerInstance); - }); - - test('Binding check singleton', () { - final expectedValue = 5; - final binding = Binding().toProvide(() => expectedValue); - - expect(binding.isSingleton, false); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding().toProvide(() => expectedValue); - - expect(binding.provider, expectedValue); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = Binding().toProvide(() => expectedValue); - expect(binding.provider, expectedValue); + test('Sets name', () { + final binding = Binding().withName('n').toInstance(5); + expect(binding.name, 'n'); }); }); - group('With name.', () { - test('Binding resolves null', () { - final binding = Binding().withName('expectedValue'); - expect(binding.provider, null); - }); - - test('Binding check mode', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - - expect(binding.mode, Mode.providerInstance); - }); - - test('Binding check key', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - - expect(binding.key, int); - }); - - test('Binding check singleton', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - - expect(binding.isSingleton, false); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - - expect(binding.provider, expectedValue); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - - expect(binding.name, 'expectedValue'); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue); - expect(binding.provider, expectedValue); - }); + test('Multiple toInstance calls change value', () { + final binding = Binding().toInstance(1).toInstance(2); + expect(binding.instance, 2); }); }); - group('Check Async provider.', () { - test('Binding resolves value asynchronously', () async { - final expectedValue = 5; - final binding = Binding().toProvideAsync(() async => expectedValue); - - final result = await binding.asyncProvider?.call(); - expect(result, expectedValue); + // --- Instance binding (asynchronous) --- + group('Async Instance Binding (toInstanceAsync)', () { + test('Resolves instanceAsync with expected value', () async { + final binding = Binding().toInstanceAsync(Future.value(42)); + expect(await binding.instanceAsync, 42); }); - test('Binding resolves value asynchronously with params', () async { - final expectedValue = 5; - final binding = Binding().toProvideAsyncWithParams( - (param) async => expectedValue + (param as int)); - - final result = await binding.asyncProviderWithParams?.call(3); - expect(result, expectedValue + 3); - }); - }); - - group('Check singleton provide.', () { - group('Without name.', () { - test('Binding resolves null', () { - final binding = Binding().singleton(); - expect(binding.provider, null); - }); - - test('Binding check mode', () { - final expectedValue = 5; - final binding = - Binding().toProvide(() => expectedValue).singleton(); - - expect(binding.mode, Mode.providerInstance); - }); - - test('Binding check singleton', () { - final expectedValue = 5; - final binding = - Binding().toProvide(() => expectedValue).singleton(); - - expect(binding.isSingleton, true); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = - Binding().toProvide(() => expectedValue).singleton(); - - expect(binding.provider, expectedValue); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = - Binding().toProvide(() => expectedValue).singleton(); - expect(binding.provider, expectedValue); - }); - }); - - group('With name.', () { - test('Binding resolves null', () { - final binding = Binding().withName('expectedValue').singleton(); - expect(binding.provider, null); - }); - - test('Binding check mode', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - - expect(binding.mode, Mode.providerInstance); - }); - - test('Binding check key', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - - expect(binding.key, int); - }); - - test('Binding check singleton', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - - expect(binding.isSingleton, true); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - - expect(binding.provider, expectedValue); - }); - - test('Binding check value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - - expect(binding.name, 'expectedValue'); - }); - - test('Binding resolves value', () { - final expectedValue = 5; - final binding = Binding() - .withName('expectedValue') - .toProvide(() => expectedValue) - .singleton(); - expect(binding.provider, expectedValue); - }); - }); - }); - - test('Binding returns null providerWithParams if not set', () { - final binding = Binding(); - expect(binding.providerWithParams(123), null); - }); - - test('Binding withName changes isNamed to true', () { - final binding = Binding().withName('foo'); - expect(binding.isNamed, true); - expect(binding.name, 'foo'); - }); - - // Проверка singleton provider вызывается один раз - test('Singleton provider only called once', () { - int counter = 0; - final binding = Binding().toProvide(() { - counter++; - return counter; - }).singleton(); - - final first = binding.provider; - final second = binding.provider; - expect(first, equals(second)); - expect(counter, 1); - }); - - // Повторный вызов toInstance влияет на значение - test('Multiple toInstance calls changes instance', () { - final binding = Binding().toInstance(1).toInstance(2); - expect(binding.instance, 2); - }); - - // Проверка mode после chaining - test('Chained withName and singleton preserves mode', () { - final binding = - Binding().toProvide(() => 3).withName("named").singleton(); - expect(binding.mode, Mode.providerInstance); - }); - - group('Check toInstanceAsync.', () { - test('Binding resolves instanceAsync with expected value', () async { - final expectedValue = 42; - final binding = - Binding().toInstanceAsync(Future.value(expectedValue)); - final result = await binding.instanceAsync; - expect(result, equals(expectedValue)); - }); - - test('Binding instanceAsync does not affect instance', () { + test('Does not affect instance', () { final binding = Binding().toInstanceAsync(Future.value(5)); expect(binding.instance, null); }); - test('Binding mode is set to instance', () { + test('Sets mode to instance', () { final binding = Binding().toInstanceAsync(Future.value(5)); expect(binding.mode, Mode.instance); }); - test('Binding isSingleton is true after toInstanceAsync', () { + test('isSingleton is true after toInstanceAsync', () { final binding = Binding().toInstanceAsync(Future.value(5)); expect(binding.isSingleton, isTrue); }); - test('Binding withName combines with toInstanceAsync', () async { + test('Composes with withName', () async { final binding = Binding() .withName('asyncValue') .toInstanceAsync(Future.value(7)); @@ -384,11 +95,177 @@ void main() { expect(await binding.instanceAsync, 7); }); - test('Binding instanceAsync keeps value after multiple awaits', () async { + test('Keeps value after multiple awaits', () async { final binding = Binding().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(); + expect(binding.provider, null); + }); + + test('Sets mode to providerInstance', () { + final binding = Binding().toProvide(() => 5); + expect(binding.mode, Mode.providerInstance); + }); + + test('isSingleton is false by default', () { + final binding = Binding().toProvide(() => 5); + expect(binding.isSingleton, false); + }); + + test('Returns provided value', () { + final binding = Binding().toProvide(() => 5); + expect(binding.provider, 5); + }); + }); + + group('With name', () { + test('Returns null by default', () { + final binding = Binding().withName('n'); + expect(binding.provider, null); + }); + + test('Sets mode to providerInstance', () { + final binding = Binding().withName('n').toProvide(() => 5); + expect(binding.mode, Mode.providerInstance); + }); + + test('Sets key', () { + final binding = Binding().withName('n').toProvide(() => 5); + expect(binding.key, int); + }); + + test('isSingleton is false by default', () { + final binding = Binding().withName('n').toProvide(() => 5); + expect(binding.isSingleton, false); + }); + + test('Returns provided value', () { + final binding = Binding().withName('n').toProvide(() => 5); + expect(binding.provider, 5); + }); + + test('Sets name', () { + final binding = Binding().withName('n').toProvide(() => 5); + expect(binding.name, 'n'); + }); + }); + }); + + // --- Async provider binding --- + group('Async Provider Binding', () { + test('Resolves asyncProvider value', () async { + final binding = Binding().toProvideAsync(() async => 5); + expect(await binding.asyncProvider?.call(), 5); + }); + + test('Resolves asyncProviderWithParams value', () async { + final binding = Binding() + .toProvideAsyncWithParams((param) async => 5 + (param as int)); + expect(await binding.asyncProviderWithParams?.call(3), 8); + }); + }); + + // --- Singleton provider binding --- + group('Singleton Provider Binding', () { + group('Without name', () { + test('Returns null if no provider set', () { + final binding = Binding().singleton(); + expect(binding.provider, null); + }); + + test('Sets mode to providerInstance', () { + final binding = Binding().toProvide(() => 5).singleton(); + expect(binding.mode, Mode.providerInstance); + }); + + test('isSingleton is true', () { + final binding = Binding().toProvide(() => 5).singleton(); + expect(binding.isSingleton, true); + }); + + test('Returns singleton value', () { + final binding = Binding().toProvide(() => 5).singleton(); + expect(binding.provider, 5); + }); + + test('Returns same value each call and provider only called once', () { + int counter = 0; + final binding = Binding().toProvide(() { + counter++; + return counter; + }).singleton(); + + final first = binding.provider; + final second = binding.provider; + expect(first, equals(second)); + expect(counter, 1); + }); + }); + + group('With name', () { + test('Returns null if no provider set', () { + final binding = Binding().withName('n').singleton(); + expect(binding.provider, null); + }); + + test('Sets mode to providerInstance', () { + final binding = + Binding().withName('n').toProvide(() => 5).singleton(); + expect(binding.mode, Mode.providerInstance); + }); + + test('Sets key', () { + final binding = + Binding().withName('n').toProvide(() => 5).singleton(); + expect(binding.key, int); + }); + + test('isSingleton is true', () { + final binding = + Binding().withName('n').toProvide(() => 5).singleton(); + expect(binding.isSingleton, true); + }); + + test('Returns singleton value', () { + final binding = + Binding().withName('n').toProvide(() => 5).singleton(); + expect(binding.provider, 5); + }); + + test('Sets name', () { + final binding = + Binding().withName('n').toProvide(() => 5).singleton(); + expect(binding.name, 'n'); + }); + }); + + test('Chained withName and singleton preserves mode', () { + final binding = + Binding().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().withName('foo'); + expect(binding.isNamed, true); + expect(binding.name, 'foo'); + }); + + test('providerWithParams returns null if not set', () { + final binding = Binding(); + expect(binding.providerWithParams(123), null); + }); + }); } diff --git a/cherrypick/test/src/scope_test.dart b/cherrypick/test/src/scope_test.dart index ed1d866..738ae74 100644 --- a/cherrypick/test/src/scope_test.dart +++ b/cherrypick/test/src/scope_test.dart @@ -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(), throwsA(isA())); }); - 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(value: expectedValue)]); expect(scope.resolve(), 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(value: "string one")]); - final scope = new Scope(parentScope); - - expect( - () => scope.installModules([TestModule(value: "string two")]), - throwsA(isA())); - }); -*/ - 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(), 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,22 @@ void main() { expect(scope.resolve(), 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(), throwsA(isA())); }); + + test("After dropModules resolves fail", () { + final scope = Scope(null)..installModules([TestModule(value: 5)]); + expect(scope.resolve(), 5); + scope.dropModules(); + expect(() => scope.resolve(), throwsA(isA())); + }); }); - group('Named dependencies', () { + // -------------------------------------------------------------------------- + group('Named Dependencies', () { test('Resolve named binding', () { final scope = Scope(null) ..installModules([ @@ -103,7 +107,8 @@ void main() { }); }); - group('Provider with params', () { + // -------------------------------------------------------------------------- + group('Provider with parameters', () { test('Resolve dependency using providerWithParams', () { final scope = Scope(null) ..installModules([ @@ -112,14 +117,12 @@ void main() { }), ]); expect(scope.resolve(params: 3), 6); - expect( - () => scope.resolve(), - throwsA(isA()), - ); + expect(() => scope.resolve(), throwsA(isA())); }); }); - group('Async resolution', () { + // -------------------------------------------------------------------------- + group('Async Resolution', () { test('Resolve async instance', () async { final scope = Scope(null) ..installModules([ @@ -148,10 +151,7 @@ void main() { }), ]); expect(await scope.resolveAsync(params: 2), 6); - expect( - () => scope.resolveAsync(), - throwsA(isA()), - ); + expect(() => scope.resolveAsync(), throwsA(isA())); }); test('tryResolveAsync returns null for missing', () async { @@ -161,34 +161,28 @@ void main() { }); }); - group("Drop modules", () { - test("After dropModules resolves fail", () { - final scope = Scope(null)..installModules([TestModule(value: 5)]); - expect(scope.resolve(), 5); - scope.dropModules(); - expect(() => scope.resolve(), throwsA(isA())); - }); - }); - - group("Subscope closing", () { - test("closeSubScope removes subscope", () { - 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))); // New instance after close - }); - }); - - group("tryResolve returns null if not found", () { - test("Returns null for missing dependency", () { + // -------------------------------------------------------------------------- + group('Optional resolution and error handling', () { + test("tryResolve returns null for missing dependency", () { final scope = Scope(null); expect(scope.tryResolve(), isNull); }); + + // Не реализован: + // test("Container bind() throws state error (if it's parent already has a resolver)", () { + // final parentScope = new Scope(null).installModules([TestModule(value: "string one")]); + // final scope = new Scope(parentScope); + + // expect( + // () => scope.installModules([TestModule(value: "string two")]), + // throwsA(isA())); + // }); }); } +// ---------------------------------------------------------------------------- +// Вспомогательные модули + class TestModule extends Module { final T value; final String? name;