From e73c854b649c566d9a2126a7ff916d9e5ac3bdec Mon Sep 17 00:00:00 2001 From: Patrick Stewart Date: Fri, 27 Dec 2024 09:11:06 -0700 Subject: [PATCH] refactor: add makeWith() alias working on wrap() 163 pass 4 fail --- .../container/lib/src/container.dart | 12 + .../container/test/make_with_test.dart | 252 ++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 incubation/container/container/test/make_with_test.dart diff --git a/incubation/container/container/lib/src/container.dart b/incubation/container/container/lib/src/container.dart index 76d21d4..1e513b1 100644 --- a/incubation/container/container/lib/src/container.dart +++ b/incubation/container/container/lib/src/container.dart @@ -1248,6 +1248,18 @@ class Container { bindIf(concrete, singleton: true); } + /// Make an instance with parameters + /// + /// This is an alias for making an instance while providing parameters. + /// It's equivalent to using withParameters() with make(). + /// + /// ```dart + /// var logger = container.makeWith({'level': 'debug'}); + /// ``` + T makeWith(Map parameters, [Type? type]) { + return withParameters(parameters, () => make(type)); + } + /// Create a factory binding for deferred resolution /// /// This method allows you to create a factory binding that will be resolved diff --git a/incubation/container/container/test/make_with_test.dart b/incubation/container/container/test/make_with_test.dart new file mode 100644 index 0000000..65a198c --- /dev/null +++ b/incubation/container/container/test/make_with_test.dart @@ -0,0 +1,252 @@ +import 'package:platformed_container/container.dart'; +import 'package:test/test.dart'; + +abstract class Logger { + void log(String message); + String get level; +} + +class ConsoleLogger implements Logger { + final String _level; + + ConsoleLogger(this._level); + + @override + void log(String message) => print('Console: $message'); + + @override + String get level => _level; +} + +void main() { + late Container container; + + setUp(() { + container = Container(MockReflector()); + }); + + group('MakeWith Tests', () { + test('makeWith passes parameters to constructor', () { + container.factory(() => + ConsoleLogger(container.getParameterOverride('level') ?? 'info')); + + var logger = container.makeWith({'level': 'debug'}); + expect(logger.level, equals('debug')); + }); + + test('makeWith works with type parameter', () { + container.factory(() => + ConsoleLogger(container.getParameterOverride('level') ?? 'info')); + + var logger = container.makeWith({'level': 'debug'}, Logger); + expect(logger.level, equals('debug')); + }); + + test('makeWith preserves parameters for nested dependencies', () { + var level = ''; + container.factory(() { + level = container.getParameterOverride('level') ?? 'info'; + return ConsoleLogger(level); + }); + + container.makeWith({'level': 'debug'}); + expect(level, equals('debug')); + }); + + test('makeWith throws when binding not found', () { + expect(() => container.makeWith({'level': 'debug'}), + throwsA(isA())); + }); + }); +} + +class MockReflector extends Reflector { + @override + String? getName(Symbol symbol) => null; + + @override + ReflectedClass? reflectClass(Type clazz) { + if (clazz == ConsoleLogger) { + return MockReflectedClass( + 'ConsoleLogger', + [], + [], + [ + MockConstructor('', [ + MockParameter('level', String, true, false), + ]) + ], + ConsoleLogger); + } + return null; + } + + @override + ReflectedType? reflectType(Type type) { + return reflectClass(type); + } + + @override + ReflectedInstance? reflectInstance(Object? instance) => null; + + @override + ReflectedFunction? reflectFunction(Function function) => null; + + @override + ReflectedType reflectFutureOf(Type type) => throw UnimplementedError(); + + @override + Type? findTypeByName(String name) => null; + + @override + ReflectedFunction? findInstanceMethod(Object instance, String methodName) => + null; + + @override + List getAnnotations(Type type) => []; + + @override + List getParameterAnnotations( + Type type, String constructorName, String parameterName) => + []; +} + +class MockConstructor implements ReflectedFunction { + final String constructorName; + final List constructorParameters; + + MockConstructor(this.constructorName, this.constructorParameters); + + @override + List get annotations => []; + + @override + bool get isGetter => false; + + @override + bool get isSetter => false; + + @override + String get name => constructorName; + + @override + List get parameters => constructorParameters; + + @override + ReflectedType? get returnType => null; + + @override + List get typeParameters => []; + + @override + ReflectedInstance invoke(Invocation invocation) => throw UnimplementedError(); +} + +class MockReflectedClass extends ReflectedType implements ReflectedClass { + @override + final List annotations; + @override + final List constructors; + @override + final List declarations; + + MockReflectedClass( + String name, + List typeParameters, + this.annotations, + this.constructors, + Type reflectedType, + ) : declarations = [], + super(reflectedType.toString(), typeParameters, reflectedType); + + @override + ReflectedInstance newInstance( + String constructorName, List positionalArguments, + [Map namedArguments = const {}, + List typeArguments = const []]) { + if (reflectedType == ConsoleLogger) { + var level = namedArguments['level'] ?? positionalArguments[0]; + return MockReflectedInstance(ConsoleLogger(level)); + } + throw UnsupportedError('Unknown type: $reflectedType'); + } + + @override + bool isAssignableTo(ReflectedType? other) { + if (reflectedType == other?.reflectedType) { + return true; + } + if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { + return true; + } + return false; + } +} + +class MockParameter implements ReflectedParameter { + @override + final String name; + @override + final bool isRequired; + @override + final bool isNamed; + final Type paramType; + final bool isVariadic; + + MockParameter(this.name, this.paramType, this.isRequired, this.isNamed, + {this.isVariadic = false}); + + @override + List get annotations => []; + + @override + ReflectedType get type => MockReflectedType(paramType); +} + +class MockReflectedType implements ReflectedType { + @override + final String name; + @override + final Type reflectedType; + + MockReflectedType(this.reflectedType) : name = reflectedType.toString(); + + @override + List get typeParameters => []; + + @override + bool isAssignableTo(ReflectedType? other) { + if (reflectedType == other?.reflectedType) { + return true; + } + if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { + return true; + } + return false; + } + + @override + ReflectedInstance newInstance( + String constructorName, List positionalArguments, + [Map namedArguments = const {}, + List typeArguments = const []]) => + throw UnimplementedError(); +} + +class MockReflectedInstance implements ReflectedInstance { + final dynamic value; + + MockReflectedInstance(this.value); + + @override + ReflectedClass get clazz => throw UnimplementedError(); + + @override + ReflectedInstance getField(String name) => throw UnimplementedError(); + + @override + dynamic get reflectee => value; + + @override + ReflectedType get type => throw UnimplementedError(); +}