1
// -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
5 using System
.Collections
.Generic
;
6 using System
.ComponentModel
.Composition
.Factories
;
7 using System
.ComponentModel
.Composition
.Hosting
;
8 using System
.ComponentModel
.Composition
.Primitives
;
11 using System
.Linq
.Expressions
;
12 using System
.Threading
;
13 using System
.UnitTesting
;
14 using Microsoft
.VisualStudio
.TestTools
.UnitTesting
;
16 namespace System
.ComponentModel
.Composition
.Hosting
19 public class AggregateCatalogTest
22 public void Constructor1_ShouldNotThrow()
24 new AggregateCatalog();
29 public void Constructor1_ShouldSetCatalogsPropertyToEmpty()
31 var catalog
= new AggregateCatalog();
33 EnumerableAssert
.IsEmpty(catalog
.Catalogs
);
39 public void Constructor1_ShouldSetPartsPropertyToEmpty()
41 var catalog
= new AggregateCatalog();
43 EnumerableAssert
.IsEmpty(catalog
.Parts
);
47 public void Constructor3_NullAsCatalogsArgument_ShouldSetCatalogsPropertyToEmpty()
49 var catalog
= new AggregateCatalog((IEnumerable
<ComposablePartCatalog
>)null);
51 EnumerableAssert
.IsEmpty(catalog
.Catalogs
);
55 public void Constructor3_EmptyIEnumerableAsCatalogsArgument_ShouldSetCatalogsPropertyToEmpty()
57 var catalog
= new AggregateCatalog(Enumerable
.Empty
<ComposablePartCatalog
>());
59 EnumerableAssert
.IsEmpty(catalog
.Catalogs
);
65 public void Constructor3_NullAsCatalogsArgument_ShouldSetPartsPropertyToEmpty()
67 var catalog
= new AggregateCatalog((IEnumerable
<ComposablePartCatalog
>)null);
69 EnumerableAssert
.IsEmpty(catalog
.Parts
);
75 public void Constructor3_EmptyIEnumerableAsCatalogsArgument_ShouldSetPartsPropertyToEmpty()
77 var catalog
= new AggregateCatalog(Enumerable
.Empty
<ComposablePartCatalog
>());
79 EnumerableAssert
.IsEmpty(catalog
.Parts
);
83 public void Constructor3_ArrayWithNullAsCatalogsArgument_ShouldThrowArgument()
85 var catalogs
= new ComposablePartCatalog
[] { null }
;
87 ExceptionAssert
.ThrowsArgument
<ArgumentException
>("catalogs", () =>
89 new AggregateCatalog(catalogs
);
94 public void Catalogs_WhenCatalogDisposed_ShouldThrowObjectDisposed()
96 var catalog
= CreateAggregateCatalog();
99 ExceptionAssert
.ThrowsDisposed(catalog
, () =>
101 var catalogs
= catalog
.Catalogs
;
106 public void Parts_WhenCatalogDisposed_ShouldThrowObjectDisposed()
108 var catalog
= CreateAggregateCatalog();
111 ExceptionAssert
.ThrowsDisposed(catalog
, () =>
113 var parts
= catalog
.Parts
;
118 public void GetExports_WhenCatalogDisposed_ShouldThrowObjectDisposed()
120 var catalog
= CreateAggregateCatalog();
122 var definition
= ImportDefinitionFactory
.Create();
124 ExceptionAssert
.ThrowsDisposed(catalog
, () =>
126 catalog
.GetExports(definition
);
131 public void GetExports_NullAsConstraintArgument_ShouldThrowArgumentNull()
133 var catalog
= CreateAggregateCatalog();
135 ExceptionAssert
.ThrowsArgument
<ArgumentNullException
>("definition", () =>
137 catalog
.GetExports((ImportDefinition
)null);
142 public void Dispose_ShouldNotThrow()
144 using (var catalog
= CreateAggregateCatalog())
150 public void Dispose_CanBeCalledMultipleTimes()
152 var catalog
= CreateAggregateCatalog();
160 public void MutableCatalogNotifications()
164 var catalog
= new AggregateCatalog();
166 var typePartCatalog
= new TypeCatalog(typeof(SharedPartStuff
));
167 var typePartCatalog1
= new TypeCatalog(typeof(SharedPartStuff
));
168 var typePartCatalog2
= new TypeCatalog(typeof(SharedPartStuff
));
169 var typePartCatalog3
= new TypeCatalog(typeof(SharedPartStuff
));
170 var typePartCatalog4
= new TypeCatalog(typeof(SharedPartStuff
));
171 var typePartCatalog5
= new TypeCatalog(typeof(SharedPartStuff
));
173 // Smoke test on inner collection
174 catalog
.Catalogs
.Add(typePartCatalog
);
175 catalog
.Catalogs
.Remove(typePartCatalog
);
176 catalog
.Catalogs
.Clear();
177 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add/Remove/Clear -- PartsAsCollection.Count is now 0");
180 catalog
.Changed
+= delegate(object source
, ComposablePartCatalogChangeEventArgs args
)
187 //Add something then verify counters
188 catalog
.Catalogs
.Add(typePartCatalog
);
189 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1, "Add -- Catalogs.Count is now 1");
190 Assert
.IsTrue(changedStep
== 2, "Add -- Changed must be fired after");
193 step
= changedStep
= 0;
195 // Remove something then verify counters
196 catalog
.Catalogs
.Remove(typePartCatalog
);
197 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add -- Catalogs.Count is now 0");
198 Assert
.IsTrue(changedStep
== 2, "Remove -- Changed must be fired after");
202 catalog
.Catalogs
.Add(typePartCatalog
);
203 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1, "Add -- Catalogs.Count is now 1");
205 step
= changedStep
= 0;
206 // Now clear the collection and verify counters
207 catalog
.Catalogs
.Clear();
208 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add -- Catalogs.Count is now 0");
209 Assert
.IsTrue(changedStep
== 2, "Remove -- Changed must be fired after");
211 // Now remove a non existent item and verify counters
212 step
= changedStep
= 0;
213 bool removed
= catalog
.Catalogs
.Remove(typePartCatalog
);
214 Assert
.IsTrue(removed
== false, "Remove -- correctly returned false");
215 Assert
.IsTrue(changedStep
== 0, "Remove -- Changed should not fire if nothing changed");
218 step
= changedStep
= 0;
219 catalog
.Catalogs
.Add(typePartCatalog
);
220 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1, "Add -- Catalogs.Count is now 1");
221 Assert
.IsTrue(changedStep
== 2, "Add -- Changed must be fired after");
223 catalog
.Catalogs
.Add(typePartCatalog1
);
224 Assert
.IsTrue(catalog
.Catalogs
.Count
== 2, "Add -- Catalogs.Count is now 1");
225 Assert
.IsTrue(changedStep
== 4, "Add -- Changing must be fired after");
227 catalog
.Catalogs
.Add(typePartCatalog2
);
228 catalog
.Catalogs
.Add(typePartCatalog3
);
229 catalog
.Catalogs
.Add(typePartCatalog4
);
230 catalog
.Catalogs
.Add(typePartCatalog5
);
231 Assert
.IsTrue(catalog
.Catalogs
.Count
== 6, "Add -- Catalogs.Count is now 1");
232 Assert
.IsTrue(changedStep
== 12, "Add -- Changing must be fired after");
234 removed
= catalog
.Catalogs
.Remove(typePartCatalog3
);
235 Assert
.IsTrue(catalog
.Catalogs
.Count
== 5, "Add -- Catalogs.Count is now 5");
236 Assert
.IsTrue(removed
== true, "Remove should have succeeded");
237 Assert
.IsTrue(changedStep
== 14, "Remove -- Changed must be fired after");
238 removed
= catalog
.Catalogs
.Remove(typePartCatalog2
);
239 removed
= catalog
.Catalogs
.Remove(typePartCatalog1
);
240 removed
= catalog
.Catalogs
.Remove(typePartCatalog4
);
241 removed
= catalog
.Catalogs
.Remove(typePartCatalog
);
242 removed
= catalog
.Catalogs
.Remove(typePartCatalog5
);
243 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add -- Catalogs.Count is now 0");
244 Assert
.IsTrue(removed
== true, "Remove should have succeeded");
245 Assert
.IsTrue(changedStep
== 24, "Remove -- Changing must be fired after");
247 // Add and then clear a lot
248 step
= changedStep
= 0;
249 catalog
.Catalogs
.Add(typePartCatalog
);
250 catalog
.Catalogs
.Add(typePartCatalog1
);
251 catalog
.Catalogs
.Add(typePartCatalog2
);
252 catalog
.Catalogs
.Add(typePartCatalog3
);
253 catalog
.Catalogs
.Add(typePartCatalog4
);
254 catalog
.Catalogs
.Add(typePartCatalog5
);
255 Assert
.IsTrue(catalog
.Catalogs
.Count
== 6, "Add -- Catalogs.Count should be 6");
256 Assert
.IsTrue(changedStep
== 12, "Add -- Changing must be fired after");
258 catalog
.Catalogs
.Clear();
259 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add -- Catalogs.Count should be 0");
261 step
= changedStep
= 0;
263 int changedStep2
= 0;
265 catalog
.Changed
+= delegate(object source
, ComposablePartCatalogChangeEventArgs args
)
269 changedStep2
= step2
;
272 catalog
.Catalogs
.Add(typePartCatalog
);
273 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1, "Add -- Catalogs.Count is now 1");
274 Assert
.IsTrue(changedStep
== 2, "Add handler 1 -- Changed must be fired after");
275 Assert
.IsTrue(changedStep2
== 98, "Add handler 2 -- Changed must be fired after");
277 catalog
.Catalogs
.Add(typePartCatalog1
);
278 Assert
.IsTrue(catalog
.Catalogs
.Count
== 2, "Add -- Catalogs.Count is now 1");
279 Assert
.IsTrue(changedStep
== 4, "Add handler 1 -- Changed must be fired after");
280 Assert
.IsTrue(changedStep2
== 96, "Add handler 2 -- Changed must be firedafter");
282 catalog
.Catalogs
.Remove(typePartCatalog
);
283 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1, "Add -- PartsAsCollection.Count is now 1");
284 Assert
.IsTrue(changedStep
== 6, "Add handler 1 -- Changed must be fired and fired after");
285 Assert
.IsTrue(changedStep2
== 94, "Add handler 2 -- Changed must be fired and fired after");
287 catalog
.Catalogs
.Clear();
288 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Add -- PartsAsCollection.Count is now 0");
289 Assert
.IsTrue(changedStep
== 8, "Add handler 1 -- Changed must be fired after");
290 Assert
.IsTrue(changedStep2
== 92, "Add handler 2 -- Changed must be fired after");
295 public void DisposeAggregatingCatalog()
297 int changedNotification
= 0;
299 var typePartCatalog1
= new TypeCatalog(typeof(SharedPartStuff
));
300 var typePartCatalog2
= new TypeCatalog(typeof(SharedPartStuff
));
301 var typePartCatalog3
= new TypeCatalog(typeof(SharedPartStuff
));
303 var assemblyPartCatalog1
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
304 var assemblyPartCatalog2
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
305 var assemblyPartCatalog3
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
308 var dirPartCatalog1
= new DirectoryCatalog(FileIO
.GetRootTemporaryDirectory());
309 var dirPartCatalog2
= new DirectoryCatalog(FileIO
.GetRootTemporaryDirectory());
310 var dirPartCatalog3
= new DirectoryCatalog(FileIO
.GetRootTemporaryDirectory());
312 using (var catalog
= new AggregateCatalog())
314 catalog
.Catalogs
.Add(typePartCatalog1
);
315 catalog
.Catalogs
.Add(typePartCatalog2
);
316 catalog
.Catalogs
.Add(typePartCatalog3
);
318 catalog
.Catalogs
.Add(assemblyPartCatalog1
);
319 catalog
.Catalogs
.Add(assemblyPartCatalog2
);
320 catalog
.Catalogs
.Add(assemblyPartCatalog3
);
323 catalog
.Catalogs
.Add(dirPartCatalog1
);
324 catalog
.Catalogs
.Add(dirPartCatalog2
);
325 catalog
.Catalogs
.Add(dirPartCatalog3
);
329 catalog
.Changed
+= delegate(object source
, ComposablePartCatalogChangeEventArgs args
)
332 ++changedNotification
;
337 Assert
.IsTrue(changedNotification
== 0, "No changed notifications");
339 //Ensure that the other catalogs are
340 ExceptionAssert
.ThrowsDisposed(typePartCatalog1
, () =>
342 var iEnum
= typePartCatalog1
.Parts
.GetEnumerator();
345 ExceptionAssert
.ThrowsDisposed(typePartCatalog2
, () =>
347 var iEnum
= typePartCatalog2
.Parts
.GetEnumerator();
350 ExceptionAssert
.ThrowsDisposed(typePartCatalog3
, () =>
352 var iEnum
= typePartCatalog3
.Parts
.GetEnumerator();
355 //Ensure that the other catalogs are
356 ExceptionAssert
.ThrowsDisposed(assemblyPartCatalog1
, () =>
358 var iEnum
= assemblyPartCatalog1
.Parts
.GetEnumerator();
361 ExceptionAssert
.ThrowsDisposed(assemblyPartCatalog2
, () =>
363 var iEnum
= assemblyPartCatalog2
.Parts
.GetEnumerator();
366 ExceptionAssert
.ThrowsDisposed(assemblyPartCatalog3
, () =>
368 var iEnum
= assemblyPartCatalog3
.Parts
.GetEnumerator();
372 //Ensure that the other catalogs are
373 ExceptionAssert
.ThrowsDisposed(dirPartCatalog1
, () =>
375 var iEnum
= dirPartCatalog1
.Parts
.GetEnumerator();
378 ExceptionAssert
.ThrowsDisposed(dirPartCatalog2
, () =>
380 var iEnum
= dirPartCatalog2
.Parts
.GetEnumerator();
383 ExceptionAssert
.ThrowsDisposed(dirPartCatalog3
, () =>
385 var iEnum
= dirPartCatalog3
.Parts
.GetEnumerator();
393 public void MutableMultithreadedEnumerations()
395 var catalog
= new AggregateCatalog();
397 ThreadStart func
= delegate()
399 var typePart
= new TypeCatalog(typeof(SharedPartStuff
));
400 var typePart1
= new TypeCatalog(typeof(SharedPartStuff
));
401 var typePart2
= new TypeCatalog(typeof(SharedPartStuff
));
402 var typePart3
= new TypeCatalog(typeof(SharedPartStuff
));
403 var typePart4
= new TypeCatalog(typeof(SharedPartStuff
));
404 var typePart5
= new TypeCatalog(typeof(SharedPartStuff
));
406 for (int i
= 0; i
< 100; i
++)
408 catalog
.Catalogs
.Add(typePart
);
409 catalog
.Catalogs
.Add(typePart1
);
410 catalog
.Catalogs
.Add(typePart2
);
411 catalog
.Catalogs
.Add(typePart3
);
412 catalog
.Catalogs
.Add(typePart4
);
413 catalog
.Catalogs
.Add(typePart5
);
415 Assert
.IsTrue(catalog
.Catalogs
.Count
>= 6, "Catalogs Collection must be at least 6 big");
417 for (int k
= 0; k
< 5; k
++)
420 // Ensure that iterating the returned queryable is okay even though there are many threads mutationg it
421 // We are really just looking to ensure that ollection changed exceptions are not thrown
423 var iq
= catalog
.Parts
.GetEnumerator();
424 while (iq
.MoveNext())
429 Assert
.IsTrue(j
>= 6, "Catalogs Collection must be at least 6 big");
431 // Ensure that iterating the returned enumerator is okay even though there are many threads mutationg it
432 // We are really just looking to ensure that collection changed exceptions are not thrown
434 var ie
= catalog
.Catalogs
.GetEnumerator();
435 while (ie
.MoveNext())
439 Assert
.IsTrue(j
>= 6, "Catalogs Collection must be at least 6 big");
443 catalog
.Catalogs
.Remove(typePart
);
444 catalog
.Catalogs
.Remove(typePart1
);
445 catalog
.Catalogs
.Remove(typePart2
);
446 catalog
.Catalogs
.Remove(typePart3
);
447 catalog
.Catalogs
.Remove(typePart4
);
448 catalog
.Catalogs
.Remove(typePart5
);
452 Thread
[] threads
= new Thread
[100];
453 for (int i
= 0; i
< threads
.Length
; i
++)
455 threads
[i
] = new Thread(func
);
458 for (int i
= 0; i
< threads
.Length
; i
++)
462 for (int i
= 0; i
< threads
.Length
; i
++)
467 Assert
.IsTrue(catalog
.Catalogs
.Count
== 0, "Collection must be empty");
471 public void CreateMainAndOtherChildren(
472 out AggregateCatalog
[] mainChildren
,
473 out AggregateCatalog
[] otherChildren
,
474 out TypeCatalog
[] componentCatalogs
)
476 componentCatalogs
= new TypeCatalog
[]
478 new TypeCatalog(typeof(SharedPartStuff
)),
479 new TypeCatalog(typeof(SharedPartStuff
)),
480 new TypeCatalog(typeof(SharedPartStuff
))
483 // Create our child catalogs
484 mainChildren
= new AggregateCatalog
[5];
485 for (int i
= 0; i
< mainChildren
.Length
; i
++)
487 mainChildren
[i
] = new AggregateCatalog(componentCatalogs
);
490 otherChildren
= new AggregateCatalog
[5];
491 for (int i
= 0; i
< otherChildren
.Length
; i
++)
493 otherChildren
[i
] = new AggregateCatalog(componentCatalogs
);
500 public void AggregatingCatalogAddAndRemoveChildren()
502 int changedCount
= 0;
503 int typesChanged
= 0;
504 EventHandler
<ComposablePartCatalogChangeEventArgs
> onChanged
= delegate(object sender
, ComposablePartCatalogChangeEventArgs e
)
507 typesChanged
+= e
.AddedDefinitions
.Concat(e
.RemovedDefinitions
).Count();
510 // Create our child catalogs
511 AggregateCatalog
[] mainChildren
;
512 AggregateCatalog
[] otherChildren
;
513 TypeCatalog
[] componentCatalogs
;
515 CreateMainAndOtherChildren(out mainChildren
, out otherChildren
, out componentCatalogs
);
517 var parent
= new AggregateCatalog(mainChildren
);
518 parent
.Changed
+= onChanged
;
520 for (int i
= 0; i
< otherChildren
.Length
; i
++)
522 parent
.Catalogs
.Add(otherChildren
[i
]);
525 Assert
.AreEqual(otherChildren
.Length
, changedCount
);
526 Assert
.AreEqual(otherChildren
.Length
* 3, typesChanged
);
531 parent
.Catalogs
.Remove(otherChildren
[0]);
532 parent
.Catalogs
.Remove(otherChildren
[1]);
534 Assert
.AreEqual(2, changedCount
);
535 Assert
.AreEqual(2 * 3, typesChanged
);
540 parent
.Catalogs
.Add(otherChildren
[0]);
541 parent
.Catalogs
.Add(otherChildren
[1]);
543 Assert
.AreEqual(2, changedCount
);
544 Assert
.AreEqual(2 * 3, typesChanged
);
549 parent
.Catalogs
.Clear();
550 Assert
.AreEqual(1, changedCount
);
551 Assert
.AreEqual((mainChildren
.Length
+ otherChildren
.Length
) * 3, typesChanged
);
556 // These have already been removed and so I should be able remove components from them without recieving notifications
557 otherChildren
[0].Catalogs
.Remove(componentCatalogs
[0]);
558 otherChildren
[1].Catalogs
.Remove(componentCatalogs
[1]);
559 Assert
.AreEqual(0, changedCount
);
560 Assert
.AreEqual(0, typesChanged
);
562 // These have already been Cleared and so I should be able remove components from them without recieving notifications
563 otherChildren
[3].Catalogs
.Remove(componentCatalogs
[0]);
564 otherChildren
[4].Catalogs
.Remove(componentCatalogs
[1]);
565 Assert
.AreEqual(0, changedCount
);
571 public void AggregatingCatalogAddAndRemoveNestedChildren()
573 int changedCount
= 0;
574 int typesChanged
= 0;
576 EventHandler
<ComposablePartCatalogChangeEventArgs
> onChanged
= delegate(object sender
, ComposablePartCatalogChangeEventArgs e
)
579 typesChanged
+= e
.AddedDefinitions
.Concat(e
.RemovedDefinitions
).Count();
582 // Create our child catalogs
583 AggregateCatalog
[] mainChildren
;
584 AggregateCatalog
[] otherChildren
;
585 TypeCatalog
[] componentCatalogs
;
586 CreateMainAndOtherChildren(out mainChildren
, out otherChildren
, out componentCatalogs
);
589 var parent
= new AggregateCatalog(mainChildren
);
590 parent
.Changed
+= onChanged
;
592 for (int i
= 0; i
< otherChildren
.Length
; i
++)
594 parent
.Catalogs
.Add(otherChildren
[i
]);
597 Assert
.AreEqual(otherChildren
.Length
, changedCount
);
598 Assert
.AreEqual(otherChildren
.Length
* 3, typesChanged
);
603 otherChildren
[0].Catalogs
.Remove(componentCatalogs
[0]);
604 otherChildren
[1].Catalogs
.Remove(componentCatalogs
[1]);
606 Assert
.AreEqual(2, changedCount
);
607 Assert
.AreEqual(2, typesChanged
);
612 otherChildren
[0].Catalogs
.Add(componentCatalogs
[0]);
613 otherChildren
[1].Catalogs
.Add(componentCatalogs
[1]);
615 Assert
.AreEqual(2, changedCount
);
616 Assert
.AreEqual(2, typesChanged
);
620 otherChildren
[1].Catalogs
.Clear();
621 Assert
.AreEqual(1, changedCount
);
622 Assert
.AreEqual(componentCatalogs
.Length
, typesChanged
);
628 public void AggregatingDisposedAndNotifications()
630 int changedCount
= 0;
631 int typesChanged
= 0;
633 EventHandler
<ComposablePartCatalogChangeEventArgs
> onChanged
= delegate(object sender
, ComposablePartCatalogChangeEventArgs e
)
636 typesChanged
+= e
.AddedDefinitions
.Concat(e
.RemovedDefinitions
).Count();
639 // Create our child catalogs
640 AggregateCatalog
[] mainChildren
;
641 AggregateCatalog
[] otherChildren
;
642 TypeCatalog
[] componentCatalogs
;
643 CreateMainAndOtherChildren(out mainChildren
, out otherChildren
, out componentCatalogs
);
646 var parent
= new AggregateCatalog(mainChildren
);
647 parent
.Changed
+= onChanged
;
649 for (int i
= 0; i
< otherChildren
.Length
; i
++)
651 parent
.Catalogs
.Add(otherChildren
[i
]);
654 Assert
.AreEqual(otherChildren
.Length
, changedCount
);
655 Assert
.AreEqual(otherChildren
.Length
* 3, typesChanged
);
662 Assert
.AreEqual(0, changedCount
);
663 Assert
.AreEqual(0, typesChanged
);
665 //Ensure that the children are also disposed
666 ExceptionAssert
.ThrowsDisposed(otherChildren
[0], () =>
668 otherChildren
[0].Catalogs
.Remove(componentCatalogs
[0]);
671 //Ensure that the children are also disposed
672 ExceptionAssert
.ThrowsDisposed(otherChildren
[4], () =>
674 otherChildren
[4].Catalogs
.Remove(componentCatalogs
[0]);
677 Assert
.AreEqual(0, changedCount
);
678 Assert
.AreEqual(0, typesChanged
);
682 public void AggregatingCatalogParmsConstructorAggregateAggregateCatalogs()
684 var aggCatalog1
= new AggregateCatalog();
685 var aggCatalog2
= new AggregateCatalog();
686 var aggCatalog3
= new AggregateCatalog();
688 // Construct with one catalog parameter
689 var catalog
= new AggregateCatalog(aggCatalog1
);
690 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1);
692 // Construct with two catalog parameters
693 catalog
= new AggregateCatalog(aggCatalog1
, aggCatalog2
);
694 Assert
.IsTrue(catalog
.Catalogs
.Count
== 2);
696 // Construct with three catalog parameters
697 catalog
= new AggregateCatalog(aggCatalog1
, aggCatalog2
, aggCatalog3
);
698 Assert
.IsTrue(catalog
.Catalogs
.Count
== 3);
703 public void AggregatingCatalogParmsConstructorAggregateAssemblyCatalogs()
705 var assemblyCatalog1
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
706 var assemblyCatalog2
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
707 var assemblyCatalog3
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
709 // Construct with one catalog parameter
710 var catalog
= new AggregateCatalog(assemblyCatalog1
);
711 Assert
.IsTrue(catalog
.Catalogs
.Count
== 1);
713 // Construct with two catalog parameters
714 catalog
= new AggregateCatalog(assemblyCatalog1
, assemblyCatalog2
);
715 Assert
.IsTrue(catalog
.Catalogs
.Count
== 2);
717 // Construct with three catalog parameters
718 catalog
= new AggregateCatalog(assemblyCatalog1
, assemblyCatalog2
, assemblyCatalog3
);
719 Assert
.IsTrue(catalog
.Catalogs
.Count
== 3);
723 public void AggregatingCatalogParmsConstructorMixedCatalogs()
725 var typePartCatalog1
= new TypeCatalog(typeof(SharedPartStuff
));
726 var assemblyCatalog2
= new AssemblyCatalog(typeof(SharedPartStuff
).Assembly
);
727 var typePartCatalog3
= new TypeCatalog(typeof(SharedPartStuff
));
729 // Construct with three catalog parameters
730 var catalog
= new AggregateCatalog(typePartCatalog1
, assemblyCatalog2
, typePartCatalog3
);
731 Assert
.IsTrue(catalog
.Catalogs
.Count
== 3);
735 public void AggregatingCatalogRaisesChangesForCatalogsPassedToConstructor()
737 var subCatalog
= CreateAggregateCatalog();
738 var testCatalog
= new AggregateCatalog(subCatalog
);
740 bool changedCalled
= false;
741 testCatalog
.Changed
+= delegate
743 changedCalled
= true;
746 subCatalog
.Catalogs
.Add(new TypeCatalog(typeof(SharedPartStuff
)));
748 Assert
.IsTrue(changedCalled
);
751 private AggregateCatalog
CreateAggregateCatalog()
753 return new AggregateCatalog();
759 public void CatalogEvents_AggregateAddRemove()
761 var catalog
= new AggregateCatalog();
762 AggregateTests(catalog
, catalog
);
768 public void CatalogEvents_DeepAggregateAddRemove()
770 var deepCatalog
= new AggregateCatalog();
771 var midCatalog
= new AggregateCatalog(new ComposablePartCatalog
[] { deepCatalog }
);
772 var topCatalog
= new AggregateCatalog(new ComposablePartCatalog
[] { midCatalog }
);
773 AggregateTests(topCatalog
, deepCatalog
);
776 private void AggregateTests(AggregateCatalog watchedCatalog
, AggregateCatalog modifiedCatalog
)
778 var fooCatalog
= new TypeCatalog(new Type
[] { typeof(FooExporter) }
);
779 var barCatalog
= new TypeCatalog(new Type
[] { typeof(BarExporter) }
);
780 var bothCatalog
= new TypeCatalog(new Type
[] { typeof(FooExporter), typeof(BarExporter) }
);
782 var catalogListener
= new CatalogListener(watchedCatalog
, modifiedCatalog
);
784 catalogListener
.VerifyAdd(fooCatalog
, typeof(FooExporter
));
785 catalogListener
.VerifyAdd(barCatalog
, typeof(BarExporter
));
786 catalogListener
.VerifyRemove(fooCatalog
, typeof(FooExporter
));
787 catalogListener
.VerifyRemove(barCatalog
, typeof(BarExporter
));
789 catalogListener
.VerifyAdd(bothCatalog
, typeof(FooExporter
), typeof(BarExporter
));
790 catalogListener
.VerifyClear(typeof(FooExporter
), typeof(BarExporter
));
792 catalogListener
.VerifyAdd(bothCatalog
, typeof(FooExporter
), typeof(BarExporter
));
793 catalogListener
.VerifyRemove(bothCatalog
, typeof(FooExporter
), typeof(BarExporter
));
797 public interface IFoo { }
798 public interface IBar { }
800 [Export(typeof(IFoo
))]
801 public class FooExporter
: IFoo
805 [Export(typeof(IBar
))]
806 public class BarExporter
: IBar
810 public class CatalogListener
812 private AggregateCatalog _watchedCatalog
;
813 private AggregateCatalog _modifiedCatalog
;
814 private string[] _expectedAdds
;
815 private string[] _expectedRemoves
;
816 private int _changedEventCount
;
817 private int _changingEventCount
;
819 public CatalogListener(AggregateCatalog watchCatalog
, AggregateCatalog modifiedCatalog
)
821 watchCatalog
.Changing
+= OnChanging
;
822 watchCatalog
.Changed
+= OnChanged
;
823 this._watchedCatalog
= watchCatalog
;
824 this._modifiedCatalog
= modifiedCatalog
;
827 public void VerifyAdd(ComposablePartCatalog catalogToAdd
, params Type
[] expectedTypesAdded
)
829 this._expectedAdds
= GetDisplayNames(expectedTypesAdded
);
831 this._modifiedCatalog
.Catalogs
.Add(catalogToAdd
);
833 Assert
.IsTrue(this._changingEventCount
== 1, "Changing event should have been called");
834 Assert
.IsTrue(this._changedEventCount
== 1, "Changed event should have been called");
839 public void VerifyRemove(ComposablePartCatalog catalogToRemove
, params Type
[] expectedTypesRemoved
)
841 this._expectedAdds
= null;
842 this._expectedRemoves
= GetDisplayNames(expectedTypesRemoved
);
844 this._modifiedCatalog
.Catalogs
.Remove(catalogToRemove
);
846 Assert
.IsTrue(this._changingEventCount
== 1, "Changing event should have been called");
847 Assert
.IsTrue(this._changedEventCount
== 1, "Changed event should have been called");
852 public void VerifyClear(params Type
[] expectedTypesRemoved
)
854 this._expectedAdds
= null;
855 this._expectedRemoves
= GetDisplayNames(expectedTypesRemoved
);
857 this._modifiedCatalog
.Catalogs
.Clear();
859 Assert
.IsTrue(this._changingEventCount
== 1, "Changing event should have been called");
860 Assert
.IsTrue(this._changedEventCount
== 1, "Changed event should have been called");
865 public void OnChanging(object sender
, ComposablePartCatalogChangeEventArgs args
)
867 Assert
.IsTrue(this._expectedAdds
!= null || this._expectedRemoves
!= null);
869 if (this._expectedAdds
== null)
871 EnumerableAssert
.IsEmpty(args
.AddedDefinitions
);
875 EnumerableAssert
.AreSequenceEqual(this._expectedAdds
, GetDisplayNames(args
.AddedDefinitions
));
878 if (this._expectedRemoves
== null)
880 EnumerableAssert
.IsEmpty(args
.RemovedDefinitions
);
884 EnumerableAssert
.AreSequenceEqual(this._expectedRemoves
, GetDisplayNames(args
.RemovedDefinitions
));
887 Assert
.IsFalse(ContainsChanges(), "The catalog should NOT contain the changes yet");
889 this._changingEventCount
++;
892 public void OnChanged(object sender
, ComposablePartCatalogChangeEventArgs args
)
894 Assert
.IsTrue(this._expectedAdds
!= null || this._expectedRemoves
!= null);
896 if (this._expectedAdds
== null)
898 EnumerableAssert
.IsEmpty(args
.AddedDefinitions
);
902 EnumerableAssert
.AreSequenceEqual(this._expectedAdds
, GetDisplayNames(args
.AddedDefinitions
));
905 if (this._expectedRemoves
== null)
907 EnumerableAssert
.IsEmpty(args
.RemovedDefinitions
);
911 EnumerableAssert
.AreSequenceEqual(this._expectedRemoves
, GetDisplayNames(args
.RemovedDefinitions
));
914 Assert
.IsNull(args
.AtomicComposition
);
915 Assert
.IsTrue(ContainsChanges(), "The catalog should contain the changes");
917 this._changedEventCount
++;
920 private bool ContainsChanges()
922 var allParts
= GetDisplayNames(this._watchedCatalog
.Parts
);
924 if (this._expectedAdds
!= null)
926 foreach (var add in this._expectedAdds
)
928 if (!allParts
.Contains(add))
935 if (this._expectedRemoves
!= null)
937 foreach (var remove in this._expectedRemoves
)
939 if (allParts
.Contains(remove))
949 private void ResetState()
951 this._expectedAdds
= null;
952 this._expectedRemoves
= null;
953 this._changedEventCount
= 0;
954 this._changingEventCount
= 0;
957 private static string[] GetDisplayNames(IEnumerable
<ComposablePartDefinition
> definitions
)
959 return definitions
.OfType
<ICompositionElement
>().Select(p
=> p
.DisplayName
).ToArray();
962 private static string[] GetDisplayNames(IEnumerable
<Type
> types
)
964 return GetDisplayNames(types
.Select(t
=> AttributedModelServices
.CreatePartDefinition(t
, null)));
969 [PartCreationPolicy(CreationPolicy
.Shared
)]
970 public class SharedPartStuff
972 Guid id
= Guid
.NewGuid();
974 public override string ToString()
976 return id
.ToString();