PageRenderTime 55ms CodeModel.GetById 25ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 1ms

/src/UnitTests/Proxy/ProxyFactoryTests.cs

http://github.com/philiplaureano/LinFu
C# | 458 lines | 328 code | 96 blank | 34 comment | 11 complexity | 7e087de00c505b6f5cad9138bd74459d MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.IO;
  4using System.Linq;
  5using LinFu.AOP.Cecil;
  6using LinFu.AOP.Cecil.Extensions;
  7using LinFu.AOP.Cecil.Interfaces;
  8using LinFu.AOP.Interfaces;
  9using LinFu.IoC;
 10using LinFu.IoC.Configuration;
 11using LinFu.Proxy;
 12using LinFu.Proxy.Interfaces;
 13using LinFu.UnitTests.Tools;
 14using Xunit;
 15using SampleLibrary;
 16using SampleLibrary.Proxy;
 17
 18namespace LinFu.UnitTests.Proxy
 19{
 20    public class ProxyFactoryTests : BaseTestFixture
 21    {
 22        private ServiceContainer container;
 23        private Loader loader;
 24        private string filename = string.Empty;
 25
 26        protected override void Init()
 27        {
 28            loader = new Loader();
 29            container = new ServiceContainer();
 30
 31            container.LoadFrom(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
 32
 33            LoadAssemblyUsing(typeof(ProxyFactory));
 34            LoadAssemblyUsing(typeof(InvocationInfoEmitter));
 35
 36            filename = string.Format("{0}.dll", Guid.NewGuid());
 37
 38            // Add the PEVerifier to the proxy generation process
 39            container.AddService<IVerifier>(new PeVerifier(filename));
 40        }
 41
 42        protected override void Term()
 43        {
 44            loader = null;
 45            container = null;
 46
 47            try
 48            {
 49                File.Delete(filename);
 50            }
 51            catch
 52            {
 53                // Do nothing
 54            }
 55        }
 56
 57        private void LoadAssemblyUsing(Type embeddedType)
 58        {
 59            var location = embeddedType.Assembly.Location;
 60            var directory = Path.GetDirectoryName(location);
 61            var assemblyFilename = Path.GetFileName(location);
 62
 63            container.LoadFrom(directory, assemblyFilename);
 64        }
 65
 66        private T CreateProxy<T>(Func<IInvocationInfo, object> implementation)
 67        {
 68            var factory = container.GetService<IProxyFactory>();
 69
 70            var interceptor = new MockInterceptor(implementation);
 71            return factory.CreateProxy<T>(interceptor);
 72        }
 73
 74        [Fact]
 75        public void ShouldAllowProxyToInheritFromMultipleInstancesOfTheSameGenericInterfaceType()
 76        {
 77            IInterceptor interceptor = new MockInterceptor(body => null);
 78
 79            var interfaces = new[] {typeof(IList<int>), typeof(IList<double>), typeof(IList<object>)};
 80            var factory = container.GetService<IProxyFactory>();
 81            var proxy = factory.CreateProxy<object>(interceptor, interfaces);
 82
 83            var proxyType = proxy.GetType();
 84
 85            // The proxy must implement all of the given interfaces
 86            foreach (var currentType in interfaces) Assert.True(currentType.IsAssignableFrom(proxyType));
 87        }
 88
 89        [Fact]
 90        public void ShouldCacheProxyTypes()
 91        {
 92            var factory = new ProxyFactory();
 93            var baseType = typeof(ISampleService);
 94
 95            var proxyType = factory.CreateProxyType(baseType, new Type[0]);
 96            var runCount = 10;
 97
 98            // All subsequent results must return the same proxy type
 99            for (var i = 0; i < runCount; i++)
100            {
101                var currentType = factory.CreateProxyType(baseType, new Type[0]);
102                Assert.Equal(proxyType, currentType);
103                Assert.Same(proxyType, currentType);
104            }
105        }
106
107        [Fact]
108        public void ShouldCallInterceptorInstance()
109        {
110            var factory = container.GetService<IProxyFactory>();
111            var mockInterceptor = new MockInterceptor(i => null);
112
113            // Create the proxy instance and then make the call
114            var proxyInstance = (ITest) factory.CreateProxy(typeof(object), mockInterceptor, typeof(ITest));
115            proxyInstance.Execute();
116
117            // The interceptor must be called
118            Assert.True(mockInterceptor.Called);
119        }
120
121        [Fact]
122        public void ShouldCreateProxyWithVirtualSetterInitializedInCtor()
123        {
124            var factory = container.GetService<IProxyFactory>();
125
126            // Assign the ref/out value for the int argument
127            Func<IInvocationInfo, object> implementation = info =>
128            {
129                var methodName = info.TargetMethod.Name;
130
131                if (methodName == "DoSomething")
132                    info.Arguments[0] = 54321;
133
134                if (methodName == "get_SomeProp")
135                    return "blah";
136
137                return null;
138            };
139
140            var interceptor = new MockInterceptor(implementation);
141            var proxy = factory.CreateProxy<SampleClassWithPropertyInitializedInCtor>(interceptor);
142
143            int value;
144            proxy.DoSomething(out value);
145
146            // The two given arguments should match
147            Assert.Equal("blah", proxy.SomeProp);
148            Assert.Equal(54321, value);
149        }
150
151        [Fact]
152        public void ShouldHaveDefaultConstructor()
153        {
154            var factory = container.GetService<IProxyFactory>();
155            var proxyType = factory.CreateProxyType(typeof(object), new Type[0]);
156            Assert.NotNull(proxyType);
157
158            var constructor = proxyType.GetConstructor(new Type[0]);
159            Assert.True(constructor != null);
160
161            var instance = constructor.Invoke(new object[0]);
162            Assert.NotNull(instance);
163        }
164
165        [Fact]
166        public void ShouldHaveDefaultProxyFactoryInstance()
167        {
168            var factory = container.GetService<IProxyFactory>();
169            Assert.NotNull(factory);
170            Assert.True(factory.GetType() == typeof(ProxyFactory));
171        }
172
173        [Fact]
174        public void ShouldHaveSerializableAttribute()
175        {
176            var factory = new ProxyFactory();
177            var proxyType = factory.CreateProxyType(typeof(ISampleService), new Type[0]);
178
179            var customAttributes = proxyType.GetCustomAttributes(typeof(SerializableAttribute), false);
180            Assert.True(customAttributes != null && customAttributes.Count() > 0);
181        }
182
183        [Fact]
184        public void ShouldImplementGivenInterfaces()
185        {
186            var interfaces = new[] {typeof(ISampleService), typeof(ISampleGenericService<int>)};
187
188            // Note: The interceptor will never be executed
189            var interceptor = new MockInterceptor(info => { throw new NotImplementedException(); });
190            var factory = container.GetService<IProxyFactory>();
191
192            var proxy = factory.CreateProxy(typeof(object), interceptor, interfaces.ToArray());
193            var proxyType = proxy.GetType();
194
195            // Make sure that the generated proxy implements
196            // all of the given interfaces
197            foreach (var currentType in interfaces) Assert.True(currentType.IsAssignableFrom(proxyType));
198        }
199
200        [Fact]
201        public void ShouldImplementIProxy()
202        {
203            var factory = container.GetService<IProxyFactory>();
204            var proxyType = factory.CreateProxyType(typeof(object), new[] {typeof(ISampleService)});
205
206            var instance = Activator.CreateInstance(proxyType);
207            Assert.True(instance is IProxy);
208            Assert.True(instance is ISampleService);
209        }
210
211        [Fact]
212        public void ShouldReportTypeArgumentsUsedInGenericMethodCall()
213        {
214            var genericParameterType = typeof(int);
215            var proxy = CreateProxy<ClassWithGenericMethod>(info =>
216            {
217                // The generic parameter type must match the given parameter type
218                Assert.Contains(genericParameterType, info.TypeArguments);
219                return null;
220            });
221
222            proxy.DoSomething<int>();
223        }
224
225        [Fact]
226        public void ShouldSupportMethodCallsWithGenericParametersFromGenericMethodTypeArguments()
227        {
228            var genericParameterType = typeof(int);
229            var proxy = CreateProxy<ClassWithParametersFromGenericMethodTypeArguments>(info =>
230            {
231                // Match the type argument
232                Assert.Contains(genericParameterType, info.TypeArguments);
233                Assert.Equal(1, info.Arguments[0]);
234                Assert.Equal(1, info.Arguments[1]);
235
236                return null;
237            });
238
239            proxy.DoSomething(1, 1);
240        }
241
242        [Fact]
243        public void ShouldSupportMethodCallsWithGenericParametersFromHostGenericTypeArguments()
244        {
245            var proxy = CreateProxy<ClassWithParametersFromHostGenericTypeArguments<double, string>>(info =>
246            {
247                // Match the type arguments
248                Assert.Equal(typeof(double), info.ParameterTypes[0]);
249                Assert.Equal(typeof(string), info.ParameterTypes[1]);
250
251                // Match the argument values
252                Assert.Equal(1.0, info.Arguments[0]);
253                Assert.Equal("Test", info.Arguments[1]);
254
255                return null;
256            });
257
258            proxy.DoSomething(1.0, "Test");
259        }
260
261        [Fact]
262        public void ShouldSupportMethodCallsWithGenericReturnValuesFromGenericMethodTypeArguments()
263        {
264            var dummyList = new List<int>();
265
266            // The dummy list will be altered if the method body is called
267            Func<IInvocationInfo, object> methodBody = info =>
268            {
269                var typeArguments = info.TypeArguments;
270
271                // Match the type arguments
272                Assert.Equal(typeof(int), typeArguments[0]);
273                dummyList.Add(12345);
274                return 12345;
275            };
276
277            var proxy = CreateProxy<ClassWithMethodReturnTypeFromGenericTypeArguments>(methodBody);
278            proxy.DoSomething<int>();
279
280            Assert.True(dummyList.Count > 0);
281        }
282
283        [Fact]
284        public void ShouldSupportMethodCallsWithGenericReturnValuesFromHostGenericTypeArguments()
285        {
286            var proxy = CreateProxy<ClassWithMethodReturnValueFromTypeArgument<int>>(
287                info =>
288                {
289                    // Make sure that the method return type 
290                    // matches the given return type
291                    Assert.True(info.ReturnType == typeof(int));
292                    return 54321;
293                });
294
295            var result = proxy.DoSomething();
296
297            Assert.Equal(54321, result);
298        }
299
300        [Fact]
301        public void ShouldSupportMethodCallsWithOpenGenericParameters()
302        {
303            var dummyList = new List<int>();
304
305            // The dummy list will be altered if the method body is called
306            Func<IInvocationInfo, object> methodBody = info =>
307            {
308                var typeArguments = info.TypeArguments;
309
310                // Match the type arguments
311                Assert.Equal(typeof(int), typeArguments[0]);
312
313                dummyList.Add(12345);
314
315                return dummyList;
316            };
317
318            var proxy = CreateProxy<ClassWithOpenGenericParameters>(methodBody);
319            proxy.DoSomething(dummyList);
320            Assert.True(dummyList.Count > 0);
321        }
322
323        [Fact]
324        public void ShouldSupportMethodCallWithNestedOpenGenericParameters()
325        {
326            var dummyList = new Dictionary<int, List<string>>();
327
328            // The dummy list will be altered if the method body is called
329            Func<IInvocationInfo, object> methodBody = info =>
330            {
331                var typeArguments = info.TypeArguments;
332
333                // Match the type arguments
334
335                //Assert.Equal(typeArguments[0], typeof(int));
336
337                dummyList.Add(1, new List<string> {"SomeValue"});
338
339                return dummyList[1];
340            };
341
342            var proxy = CreateProxy<ClassWithNestedOpenGenericParameters>(methodBody);
343            proxy.DoSomething(dummyList);
344            Assert.True(dummyList.Count > 0);
345        }
346
347        [Fact]
348        public void ShouldSupportMethodsCallsWithGenericTypeDefinitionReturnType()
349        {
350            var dummyList = new List<int>();
351
352            // The dummy list will be altered if the method body is called
353            Func<IInvocationInfo, object> methodBody = info =>
354            {
355                var typeArguments = info.TypeArguments;
356
357                // Match the type arguments
358
359                Assert.Equal(typeof(int), typeArguments[0]);
360                dummyList.Add(12345);
361                return dummyList;
362            };
363
364            var proxy = CreateProxy<ClassWithGenericTypeDefinitionReturnType>(methodBody);
365            proxy.DoSomething<int>();
366            Assert.True(dummyList.Count > 0);
367        }
368
369        [Fact]
370        public void ShouldSupportOutArguments()
371        {
372            var factory = container.GetService<IProxyFactory>();
373
374            // Assign the ref/out value for the int argument
375            Func<IInvocationInfo, object> implementation = info =>
376            {
377                info.Arguments[0] = 54321;
378                return null;
379            };
380
381            var interceptor = new MockInterceptor(implementation);
382            var proxy = factory.CreateProxy<ClassWithVirtualMethodWithOutParameter>(interceptor);
383
384            int value;
385            proxy.DoSomething(out value);
386
387            // The two given arguments should match
388            Assert.Equal(54321, value);
389        }
390
391        [Fact]
392        public void ShouldSupportRefArguments()
393        {
394            var factory = container.GetService<IProxyFactory>();
395
396            // Assign the ref/out value for the int argument
397            Func<IInvocationInfo, object> implementation = info =>
398            {
399                info.Arguments[0] = 54321;
400                return null;
401            };
402
403            var interceptor = new MockInterceptor(implementation);
404            var proxy = factory.CreateProxy<ClassWithVirtualByRefMethod>(interceptor);
405
406            var value = 0;
407            proxy.ByRefMethod(ref value);
408
409            // The two given arguments should match
410            Assert.Equal(54321, value);
411        }
412
413
414        [Fact]
415        public void ShouldSupportSerialization()
416        {
417            var dummyList = new List<int>();
418
419            // The dummy list will be altered if the method body is called
420            Func<IInvocationInfo, object> methodBody = info =>
421            {
422                var typeArguments = info.TypeArguments;
423
424                // Match the type arguments
425                Assert.Equal(typeof(int), typeArguments[0]);
426                dummyList.Add(12345);
427                return dummyList;
428            };
429
430            var proxy = CreateProxy<ClassWithGenericTypeDefinitionReturnType>(methodBody);
431            proxy.DoSomething<int>();
432            Assert.True(dummyList.Count > 0);
433        }
434
435        [Fact]
436        public void ShouldSupportSubclassingFromGenericTypes()
437        {
438            var factory = container.GetService<IProxyFactory>();
439            var actualList = new List<int>();
440
441            Func<IInvocationInfo, object> implementation = info =>
442            {
443                IList<int> list = actualList;
444                return info.Proceed(list);
445            };
446            var interceptor = new MockInterceptor(implementation);
447            var proxy = factory.CreateProxy<IList<int>>(interceptor);
448
449            // Any item added to the proxy list should be added to the 
450            // actual list
451            proxy.Add(12345);
452
453            Assert.True(interceptor.Called);
454            Assert.True(actualList.Count > 0);
455            Assert.True(actualList[0] == 12345);
456        }
457    }
458}