Diff of /Implementation/APUnitTestFramework/DependencyResolver.cs [000000] .. [5a4bff]  Maximize  Restore

Switch to unified view

a b/Implementation/APUnitTestFramework/DependencyResolver.cs
1
using _3S.CoDeSys.Core;
2
using _3S.CoDeSys.Core.ComponentModel;
3
using _3S.CoDeSys.Core.Components;
4
using _3S.CoDeSys.Core.Views;
5
using System;
6
using System.Collections;
7
using System.Collections.Generic;
8
using System.Linq;
9
using System.Reflection;
10
using System.Xml;
11
12
namespace _3S.APUnitTestFramework
13
{
14
    class DependencyResolver
15
    {
16
        public DependencyResolver(Testbed testbed, string profileName, Profile profile)
17
        {
18
            if (testbed == null)
19
                throw new ArgumentNullException(nameof(testbed));
20
21
            _testbed = testbed;
22
23
            var byTypeGuid = new Dictionary<Guid, IValueProvider>();
24
            var byItfType = new Dictionary<Type, List<IValueProvider>>();
25
            foreach (var kvp in testbed.Mocks)
26
            {
27
                var prototype = kvp.Value.CreatePrototypeFunc();
28
                var valueProvider = new MockValueProvider(kvp.Key, prototype, kvp.Value);
29
                byTypeGuid[kvp.Key] = valueProvider;
30
31
                foreach (var itfType in prototype.GetType().GetInterfaces())
32
                {
33
                    List<IValueProvider> valueProviderList;
34
                    byItfType.TryGetValue(itfType, out valueProviderList);
35
                    if (valueProviderList == null)
36
                    {
37
                        valueProviderList = new List<IValueProvider>();
38
                        byItfType[itfType] = valueProviderList;
39
                    }
40
                    valueProviderList.Add(valueProvider);
41
                }
42
            }
43
44
            _mockFactoriesByTypeGuid = byTypeGuid;
45
            _mockFactoriesByItfType = byItfType.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToArray());
46
            _profileName = profileName ?? ComponentManager.Singleton.ActiveProfileName;
47
            _profile = profile ?? ComponentManager.Singleton.ActiveProfile;
48
        }
49
50
        public IValueProvider ResolveSingle(Type itfType, bool optional, MemberInfo member)
51
        {
52
            IValueProvider[] results;
53
            _mockFactoriesByItfType.TryGetValue(itfType, out results);
54
55
            if (results == null)
56
            {
57
                // We did not find an implementation among the mocks.
58
                // Try the additional plug-ins, if any. This discovery is similar to the original
59
                // component model implementation. In the case of any doubts, look there.
60
61
                if (_systemTypeInfos == null)
62
                    _systemTypeInfos = ComponentManager.Singleton.GetSystemTypes();
63
64
                var itfTypeFullName = itfType.FullName;
65
                Guid systemTypeGuid;
66
                try
67
                {
68
                    var enum1 = Enumerable.Where(_systemTypeInfos, typeInfo => typeInfo.TypeName == itfTypeFullName || typeInfo.ItfTypesFast.Contains(itfTypeFullName));
69
                    var enum2 = Enumerable.Select(enum1, typeInfo => typeInfo.TypeGuid);
70
                    systemTypeGuid = Enumerable.SingleOrDefault(enum2);
71
                }
72
                catch
73
                {
74
                    var exception = new MultipleInstancesForInjectionException(member);
75
                    _testbed.RaiseDependencyError(exception, itfType, null);
76
                    return new ExceptionValueProvider(exception);
77
                }
78
79
                if (systemTypeGuid != Guid.Empty)
80
                    return new SystemInstanceValueProvider(systemTypeGuid);
81
82
                if (itfType.IsAssignableFrom(SystemInstances.MessageService.GetType()))
83
                    return new MessageServiceValueProvider();
84
85
                IValueProvider vp = null;
86
                foreach (var t in ComponentManager.Singleton.PlugInCache.GetTypesFast(itfTypeFullName, null))
87
                {
88
                    if (vp == null)
89
                    {
90
                        vp = new TypeGuidValueProvider(t);
91
                    }
92
                    else
93
                    {
94
                        var exception = new MultipleInstancesForInjectionException(member);
95
                        _testbed.RaiseDependencyError(exception, itfType, null);
96
                        return new ExceptionValueProvider(exception);
97
                    }
98
                }
99
100
                if (vp != null)
101
                    results = new[] { vp };
102
            }
103
104
            if (results == null && optional)
105
            {
106
                return new NullValueProvider();
107
            }
108
            else if (results == null)
109
            {
110
                var exception = new NoInstanceForInjectionException(member);
111
                _testbed.RaiseDependencyError(exception, itfType, null);
112
                return new ExceptionValueProvider(exception);
113
            }
114
            else if (results.Length == 1)
115
            {
116
                return results[0];
117
            }
118
            else
119
            {
120
                var exception = new MultipleInstancesForInjectionException(member);
121
                _testbed.RaiseDependencyError(exception, itfType, null);
122
                return new ExceptionValueProvider(exception);
123
            }
124
        }
125
126
        public IValueProvider ResolveSpecific(Guid typeGuid, Type itfType, bool optional, MemberInfo member)
127
        {
128
            IValueProvider result;
129
            _mockFactoriesByTypeGuid.TryGetValue(typeGuid, out result);
130
131
            if (result == null)
132
            {
133
                // We did not find an implementation among the mocks.
134
                // Try the additional plug-ins, if any. This discovery is similar to the original
135
                // component model implementation. In the case of any doubts, look there.
136
137
                var exists = false;
138
                try
139
                {
140
                    exists = ComponentManager.Singleton.TryGetPlugInType(typeGuid, true) != null;
141
                }
142
                catch { }
143
144
                if (exists)
145
                    return new TypeGuidValueProvider(typeGuid);
146
            }
147
148
            if (result == null && optional)
149
            {
150
                return new NullValueProvider();
151
            }
152
            else if (result == null)
153
            {
154
                var exception = new NoInstanceForInjectionException(member);
155
                _testbed.RaiseDependencyError(exception, itfType, typeGuid);
156
                return new ExceptionValueProvider(exception);
157
            }
158
            else
159
            {
160
                return result;
161
            }
162
        }
163
164
        public IEnumerable<IValueProvider> ResolveMultiple(Type itfType, bool optional, MemberInfo member)
165
        {
166
            IValueProvider[] results;
167
            _mockFactoriesByItfType.TryGetValue(itfType, out results);
168
169
            if (results == null)
170
            {
171
                // We did not find an implementation among the mocks.
172
                // Try the additional plug-ins, if any. This discovery is similar to the original
173
                // component model implementation. In the case of any doubts, look there.
174
175
                var typeGuids = ComponentManager.Singleton.PlugInCache.GetTypesFast(itfType.FullName, null);
176
                if (Enumerable.Any(typeGuids))
177
                    results = typeGuids.Select(typeGuid => new TypeGuidValueProvider(typeGuid)).ToArray();
178
            }
179
180
            if (results == null && optional)
181
            {
182
                return new IValueProvider[0];
183
            }
184
            else if (results == null)
185
            {
186
                var exception = new NoInstanceForInjectionException(member);
187
                _testbed.RaiseDependencyError(exception, itfType, null);
188
                return new ExceptionValueProvider(exception);
189
            }
190
            else
191
            {
192
                return results;
193
            }
194
        }
195
196
        public void ResolveProfile(MemberInfo member, out string profileName, out Profile profile)
197
        {
198
            profileName = _profileName;
199
            profile = _profile;
200
        }
201
202
        public IWinFormWrapper ResolveFrameForm(MemberInfo member)
203
        {
204
            if (_frameForm == null)
205
                _frameForm = ResolveSingle(typeof(IWinFormWrapper), true, member).CreateInstance<IWinFormWrapper>();
206
207
            return _frameForm;
208
        }
209
210
        private Testbed _testbed;
211
        private IDictionary<Guid, IValueProvider> _mockFactoriesByTypeGuid;
212
        private IDictionary<Type, IValueProvider[]> _mockFactoriesByItfType;
213
        private string _profileName;
214
        private Profile _profile;
215
        private IWinFormWrapper _frameForm;
216
        private TypeInformation[] _systemTypeInfos;
217
    }
