1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.ComponentModel.Composition.Hosting;
\r
7 using System.ComponentModel.Composition.Primitives;
\r
9 using System.UnitTesting;
\r
10 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
11 using System.ComponentModel.Composition.Factories;
\r
13 namespace System.ComponentModel.Composition
\r
16 public class ExportProviderEventTests
\r
19 public void BatchAdd_ShouldFireEvents()
\r
21 var container = ContainerFactory.Create();
\r
22 var eventListener = new ExportProviderListener(container, container);
\r
24 var batch = new CompositionBatch();
\r
25 batch.AddExportedValue<object>("MyExport", new object());
\r
26 eventListener.VerifyCompose(batch);
\r
30 public void BatchRemove_ShouldFireEvents()
\r
32 var container = ContainerFactory.Create();
\r
33 var batch = new CompositionBatch();
\r
34 var exportPart = batch.AddExportedValue<object>("MyExport", new object());
\r
35 container.Compose(batch);
\r
37 var eventListener = new ExportProviderListener(container, container);
\r
39 batch = new CompositionBatch();
\r
40 batch.RemovePart(exportPart);
\r
41 eventListener.VerifyCompose(batch);
\r
45 public void BatchAddRemove_ShouldFireEvents()
\r
47 var container = ContainerFactory.Create();
\r
48 var batch = new CompositionBatch();
\r
49 var exportPart = batch.AddExportedValue<object>("MyExport", new object());
\r
50 container.Compose(batch);
\r
52 var eventListener = new ExportProviderListener(container, container);
\r
54 batch = new CompositionBatch();
\r
55 batch.RemovePart(exportPart);
\r
56 batch.AddExportedValue<object>("MyExport2", new object());
\r
57 eventListener.VerifyCompose(batch);
\r
61 public void BatchMultipleAdds_ShouldFireEvents()
\r
63 var container = ContainerFactory.Create();
\r
64 var eventListener = new ExportProviderListener(container, container);
\r
66 var batch = new CompositionBatch();
\r
67 batch.AddExportedValue<object>("MyExport", new object());
\r
68 batch.AddExportedValue<object>("MyExport2", new object());
\r
69 batch.AddExportedValue<object>("MyExport3", new object());
\r
70 eventListener.VerifyCompose(batch);
\r
74 public void BatchNestedContainerAdds_ShouldFireEvents()
\r
76 var parentContainer = ContainerFactory.Create();
\r
77 var container = ContainerFactory.Create(parentContainer);
\r
78 var eventListener = new ExportProviderListener(parentContainer, container);
\r
80 var batch = new CompositionBatch();
\r
81 batch.AddExportedValue<object>("MyExport", new object());
\r
82 eventListener.VerifyCompose(batch);
\r
86 public class SampleCatalogExport { }
\r
89 public void CatalogAdd_ShouldFireEvents()
\r
91 var catalog = new TypeCatalog(typeof(SampleCatalogExport));
\r
92 var aggCat = new AggregateCatalog();
\r
93 var container = ContainerFactory.Create(aggCat);
\r
94 var eventListener = new ExportProviderListener(container, container);
\r
96 eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));
\r
100 public void CatalogRemove_ShouldFireEvents()
\r
102 var catalog = new TypeCatalog(typeof(SampleCatalogExport));
\r
103 var aggCat = new AggregateCatalog();
\r
104 var container = ContainerFactory.Create(aggCat);
\r
106 aggCat.Catalogs.Add(catalog);
\r
107 var eventListener = new ExportProviderListener(container, container);
\r
109 eventListener.VerifyCatalogRemove(() => aggCat.Catalogs.Remove(catalog), typeof(SampleCatalogExport));
\r
113 public class SampleCatalogExport2 { }
\r
116 public void CatalogMultipleAdds_ShouldFireEvents()
\r
118 var catalog = new TypeCatalog(typeof(SampleCatalogExport));
\r
119 var aggCat = new AggregateCatalog();
\r
120 var container = ContainerFactory.Create(aggCat);
\r
121 var eventListener = new ExportProviderListener(container, container);
\r
123 var otherAggCat = new AggregateCatalog(new TypeCatalog(typeof(SampleCatalogExport)), new TypeCatalog(typeof(SampleCatalogExport2)));
\r
125 eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(otherAggCat), typeof(SampleCatalogExport), typeof(SampleCatalogExport2));
\r
129 public void CatalogNestedContainerAdds_ShouldFireEvents()
\r
131 var catalog = new TypeCatalog(typeof(SampleCatalogExport));
\r
132 var aggCat = new AggregateCatalog();
\r
133 var parentContainer = ContainerFactory.Create(aggCat);
\r
134 var container = ContainerFactory.Create(parentContainer);
\r
135 var eventListener = new ExportProviderListener(parentContainer, container);
\r
137 eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));
\r
140 public class ExportProviderListener
\r
142 private CompositionContainer _container;
\r
143 private ExportProvider _watchedProvider;
\r
144 private string[] _expectedAdds;
\r
145 private string[] _expectedRemoves;
\r
146 private int _changedEventCount;
\r
147 private int _changingEventCount;
\r
149 public ExportProviderListener(CompositionContainer container, ExportProvider watchExportProvider)
\r
151 watchExportProvider.ExportsChanged += OnExportsChanged;
\r
152 watchExportProvider.ExportsChanging += OnExportsChanging;
\r
153 this._watchedProvider = watchExportProvider;
\r
154 this._container = container;
\r
157 public void VerifyCompose(CompositionBatch batch)
\r
159 this._expectedAdds = GetContractNames(batch.PartsToAdd);
\r
160 this._expectedRemoves = GetContractNames(batch.PartsToRemove);
\r
162 this._container.Compose(batch);
\r
164 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
165 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
170 public void VerifyCatalogAdd(Action doAdd, params Type[] expectedTypesAdded)
\r
172 this._expectedAdds = GetContractNames(expectedTypesAdded);
\r
176 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
177 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
182 public void VerifyCatalogRemove(Action doRemove, params Type[] expectedTypesRemoved)
\r
184 this._expectedRemoves = GetContractNames(expectedTypesRemoved);
\r
188 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
189 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
194 public void OnExportsChanging(object sender, ExportsChangeEventArgs args)
\r
196 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
\r
198 if (this._expectedAdds == null)
\r
200 EnumerableAssert.IsEmpty(args.AddedExports);
\r
204 foreach (var add in this._expectedAdds)
\r
206 Assert.IsFalse(this._container.IsPresent(add), "Added exports should ot be added yet during changing");
\r
210 if (this._expectedRemoves == null)
\r
212 EnumerableAssert.IsEmpty(args.RemovedExports);
\r
216 foreach (var remove in this._expectedRemoves)
\r
218 Assert.IsTrue(this._container.IsPresent(remove), "Removed exports should not be removed yet during changing");
\r
222 this._changingEventCount++;
\r
225 public void OnExportsChanged(object sender, ExportsChangeEventArgs args)
\r
227 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
\r
229 if (this._expectedAdds == null)
\r
231 EnumerableAssert.IsEmpty(args.AddedExports);
\r
235 foreach (var add in this._expectedAdds)
\r
237 Assert.IsTrue(this._container.IsPresent(add), "Added exports should be added during changed");
\r
241 if (this._expectedRemoves == null)
\r
243 EnumerableAssert.IsEmpty(args.RemovedExports);
\r
247 foreach (var remove in this._expectedRemoves)
\r
249 Assert.IsFalse(this._container.IsPresent(remove), "Removed exports should be removed during changed");
\r
253 Assert.IsNull(args.AtomicComposition);
\r
255 this._changedEventCount++;
\r
258 private void ResetState()
\r
260 this._expectedAdds = null;
\r
261 this._expectedRemoves = null;
\r
262 this._changedEventCount = 0;
\r
263 this._changingEventCount = 0;
\r
266 private static string[] GetContractNames(IEnumerable<ExportDefinition> definitions)
\r
268 return definitions.Select(e => e.ContractName).ToArray();
\r
271 private static string[] GetContractNames(IEnumerable<ComposablePart> parts)
\r
273 return GetContractNames(parts.SelectMany(p => p.ExportDefinitions));
\r
276 private static string[] GetContractNames(IEnumerable<Type> types)
\r
278 return GetContractNames(types.Select(t => AttributedModelServices.CreatePartDefinition(t, null)).SelectMany(p => p.ExportDefinitions));
\r