PageRenderTime 44ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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