LCOV - code coverage report
Current view: top level - lib - injector_x.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 68 68 100.0 %
Date: 2021-05-10 09:07:15 Functions: 0 0 -

          Line data    Source code
       1             : library injector_x;
       2             : 
       3             : class InjectionNotFound implements Exception {
       4           1 :   InjectionNotFound(this.message);
       5             :   final String message;
       6             : }
       7             : 
       8             : class DuplicateInjectionFound implements Exception {
       9           1 :   DuplicateInjectionFound(this.message);
      10             :   final String message;
      11             : }
      12             : 
      13             : abstract class INeedle<T> {
      14             :   Type getType();
      15             :   T? getMock();
      16             :   bool isNewInstance();
      17             : }
      18             : 
      19             : class Needle<T> implements INeedle<T> {
      20             :   late Type type;
      21             :   final bool newInstance;
      22           3 :   Needle({this.newInstance = false}) {
      23           3 :     type = T;
      24             :   }
      25             : 
      26           3 :   @override
      27             :   T? getMock() {
      28             :     return null;
      29             :   }
      30             : 
      31           3 :   @override
      32             :   Type getType() {
      33           3 :     return this.type;
      34             :   }
      35             : 
      36           3 :   @override
      37             :   bool isNewInstance() {
      38           3 :     return this.newInstance;
      39             :   }
      40             : }
      41             : 
      42             : class NeedleMock<T> implements INeedle<T> {
      43             :   late Type type;
      44             :   final T mock;
      45             : 
      46           3 :   NeedleMock({Type? type, required this.mock}) {
      47             :     if (type == null) {
      48           3 :       this.type = T;
      49             :     } else {
      50           1 :       this.type = type;
      51             :     }
      52             :   }
      53             : 
      54           3 :   @override
      55             :   T? getMock() {
      56           3 :     return mock;
      57             :   }
      58             : 
      59           3 :   @override
      60             :   Type getType() {
      61           3 :     return this.type;
      62             :   }
      63             : 
      64           1 :   @override
      65             :   bool isNewInstance() {
      66             :     return true;
      67             :   }
      68             : }
      69             : 
      70             : abstract class Injectable {
      71             :   final List<INeedle>? needles;
      72           3 :   Injectable({this.needles});
      73             : }
      74             : 
      75             : typedef InjectableAdd<T> = T Function();
      76             : 
      77             : class _InjectStore<T extends Object> {
      78             :   final String key;
      79             :   final InjectableAdd<T> injectable;
      80             :   final bool isSingleton;
      81             :   dynamic singleton;
      82           3 :   _InjectStore({
      83             :     required this.key,
      84             :     required this.singleton,
      85             :     required this.injectable,
      86             :     required this.isSingleton,
      87             :   });
      88             : }
      89             : 
      90             : class InjectorXBind {
      91           9 :   static final List<_InjectStore> _store = [];
      92             : 
      93           3 :   static bool _checkKeyExists(String key) {
      94          18 :     return _store.where((e) => e.key == key).isNotEmpty;
      95             :   }
      96             : 
      97           3 :   static void add<T extends Object>(InjectableAdd<T> injectable,
      98             :       {bool singleton = false}) {
      99           6 :     if (_checkKeyExists(T.toString())) {
     100           3 :       throw DuplicateInjectionFound("${T.toString()} is duplicate.");
     101             :     }
     102           9 :     _store.add(_InjectStore<T>(
     103           3 :       key: T.toString(),
     104             :       singleton: null,
     105             :       injectable: injectable,
     106             :       isSingleton: singleton,
     107             :     ));
     108             :   }
     109             : 
     110           1 :   static T get<T extends Object>({bool newInstance = false}) {
     111             :     try {
     112           1 :       return getByType(T, newInstance: newInstance) as T;
     113           1 :     } on Exception catch (e) {
     114             :       throw e;
     115             :     }
     116             :   }
     117             : 
     118           3 :   static dynamic getByType(Type type, {bool newInstance = false}) {
     119           6 :     if (!_checkKeyExists(type.toString())) {
     120           3 :       throw InjectionNotFound("Injection not found from ${type.toString()}.");
     121             :     }
     122             : 
     123          21 :     var ref = _store.where((e) => e.key == type.toString()).first;
     124             : 
     125           3 :     if (!ref.isSingleton) {
     126           6 :       return ref.injectable();
     127             :     } else {
     128             :       if (!newInstance) {
     129           1 :         var singleton = ref.singleton;
     130             :         if (singleton == null) {
     131           3 :           ref.singleton = ref.injectable();
     132             :         }
     133           1 :         return ref.singleton;
     134             :       } else {
     135           2 :         return ref.injectable();
     136             :       }
     137             :     }
     138             :   }
     139             : }
     140             : 
     141             : class InjectorX {
     142           3 :   InjectorX(this.injectNeedles) {
     143           6 :     for (var needle in injectNeedles) {
     144           3 :       if (needle.getMock() != null) {
     145          15 :         _refs[needle.getType().toString()] = needle.getMock();
     146             :       } else {
     147           6 :         var obj = InjectorXBind.getByType(needle.getType(),
     148           3 :             newInstance: needle.isNewInstance());
     149          12 :         _refs[needle.getType().toString()] = obj;
     150             :       }
     151             :     }
     152             :   }
     153             : 
     154             :   final List<INeedle> injectNeedles;
     155             :   final Map<String, dynamic> _refs = {};
     156             : 
     157           3 :   T get<T>() {
     158           3 :     var key = T.toString();
     159           6 :     if (_refs.containsKey(key)) {
     160           9 :       return _refs[T.toString()];
     161             :     } else {
     162           3 :       print("The injection reference ${T.toString()} is not found");
     163           1 :       throw InjectionNotFound(
     164           2 :           "The injection reference ${T.toString()} is not found");
     165             :     }
     166             :   }
     167             : }
     168             : 
     169             : abstract class Inject<T extends Inject<T>> extends Injectable {
     170           6 :   Inject({List<Needle>? needles}) : super(needles: needles) {
     171           7 :     this.injector(InjectorX(needles ?? []));
     172             :   }
     173             : 
     174           3 :   T injectMocks(List<NeedleMock> needleMocks) {
     175           3 :     var localNeedles = <INeedle>[];
     176           3 :     if (this.needles != null) {
     177           6 :       for (var arg in needleMocks) {
     178             :         localNeedles = this
     179           3 :             .needles!
     180           6 :             .where((e) =>
     181           9 :                 e.getType().toString() !=
     182           9 :                 arg.type.toString().replaceAll("Mock", ""))
     183           3 :             .toList();
     184             :       }
     185             :     }
     186             : 
     187           3 :     needleMocks.addAll(
     188           3 :         localNeedles.map((e) => NeedleMock(type: e.getType(), mock: null)));
     189           6 :     this.injector(InjectorX(needleMocks));
     190             :     return this as T;
     191             :   }
     192             : 
     193             :   void injector(InjectorX handler);
     194             : }

Generated by: LCOV version 1.15