1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.ComponentModel.Composition.Factories;
\r
7 using System.ComponentModel.Composition.Hosting;
\r
8 using System.ComponentModel.Composition.Primitives;
\r
11 using System.Linq.Expressions;
\r
12 using System.Threading;
\r
13 using System.UnitTesting;
\r
14 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
16 namespace System.ComponentModel.Composition.Hosting
\r
19 public class AggregateCatalogTest
\r
22 public void Constructor1_ShouldNotThrow()
\r
24 new AggregateCatalog();
\r
29 public void Constructor1_ShouldSetCatalogsPropertyToEmpty()
\r
31 var catalog = new AggregateCatalog();
\r
33 EnumerableAssert.IsEmpty(catalog.Catalogs);
\r
37 public void Constructor1_ShouldSetPartsPropertyToEmpty()
\r
39 var catalog = new AggregateCatalog();
\r
41 EnumerableAssert.IsEmpty(catalog.Parts);
\r
45 public void Constructor3_NullAsCatalogsArgument_ShouldSetCatalogsPropertyToEmpty()
\r
47 var catalog = new AggregateCatalog((IEnumerable<ComposablePartCatalog>)null);
\r
49 EnumerableAssert.IsEmpty(catalog.Catalogs);
\r
53 public void Constructor3_EmptyIEnumerableAsCatalogsArgument_ShouldSetCatalogsPropertyToEmpty()
\r
55 var catalog = new AggregateCatalog(Enumerable.Empty<ComposablePartCatalog>());
\r
57 EnumerableAssert.IsEmpty(catalog.Catalogs);
\r
61 public void Constructor3_NullAsCatalogsArgument_ShouldSetPartsPropertyToEmpty()
\r
63 var catalog = new AggregateCatalog((IEnumerable<ComposablePartCatalog>)null);
\r
65 EnumerableAssert.IsEmpty(catalog.Parts);
\r
69 public void Constructor3_EmptyIEnumerableAsCatalogsArgument_ShouldSetPartsPropertyToEmpty()
\r
71 var catalog = new AggregateCatalog(Enumerable.Empty<ComposablePartCatalog>());
\r
73 EnumerableAssert.IsEmpty(catalog.Parts);
\r
77 public void Constructor3_ArrayWithNullAsCatalogsArgument_ShouldThrowArgument()
\r
79 var catalogs = new ComposablePartCatalog[] { null };
\r
81 ExceptionAssert.ThrowsArgument<ArgumentException>("catalogs", () =>
\r
83 new AggregateCatalog(catalogs);
\r
88 public void Catalogs_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
90 var catalog = CreateAggregateCatalog();
\r
93 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
95 var catalogs = catalog.Catalogs;
\r
100 public void Parts_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
102 var catalog = CreateAggregateCatalog();
\r
105 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
107 var parts = catalog.Parts;
\r
112 public void GetExports_WhenCatalogDisposed_ShouldThrowObjectDisposed()
\r
114 var catalog = CreateAggregateCatalog();
\r
116 var definition = ImportDefinitionFactory.Create();
\r
118 ExceptionAssert.ThrowsDisposed(catalog, () =>
\r
120 catalog.GetExports(definition);
\r
125 public void GetExports_NullAsConstraintArgument_ShouldThrowArgumentNull()
\r
127 var catalog = CreateAggregateCatalog();
\r
129 ExceptionAssert.ThrowsArgument<ArgumentNullException>("definition", () =>
\r
131 catalog.GetExports((ImportDefinition)null);
\r
136 public void Dispose_ShouldNotThrow()
\r
138 using (var catalog = CreateAggregateCatalog())
\r
144 public void Dispose_CanBeCalledMultipleTimes()
\r
146 var catalog = CreateAggregateCatalog();
\r
154 public void MutableCatalogNotifications()
\r
157 int changedStep = 0;
\r
158 var catalog = new AggregateCatalog();
\r
160 var typePartCatalog = new TypeCatalog(typeof(SharedPartStuff));
\r
161 var typePartCatalog1 = new TypeCatalog(typeof(SharedPartStuff));
\r
162 var typePartCatalog2 = new TypeCatalog(typeof(SharedPartStuff));
\r
163 var typePartCatalog3 = new TypeCatalog(typeof(SharedPartStuff));
\r
164 var typePartCatalog4 = new TypeCatalog(typeof(SharedPartStuff));
\r
165 var typePartCatalog5 = new TypeCatalog(typeof(SharedPartStuff));
\r
167 // Smoke test on inner collection
\r
168 catalog.Catalogs.Add(typePartCatalog);
\r
169 catalog.Catalogs.Remove(typePartCatalog);
\r
170 catalog.Catalogs.Clear();
\r
171 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add/Remove/Clear -- PartsAsCollection.Count is now 0");
\r
173 // Add notifications
\r
174 catalog.Changed += delegate(object source, ComposablePartCatalogChangeEventArgs args)
\r
178 changedStep = step;
\r
181 //Add something then verify counters
\r
182 catalog.Catalogs.Add(typePartCatalog);
\r
183 Assert.IsTrue(catalog.Catalogs.Count == 1, "Add -- Catalogs.Count is now 1");
\r
184 Assert.IsTrue(changedStep == 2, "Add -- Changed must be fired after");
\r
187 step = changedStep = 0;
\r
189 // Remove something then verify counters
\r
190 catalog.Catalogs.Remove(typePartCatalog);
\r
191 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add -- Catalogs.Count is now 0");
\r
192 Assert.IsTrue(changedStep == 2, "Remove -- Changed must be fired after");
\r
196 catalog.Catalogs.Add(typePartCatalog);
\r
197 Assert.IsTrue(catalog.Catalogs.Count == 1, "Add -- Catalogs.Count is now 1");
\r
199 step = changedStep = 0;
\r
200 // Now clear the collection and verify counters
\r
201 catalog.Catalogs.Clear();
\r
202 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add -- Catalogs.Count is now 0");
\r
203 Assert.IsTrue(changedStep == 2, "Remove -- Changed must be fired after");
\r
205 // Now remove a non existent item and verify counters
\r
206 step = changedStep = 0;
\r
207 bool removed = catalog.Catalogs.Remove(typePartCatalog);
\r
208 Assert.IsTrue(removed == false, "Remove -- correctly returned false");
\r
209 Assert.IsTrue(changedStep == 0, "Remove -- Changed should not fire if nothing changed");
\r
212 step = changedStep = 0;
\r
213 catalog.Catalogs.Add(typePartCatalog);
\r
214 Assert.IsTrue(catalog.Catalogs.Count == 1, "Add -- Catalogs.Count is now 1");
\r
215 Assert.IsTrue(changedStep == 2, "Add -- Changed must be fired after");
\r
217 catalog.Catalogs.Add(typePartCatalog1);
\r
218 Assert.IsTrue(catalog.Catalogs.Count == 2, "Add -- Catalogs.Count is now 1");
\r
219 Assert.IsTrue(changedStep == 4, "Add -- Changing must be fired after");
\r
221 catalog.Catalogs.Add(typePartCatalog2);
\r
222 catalog.Catalogs.Add(typePartCatalog3);
\r
223 catalog.Catalogs.Add(typePartCatalog4);
\r
224 catalog.Catalogs.Add(typePartCatalog5);
\r
225 Assert.IsTrue(catalog.Catalogs.Count == 6, "Add -- Catalogs.Count is now 1");
\r
226 Assert.IsTrue(changedStep == 12, "Add -- Changing must be fired after");
\r
228 removed = catalog.Catalogs.Remove(typePartCatalog3);
\r
229 Assert.IsTrue(catalog.Catalogs.Count == 5, "Add -- Catalogs.Count is now 5");
\r
230 Assert.IsTrue(removed == true, "Remove should have succeeded");
\r
231 Assert.IsTrue(changedStep == 14, "Remove -- Changed must be fired after");
\r
232 removed = catalog.Catalogs.Remove(typePartCatalog2);
\r
233 removed = catalog.Catalogs.Remove(typePartCatalog1);
\r
234 removed = catalog.Catalogs.Remove(typePartCatalog4);
\r
235 removed = catalog.Catalogs.Remove(typePartCatalog);
\r
236 removed = catalog.Catalogs.Remove(typePartCatalog5);
\r
237 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add -- Catalogs.Count is now 0");
\r
238 Assert.IsTrue(removed == true, "Remove should have succeeded");
\r
239 Assert.IsTrue(changedStep == 24, "Remove -- Changing must be fired after");
\r
241 // Add and then clear a lot
\r
242 step = changedStep = 0;
\r
243 catalog.Catalogs.Add(typePartCatalog);
\r
244 catalog.Catalogs.Add(typePartCatalog1);
\r
245 catalog.Catalogs.Add(typePartCatalog2);
\r
246 catalog.Catalogs.Add(typePartCatalog3);
\r
247 catalog.Catalogs.Add(typePartCatalog4);
\r
248 catalog.Catalogs.Add(typePartCatalog5);
\r
249 Assert.IsTrue(catalog.Catalogs.Count == 6, "Add -- Catalogs.Count should be 6");
\r
250 Assert.IsTrue(changedStep == 12, "Add -- Changing must be fired after");
\r
252 catalog.Catalogs.Clear();
\r
253 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add -- Catalogs.Count should be 0");
\r
255 step = changedStep = 0;
\r
257 int changedStep2 = 0;
\r
259 catalog.Changed += delegate(object source, ComposablePartCatalogChangeEventArgs args)
\r
263 changedStep2 = step2;
\r
266 catalog.Catalogs.Add(typePartCatalog);
\r
267 Assert.IsTrue(catalog.Catalogs.Count == 1, "Add -- Catalogs.Count is now 1");
\r
268 Assert.IsTrue(changedStep == 2, "Add handler 1 -- Changed must be fired after");
\r
269 Assert.IsTrue(changedStep2 == 98, "Add handler 2 -- Changed must be fired after");
\r
271 catalog.Catalogs.Add(typePartCatalog1);
\r
272 Assert.IsTrue(catalog.Catalogs.Count == 2, "Add -- Catalogs.Count is now 1");
\r
273 Assert.IsTrue(changedStep == 4, "Add handler 1 -- Changed must be fired after");
\r
274 Assert.IsTrue(changedStep2 == 96, "Add handler 2 -- Changed must be firedafter");
\r
276 catalog.Catalogs.Remove(typePartCatalog);
\r
277 Assert.IsTrue(catalog.Catalogs.Count == 1, "Add -- PartsAsCollection.Count is now 1");
\r
278 Assert.IsTrue(changedStep == 6, "Add handler 1 -- Changed must be fired and fired after");
\r
279 Assert.IsTrue(changedStep2 == 94, "Add handler 2 -- Changed must be fired and fired after");
\r
281 catalog.Catalogs.Clear();
\r
282 Assert.IsTrue(catalog.Catalogs.Count == 0, "Add -- PartsAsCollection.Count is now 0");
\r
283 Assert.IsTrue(changedStep == 8, "Add handler 1 -- Changed must be fired after");
\r
284 Assert.IsTrue(changedStep2 == 92, "Add handler 2 -- Changed must be fired after");
\r
289 public void DisposeAggregatingCatalog()
\r
291 int changedNotification = 0;
\r
293 var typePartCatalog1 = new TypeCatalog(typeof(SharedPartStuff));
\r
294 var typePartCatalog2 = new TypeCatalog(typeof(SharedPartStuff));
\r
295 var typePartCatalog3 = new TypeCatalog(typeof(SharedPartStuff));
\r
297 var assemblyPartCatalog1 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
298 var assemblyPartCatalog2 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
299 var assemblyPartCatalog3 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
302 var dirPartCatalog1 = new DirectoryCatalog(FileIO.GetRootTemporaryDirectory());
\r
303 var dirPartCatalog2 = new DirectoryCatalog(FileIO.GetRootTemporaryDirectory());
\r
304 var dirPartCatalog3 = new DirectoryCatalog(FileIO.GetRootTemporaryDirectory());
\r
306 using (var catalog = new AggregateCatalog())
\r
308 catalog.Catalogs.Add(typePartCatalog1);
\r
309 catalog.Catalogs.Add(typePartCatalog2);
\r
310 catalog.Catalogs.Add(typePartCatalog3);
\r
312 catalog.Catalogs.Add(assemblyPartCatalog1);
\r
313 catalog.Catalogs.Add(assemblyPartCatalog2);
\r
314 catalog.Catalogs.Add(assemblyPartCatalog3);
\r
317 catalog.Catalogs.Add(dirPartCatalog1);
\r
318 catalog.Catalogs.Add(dirPartCatalog2);
\r
319 catalog.Catalogs.Add(dirPartCatalog3);
\r
322 // Add notifications
\r
323 catalog.Changed += delegate(object source, ComposablePartCatalogChangeEventArgs args)
\r
326 ++changedNotification;
\r
331 Assert.IsTrue(changedNotification == 0, "No changed notifications");
\r
333 //Ensure that the other catalogs are
\r
334 ExceptionAssert.ThrowsDisposed(typePartCatalog1, () =>
\r
336 var iEnum = typePartCatalog1.Parts.GetEnumerator();
\r
339 ExceptionAssert.ThrowsDisposed(typePartCatalog2, () =>
\r
341 var iEnum = typePartCatalog2.Parts.GetEnumerator();
\r
344 ExceptionAssert.ThrowsDisposed(typePartCatalog3, () =>
\r
346 var iEnum = typePartCatalog3.Parts.GetEnumerator();
\r
349 //Ensure that the other catalogs are
\r
350 ExceptionAssert.ThrowsDisposed(assemblyPartCatalog1, () =>
\r
352 var iEnum = assemblyPartCatalog1.Parts.GetEnumerator();
\r
355 ExceptionAssert.ThrowsDisposed(assemblyPartCatalog2, () =>
\r
357 var iEnum = assemblyPartCatalog2.Parts.GetEnumerator();
\r
360 ExceptionAssert.ThrowsDisposed(assemblyPartCatalog3, () =>
\r
362 var iEnum = assemblyPartCatalog3.Parts.GetEnumerator();
\r
366 //Ensure that the other catalogs are
\r
367 ExceptionAssert.ThrowsDisposed(dirPartCatalog1, () =>
\r
369 var iEnum = dirPartCatalog1.Parts.GetEnumerator();
\r
372 ExceptionAssert.ThrowsDisposed(dirPartCatalog2, () =>
\r
374 var iEnum = dirPartCatalog2.Parts.GetEnumerator();
\r
377 ExceptionAssert.ThrowsDisposed(dirPartCatalog3, () =>
\r
379 var iEnum = dirPartCatalog3.Parts.GetEnumerator();
\r
387 public void MutableMultithreadedEnumerations()
\r
389 var catalog = new AggregateCatalog();
\r
391 ThreadStart func = delegate()
\r
393 var typePart = new TypeCatalog(typeof(SharedPartStuff));
\r
394 var typePart1 = new TypeCatalog(typeof(SharedPartStuff));
\r
395 var typePart2 = new TypeCatalog(typeof(SharedPartStuff));
\r
396 var typePart3 = new TypeCatalog(typeof(SharedPartStuff));
\r
397 var typePart4 = new TypeCatalog(typeof(SharedPartStuff));
\r
398 var typePart5 = new TypeCatalog(typeof(SharedPartStuff));
\r
400 for (int i = 0; i < 100; i++)
\r
402 catalog.Catalogs.Add(typePart);
\r
403 catalog.Catalogs.Add(typePart1);
\r
404 catalog.Catalogs.Add(typePart2);
\r
405 catalog.Catalogs.Add(typePart3);
\r
406 catalog.Catalogs.Add(typePart4);
\r
407 catalog.Catalogs.Add(typePart5);
\r
409 Assert.IsTrue(catalog.Catalogs.Count >= 6, "Catalogs Collection must be at least 6 big");
\r
411 for (int k = 0; k < 5; k++)
\r
414 // Ensure that iterating the returned queryable is okay even though there are many threads mutationg it
\r
415 // We are really just looking to ensure that ollection changed exceptions are not thrown
\r
417 var iq = catalog.Parts.GetEnumerator();
\r
418 while (iq.MoveNext())
\r
423 Assert.IsTrue(j >= 6, "Catalogs Collection must be at least 6 big");
\r
425 // Ensure that iterating the returned enumerator is okay even though there are many threads mutationg it
\r
426 // We are really just looking to ensure that collection changed exceptions are not thrown
\r
428 var ie = catalog.Catalogs.GetEnumerator();
\r
429 while (ie.MoveNext())
\r
433 Assert.IsTrue(j >= 6, "Catalogs Collection must be at least 6 big");
\r
437 catalog.Catalogs.Remove(typePart);
\r
438 catalog.Catalogs.Remove(typePart1);
\r
439 catalog.Catalogs.Remove(typePart2);
\r
440 catalog.Catalogs.Remove(typePart3);
\r
441 catalog.Catalogs.Remove(typePart4);
\r
442 catalog.Catalogs.Remove(typePart5);
\r
446 Thread[] threads = new Thread[100];
\r
447 for (int i = 0; i < threads.Length; i++)
\r
449 threads[i] = new Thread(func);
\r
452 for (int i = 0; i < threads.Length; i++)
\r
454 threads[i].Start();
\r
456 for (int i = 0; i < threads.Length; i++)
\r
461 Assert.IsTrue(catalog.Catalogs.Count == 0, "Collection must be empty");
\r
465 public void CreateMainAndOtherChildren(
\r
466 out AggregateCatalog[] mainChildren,
\r
467 out AggregateCatalog[] otherChildren,
\r
468 out TypeCatalog[] componentCatalogs)
\r
470 componentCatalogs = new TypeCatalog[]
\r
472 new TypeCatalog(typeof(SharedPartStuff)),
\r
473 new TypeCatalog(typeof(SharedPartStuff)),
\r
474 new TypeCatalog(typeof(SharedPartStuff))
\r
477 // Create our child catalogs
\r
478 mainChildren = new AggregateCatalog[5];
\r
479 for (int i = 0; i < mainChildren.Length; i++)
\r
481 mainChildren[i] = new AggregateCatalog(componentCatalogs);
\r
484 otherChildren = new AggregateCatalog[5];
\r
485 for (int i = 0; i < otherChildren.Length; i++)
\r
487 otherChildren[i] = new AggregateCatalog(componentCatalogs);
\r
492 public void AggregatingCatalogAddAndRemoveChildren()
\r
494 int changedCount = 0;
\r
495 int typesChanged = 0;
\r
496 EventHandler<ComposablePartCatalogChangeEventArgs> onChanged = delegate(object sender, ComposablePartCatalogChangeEventArgs e)
\r
499 typesChanged += e.AddedDefinitions.Concat(e.RemovedDefinitions).Count();
\r
502 // Create our child catalogs
\r
503 AggregateCatalog[] mainChildren;
\r
504 AggregateCatalog[] otherChildren;
\r
505 TypeCatalog[] componentCatalogs;
\r
507 CreateMainAndOtherChildren(out mainChildren, out otherChildren, out componentCatalogs);
\r
509 var parent = new AggregateCatalog(mainChildren);
\r
510 parent.Changed += onChanged;
\r
512 for (int i = 0; i < otherChildren.Length; i++)
\r
514 parent.Catalogs.Add(otherChildren[i]);
\r
517 Assert.AreEqual(otherChildren.Length, changedCount);
\r
518 Assert.AreEqual(otherChildren.Length * 3, typesChanged);
\r
523 parent.Catalogs.Remove(otherChildren[0]);
\r
524 parent.Catalogs.Remove(otherChildren[1]);
\r
526 Assert.AreEqual(2, changedCount);
\r
527 Assert.AreEqual(2 * 3, typesChanged);
\r
532 parent.Catalogs.Add(otherChildren[0]);
\r
533 parent.Catalogs.Add(otherChildren[1]);
\r
535 Assert.AreEqual(2, changedCount);
\r
536 Assert.AreEqual(2 * 3, typesChanged);
\r
541 parent.Catalogs.Clear();
\r
542 Assert.AreEqual(1, changedCount);
\r
543 Assert.AreEqual((mainChildren.Length + otherChildren.Length) * 3, typesChanged);
\r
548 // These have already been removed and so I should be able remove components from them without recieving notifications
\r
549 otherChildren[0].Catalogs.Remove(componentCatalogs[0]);
\r
550 otherChildren[1].Catalogs.Remove(componentCatalogs[1]);
\r
551 Assert.AreEqual(0, changedCount);
\r
552 Assert.AreEqual(0, typesChanged);
\r
554 // These have already been Cleared and so I should be able remove components from them without recieving notifications
\r
555 otherChildren[3].Catalogs.Remove(componentCatalogs[0]);
\r
556 otherChildren[4].Catalogs.Remove(componentCatalogs[1]);
\r
557 Assert.AreEqual(0, changedCount);
\r
561 public void AggregatingCatalogAddAndRemoveNestedChildren()
\r
563 int changedCount = 0;
\r
564 int typesChanged = 0;
\r
566 EventHandler<ComposablePartCatalogChangeEventArgs> onChanged = delegate(object sender, ComposablePartCatalogChangeEventArgs e)
\r
569 typesChanged += e.AddedDefinitions.Concat(e.RemovedDefinitions).Count();
\r
572 // Create our child catalogs
\r
573 AggregateCatalog[] mainChildren;
\r
574 AggregateCatalog[] otherChildren;
\r
575 TypeCatalog[] componentCatalogs;
\r
576 CreateMainAndOtherChildren(out mainChildren, out otherChildren, out componentCatalogs);
\r
579 var parent = new AggregateCatalog(mainChildren);
\r
580 parent.Changed += onChanged;
\r
582 for (int i = 0; i < otherChildren.Length; i++)
\r
584 parent.Catalogs.Add(otherChildren[i]);
\r
587 Assert.AreEqual(otherChildren.Length, changedCount);
\r
588 Assert.AreEqual(otherChildren.Length * 3, typesChanged);
\r
593 otherChildren[0].Catalogs.Remove(componentCatalogs[0]);
\r
594 otherChildren[1].Catalogs.Remove(componentCatalogs[1]);
\r
596 Assert.AreEqual(2, changedCount);
\r
597 Assert.AreEqual(2, typesChanged);
\r
602 otherChildren[0].Catalogs.Add(componentCatalogs[0]);
\r
603 otherChildren[1].Catalogs.Add(componentCatalogs[1]);
\r
605 Assert.AreEqual(2, changedCount);
\r
606 Assert.AreEqual(2, typesChanged);
\r
610 otherChildren[1].Catalogs.Clear();
\r
611 Assert.AreEqual(1, changedCount);
\r
612 Assert.AreEqual(componentCatalogs.Length, typesChanged);
\r
616 public void AggregatingDisposedAndNotifications()
\r
618 int changedCount = 0;
\r
619 int typesChanged = 0;
\r
621 EventHandler<ComposablePartCatalogChangeEventArgs> onChanged = delegate(object sender, ComposablePartCatalogChangeEventArgs e)
\r
624 typesChanged += e.AddedDefinitions.Concat(e.RemovedDefinitions).Count();
\r
627 // Create our child catalogs
\r
628 AggregateCatalog[] mainChildren;
\r
629 AggregateCatalog[] otherChildren;
\r
630 TypeCatalog[] componentCatalogs;
\r
631 CreateMainAndOtherChildren(out mainChildren, out otherChildren, out componentCatalogs);
\r
634 var parent = new AggregateCatalog(mainChildren);
\r
635 parent.Changed += onChanged;
\r
637 for (int i = 0; i < otherChildren.Length; i++)
\r
639 parent.Catalogs.Add(otherChildren[i]);
\r
642 Assert.AreEqual(otherChildren.Length, changedCount);
\r
643 Assert.AreEqual(otherChildren.Length * 3, typesChanged);
\r
650 Assert.AreEqual(0, changedCount);
\r
651 Assert.AreEqual(0, typesChanged);
\r
653 //Ensure that the children are also disposed
\r
654 ExceptionAssert.ThrowsDisposed(otherChildren[0], () =>
\r
656 otherChildren[0].Catalogs.Remove(componentCatalogs[0]);
\r
659 //Ensure that the children are also disposed
\r
660 ExceptionAssert.ThrowsDisposed(otherChildren[4], () =>
\r
662 otherChildren[4].Catalogs.Remove(componentCatalogs[0]);
\r
665 Assert.AreEqual(0, changedCount);
\r
666 Assert.AreEqual(0, typesChanged);
\r
670 public void AggregatingCatalogParmsConstructorAggregateAggregateCatalogs()
\r
672 var aggCatalog1 = new AggregateCatalog();
\r
673 var aggCatalog2 = new AggregateCatalog();
\r
674 var aggCatalog3 = new AggregateCatalog();
\r
676 // Construct with one catalog parameter
\r
677 var catalog = new AggregateCatalog(aggCatalog1);
\r
678 Assert.IsTrue(catalog.Catalogs.Count == 1);
\r
680 // Construct with two catalog parameters
\r
681 catalog = new AggregateCatalog(aggCatalog1, aggCatalog2);
\r
682 Assert.IsTrue(catalog.Catalogs.Count == 2);
\r
684 // Construct with three catalog parameters
\r
685 catalog = new AggregateCatalog(aggCatalog1, aggCatalog2, aggCatalog3);
\r
686 Assert.IsTrue(catalog.Catalogs.Count == 3);
\r
691 public void AggregatingCatalogParmsConstructorAggregateAssemblyCatalogs()
\r
693 var assemblyCatalog1 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
694 var assemblyCatalog2 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
695 var assemblyCatalog3 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
697 // Construct with one catalog parameter
\r
698 var catalog = new AggregateCatalog(assemblyCatalog1);
\r
699 Assert.IsTrue(catalog.Catalogs.Count == 1);
\r
701 // Construct with two catalog parameters
\r
702 catalog = new AggregateCatalog(assemblyCatalog1, assemblyCatalog2);
\r
703 Assert.IsTrue(catalog.Catalogs.Count == 2);
\r
705 // Construct with three catalog parameters
\r
706 catalog = new AggregateCatalog(assemblyCatalog1, assemblyCatalog2, assemblyCatalog3);
\r
707 Assert.IsTrue(catalog.Catalogs.Count == 3);
\r
711 public void AggregatingCatalogParmsConstructorMixedCatalogs()
\r
713 var typePartCatalog1 = new TypeCatalog(typeof(SharedPartStuff));
\r
714 var assemblyCatalog2 = new AssemblyCatalog(typeof(SharedPartStuff).Assembly);
\r
715 var typePartCatalog3 = new TypeCatalog(typeof(SharedPartStuff));
\r
717 // Construct with three catalog parameters
\r
718 var catalog = new AggregateCatalog(typePartCatalog1, assemblyCatalog2, typePartCatalog3);
\r
719 Assert.IsTrue(catalog.Catalogs.Count == 3);
\r
723 public void AggregatingCatalogRaisesChangesForCatalogsPassedToConstructor()
\r
725 var subCatalog = CreateAggregateCatalog();
\r
726 var testCatalog = new AggregateCatalog(subCatalog);
\r
728 bool changedCalled = false;
\r
729 testCatalog.Changed += delegate
\r
731 changedCalled = true;
\r
734 subCatalog.Catalogs.Add(new TypeCatalog(typeof(SharedPartStuff)));
\r
736 Assert.IsTrue(changedCalled);
\r
739 private AggregateCatalog CreateAggregateCatalog()
\r
741 return new AggregateCatalog();
\r
745 public void CatalogEvents_AggregateAddRemove()
\r
747 var catalog = new AggregateCatalog();
\r
748 AggregateTests(catalog, catalog);
\r
752 public void CatalogEvents_DeepAggregateAddRemove()
\r
754 var deepCatalog = new AggregateCatalog();
\r
755 var midCatalog = new AggregateCatalog(new ComposablePartCatalog[] { deepCatalog });
\r
756 var topCatalog = new AggregateCatalog(new ComposablePartCatalog[] { midCatalog });
\r
757 AggregateTests(topCatalog, deepCatalog);
\r
760 private void AggregateTests(AggregateCatalog watchedCatalog, AggregateCatalog modifiedCatalog)
\r
762 var fooCatalog = new TypeCatalog(new Type[] { typeof(FooExporter) });
\r
763 var barCatalog = new TypeCatalog(new Type[] { typeof(BarExporter) });
\r
764 var bothCatalog = new TypeCatalog(new Type[] { typeof(FooExporter), typeof(BarExporter) });
\r
766 var catalogListener = new CatalogListener(watchedCatalog, modifiedCatalog);
\r
768 catalogListener.VerifyAdd(fooCatalog, typeof(FooExporter));
\r
769 catalogListener.VerifyAdd(barCatalog, typeof(BarExporter));
\r
770 catalogListener.VerifyRemove(fooCatalog, typeof(FooExporter));
\r
771 catalogListener.VerifyRemove(barCatalog, typeof(BarExporter));
\r
773 catalogListener.VerifyAdd(bothCatalog, typeof(FooExporter), typeof(BarExporter));
\r
774 catalogListener.VerifyClear(typeof(FooExporter), typeof(BarExporter));
\r
776 catalogListener.VerifyAdd(bothCatalog, typeof(FooExporter), typeof(BarExporter));
\r
777 catalogListener.VerifyRemove(bothCatalog, typeof(FooExporter), typeof(BarExporter));
\r
781 public interface IFoo { }
\r
782 public interface IBar { }
\r
784 [Export(typeof(IFoo))]
\r
785 public class FooExporter : IFoo
\r
789 [Export(typeof(IBar))]
\r
790 public class BarExporter : IBar
\r
794 public class CatalogListener
\r
796 private AggregateCatalog _watchedCatalog;
\r
797 private AggregateCatalog _modifiedCatalog;
\r
798 private string[] _expectedAdds;
\r
799 private string[] _expectedRemoves;
\r
800 private int _changedEventCount;
\r
801 private int _changingEventCount;
\r
803 public CatalogListener(AggregateCatalog watchCatalog, AggregateCatalog modifiedCatalog)
\r
805 watchCatalog.Changing += OnChanging;
\r
806 watchCatalog.Changed += OnChanged;
\r
807 this._watchedCatalog = watchCatalog;
\r
808 this._modifiedCatalog = modifiedCatalog;
\r
811 public void VerifyAdd(ComposablePartCatalog catalogToAdd, params Type[] expectedTypesAdded)
\r
813 this._expectedAdds = GetDisplayNames(expectedTypesAdded);
\r
815 this._modifiedCatalog.Catalogs.Add(catalogToAdd);
\r
817 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
818 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
823 public void VerifyRemove(ComposablePartCatalog catalogToRemove, params Type[] expectedTypesRemoved)
\r
825 this._expectedAdds = null;
\r
826 this._expectedRemoves = GetDisplayNames(expectedTypesRemoved);
\r
828 this._modifiedCatalog.Catalogs.Remove(catalogToRemove);
\r
830 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
831 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
836 public void VerifyClear(params Type[] expectedTypesRemoved)
\r
838 this._expectedAdds = null;
\r
839 this._expectedRemoves = GetDisplayNames(expectedTypesRemoved);
\r
841 this._modifiedCatalog.Catalogs.Clear();
\r
843 Assert.IsTrue(this._changingEventCount == 1, "Changing event should have been called");
\r
844 Assert.IsTrue(this._changedEventCount == 1, "Changed event should have been called");
\r
849 public void OnChanging(object sender, ComposablePartCatalogChangeEventArgs args)
\r
851 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
\r
853 if (this._expectedAdds == null)
\r
855 EnumerableAssert.IsEmpty(args.AddedDefinitions);
\r
859 EnumerableAssert.AreSequenceEqual(this._expectedAdds, GetDisplayNames(args.AddedDefinitions));
\r
862 if (this._expectedRemoves == null)
\r
864 EnumerableAssert.IsEmpty(args.RemovedDefinitions);
\r
868 EnumerableAssert.AreSequenceEqual(this._expectedRemoves, GetDisplayNames(args.RemovedDefinitions));
\r
871 Assert.IsFalse(ContainsChanges(), "The catalog should NOT contain the changes yet");
\r
873 this._changingEventCount++;
\r
876 public void OnChanged(object sender, ComposablePartCatalogChangeEventArgs args)
\r
878 Assert.IsTrue(this._expectedAdds != null || this._expectedRemoves != null);
\r
880 if (this._expectedAdds == null)
\r
882 EnumerableAssert.IsEmpty(args.AddedDefinitions);
\r
886 EnumerableAssert.AreSequenceEqual(this._expectedAdds, GetDisplayNames(args.AddedDefinitions));
\r
889 if (this._expectedRemoves == null)
\r
891 EnumerableAssert.IsEmpty(args.RemovedDefinitions);
\r
895 EnumerableAssert.AreSequenceEqual(this._expectedRemoves, GetDisplayNames(args.RemovedDefinitions));
\r
898 Assert.IsNull(args.AtomicComposition);
\r
899 Assert.IsTrue(ContainsChanges(), "The catalog should contain the changes");
\r
901 this._changedEventCount++;
\r
904 private bool ContainsChanges()
\r
906 var allParts = GetDisplayNames(this._watchedCatalog.Parts);
\r
908 if (this._expectedAdds != null)
\r
910 foreach (var add in this._expectedAdds)
\r
912 if (!allParts.Contains(add))
\r
919 if (this._expectedRemoves != null)
\r
921 foreach (var remove in this._expectedRemoves)
\r
923 if (allParts.Contains(remove))
\r
933 private void ResetState()
\r
935 this._expectedAdds = null;
\r
936 this._expectedRemoves = null;
\r
937 this._changedEventCount = 0;
\r
938 this._changingEventCount = 0;
\r
941 private static string[] GetDisplayNames(IEnumerable<ComposablePartDefinition> definitions)
\r
943 return definitions.OfType<ICompositionElement>().Select(p => p.DisplayName).ToArray();
\r
946 private static string[] GetDisplayNames(IEnumerable<Type> types)
\r
948 return GetDisplayNames(types.Select(t => AttributedModelServices.CreatePartDefinition(t, null)));
\r
953 [PartCreationPolicy(CreationPolicy.Shared)]
\r
954 public class SharedPartStuff
\r
956 Guid id = Guid.NewGuid();
\r
958 public override string ToString()
\r
960 return id.ToString();
\r