218
219
    interface IValueProvider
220
    {
221
        Guid TypeGuid { get; }
222
        Type Type { get; }
223
        TypeInformation TypeInformation { get; }
224
        T CreateInstance<T>() where T : class;
225
    }
226
227
    class MockValueProvider : IValueProvider
228
    {
229
        public MockValueProvider(Guid typeGuid, object prototype, MockConstructor mockConstructor)
230
        {
231
            if (mockConstructor == null)
232
                throw new ArgumentNullException(nameof(mockConstructor));
233
234
            TypeGuid = typeGuid;
235
            Type = prototype.GetType();
236
            _mockConstructor = mockConstructor;
237
238
            // As the TypeInformation type does not have any suitable public constructors for us,
239
            // we must (partially) construct the instance using reflection and fake XML,
240
            // unfortunately.
241
242
            XmlDocument plugInInfoXmlDocument = new XmlDocument();
243
            plugInInfoXmlDocument.AppendChild(plugInInfoXmlDocument.CreateElement("ROOT"));
244
            plugInInfoXmlDocument.DocumentElement.SetAttribute("AssemblyName", Assembly.GetExecutingAssembly().FullName);
245
            plugInInfoXmlDocument.DocumentElement.SetAttribute("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
246
            plugInInfoXmlDocument.DocumentElement.SetAttribute("GUID", XmlConvert.ToString(Guid.NewGuid()));
247
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Version", "1.0.0.0");
248
            plugInInfoXmlDocument.DocumentElement.SetAttribute("System", XmlConvert.ToString(false));
249
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Company", "The Unit Test Company");
250
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Copyright", "Copyright © 2016 by The Unit Test Company. All rights reserved.");
251
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Description", "Generated mock plug-in for the Unit Test Framework.");
252
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Product", "CODESYS Automation Platform Unit Test Framework");
253
            plugInInfoXmlDocument.DocumentElement.SetAttribute("Title", "CODESYS Automation Platform Unit Test Framework");
254
            XmlElement typeElement = plugInInfoXmlDocument.CreateElement("Type");
255
            plugInInfoXmlDocument.DocumentElement.AppendChild(typeElement);
256
            typeElement.SetAttribute("GUID", XmlConvert.ToString(TypeGuid));
257
            typeElement.SetAttribute("Name", Type.FullName);
258
            typeElement.SetAttribute("ItfTypes", string.Join(";", prototype.GetType().GetInterfaces().Select(itf => itf.FullName)));
259
260
            var plugInInfoCtor = typeof(PlugInInformation).GetConstructor(
261
                BindingFlags.Instance | BindingFlags.NonPublic,
262
                null,
263
                new[] { typeof(XmlElement) },
264
                null);
265
            var plugInInfo = (PlugInInformation)plugInInfoCtor.Invoke(new object[] { plugInInfoXmlDocument.DocumentElement });
266
267
            TypeInformation = plugInInfo.TypeInfosFast.First(); // We added exactly one type above, so we should able to get it back now.
268
        }
269
270
        public Guid TypeGuid { get; private set; }
271
        public Type Type { get; private set; }
272
        public TypeInformation TypeInformation { get; private set; }
273
274
        public T CreateInstance<T>() where T : class
275
        {
276
            if (_mockConstructor.SystemInstance)
277
            {
278
                if (_systemInstance == null)
279
                    _systemInstance = _mockConstructor.CreateFunc();
280
                return (T)_systemInstance;
281
            }
282
            else
283
            {
284
                return (T)_mockConstructor.CreateFunc();
285
            }
286
        }
287
288
        private MockConstructor _mockConstructor;
289
        private object _systemInstance;
290
    }
291
292
    class NullValueProvider : IValueProvider
293
    {
294
        public Guid TypeGuid
295
        {
296
            get { return Guid.Empty; }
297
        }
298
299
        public Type Type
300
        {
301
            get { return null; }
302
        }
303
304
        public TypeInformation TypeInformation
305
        {
306
            get { return null; }
307
        }
308
309
        public T CreateInstance<T>() where T : class
310
        {
311
            return null;
312
        }
313
    }
314
315
    class SystemInstanceValueProvider : IValueProvider
316
    {
317
        public SystemInstanceValueProvider(Guid typeGuid)
318
        {
319
            TypeGuid = typeGuid;
320
        }
321
322
        public Type Type
323
        {
324
            get { return ComponentManager.Singleton.TryGetPlugInType(TypeGuid, true); }
325
        }
326
327
        public Guid TypeGuid { get; private set; }
328
329
        public TypeInformation TypeInformation
330
        {
331
            get { return ComponentManager.Singleton.PlugInCache.GetTypeInformation(TypeGuid, null); }
332
        }
333
334
        public T CreateInstance<T>() where T : class
335
        {
336
            return ComponentManager.Singleton.TryGetSystemInstance<T>();
337
        }
338
    }
339
340
    class MessageServiceValueProvider : IValueProvider
341
    {
342
        public Type Type
343
        {
344
            get { return SystemInstances.MessageService.GetType(); }
345
        }
346
347
        public Guid TypeGuid
348
        {
349
            get
350
            {
351
                if (s_typeGuid == null)
352
                {
353
                    var attr = TypeGuidAttribute.FromObject(SystemInstances.MessageService);
354
                    s_typeGuid = attr != null ? attr.Guid : Guid.Empty;
355
                }
356
                return s_typeGuid.Value;
357
            }
358
        }
359
360
        private static Guid? s_typeGuid;
361
362
        public TypeInformation TypeInformation
363
        {
364
            get { return ComponentManager.Singleton.PlugInCache.GetTypeInformation(TypeGuid, null); }
365
        }
366
367
        public T CreateInstance<T>() where T : class
368
        {
369
            return (T)SystemInstances.MessageService;
370
        }
371
    }
372
373
    class TypeGuidValueProvider : IValueProvider
374
    {
375
        public TypeGuidValueProvider(Guid typeGuid)
376
        {
377
            TypeGuid = typeGuid;
378
        }
379
380
        public Type Type
381
        {
382
            get { return ComponentManager.Singleton.TryGetPlugInType(TypeGuid, true); }
383
        }
384
385
        public Guid TypeGuid { get; private set; }
386
387
        public TypeInformation TypeInformation
388
        {
389
            get { return ComponentManager.Singleton.PlugInCache.GetTypeInformation(TypeGuid, null); }
390
        }
391
392
        public T CreateInstance<T>() where T : class
393
        {
394
            return ComponentManager.Singleton.TryCreateInstance<T>(TypeGuid);
395
        }
396
    }
397
398
    class ExceptionValueProvider : IValueProvider, IEnumerable<IValueProvider>
399
    {
400
        public ExceptionValueProvider(Exception exception)
401
        {
402
            _exception = exception;
403
        }
404
405
        public Type Type
406
        {
407
            get { throw _exception; }
408
        }
409
410
        public Guid TypeGuid
411
        {
412
            get { throw _exception; }
413
        }
414
415
        public TypeInformation TypeInformation
416
        {
417
            get { throw _exception; }
418
        }
419
420
        public T CreateInstance<T>() where T : class
421
        {
422
            throw _exception;
423
        }
424
425
        public IEnumerator<IValueProvider> GetEnumerator()
426
        {
427
            throw _exception;
428
        }
429
430
        IEnumerator IEnumerable.GetEnumerator()
431
        {
432
            throw _exception;
433
        }
434
435
        private Exception _exception;
436
    }
437
}