ExportProviderEventTests.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition.Hosting;
  7. using System.ComponentModel.Composition.Primitives;
  8. using System.Linq;
  9. using System.UnitTesting;
  10. using Microsoft.VisualStudio.TestTools.UnitTesting;
  11. using System.ComponentModel.Composition.Factories;
  12. namespace System.ComponentModel.Composition
  13. {
  14. [TestClass]
  15. public class ExportProviderEventTests
  16. {
  17. [TestMethod]
  18. public void BatchAdd_ShouldFireEvents()
  19. {
  20. var container = ContainerFactory.Create();
  21. var eventListener = new ExportProviderListener(container, container);
  22. var batch = new CompositionBatch();
  23. batch.AddExportedValue<object>("MyExport", new object());
  24. eventListener.VerifyCompose(batch);
  25. }
  26. [TestMethod]
  27. public void BatchRemove_ShouldFireEvents()
  28. {
  29. var container = ContainerFactory.Create();
  30. var batch = new CompositionBatch();
  31. var exportPart = batch.AddExportedValue<object>("MyExport", new object());
  32. container.Compose(batch);
  33. var eventListener = new ExportProviderListener(container, container);
  34. batch = new CompositionBatch();
  35. batch.RemovePart(exportPart);
  36. eventListener.VerifyCompose(batch);
  37. }
  38. [TestMethod]
  39. public void BatchAddRemove_ShouldFireEvents()
  40. {
  41. var container = ContainerFactory.Create();
  42. var batch = new CompositionBatch();
  43. var exportPart = batch.AddExportedValue<object>("MyExport", new object());
  44. container.Compose(batch);
  45. var eventListener = new ExportProviderListener(container, container);
  46. batch = new CompositionBatch();
  47. batch.RemovePart(exportPart);
  48. batch.AddExportedValue<object>("MyExport2", new object());
  49. eventListener.VerifyCompose(batch);
  50. }
  51. [TestMethod]
  52. public void BatchMultipleAdds_ShouldFireEvents()
  53. {
  54. var container = ContainerFactory.Create();
  55. var eventListener = new ExportProviderListener(container, container);
  56. var batch = new CompositionBatch();
  57. batch.AddExportedValue<object>("MyExport", new object());
  58. batch.AddExportedValue<object>("MyExport2", new object());
  59. batch.AddExportedValue<object>("MyExport3", new object());
  60. eventListener.VerifyCompose(batch);
  61. }
  62. [TestMethod]
  63. public void BatchNestedContainerAdds_ShouldFireEvents()
  64. {
  65. var parentContainer = ContainerFactory.Create();
  66. var container = ContainerFactory.Create(parentContainer);
  67. var eventListener = new ExportProviderListener(parentContainer, container);
  68. var batch = new CompositionBatch();
  69. batch.AddExportedValue<object>("MyExport", new object());
  70. eventListener.VerifyCompose(batch);
  71. }
  72. [Export]
  73. public class SampleCatalogExport { }
  74. [TestMethod]
  75. public void CatalogAdd_ShouldFireEvents()
  76. {
  77. var catalog = new TypeCatalog(typeof(SampleCatalogExport));
  78. var aggCat = new AggregateCatalog();
  79. var container = ContainerFactory.Create(aggCat);
  80. var eventListener = new ExportProviderListener(container, container);
  81. eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));
  82. }
  83. [TestMethod]
  84. public void CatalogRemove_ShouldFireEvents()
  85. {
  86. var catalog = new TypeCatalog(typeof(SampleCatalogExport));
  87. var aggCat = new AggregateCatalog();
  88. var container = ContainerFactory.Create(aggCat);
  89. aggCat.Catalogs.Add(catalog);
  90. var eventListener = new ExportProviderListener(container, container);
  91. eventListener.VerifyCatalogRemove(() => aggCat.Catalogs.Remove(catalog), typeof(SampleCatalogExport));
  92. }
  93. [Export]
  94. public class SampleCatalogExport2 { }
  95. [TestMethod]
  96. [Ignore]
  97. [WorkItem(812029)]
  98. public void CatalogMultipleAdds_ShouldFireEvents()
  99. {
  100. var catalog = new TypeCatalog(typeof(SampleCatalogExport));
  101. var aggCat = new AggregateCatalog();
  102. var container = ContainerFactory.Create(aggCat);
  103. var eventListener = new ExportProviderListener(container, container);
  104. var otherAggCat = new AggregateCatalog(new TypeCatalog(typeof(SampleCatalogExport)), new TypeCatalog(typeof(SampleCatalogExport2)));
  105. eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(otherAggCat), typeof(SampleCatalogExport), typeof(SampleCatalogExport2));
  106. }
  107. [TestMethod]
  108. public void CatalogNestedContainerAdds_ShouldFireEvents()
  109. {
  110. var catalog = new TypeCatalog(typeof(SampleCatalogExport));
  111. var aggCat = new AggregateCatalog();
  112. var parentContainer = ContainerFactory.Create(aggCat);
  113. var container = ContainerFactory.Create(parentContainer);
  114. var eventListener = new ExportProviderListener(parentContainer, container);
  115. eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));
  116. }
  117. public class ExportProviderListener
  118. {
  119. private CompositionContainer _container;
  120. private ExportProvider _watchedProvider;
  121. private string[] _expectedAdds;
  122. private string[] _expectedRemoves;
  123. private int _changedEventCount;
  124. private int _changingEventCount;
  125. public ExportProviderListener(CompositionContainer container, ExportProvider watchExportProvider)
  126. {
  127. watchExportProvider.ExportsChanged += OnExportsChanged;
  128. watchExportProvider.ExportsChanging += OnExportsChanging;
  129. this._watchedProvider = watchExportProvider;
  130. this._container = container;
  131. }
  132. public void VerifyCompose(CompositionBatch batch)
  133. {
  134. this._expectedAdds = GetContractNames(batch.PartsToAdd);
  135. this._expectedRemoves = GetContractNames(batch.PartsToRemove);
  136. this._container.Compose(batch);
  137. Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
  138. Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
  139. ResetState();
  140. }
  141. public void VerifyCatalogAdd(Action doAdd, params Type[] expectedTypesAdded)
  142. {
  143. this._expectedAdds = GetContractNames(expectedTypesAdded);
  144. doAdd();
  145. Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
  146. Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
  147. ResetState();
  148. }
  149. public void VerifyCatalogRemove(Action doRemove, params Type[] expectedTypesRemoved)
  150. {
  151. this._expectedRemoves = GetContractNames(expectedTypesRemoved);
  152. doRemove();
  153. Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
  154. Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
  155. ResetState();
  156. }
  157. public void OnExportsChanging(object sender, ExportsChangeEventArgs args)
  158. {
  159. Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
  160. if (this._expectedAdds == null)
  161. {
  162. EnumerableAssert.IsEmpty(args.AddedExports);
  163. }
  164. else
  165. {
  166. foreach (var add in this._expectedAdds)
  167. {
  168. Assert.IsFalse(this._container.IsPresent(add), "Added exports should ot be added yet during changing");
  169. }
  170. }
  171. if (this._expectedRemoves == null)
  172. {
  173. EnumerableAssert.IsEmpty(args.RemovedExports);
  174. }
  175. else
  176. {
  177. foreach (var remove in this._expectedRemoves)
  178. {
  179. Assert.IsTrue(this._container.IsPresent(remove), "Removed exports should not be removed yet during changing");
  180. }
  181. }
  182. this._changingEventCount++;
  183. }
  184. public void OnExportsChanged(object sender, ExportsChangeEventArgs args)
  185. {
  186. Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
  187. if (this._expectedAdds == null)
  188. {
  189. EnumerableAssert.IsEmpty(args.AddedExports);
  190. }
  191. else
  192. {
  193. foreach (var add in this._expectedAdds)
  194. {
  195. Assert.IsTrue(this._container.IsPresent(add), "Added exports should be added during changed");
  196. }
  197. }
  198. if (this._expectedRemoves == null)
  199. {
  200. EnumerableAssert.IsEmpty(args.RemovedExports);
  201. }
  202. else
  203. {
  204. foreach (var remove in this._expectedRemoves)
  205. {
  206. Assert.IsFalse(this._container.IsPresent(remove), "Removed exports should be removed during changed");
  207. }
  208. }
  209. Assert.IsNull(args.AtomicComposition);
  210. this._changedEventCount++;
  211. }
  212. private void ResetState()
  213. {
  214. this._expectedAdds = null;
  215. this._expectedRemoves = null;
  216. this._changedEventCount = 0;
  217. this._changingEventCount = 0;
  218. }
  219. private static string[] GetContractNames(IEnumerable<ExportDefinition> definitions)
  220. {
  221. return definitions.Select(e => e.ContractName).ToArray();
  222. }
  223. private static string[] GetContractNames(IEnumerable<ComposablePart> parts)
  224. {
  225. return GetContractNames(parts.SelectMany(p => p.ExportDefinitions));
  226. }
  227. private static string[] GetContractNames(IEnumerable<Type> types)
  228. {
  229. return GetContractNames(types.Select(t => AttributedModelServices.CreatePartDefinition(t, null)).SelectMany(p => p.ExportDefinitions));
  230. }
  231. }
  232. }
  233. }