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

/mcs/class/System.ComponentModel.Composition/Tests/ComponentModelUnitTest/System/ComponentModel/Composition/ComposablePartExtensibilityTests.cs

https://bitbucket.org/danipen/mono
C# | 292 lines | 225 code | 54 blank | 13 comment | 3 complexity | cebb7156a839ffbe66359fd783cf77a0 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition;
  7. using System.Linq;
  8. using System.Reflection;
  9. using Microsoft.VisualStudio.TestTools.UnitTesting;
  10. using System.ComponentModel.Composition.Factories;
  11. using System.ComponentModel.Composition.Hosting;
  12. using System.ComponentModel.Composition.Primitives;
  13. using System.ComponentModel.Composition.UnitTesting;
  14. using System.UnitTesting;
  15. namespace System.ComponentModel.Composition
  16. {
  17. [TestClass]
  18. public class ComposablePartExtensibilityTests
  19. {
  20. [TestMethod]
  21. public void PhaseTest()
  22. {
  23. CompositionContainer container = ContainerFactory.Create();
  24. CompositionBatch batch = new CompositionBatch();
  25. var part = new OrderingTestComposablePart();
  26. part.AddImport("Import1", ImportCardinality.ExactlyOne, true, false);
  27. part.AddExport("Export1", 1);
  28. part.CallOrder.Enqueue("Import:Import1");
  29. part.CallOrder.Enqueue("OnComposed");
  30. batch.AddExportedValue("Import1", 20);
  31. batch.AddPart(part);
  32. container.Compose(batch);
  33. // Export shouldn't be called until it is pulled on by someone.
  34. var export = container.GetExport<object>("Export1");
  35. part.CallOrder.Enqueue("Export:Export1");
  36. Assert.AreEqual(1, export.Value);
  37. Assert.IsTrue(part.CallOrder.Count == 0);
  38. }
  39. [TestMethod]
  40. public void ImportTest()
  41. {
  42. var exporter = new TestExportBinder();
  43. var importer = new TestImportBinder();
  44. CompositionContainer container = ContainerFactory.Create();
  45. CompositionBatch batch = new CompositionBatch();
  46. batch.AddPart(importer);
  47. batch.AddPart(exporter);
  48. container.Compose(batch);
  49. ExportsAssert.AreEqual(importer.SetImports["single"], 42);
  50. ExportsAssert.AreEqual(importer.SetImports["multi"], 1, 2, 3);
  51. }
  52. [TestMethod]
  53. public void ConstructorInjectionSimpleCase()
  54. {
  55. var container = ContainerFactory.Create();
  56. CompositionBatch batch = new CompositionBatch();
  57. batch.AddPart(new ConstructorInjectionComposablePart(typeof(Foo)));
  58. batch.AddExportedValue<IBar>(new Bar("Bar Value"));
  59. container.Compose(batch);
  60. var import = container.GetExport<Foo>();
  61. var foo = import.Value;
  62. Assert.AreEqual("Bar Value", foo.Bar.Value);
  63. }
  64. [TestMethod]
  65. public void ConstructorInjectionCycle()
  66. {
  67. var container = ContainerFactory.Create();
  68. CompositionBatch batch = new CompositionBatch();
  69. batch.AddPart(new ConstructorInjectionComposablePart(typeof(AClass)));
  70. batch.AddPart(new ConstructorInjectionComposablePart(typeof(BClass)));
  71. CompositionAssert.ThrowsErrors(ErrorId.ImportEngine_PartCannotSetImport,
  72. ErrorId.ImportEngine_PartCannotSetImport, RetryMode.DoNotRetry, () =>
  73. {
  74. container.Compose(batch);
  75. });
  76. }
  77. }
  78. internal class OrderingTestComposablePart : ConcreteComposablePart
  79. {
  80. public Queue<string> CallOrder = new Queue<string>();
  81. public OrderingTestComposablePart()
  82. {
  83. }
  84. public new void AddExport(string contractName, object value)
  85. {
  86. var export = ExportFactory.Create(contractName, () =>
  87. {
  88. this.OnGetExport(contractName); return value;
  89. });
  90. base.AddExport(export);
  91. }
  92. private void OnGetExport(string contractName)
  93. {
  94. Assert.AreEqual("Export:" + contractName, CallOrder.Dequeue());
  95. }
  96. public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
  97. {
  98. ContractBasedImportDefinition contractBasedImportDefinition = (ContractBasedImportDefinition)definition;
  99. Assert.AreEqual("Import:" + contractBasedImportDefinition.ContractName, CallOrder.Dequeue());
  100. base.SetImport(definition, exports);
  101. }
  102. public override void Activate()
  103. {
  104. Assert.AreEqual("OnComposed", CallOrder.Dequeue());
  105. base.Activate();
  106. }
  107. }
  108. internal class TestExportBinder : ConcreteComposablePart
  109. {
  110. public TestExportBinder()
  111. {
  112. AddExport("single", 42);
  113. AddExport("multi", 1);
  114. AddExport("multi", 2);
  115. AddExport("multi", 3);
  116. }
  117. }
  118. internal class TestImportBinder : ConcreteComposablePart
  119. {
  120. public TestImportBinder()
  121. {
  122. AddImport("single", ImportCardinality.ExactlyOne, true, false);
  123. AddImport("multi", ImportCardinality.ZeroOrMore, true, false);
  124. }
  125. }
  126. public class Foo
  127. {
  128. public Foo(IBar bar)
  129. {
  130. Bar = bar;
  131. }
  132. public IBar Bar { get; private set; }
  133. }
  134. public interface IBar
  135. {
  136. string Value { get; }
  137. }
  138. public class Bar : IBar
  139. {
  140. public Bar(string value)
  141. {
  142. Value = value;
  143. }
  144. public string Value { get; private set; }
  145. }
  146. public class FooBar
  147. {
  148. [Import("Foo")]
  149. public Foo Foo { get; set; }
  150. }
  151. public class AClass
  152. {
  153. public AClass(BClass b)
  154. {
  155. }
  156. public BClass B { get; private set; }
  157. }
  158. public class BClass
  159. {
  160. public BClass(AClass a)
  161. {
  162. this.A = a;
  163. }
  164. public AClass A { get; private set; }
  165. }
  166. internal class ConstructorInjectionComposablePart : ConcreteComposablePart
  167. {
  168. private Type _type;
  169. private ConstructorInfo _constructor;
  170. private Dictionary<ImportDefinition, object> _imports;
  171. private bool currentlyExecuting = false;
  172. public ConstructorInjectionComposablePart(Type type)
  173. {
  174. this._type = type;
  175. // Note that this just blindly takes the first constructor...
  176. this._constructor = this._type.GetConstructors().FirstOrDefault();
  177. Assert.IsNotNull(this._constructor);
  178. foreach (var param in this._constructor.GetParameters())
  179. {
  180. string name = AttributedModelServices.GetContractName(param.ParameterType);
  181. AddImport(name, ImportCardinality.ExactlyOne, true, true);
  182. }
  183. string contractName = AttributedModelServices.GetContractName(type);
  184. string typeIdentity = AttributedModelServices.GetTypeIdentity(type);
  185. var metadata = new Dictionary<string, object>();
  186. metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName, typeIdentity);
  187. Export composableExport = ExportFactory.Create(
  188. contractName,
  189. metadata,
  190. GetInstance);
  191. this.AddExport(composableExport);
  192. this._imports = new Dictionary<ImportDefinition, object>();
  193. }
  194. private object GetInstance()
  195. {
  196. var result = CompositionResult.SucceededResult;
  197. // We only need this guard if we are pulling on the lazy exports during this call
  198. // but if we do the pulling in SetImport it isn't needed.
  199. //if (currentlyExecuting)
  200. //{
  201. // var issue = CompositionError.Create("CM:CreationCycleDetected",
  202. // "This failed because there is a creation cycle");
  203. // return result.MergeIssue(issue).ToResult<object>(null);
  204. //}
  205. try
  206. {
  207. currentlyExecuting = true;
  208. List<object> constructorArgs = new List<object>();
  209. foreach (ImportDefinition import in this.ImportDefinitions
  210. .Where(i => i.IsPrerequisite))
  211. {
  212. object importValue;
  213. if (!this._imports.TryGetValue(import, out importValue))
  214. {
  215. result = result.MergeError(CompositionError.Create(CompositionErrorId.ImportNotSetOnPart,
  216. "The import '{0}' is required for construction of '{1}'", import.ToString(), _type.FullName));
  217. continue;
  218. }
  219. constructorArgs.Add(importValue);
  220. }
  221. if (!result.Succeeded)
  222. {
  223. throw new CompositionException(result.Errors);
  224. }
  225. object obj = this._constructor.Invoke(constructorArgs.ToArray());
  226. return obj;
  227. }
  228. finally
  229. {
  230. currentlyExecuting = false;
  231. }
  232. }
  233. public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
  234. {
  235. _imports[definition] = exports.First().Value;
  236. }
  237. }
  238. }