f8b5b9b83c1a6a214b232e757b34365311fa6aba
[mono.git] / mcs / class / System.ComponentModel.Composition / Tests / ComponentModelUnitTest / System / Integration / ExportProviderEventTests.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.ComponentModel.Composition.Hosting;\r
7 using System.ComponentModel.Composition.Primitives;\r
8 using System.Linq;\r
9 using System.UnitTesting;\r
10 using Microsoft.VisualStudio.TestTools.UnitTesting;\r
11 using System.ComponentModel.Composition.Factories;\r
12 \r
13 namespace System.ComponentModel.Composition\r
14 {\r
15     [TestClass]\r
16     public class ExportProviderEventTests\r
17     {\r
18         [TestMethod]\r
19         public void BatchAdd_ShouldFireEvents()\r
20         {\r
21             var container = ContainerFactory.Create();\r
22             var eventListener = new ExportProviderListener(container, container);\r
23 \r
24             var batch = new CompositionBatch();\r
25             batch.AddExportedValue<object>("MyExport", new object());\r
26             eventListener.VerifyCompose(batch);\r
27         }\r
28 \r
29         [TestMethod]\r
30         public void BatchRemove_ShouldFireEvents()\r
31         {\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
36 \r
37             var eventListener = new ExportProviderListener(container, container);\r
38 \r
39             batch = new CompositionBatch();\r
40             batch.RemovePart(exportPart);\r
41             eventListener.VerifyCompose(batch);\r
42         }\r
43 \r
44         [TestMethod]\r
45         public void BatchAddRemove_ShouldFireEvents()\r
46         {\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
51 \r
52             var eventListener = new ExportProviderListener(container, container);\r
53 \r
54             batch = new CompositionBatch();\r
55             batch.RemovePart(exportPart);\r
56             batch.AddExportedValue<object>("MyExport2", new object());\r
57             eventListener.VerifyCompose(batch);\r
58         }\r
59 \r
60         [TestMethod]\r
61         public void BatchMultipleAdds_ShouldFireEvents()\r
62         {\r
63             var container = ContainerFactory.Create();\r
64             var eventListener = new ExportProviderListener(container, container);\r
65 \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
71         }\r
72 \r
73         [TestMethod]\r
74         public void BatchNestedContainerAdds_ShouldFireEvents()\r
75         {\r
76             var parentContainer = ContainerFactory.Create();\r
77             var container = ContainerFactory.Create(parentContainer);\r
78             var eventListener = new ExportProviderListener(parentContainer, container);\r
79 \r
80             var batch = new CompositionBatch();\r
81             batch.AddExportedValue<object>("MyExport", new object());\r
82             eventListener.VerifyCompose(batch);\r
83         }\r
84 \r
85         [Export]\r
86         public class SampleCatalogExport { }\r
87 \r
88         [TestMethod]\r
89         public void CatalogAdd_ShouldFireEvents()\r
90         {\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
95 \r
96             eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));\r
97         }\r
98 \r
99         [TestMethod]\r
100         public void CatalogRemove_ShouldFireEvents()\r
101         {\r
102             var catalog = new TypeCatalog(typeof(SampleCatalogExport));\r
103             var aggCat = new AggregateCatalog();\r
104             var container = ContainerFactory.Create(aggCat);\r
105 \r
106             aggCat.Catalogs.Add(catalog);\r
107             var eventListener = new ExportProviderListener(container, container);\r
108 \r
109             eventListener.VerifyCatalogRemove(() => aggCat.Catalogs.Remove(catalog), typeof(SampleCatalogExport));\r
110         }\r
111 \r
112         [Export]\r
113         public class SampleCatalogExport2 { }\r
114 \r
115         [TestMethod]\r
116         public void CatalogMultipleAdds_ShouldFireEvents()\r
117         {\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
122 \r
123             var otherAggCat = new AggregateCatalog(new TypeCatalog(typeof(SampleCatalogExport)), new TypeCatalog(typeof(SampleCatalogExport2)));\r
124 \r
125             eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(otherAggCat), typeof(SampleCatalogExport), typeof(SampleCatalogExport2));\r
126         }\r
127 \r
128         [TestMethod]\r
129         public void CatalogNestedContainerAdds_ShouldFireEvents()\r
130         {\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
136 \r
137             eventListener.VerifyCatalogAdd(() => aggCat.Catalogs.Add(catalog), typeof(SampleCatalogExport));\r
138         }\r
139 \r
140         public class ExportProviderListener\r
141         {\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
148 \r
149             public ExportProviderListener(CompositionContainer container, ExportProvider watchExportProvider)\r
150             {\r
151                 watchExportProvider.ExportsChanged += OnExportsChanged;\r
152                 watchExportProvider.ExportsChanging += OnExportsChanging;\r
153                 this._watchedProvider = watchExportProvider;\r
154                 this._container = container;\r
155             }\r
156 \r
157             public void VerifyCompose(CompositionBatch batch)\r
158             {\r
159                 this._expectedAdds = GetContractNames(batch.PartsToAdd);\r
160                 this._expectedRemoves = GetContractNames(batch.PartsToRemove);\r
161 \r
162                 this._container.Compose(batch);\r
163 \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
166 \r
167                 ResetState();\r
168             }\r
169 \r
170             public void VerifyCatalogAdd(Action doAdd, params Type[] expectedTypesAdded)\r
171             {\r
172                 this._expectedAdds = GetContractNames(expectedTypesAdded);\r
173 \r
174                 doAdd();\r
175 \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
178 \r
179                 ResetState();\r
180             }\r
181 \r
182             public void VerifyCatalogRemove(Action doRemove, params Type[] expectedTypesRemoved)\r
183             {\r
184                 this._expectedRemoves = GetContractNames(expectedTypesRemoved);\r
185 \r
186                 doRemove();\r
187 \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
190 \r
191                 ResetState();\r
192             }\r
193 \r
194             public void OnExportsChanging(object sender, ExportsChangeEventArgs args)\r
195             {\r
196                 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);\r
197 \r
198                 if (this._expectedAdds == null)\r
199                 {\r
200                     EnumerableAssert.IsEmpty(args.AddedExports);\r
201                 }\r
202                 else\r
203                 {\r
204                     foreach (var add in this._expectedAdds)\r
205                     {\r
206                         Assert.IsFalse(this._container.IsPresent(add), "Added exports should ot be added yet during changing");\r
207                     }\r
208                 }\r
209 \r
210                 if (this._expectedRemoves == null)\r
211                 {\r
212                     EnumerableAssert.IsEmpty(args.RemovedExports);\r
213                 }\r
214                 else\r
215                 {\r
216                     foreach (var remove in this._expectedRemoves)\r
217                     {\r
218                         Assert.IsTrue(this._container.IsPresent(remove), "Removed exports should not be removed yet during changing");\r
219                     }\r
220                 }\r
221 \r
222                 this._changingEventCount++;\r
223             }\r
224 \r
225             public void OnExportsChanged(object sender, ExportsChangeEventArgs args)\r
226             {\r
227                 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);\r
228 \r
229                 if (this._expectedAdds == null)\r
230                 {\r
231                     EnumerableAssert.IsEmpty(args.AddedExports);\r
232                 }\r
233                 else\r
234                 {\r
235                     foreach (var add in this._expectedAdds)\r
236                     {\r
237                         Assert.IsTrue(this._container.IsPresent(add), "Added exports should be added during changed");\r
238                     }\r
239                 }\r
240 \r
241                 if (this._expectedRemoves == null)\r
242                 {\r
243                     EnumerableAssert.IsEmpty(args.RemovedExports);\r
244                 }\r
245                 else\r
246                 {\r
247                     foreach (var remove in this._expectedRemoves)\r
248                     {\r
249                         Assert.IsFalse(this._container.IsPresent(remove), "Removed exports should be removed during changed");\r
250                     }\r
251                 }\r
252 \r
253                 Assert.IsNull(args.AtomicComposition);\r
254 \r
255                 this._changedEventCount++;\r
256             }\r
257 \r
258             private void ResetState()\r
259             {\r
260                 this._expectedAdds = null;\r
261                 this._expectedRemoves = null;\r
262                 this._changedEventCount = 0;\r
263                 this._changingEventCount = 0;\r
264             }\r
265 \r
266             private static string[] GetContractNames(IEnumerable<ExportDefinition> definitions)\r
267             {\r
268                 return definitions.Select(e => e.ContractName).ToArray();\r
269             }\r
270 \r
271             private static string[] GetContractNames(IEnumerable<ComposablePart> parts)\r
272             {\r
273                 return GetContractNames(parts.SelectMany(p => p.ExportDefinitions));\r
274             }\r
275 \r
276             private static string[] GetContractNames(IEnumerable<Type> types)\r
277             {\r
278                 return GetContractNames(types.Select(t => AttributedModelServices.CreatePartDefinition(t, null)).SelectMany(p => p.ExportDefinitions));\r
279             }\r
280         }\r
281     }\r
282 }\r