import 'package:platform_contracts/contracts.dart'; import 'package:platform_container/platform_container.dart'; import 'package:test/test.dart'; import 'package:mockito/mockito.dart'; import 'package:mockito/annotations.dart'; import '../laravel_container_test.mocks.dart'; import '../stubs.dart'; @GenerateMocks([ ReflectorContract, ReflectedClassContract, ReflectedInstanceContract, ReflectedFunctionContract, ReflectedParameterContract, ReflectedTypeContract ]) void main() { late IlluminateContainer container; late MockReflectorContract reflector; late MockReflectedClassContract reflectedClass; late MockReflectedInstanceContract reflectedInstance; late MockReflectedFunctionContract reflectedFunction; late MockReflectedParameterContract reflectedParameter; late MockReflectedTypeContract reflectedType; setUp(() { reflector = MockReflectorContract(); reflectedClass = MockReflectedClassContract(); reflectedInstance = MockReflectedInstanceContract(); reflectedFunction = MockReflectedFunctionContract(); reflectedParameter = MockReflectedParameterContract(); reflectedType = MockReflectedTypeContract(); container = IlluminateContainer(reflector); // Setup default reflection behavior when(reflector.reflectClass(any)).thenReturn(reflectedClass); when(reflectedClass.newInstance('', [])).thenReturn(reflectedInstance); }); group('Container Basic Resolution', () { test('testClosureResolution', () { container.bind((c) => 'Taylor'); expect(container.make(), equals('Taylor')); }); test('testBindIfDoesntRegisterIfServiceAlreadyRegistered', () { container.bind((c) => 'Taylor'); container.bindIf((c) => 'Dayle'); expect(container.make(), equals('Taylor')); }); test('testBindIfDoesRegisterIfServiceNotRegisteredYet', () { container.bindIf((c) => 'Dayle'); expect(container.make(), equals('Dayle')); }); test('testAutoConcreteResolution', () { final instance = ContainerConcreteStub(); when(reflectedInstance.reflectee).thenReturn(instance); expect(container.make(), isA()); }); }); group('Container Singleton', () { test('testSharedClosureResolution', () { container .singleton((c) => ContainerConcreteStub()); final first = container.make(); final second = container.make(); expect(identical(first, second), isTrue); }); test('testSingletonIfDoesntRegisterIfBindingAlreadyRegistered', () { container .singleton((c) => ContainerConcreteStub()); final first = container.make(); container .singletonIf((c) => ContainerConcreteStub()); final second = container.make(); expect(identical(first, second), isTrue); }); test('testSingletonIfDoesRegisterIfBindingNotRegisteredYet', () { container .singletonIf((c) => ContainerConcreteStub()); final first = container.make(); final second = container.make(); expect(identical(first, second), isTrue); }); test('testBindingAnInstanceAsShared', () { final instance = ContainerConcreteStub(); container.instance(instance); expect( identical(container.make(), instance), isTrue); }); }); group('Container Scoped', () { test('testScopedClosureResolution', () { container.scoped((c) => ContainerConcreteStub()); final first = container.make(); final second = container.make(); expect(identical(first, second), isTrue); container.forgetScopedInstances(); final third = container.make(); expect(identical(second, third), isFalse); }); test('testScopedIfDoesntRegisterIfBindingAlreadyRegistered', () { container.scoped((c) => ContainerConcreteStub()); final first = container.make(); container.scopedIf((c) => ContainerConcreteStub()); final second = container.make(); expect(identical(first, second), isTrue); }); test('testScopedIfDoesRegisterIfBindingNotRegisteredYet', () { container.scopedIf((c) => ContainerConcreteStub()); final first = container.make(); final second = container.make(); expect(identical(first, second), isTrue); }); }); group('Container Dependencies', () { test('testAbstractToConcreteResolution', () { final impl = ContainerImplementationStub(); final dependent = ContainerDependentStub(impl); when(reflectedInstance.reflectee).thenReturn(dependent); container .bind((c) => ContainerImplementationStub()); final instance = container.make(); expect(instance.impl, isA()); }); test('testNestedDependencyResolution', () { final impl = ContainerImplementationStub(); final dependent = ContainerDependentStub(impl); final nested = ContainerNestedDependentStub(dependent); when(reflectedInstance.reflectee).thenReturn(nested); container .bind((c) => ContainerImplementationStub()); final instance = container.make(); expect(instance.inner, isA()); expect(instance.inner.impl, isA()); }); test('testContainerIsPassedToResolvers', () { container.bind((c) => c); final resolved = container.make(); expect(identical(resolved, container), isTrue); }); }); group('Container Aliases', () { test('testAliases', () { final impl = ContainerImplementationStub('bar'); when(reflectedInstance.reflectee).thenReturn(impl); container.bind((c) => impl); container.alias(IContainerContractStub, ContainerImplementationStub); expect( container.make().getValue(), equals('bar')); expect(container.make().getValue(), equals('bar')); expect(container.isAlias('ContainerImplementationStub'), isTrue); }); test('testAliasesWithArrayOfParameters', () { final impl = ContainerImplementationStub('foo'); when(reflectedInstance.reflectee).thenReturn(impl); container.bind((c) => impl); container.alias(IContainerContractStub, ContainerImplementationStub); expect( container.make().getValue(), equals('foo')); expect(container.make().getValue(), equals('foo')); }); test('testGetAliasRecursive', () { final impl = ContainerImplementationStub('foo'); when(reflectedInstance.reflectee).thenReturn(impl); // Bind the implementation to the interface container.bind((c) => impl); // Create alias chain in reverse order container.alias(ContainerImplementationStub, StubAlias); container.alias(IContainerContractStub, ContainerImplementationStub); // Verify immediate aliases expect( container.getAlias(StubAlias), equals(ContainerImplementationStub)); expect(container.getAlias(ContainerImplementationStub), equals(IContainerContractStub)); // Verify instance resolution through alias chain final instance = container.make(); expect(instance.getValue(), equals('foo')); }); }); group('Container State', () { test('testBindingsCanBeOverridden', () { container.bind((c) => 'bar'); container.bind((c) => 'baz'); expect(container.make(), equals('baz')); }); test('testContainerFlushFlushesAllBindingsAliasesAndResolvedInstances', () { container .bind((c) => ContainerImplementationStub()); container.bind((c) => ContainerConcreteStub()); container.tag([ContainerConcreteStub], 'services'); container.alias(IContainerContractStub, ContainerImplementationStub); expect(container.has(), isTrue); expect(container.has(), isTrue); expect(container.isAlias('ContainerImplementationStub'), isTrue); container.flush(); expect(container.has(), isFalse); expect(container.has(), isFalse); expect(container.isAlias('ContainerImplementationStub'), isFalse); }); test('testForgetInstanceForgetsInstance', () { final instance = ContainerConcreteStub(); container.instance(instance); expect(container.has(), isTrue); container.forgetInstance(ContainerConcreteStub); expect(container.has(), isFalse); }); test('testForgetInstancesForgetsAllInstances', () { final instance1 = ContainerConcreteStub(); final instance2 = ContainerImplementationStub(); container.instance(instance1); container.instance(instance2); expect(container.has(), isTrue); expect(container.has(), isTrue); container.forgetInstances(); expect(container.has(), isFalse); expect(container.has(), isFalse); }); }); }