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
9 using System.ComponentModel.Composition.UnitTesting;
\r
11 using System.Runtime.InteropServices;
\r
12 using System.UnitTesting;
\r
13 using Microsoft.VisualStudio.TestTools.UnitTesting;
\r
15 namespace System.ComponentModel.Composition
\r
18 public class CompositionContainerImportTests
\r
20 // Exporting collectin values is not supported
\r
22 public void ImportValues()
\r
24 var container = ContainerFactory.Create();
\r
25 Importer importer = new Importer();
\r
26 Exporter exporter42 = new Exporter(42);
\r
28 CompositionBatch batch = new CompositionBatch();
\r
29 batch.AddPart(importer);
\r
30 batch.AddPart(exporter42);
\r
32 CompositionAssert.ThrowsError(ErrorId.ImportEngine_PartCannotSetImport,
\r
33 ErrorId.ReflectionModel_ImportNotAssignableFromExport, RetryMode.DoNotRetry, () =>
\r
35 container.Compose(batch);
\r
40 public void ImportSingle()
\r
42 var container = ContainerFactory.Create();
\r
43 var importer = new Int32Importer();
\r
44 var exporter = new Int32Exporter(42);
\r
46 CompositionBatch batch = new CompositionBatch();
\r
47 batch.AddPart(importer);
\r
48 batch.AddPart(exporter);
\r
49 container.Compose(batch);
\r
51 Assert.AreEqual(42, importer.Value, "Expecting value to be imported");
\r
56 public void ImportSingleFromInternal()
\r
58 var container = ContainerFactory.Create();
\r
59 var importer = new Int32Importer();
\r
60 var exporter = new Int32ExporterInternal(42);
\r
62 CompositionBatch batch = new CompositionBatch();
\r
63 batch.AddPart(importer);
\r
64 batch.AddPart(exporter);
\r
65 container.Compose(batch);
\r
67 Assert.AreEqual(42, importer.Value, "Expecting value to be imported");
\r
71 public void ImportSingleToInternal()
\r
73 var container = ContainerFactory.Create();
\r
74 var importer = new Int32ImporterInternal();
\r
75 var exporter = new Int32Exporter(42);
\r
77 CompositionBatch batch = new CompositionBatch();
\r
78 batch.AddPart(importer);
\r
79 batch.AddPart(exporter);
\r
80 container.Compose(batch);
\r
82 Assert.AreEqual(42, importer.Value, "Expecting value to be imported");
\r
86 public void ImportSingleIntoCollection()
\r
88 var container = ContainerFactory.Create();
\r
89 var importer = new Int32CollectionImporter();
\r
90 var exporter = new Int32Exporter(42);
\r
92 CompositionBatch batch = new CompositionBatch();
\r
93 batch.AddPart(importer);
\r
94 batch.AddPart(exporter);
\r
95 container.Compose(batch);
\r
97 EnumerableAssert.AreEqual(importer.Values, 42);
\r
101 public void ImportValuesNameless()
\r
103 var container = ContainerFactory.Create();
\r
104 ImporterNameless importer;
\r
105 ExporterNameless exporter42 = new ExporterNameless(42);
\r
107 CompositionBatch batch = new CompositionBatch();
\r
108 batch.AddPart(importer = new ImporterNameless());
\r
109 batch.AddPart(exporter42);
\r
110 container.Compose(batch);
\r
112 Assert.AreEqual(42, importer.ValueReadWrite);
\r
113 Assert.AreEqual(42, importer.MetadataReadWrite.Value);
\r
117 public void ImportValueExceptionMissing()
\r
119 var container = ContainerFactory.Create();
\r
122 CompositionBatch batch = new CompositionBatch();
\r
123 batch.AddPart(importer = new Importer());
\r
125 CompositionAssert.ThrowsChangeRejectedError(ErrorId.ImportEngine_PartCannotSetImport,
\r
126 ErrorId.ImportEngine_ImportCardinalityMismatch,
\r
127 RetryMode.DoNotRetry, () =>
\r
129 container.Compose(batch);
\r
134 public void ImportValueExceptionMultiple()
\r
136 var container = ContainerFactory.Create();
\r
137 Importer importer = new Importer();
\r
138 Exporter exporter42 = new Exporter(42);
\r
139 Exporter exporter6 = new Exporter(6);
\r
141 CompositionBatch batch = new CompositionBatch();
\r
142 batch.AddPart(importer);
\r
143 batch.AddPart(exporter42);
\r
144 batch.AddPart(exporter6);
\r
146 CompositionAssert.ThrowsChangeRejectedError(ErrorId.ImportEngine_PartCannotSetImport,
\r
147 RetryMode.DoNotRetry, () =>
\r
149 container.Compose(batch);
\r
154 public void ImportValueExceptionSetterException()
\r
156 var container = ContainerFactory.Create();
\r
157 ImporterInvalidSetterException importer = new ImporterInvalidSetterException();
\r
158 Exporter exporter42 = new Exporter(42);
\r
160 CompositionBatch batch = new CompositionBatch();
\r
161 batch.AddPart(importer);
\r
162 batch.AddPart(exporter42);
\r
164 CompositionAssert.ThrowsError(ErrorId.ImportEngine_PartCannotActivate,
\r
165 ErrorId.ReflectionModel_ImportThrewException,
\r
166 RetryMode.DoNotRetry, () =>
\r
168 container.Compose(batch);
\r
173 public void ImportValueExceptionLazily()
\r
175 var catalog = new AssemblyCatalog(typeof(ImportImporterInvalidSetterExceptionLazily).Assembly);
\r
176 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(ImportImporterInvalidSetterExceptionLazily), typeof(ImporterInvalidSetterException));
\r
177 var invalidLazy = container.GetExportedValue<ImportImporterInvalidSetterExceptionLazily>();
\r
179 CompositionAssert.ThrowsError(ErrorId.ImportEngine_PartCannotGetExportedValue,
\r
180 ErrorId.ImportEngine_PartCannotActivate,
\r
181 ErrorId.ReflectionModel_ImportThrewException, RetryMode.DoNotRetry, () =>
\r
183 var value = invalidLazy.Value.Value;
\r
190 public void ImportValueComComponent()
\r
192 CTaskScheduler scheduler = new CTaskScheduler();
\r
196 var container = ContainerFactory.Create();
\r
197 var importer = new ImportComComponent();
\r
199 CompositionBatch batch = new CompositionBatch();
\r
200 batch.AddParts(importer);
\r
201 batch.AddExportedValue<ITaskScheduler>("TaskScheduler", (ITaskScheduler)scheduler);
\r
203 container.Compose(batch);
\r
205 Assert.AreEqual(scheduler, importer.TaskScheduler);
\r
209 Marshal.ReleaseComObject(scheduler);
\r
214 public void DelayImportValueComComponent()
\r
216 CTaskScheduler scheduler = new CTaskScheduler();
\r
220 var container = ContainerFactory.Create();
\r
221 var importer = new DelayImportComComponent();
\r
223 CompositionBatch batch = new CompositionBatch();
\r
224 batch.AddParts(importer);
\r
225 batch.AddExportedValue<ITaskScheduler>("TaskScheduler", (ITaskScheduler)scheduler);
\r
227 container.Compose(batch);
\r
229 Assert.AreEqual(scheduler, importer.TaskScheduler.Value);
\r
233 Marshal.ReleaseComObject(scheduler);
\r
239 [TestProperty("Type", "Integration")]
\r
240 public void OptionalImportsOfValueTypesAreBoundToDefaultWhenNotSatisfied()
\r
242 var container = ContainerFactory.Create();
\r
243 var importer = new OptionalImport();
\r
245 CompositionBatch batch = new CompositionBatch();
\r
246 batch.AddPart(importer);
\r
247 container.Compose(batch);
\r
249 Assert.AreEqual(1, importer.ValueTypeSetCount);
\r
250 Assert.AreEqual(0, importer.ValueType);
\r
254 [TestProperty("Type", "Integration")]
\r
255 public void OptionalImportsOfNullableValueTypesAreBoundToDefaultWhenNotSatisfied()
\r
257 var container = ContainerFactory.Create();
\r
258 var importer = new OptionalImport();
\r
260 CompositionBatch batch = new CompositionBatch();
\r
261 batch.AddPart(importer);
\r
262 container.Compose(batch);
\r
264 Assert.AreEqual(1, importer.NullableValueTypeSetCount);
\r
265 Assert.IsNull(importer.NullableValueType);
\r
269 [TestProperty("Type", "Integration")]
\r
270 public void OptionalImportsOfReferenceTypesAreBoundToDefaultWhenNotSatisfied()
\r
272 var container = ContainerFactory.Create();
\r
273 var importer = new OptionalImport();
\r
275 CompositionBatch batch = new CompositionBatch();
\r
276 batch.AddPart(importer);
\r
277 container.Compose(batch);
\r
279 Assert.AreEqual(1, importer.ReferenceTypeSetCount);
\r
280 Assert.IsNull(importer.ReferenceType);
\r
284 [TestProperty("Type", "Integration")]
\r
285 public void OptionalImportsOfExportValueTypesAreBoundToDefaultWhenNotSatisfied()
\r
287 var container = ContainerFactory.Create();
\r
288 var importer = new OptionalExport();
\r
290 CompositionBatch batch = new CompositionBatch();
\r
291 batch.AddPart(importer);
\r
292 container.Compose(batch);
\r
294 Assert.AreEqual(1, importer.ValueTypeSetCount);
\r
295 Assert.IsNull(importer.ValueType);
\r
299 [TestProperty("Type", "Integration")]
\r
300 public void OptionalImportsOfExportNullableValueTypesAreBoundToDefaultWhenNotSatisfied()
\r
302 var container = ContainerFactory.Create();
\r
303 var importer = new OptionalExport();
\r
305 CompositionBatch batch = new CompositionBatch();
\r
306 batch.AddPart(importer);
\r
307 container.Compose(batch);
\r
309 Assert.AreEqual(1, importer.NullableValueTypeSetCount);
\r
310 Assert.IsNull(importer.NullableValueType);
\r
314 [TestProperty("Type", "Integration")]
\r
315 public void OptionalImportsOfExportReferenceTypesAreBoundToDefaultWhenNotSatisfied()
\r
317 var container = ContainerFactory.Create();
\r
318 var importer = new OptionalExport();
\r
320 CompositionBatch batch = new CompositionBatch();
\r
321 batch.AddPart(importer);
\r
322 container.Compose(batch);
\r
324 Assert.AreEqual(1, importer.ReferenceTypeSetCount);
\r
325 Assert.IsNull(importer.ReferenceType);
\r
329 [TestProperty("Type", "Integration")]
\r
330 public void OptionalImportsOfValueTypesAreReboundToDefaultWhenExportIsRemoved()
\r
332 var container = ContainerFactory.Create();
\r
333 var importer = new OptionalImport();
\r
335 CompositionBatch batch = new CompositionBatch();
\r
336 batch.AddPart(importer);
\r
337 var key = batch.AddExportedValue("ValueType", 10);
\r
339 container.Compose(batch);
\r
341 Assert.AreEqual(1, importer.ValueTypeSetCount);
\r
342 Assert.AreEqual(10, importer.ValueType);
\r
344 batch = new CompositionBatch();
\r
345 batch.RemovePart(key);
\r
346 container.Compose(batch);
\r
348 Assert.AreEqual(2, importer.ValueTypeSetCount);
\r
349 Assert.AreEqual(0, importer.ValueType);
\r
353 [TestProperty("Type", "Integration")]
\r
354 public void OptionalImportsOfNullableValueTypesAreReboundToDefaultWhenExportIsRemoved()
\r
356 var container = ContainerFactory.Create();
\r
357 var importer = new OptionalImport();
\r
359 CompositionBatch batch = new CompositionBatch();
\r
360 batch.AddPart(importer);
\r
361 var key = batch.AddExportedValue<int?>("NullableValueType", 10);
\r
363 container.Compose(batch);
\r
364 Assert.AreEqual(1, importer.NullableValueTypeSetCount);
\r
365 Assert.AreEqual(10, importer.NullableValueType);
\r
367 batch = new CompositionBatch();
\r
368 batch.RemovePart(key);
\r
369 container.Compose(batch);
\r
371 Assert.AreEqual(2, importer.NullableValueTypeSetCount);
\r
372 Assert.IsNull(importer.NullableValueType);
\r
376 [TestProperty("Type", "Integration")]
\r
377 public void OptionalImportsOfReferenceTypesAreReboundToDefaultWhenExportIsRemoved()
\r
379 var container = ContainerFactory.Create();
\r
380 var importer = new OptionalImport();
\r
382 CompositionBatch batch = new CompositionBatch();
\r
383 batch.AddPart(importer);
\r
384 var key = batch.AddExportedValue("ReferenceType", "Bar");
\r
386 container.Compose(batch);
\r
387 Assert.AreEqual(1, importer.ReferenceTypeSetCount);
\r
388 Assert.AreEqual("Bar", importer.ReferenceType);
\r
390 batch = new CompositionBatch();
\r
391 batch.RemovePart(key);
\r
392 container.Compose(batch);
\r
394 Assert.AreEqual(2, importer.ReferenceTypeSetCount);
\r
395 Assert.IsNull(importer.ReferenceType);
\r
399 [TestProperty("Type", "Integration")]
\r
400 public void OptionalImportsOfExportValueTypesAreReboundToDefaultWhenExportIsRemoved()
\r
402 var container = ContainerFactory.Create();
\r
403 var importer = new OptionalExport();
\r
405 CompositionBatch batch = new CompositionBatch();
\r
406 batch.AddPart(importer);
\r
407 var key = batch.AddExportedValue("ValueType", 10);
\r
409 container.Compose(batch);
\r
411 Assert.AreEqual(1, importer.ValueTypeSetCount);
\r
412 Assert.AreEqual(10, importer.ValueType.Value);
\r
414 batch = new CompositionBatch();
\r
415 batch.RemovePart(key);
\r
416 container.Compose(batch);
\r
418 Assert.AreEqual(2, importer.ValueTypeSetCount);
\r
419 Assert.IsNull(importer.ValueType);
\r
423 [TestProperty("Type", "Integration")]
\r
424 public void OptionalImportsOfExportNullableValueTypesAreReboundToDefaultWhenExportIsRemoved()
\r
426 var container = ContainerFactory.Create();
\r
427 var importer = new OptionalExport();
\r
429 CompositionBatch batch = new CompositionBatch();
\r
430 batch.AddPart(importer);
\r
431 var key = batch.AddExportedValue<int?>("NullableValueType", 10);
\r
433 container.Compose(batch);
\r
434 Assert.AreEqual(1, importer.NullableValueTypeSetCount);
\r
435 Assert.AreEqual(10, importer.NullableValueType.Value);
\r
437 batch = new CompositionBatch();
\r
438 batch.RemovePart(key);
\r
439 container.Compose(batch);
\r
441 Assert.AreEqual(2, importer.NullableValueTypeSetCount);
\r
442 Assert.IsNull(importer.NullableValueType);
\r
446 [TestProperty("Type", "Integration")]
\r
447 public void OptionalImportsOfExportReferenceTypesAreReboundToDefaultWhenExportIsRemoved()
\r
449 var container = ContainerFactory.Create();
\r
450 var importer = new OptionalExport();
\r
452 CompositionBatch batch = new CompositionBatch();
\r
453 batch.AddPart(importer);
\r
454 var key = batch.AddExportedValue("ReferenceType", "Bar");
\r
456 container.Compose(batch);
\r
457 Assert.AreEqual(1, importer.ReferenceTypeSetCount);
\r
458 Assert.AreEqual("Bar", importer.ReferenceType.Value);
\r
460 batch = new CompositionBatch();
\r
461 batch.RemovePart(key);
\r
462 container.Compose(batch);
\r
464 Assert.AreEqual(2, importer.ReferenceTypeSetCount);
\r
465 Assert.IsNull(importer.ReferenceType);
\r
468 public class OptionalImport
\r
470 public int ValueTypeSetCount;
\r
471 public int NullableValueTypeSetCount;
\r
472 public int ReferenceTypeSetCount;
\r
474 private int _valueType;
\r
475 private int? _nullableValueType;
\r
476 private string _referenceType;
\r
478 [Import("ValueType", AllowDefault = true, AllowRecomposition = true)]
\r
479 public int ValueType
\r
481 get { return _valueType; }
\r
484 ValueTypeSetCount++;
\r
485 _valueType = value;
\r
489 [Import("NullableValueType", AllowDefault = true, AllowRecomposition = true)]
\r
490 public int? NullableValueType
\r
492 get { return _nullableValueType; }
\r
495 NullableValueTypeSetCount++;
\r
496 _nullableValueType = value;
\r
500 [Import("ReferenceType", AllowDefault = true, AllowRecomposition = true)]
\r
501 public string ReferenceType
\r
503 get { return _referenceType; }
\r
506 ReferenceTypeSetCount++;
\r
507 _referenceType = value;
\r
512 public class OptionalExport
\r
514 public int ValueTypeSetCount;
\r
515 public int NullableValueTypeSetCount;
\r
516 public int ReferenceTypeSetCount;
\r
518 private Lazy<int> _valueType;
\r
519 private Lazy<int?> _nullableValueType;
\r
520 private Lazy<string> _referenceType;
\r
522 [Import("ValueType", AllowDefault = true, AllowRecomposition = true)]
\r
523 public Lazy<int> ValueType
\r
525 get { return _valueType; }
\r
528 ValueTypeSetCount++;
\r
529 _valueType = value;
\r
533 [Import("NullableValueType", AllowDefault = true, AllowRecomposition = true)]
\r
534 public Lazy<int?> NullableValueType
\r
536 get { return _nullableValueType; }
\r
539 NullableValueTypeSetCount++;
\r
540 _nullableValueType = value;
\r
544 [Import("ReferenceType", AllowDefault = true, AllowRecomposition = true)]
\r
545 public Lazy<string> ReferenceType
\r
547 get { return _referenceType; }
\r
550 ReferenceTypeSetCount++;
\r
551 _referenceType = value;
\r
556 private class DelayDuckImporter
\r
559 public Lazy<IDuck> Duck
\r
566 private class DuckImporter
\r
576 public class QuackLikeADuck
\r
578 public virtual string Quack()
\r
584 public interface IDuck
\r
592 [Guid("148BD52A-A2AB-11CE-B11F-00AA00530503")]
\r
593 private class CTaskScheduler
\r
594 { // This interface doesn't implement
\r
595 // ITaskScheduler deliberately
\r
598 [Guid("148BD527-A2AB-11CE-B11F-00AA00530503")]
\r
599 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
\r
600 private interface ITaskScheduler
\r
605 private class ImportComComponent
\r
607 [Import("TaskScheduler")]
\r
608 public ITaskScheduler TaskScheduler
\r
615 private class DelayImportComComponent
\r
617 [Import("TaskScheduler")]
\r
618 public Lazy<ITaskScheduler> TaskScheduler
\r
627 public class Importer
\r
634 public int ValueReadWrite { get; set; }
\r
636 [ImportMany("Value")]
\r
637 public IList<int> SingleValueCollectionReadWrite { get; set; }
\r
639 [Import("EmptyValue", AllowDefault = true)]
\r
640 public int ValueEmptyOptional { get; set; }
\r
642 [ImportMany("CollectionValue", typeof(IList<int>))]
\r
643 public IList<int> ValueCollection { get; set; }
\r
647 public class ImporterNameless
\r
650 public ImporterNameless()
\r
655 public int ValueReadWrite { get; set; }
\r
658 public Lazy<int> MetadataReadWrite { get; set; }
\r
662 public class ImporterInvalidWrongType
\r
665 public DateTime ValueReadWrite { get; set; }
\r
669 public class ImporterInvalidSetterException
\r
671 [ImportMany("Value")]
\r
672 public IEnumerable<int> ValueReadWrite { get { return null; } set { throw new InvalidOperationException(); } }
\r
676 public class ImportImporterInvalidSetterExceptionLazily
\r
679 public Lazy<ImporterInvalidSetterException> Value { get; set; }
\r
683 [PartNotDiscoverable]
\r
684 public class Exporter
\r
686 List<int> collectionValue = new List<int>();
\r
688 public Exporter(int value)
\r
694 public int Value { get; set; }
\r
697 [Export("CollectionValue")]
\r
698 public IList<int> CollectionValue { get { return collectionValue; } }
\r
702 public class ExporterNameless
\r
705 public ExporterNameless(int value)
\r
711 public int Value { get; set; }
\r
715 public class ExportsString
\r
718 public string ExportedString = "Test";
\r
721 public class ExportsInvalidListOfExportOfString
\r
723 [Export(typeof(List<Lazy<string>>))]
\r
724 public string ExportedString = "Test";
\r
727 public class ExportsValidListOfExportOfString
\r
729 [Export(typeof(List<Lazy<string>>))]
\r
730 public List<Lazy<string>> ExportedString = new List<Lazy<string>>();
\r
734 public class ImportsListOfExportOfString
\r
736 [Import(AllowDefault = true)]
\r
737 public List<Lazy<string>> ExportedList { get; set; }
\r
741 public void ImportListOfExportWithOnlySingleElementsAvailable_ShouldNotFindExport()
\r
743 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(ExportsString), typeof(ImportsListOfExportOfString));
\r
744 var importer = container.GetExportedValue<ImportsListOfExportOfString>();
\r
745 Assert.IsNull(importer.ExportedList);
\r
747 var part = AttributedModelServices.CreatePartDefinition(typeof(ImportsListOfExportOfString), null);
\r
748 var contract = AttributedModelServices.GetContractName(typeof(List<Lazy<string>>));
\r
749 Assert.AreEqual(contract, ((ContractBasedImportDefinition)part.ImportDefinitions.First()).ContractName);
\r
753 public void ImportListOfExportWithInvalidCollectionAvailable_ShouldThrowMismatch()
\r
755 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(ExportsInvalidListOfExportOfString), typeof(ImportsListOfExportOfString));
\r
757 CompositionAssert.ThrowsError(ErrorId.ImportEngine_PartCannotGetExportedValue, () =>
\r
758 container.GetExportedValue<ImportsListOfExportOfString>());
\r
762 public void ImportListOfExportWithValidCollectionAvailable_ShouldSatisfyImport()
\r
764 var container = ContainerFactory.CreateWithAttributedCatalog(typeof(ExportsValidListOfExportOfString), typeof(ImportsListOfExportOfString));
\r
765 var importer = container.GetExportedValue<ImportsListOfExportOfString>();
\r
766 Assert.AreEqual(0, importer.ExportedList.Count);
\r