update MEF to preview 9
[mcs.git] / class / System.ComponentModel.Composition / Tests / ComponentModelUnitTest / System / ComponentModel / Composition / Hosting / CatalogExportProviderTests.cs
blob3e0eb928b815a3e5fc02d88194c27e961f024f3b
1 // -----------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // -----------------------------------------------------------------------
4 using System;
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.ComponentModel.Composition.Diagnostics;
8 using System.ComponentModel.Composition.Factories;
9 using System.ComponentModel.Composition.Hosting;
10 using System.ComponentModel.Composition.Primitives;
11 using System.Linq;
12 using System.UnitTesting;
13 using Microsoft.VisualStudio.TestTools.UnitTesting;
15 namespace System.ComponentModel.Composition
17 [TestClass]
18 public class ComposablePartCatalogExportProviderTests
20 [TestMethod]
21 public void Constructor_NullAsCatalogArgument_ShouldThrowArgumentNull()
23 ExceptionAssert.ThrowsArgument<ArgumentNullException>("catalog", () =>
25 new CatalogExportProvider((ComposablePartCatalog)null);
26 });
29 [TestMethod]
30 public void Constructor_ValueAsCatalogArgument_ShouldSetCatalogPropertyToEmpty()
32 var expectations = Expectations.GetCatalogs();
34 foreach (var e in expectations)
36 var provider = new CatalogExportProvider(e);
38 Assert.AreSame(e, provider.Catalog);
42 [TestMethod]
43 public void Catalog_WhenDisposed_ShouldThrowObjectDisposed()
45 var provider = CreateCatalogExportProvider();
46 provider.Dispose();
48 ExceptionAssert.ThrowsDisposed(provider, () =>
50 var catalog = provider.Catalog;
51 });
54 [TestMethod]
55 public void SourceProvider_NullAsValueArgument_ShouldThrowArgumentNull()
57 var provider = CreateCatalogExportProvider();
59 ExceptionAssert.ThrowsArgument<ArgumentNullException>("value", () =>
61 provider.SourceProvider = null;
62 });
65 [TestMethod]
66 public void GetExports_WhenRejectedDefinitionRequiredImportIsAdded_ShouldBeResurrected()
68 var part = PartFactory.CreateImporterExporter("Export", "Import");
70 var provider = CreateCatalogExportProvider(part);
71 var sourceProvider = ExportProviderFactory.CreateRecomposable();
72 provider.SourceProvider = sourceProvider;
74 var exports = provider.GetExports<object>("Export");
76 EnumerableAssert.IsEmpty(exports, "definition should have been rejected.");
78 // Resurrect the definition
79 sourceProvider.AddExport("Import", new object());
81 exports = provider.GetExports<object>("Export");
83 Assert.AreEqual(1, exports.Count(), "definition should have been resurrected.");
86 [TestMethod]
87 public void GetExports_WhenMultipleRejectedDefinitionsRequiredImportsAreAdded_ShouldBeResurrected()
89 var part1 = PartFactory.CreateImporterExporter("Export", "Import");
90 var part2 = PartFactory.CreateImporterExporter("Export", "Import");
92 var provider = CreateCatalogExportProvider(part1, part2);
93 var sourceProvider = ExportProviderFactory.CreateRecomposable();
94 provider.SourceProvider = sourceProvider;
96 var exports = provider.GetExports<object>("Export");
98 EnumerableAssert.IsEmpty(exports, "definition1 and definition2 should have been rejected.");
100 // Resurrect both definitions
101 sourceProvider.AddExport("Import", new object());
103 exports = provider.GetExports<object>("Export");
105 Assert.AreEqual(2, exports.Count(), "definition1 and definition2 should have been resurrected.");
108 [TestMethod]
109 [WorkItem(743740)]
110 public void GetExports_AfterResurrectedDefinitionHasBeenRemovedAndReaddedToCatalog_ShouldNotBeTreatedAsRejected()
112 var definition1 = PartDefinitionFactory.Create(PartFactory.CreateImporterExporter("Export", "Import"));
113 var definition2 = PartDefinitionFactory.Create(PartFactory.CreateImporterExporter("Export", "Import"));
114 var catalog = CatalogFactory.CreateMutable(definition1, definition2);
116 var provider = CreateCatalogExportProvider(catalog);
117 var sourceProvider = ExportProviderFactory.CreateRecomposable();
118 provider.SourceProvider = sourceProvider;
120 var exports = provider.GetExports<object>("Export");
122 EnumerableAssert.IsEmpty(exports, "definition1 and definition2 should have been rejected.");
124 // Resurrect both definitions
125 sourceProvider.AddExport("Import", new object());
127 exports = provider.GetExports<object>("Export");
129 Assert.AreEqual(2, exports.Count(), "definition1 and definition2 should have been resurrected.");
131 catalog.RemoveDefinition(definition1);
133 exports = provider.GetExports<object>("Export");
134 Assert.AreEqual(1, exports.Count(), "definition1 should have been removed.");
136 catalog.AddDefinition(definition1);
138 exports = provider.GetExports<object>("Export");
140 Assert.AreEqual(2, exports.Count(), "definition1 and definition2 should be both present.");
143 #if !SILVERLIGHT
145 [TestMethod]
146 public void GetExports_WhenDefinitionIsRejected_ShouldTraceWarning()
148 using (TraceContext context = new TraceContext(SourceLevels.Warning))
150 var part = PartFactory.CreateImporterExporter("Export", "Import");
151 var provider = CreateCatalogExportProvider(part);
152 provider.SourceProvider = ExportProviderFactory.CreateRecomposable();
154 ExceptionAssert.Throws<ImportCardinalityMismatchException>(() =>
156 provider.GetExport<object>("Export");
160 Assert.IsNotNull(context.LastTraceEvent);
161 Assert.AreEqual(context.LastTraceEvent.EventType, TraceEventType.Warning);
162 Assert.AreEqual(context.LastTraceEvent.Id, TraceId.Rejection_DefinitionRejected);
166 [TestMethod]
167 public void GetExports_WhenDefinitionIsResurrected_ShouldTraceInformation()
169 using (TraceContext context = new TraceContext(SourceLevels.Information))
171 var part = PartFactory.CreateImporterExporter("Export", "Import");
172 var sourceProvider = ExportProviderFactory.CreateRecomposable();
173 var provider = CreateCatalogExportProvider(part);
174 provider.SourceProvider = sourceProvider;
176 ExceptionAssert.Throws<ImportCardinalityMismatchException>(() =>
178 provider.GetExport<object>("Export");
181 // Add the required export to the source provider 'resurrect' the part
182 sourceProvider.AddExport("Import", "Value");
184 provider.GetExport<object>("Export");
186 Assert.IsNotNull(context.LastTraceEvent);
187 Assert.AreEqual(context.LastTraceEvent.EventType, TraceEventType.Information);
188 Assert.AreEqual(context.LastTraceEvent.Id, TraceId.Rejection_DefinitionResurrected);
192 [TestMethod]
193 public void GetExports_WhenDefinitionsAreResurrected_ShouldTraceInformation()
195 using (TraceContext context = new TraceContext(SourceLevels.Information))
197 var part1 = PartFactory.CreateImporterExporter("Export", "Import");
198 var part2 = PartFactory.CreateImporterExporter("Export", "Import");
200 var sourceProvider = ExportProviderFactory.CreateRecomposable();
201 var provider = CreateCatalogExportProvider(part1, part2);
202 provider.SourceProvider = sourceProvider;
204 EnumerableAssert.IsEmpty(provider.GetExports<object>("Export"));
206 // Add the required export to the source provider 'resurrect' the part
207 sourceProvider.AddExport("Import", "Value");
209 provider.GetExports<object>("Export");
211 Assert.AreEqual(4, context.TraceEvents.Count); // 2 for rejection, 2 for resurrection
212 Assert.AreEqual(context.TraceEvents[2].EventType, TraceEventType.Information);
213 Assert.AreEqual(context.TraceEvents[3].EventType, TraceEventType.Information);
214 Assert.AreEqual(context.TraceEvents[2].Id, TraceId.Rejection_DefinitionResurrected);
215 Assert.AreEqual(context.TraceEvents[3].Id, TraceId.Rejection_DefinitionResurrected);
218 #endif
220 [TestMethod]
221 [TestProperty("Type", "Integration")]
222 public void BasicTest()
224 var catalog = CatalogFactory.CreateDefaultAttributed();
225 var catalogExportProvider = new CatalogExportProvider(catalog);
226 catalogExportProvider.SourceProvider = catalogExportProvider;
227 var testName = AttributedModelServices.GetContractName(typeof(CatalogComponentTest));
228 var testNameNonComponent = AttributedModelServices.GetContractName(typeof(CatalogComponentTestNonComponentPart));
229 var testInterfaceName = AttributedModelServices.GetContractName(typeof(ICatalogComponentTest));
231 Assert.AreEqual(1, catalogExportProvider.GetExports(ImportFromContract(testName)).Count());
232 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContract(testNameNonComponent)).Count());
234 var exports = catalogExportProvider.GetExports(ImportFromContract(testInterfaceName));
235 Assert.AreEqual(2, exports.Count(), "There should be 2 of them");
237 foreach (var i in exports)
238 Assert.IsNotNull(i.Value, "Should get a value");
242 [TestMethod]
243 [TestProperty("Type", "Integration")]
244 public void BasicTestWithRequiredMetadata_NoTypeConstraint()
246 var catalog = CatalogFactory.CreateDefaultAttributed();
247 var catalogExportProvider = new CatalogExportProvider(catalog);
248 catalogExportProvider.SourceProvider = catalogExportProvider;
250 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] {typeof(object)})).Count());
252 Assert.AreEqual(1, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(object) })).Count());
253 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo", "Bar" }, new Type[] { typeof(object), typeof(object) })).Count());
255 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] { typeof(object) })).Count());
256 Assert.AreEqual(1, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(object) })).Count());
259 [TestMethod]
260 [TestProperty("Type", "Integration")]
261 public void BasicTestWithRequiredMetadata_TypeConstraint()
263 var catalog = CatalogFactory.CreateDefaultAttributed();
264 var catalogExportProvider = new CatalogExportProvider(catalog);
265 catalogExportProvider.SourceProvider = catalogExportProvider;
267 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] { typeof(string) })).Count());
269 Assert.AreEqual(1, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(string) })).Count());
270 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo", "Bar" }, new Type[] { typeof(string), typeof(string) })).Count());
272 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] { typeof(string) })).Count());
273 Assert.AreEqual(1, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(string) })).Count());
277 [TestMethod]
278 [TestProperty("Type", "Integration")]
279 public void BasicTestWithRequiredMetadata_WrongTypeConstraint()
281 var catalog = CatalogFactory.CreateDefaultAttributed();
282 var catalogExportProvider = new CatalogExportProvider(catalog);
283 catalogExportProvider.SourceProvider = catalogExportProvider;
285 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] { typeof(int) })).Count());
287 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(int) })).Count());
288 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo", "Bar" }, new Type[] { typeof(int), typeof(int) })).Count());
290 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithNoFoo", new string[] { "Foo" }, new Type[] { typeof(int) })).Count());
291 Assert.AreEqual(0, catalogExportProvider.GetExports(ImportFromContractAndMetadata("MyExporterWithFoo", new string[] { "Foo" }, new Type[] { typeof(int) })).Count());
295 [TestMethod]
296 [TestProperty("Type", "Integration")]
297 public void ComponentCatalogResolverGetStaticExport()
299 var catalog = CatalogFactory.CreateDefaultAttributed();
300 var catalogExportProvider = new CatalogExportProvider(catalog);
301 catalogExportProvider.SourceProvider = catalogExportProvider;
303 var exports = catalogExportProvider.GetExports(ImportFromContract("StaticString"));
304 Assert.AreEqual(1, exports.Count());
305 Assert.AreEqual("StaticString", exports.First().Value);
308 [TestMethod]
309 [TestProperty("Type", "Integration")]
310 public void ComponentCatalogResolverComponentCatalogExportReference()
312 var catalog = CatalogFactory.CreateDefaultAttributed();
313 var catalogExportProvider = new CatalogExportProvider(catalog);
314 catalogExportProvider.SourceProvider = catalogExportProvider;
316 var exports = catalogExportProvider.GetExports(ImportFromContract(AttributedModelServices.GetContractName(typeof(MyExporterWithValidMetadata))));
318 Assert.AreEqual(1, exports.Count());
320 var export = exports.First();
321 Assert.AreEqual("world", export.Metadata["hello"]);
323 Assert.IsInstanceOfType(export.Value, typeof(MyExporterWithValidMetadata));
326 [TestMethod]
327 [TestProperty("Type", "Integration")]
328 public void ValueTypeFromCatalog()
330 var catalog = CatalogFactory.CreateDefaultAttributed();
331 var container = new CompositionContainer(catalog);
332 int singletonResult = container.GetExportedValue<int>("{AssemblyCatalogResolver}SingletonValueType");
333 Assert.AreEqual(17, singletonResult, "expecting value type resolved from catalog");
334 int factoryResult = container.GetExportedValue<int>("{AssemblyCatalogResolver}FactoryValueType");
335 Assert.AreEqual(18, factoryResult, "expecting value type resolved from catalog");
338 [Export]
339 [PartCreationPolicy(CreationPolicy.Any)]
340 public class CreationPolicyAny
345 [TestMethod]
346 public void CreationPolicyAny_MultipleCallsReturnSameInstance()
348 var catalog = CatalogFactory.CreateAttributed(typeof (CreationPolicyAny));
349 var provider = new CatalogExportProvider(catalog);
350 provider.SourceProvider = ContainerFactory.Create();
352 var export = provider.GetExportedValue<CreationPolicyAny>();
354 for (int i = 0; i < 5; i++) // 5 is arbitrarily chosen
356 var export1 = provider.GetExportedValue<CreationPolicyAny>();
358 Assert.AreEqual(export, export1);
362 [Export]
363 [PartCreationPolicy(CreationPolicy.Shared)]
364 public class CreationPolicyShared
369 [TestMethod]
370 public void CreationPolicyShared_MultipleCallsReturnSameInstance()
372 var catalog = CatalogFactory.CreateAttributed(typeof(CreationPolicyShared));
373 var provider = new CatalogExportProvider(catalog);
374 provider.SourceProvider = ContainerFactory.Create();
376 var export = provider.GetExportedValue<CreationPolicyShared>();
378 for (int i = 0; i < 5; i++) // 5 is arbitrarily chosen
380 var export1 = provider.GetExportedValue<CreationPolicyShared>();
382 Assert.AreEqual(export, export1);
386 [Export]
387 [PartCreationPolicy(CreationPolicy.NonShared)]
388 public class CreationPolicyNonShared
393 [TestMethod]
394 public void CreationPolicyNonShared_MultipleCallsReturnsDifferentInstances()
396 var catalog = CatalogFactory.CreateAttributed(typeof(CreationPolicyNonShared));
397 var provider = new CatalogExportProvider(catalog);
398 provider.SourceProvider = ContainerFactory.Create();
400 List<CreationPolicyNonShared> list = new List<CreationPolicyNonShared>();
401 var export = provider.GetExportedValue<CreationPolicyNonShared>();
402 list.Add(export);
404 for (int i = 0; i < 5; i++) // 5 is arbitrarily chosen
406 export = provider.GetExportedValue<CreationPolicyNonShared>();
408 CollectionAssert.DoesNotContain(list, export);
409 list.Add(export);
413 [TestMethod]
414 [WorkItem(684514)]
415 public void GetExports_NoSourceProvider_ShouldThrowInvalidOperation()
417 var catalog = CatalogFactory.CreateAttributed();
418 var provider = new CatalogExportProvider(catalog);
420 ExceptionAssert.Throws<InvalidOperationException>(() =>
421 provider.GetExports(ImportFromContract("Foo")));
424 [TestMethod]
425 [TestProperty("Type", "Integration")]
426 [Ignore]
427 [WorkItem(561310)]
428 public void Recomposition_PartDefWithRecomposableImportIsRemoved_ExportsMatchingImportChanged_ShouldNotBeRecomposed()
430 string dependencyContractName = "dependency";
431 var exportValue = new object();
433 var exporterPart = PartFactory.CreateExporter(dependencyContractName, exportValue);
434 var importerPart = PartFactory.CreateImporter(dependencyContractName, true);
436 var exporterCatalog = CatalogFactory.Create(exporterPart);
437 var importerCatalog = CatalogFactory.Create(importerPart);
439 var aggregateCatalog = CatalogFactory.CreateAggregateCatalog(importerCatalog, exporterCatalog);
441 var provider = new CatalogExportProvider(aggregateCatalog);
442 provider.SourceProvider = provider;
444 var exports = provider.GetExports(importerPart.ImportDefinitions.Single());
445 Assert.AreEqual(exportValue, importerPart.Value, "Importer was not composed");
447 aggregateCatalog.Catalogs.Remove(importerCatalog);
448 aggregateCatalog.Catalogs.Remove(exporterCatalog);
450 Assert.AreEqual(exportValue, importerPart.Value, "Importer was unexpectedly recomposed");
453 [TestMethod]
454 [TestProperty("Type", "Integration")]
455 [Ignore]
456 [WorkItem(561310)]
457 public void Recomposition_PartDefWithNonRecomposableImportIsRemoved_ExportsMatchingImportChanged_ShouldNotBeRejected()
459 string dependencyContractName = "dependency";
460 var exportValue = new object();
462 var exporterPart = PartFactory.CreateExporter(dependencyContractName, exportValue);
463 var importerPart = PartFactory.CreateImporter(dependencyContractName, false);
465 var exporterCatalog = CatalogFactory.Create(exporterPart);
466 var importerCatalog = CatalogFactory.Create(importerPart);
468 var aggregateCatalog = CatalogFactory.CreateAggregateCatalog(importerCatalog, exporterCatalog);
470 var provider = new CatalogExportProvider(aggregateCatalog);
471 provider.SourceProvider = provider;
473 var exports = provider.GetExports(importerPart.ImportDefinitions.Single());
474 Assert.AreEqual(exportValue, importerPart.Value, "Importer was not composed");
476 aggregateCatalog.Catalogs.Remove(importerCatalog);
477 aggregateCatalog.Catalogs.Remove(exporterCatalog);
479 Assert.AreEqual(exportValue, importerPart.Value, "Importer was unexpectedly recomposed");
482 [TestMethod]
483 public void CanBeCollectedAfterDispose()
485 AggregateExportProvider sourceExportProvider = new AggregateExportProvider();
486 var catalog = new AggregateCatalog(CatalogFactory.CreateDefaultAttributed());
487 var catalogExportProvider = new CatalogExportProvider(catalog);
488 catalogExportProvider.SourceProvider = sourceExportProvider;
490 WeakReference weakCatalogExportProvider = new WeakReference(catalogExportProvider);
491 catalogExportProvider.Dispose();
492 catalogExportProvider = null;
494 GC.Collect();
495 GC.WaitForPendingFinalizers();
497 Assert.IsFalse(weakCatalogExportProvider.IsAlive);
499 GC.KeepAlive(sourceExportProvider);
500 GC.KeepAlive(catalog);
503 [TestMethod]
504 public void RemovingAndReAddingMultipleDefinitionsFromCatalog()
506 var fixedParts = new TypeCatalog(typeof(RootMultipleImporter), typeof(ExportedService));
507 var changingParts = new TypeCatalog(typeof(Exporter1), typeof(Exporter2));
508 var catalog = new AggregateCatalog();
509 catalog.Catalogs.Add(fixedParts);
510 catalog.Catalogs.Add(changingParts);
511 var catalogExportProvider = new CatalogExportProvider(catalog);
512 catalogExportProvider.SourceProvider = catalogExportProvider;
514 var root = catalogExportProvider.GetExport<RootMultipleImporter>().Value;
515 Assert.AreEqual(2, root.Imports.Length);
517 catalog.Catalogs.Remove(changingParts);
518 Assert.AreEqual(0, root.Imports.Length);
520 catalog.Catalogs.Add(changingParts);
521 Assert.AreEqual(2, root.Imports.Length);
524 [Export]
525 public class RootMultipleImporter
527 [ImportMany(AllowRecomposition = true)]
528 public IExportedInterface[] Imports { get; set; }
530 public interface IExportedInterface
533 [Export(typeof(IExportedInterface))]
534 public class Exporter1 : IExportedInterface
536 [Import]
537 public ExportedService Service { get; set; }
539 [Export(typeof(IExportedInterface))]
540 public class Exporter2 : IExportedInterface
542 [Import]
543 public ExportedService Service { get; set; }
545 [Export]
546 public class ExportedService
552 private static ImportDefinition ImportFromContract(string contractName)
554 return ImportDefinitionFactory.CreateDefault(contractName,
556 ImportCardinality.ZeroOrMore,
557 false,
558 false);
561 private static ImportDefinition ImportFromContractAndMetadata(string contractName, string[] metadataKeys, Type[] metadataValues)
563 Assert.AreEqual(metadataKeys.Length, metadataValues.Length);
564 Dictionary<string, Type> requiredMetadata = new Dictionary<string, Type>();
565 for (int i = 0; i < metadataKeys.Length; i++)
567 requiredMetadata.Add(metadataKeys[i], metadataValues[i]);
570 return new ContractBasedImportDefinition(contractName,
571 (string)null,
572 requiredMetadata,
573 ImportCardinality.ZeroOrMore,
574 false,
575 false,
576 CreationPolicy.Any);
579 private static CatalogExportProvider CreateCatalogExportProvider()
581 return CreateCatalogExportProvider(CatalogFactory.Create());
584 private static CatalogExportProvider CreateCatalogExportProvider(params ComposablePartDefinition[] definitions)
586 return CreateCatalogExportProvider(CatalogFactory.Create(definitions));
589 private static CatalogExportProvider CreateCatalogExportProvider(params ComposablePart[] parts)
591 return CreateCatalogExportProvider(CatalogFactory.Create(parts));
594 private static CatalogExportProvider CreateCatalogExportProvider(ComposablePartCatalog catalog)
596 return new CatalogExportProvider(catalog);