1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.ComponentModel.Composition.Diagnostics;
7 using System.ComponentModel.Composition.Extensibility;
8 using System.ComponentModel.Composition.Factories;
9 using System.ComponentModel.Composition.Primitives;
10 using System.Diagnostics;
11 using System.Linq;
12 using System.UnitTesting;
13 using Microsoft.Internal;
14 using Xunit;
15 
16 namespace System.ComponentModel.Composition.ReflectionModel
17 {
18     public class ReflectionComposablePartTests
19     {
20         [Fact]
21         [ActiveIssue(25498, TestPlatforms.AnyUnix)] // System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types.Retrieve the LoaderExceptions property for more information.
Constructor1_DefinitionAsDefinitionArgument_ShouldSetOriginProperty()22         public void Constructor1_DefinitionAsDefinitionArgument_ShouldSetOriginProperty()
23         {
24             var expectations = Expectations.GetAttributedDefinitions();
25 
26             foreach (var e in expectations)
27             {
28                 var definition = (ICompositionElement)new ReflectionComposablePart(e);
29 
30                 Assert.Same(e, definition.Origin);
31             }
32         }
33 
34         [Fact]
Constructor1_NullAsDefinitionArgument_ShouldThrowArgumentNull()35         public void Constructor1_NullAsDefinitionArgument_ShouldThrowArgumentNull()
36         {
37             Assert.Throws<ArgumentNullException>("definition", () =>
38             {
39                 new ReflectionComposablePart((ReflectionComposablePartDefinition)null);
40             });
41         }
42 
43         [Fact]
Constructor2_NullAsAttributedPartArgument_ShouldThrowArgumentNull()44         public void Constructor2_NullAsAttributedPartArgument_ShouldThrowArgumentNull()
45         {
46             Assert.Throws<ArgumentNullException>("attributedPart", () =>
47             {
48                 new ReflectionComposablePart(PartDefinitionFactory.CreateAttributed(), (object)null);
49             });
50         }
51 
52         [Fact]
Constructor2_ValueTypeAsAttributedPartArgument_ShouldThrowArgument()53         public void Constructor2_ValueTypeAsAttributedPartArgument_ShouldThrowArgument()
54         {
55             Assert.Throws<ArgumentException>("attributedPart", () =>
56             {
57                 new ReflectionComposablePart(PartDefinitionFactory.CreateAttributed(), 42);
58             });
59         }
60 
61         [Fact]
Constructor1_AttributedComposablePartDefintion_ShouldProduceValidObject()62         public void Constructor1_AttributedComposablePartDefintion_ShouldProduceValidObject()
63         {
64             var definition = PartDefinitionFactory.CreateAttributed(typeof(MyExport));
65             var part = new ReflectionComposablePart(definition);
66 
67             Assert.Equal(definition, part.Definition);
68             Assert.NotNull(part.Metadata);
69 
70             Assert.False(part is IDisposable);
71         }
72 
73         [Fact]
Constructor1_AttributedComposablePartDefintion_Disposable_ShouldProduceValidObject()74         public void Constructor1_AttributedComposablePartDefintion_Disposable_ShouldProduceValidObject()
75         {
76             var definition = PartDefinitionFactory.CreateAttributed(typeof(DisposablePart));
77             var part = new DisposableReflectionComposablePart(definition);
78 
79             Assert.Equal(definition, part.Definition);
80             Assert.NotNull(part.Metadata);
81 
82             Assert.True(part is IDisposable);
83         }
84 
85         [Fact]
Constructor1_Type_ShouldProduceValidObject()86         public void Constructor1_Type_ShouldProduceValidObject()
87         {
88             var part = new ReflectionComposablePart(PartDefinitionFactory.CreateAttributed(typeof(MyExport)));
89         }
90 
91         [Fact]
Constructor1_Object_ShouldProduceValidObject()92         public void Constructor1_Object_ShouldProduceValidObject()
93         {
94             var part = new ReflectionComposablePart(PartDefinitionFactory.CreateAttributed(typeof(MyExport)), new MyExport());
95         }
96 
97         [Fact]
Metadata_WhenDisposed_ShouldThrowObjectDisposed()98         public void Metadata_WhenDisposed_ShouldThrowObjectDisposed()
99         {
100             var part = CreateDefaultDisposablePart();
101             ((IDisposable)part).Dispose();
102 
103             ExceptionAssert.ThrowsDisposed(part, () =>
104             {
105                 var metadata = part.Metadata;
106             });
107         }
108 
109         [Fact]
ImportDefinitions_WhenDisposed_ShouldThrowObjectDisposed()110         public void ImportDefinitions_WhenDisposed_ShouldThrowObjectDisposed()
111         {
112             var part = CreateDefaultDisposablePart();
113             ((IDisposable)part).Dispose();
114 
115             ExceptionAssert.ThrowsDisposed(part, () =>
116             {
117                 var definitions = part.ImportDefinitions;
118             });
119         }
120 
121         [Fact]
ExportDefinitions_WhenDisposed_ShouldThrowObjectDisposed()122         public void ExportDefinitions_WhenDisposed_ShouldThrowObjectDisposed()
123         {
124             var part = CreateDefaultDisposablePart();
125             ((IDisposable)part).Dispose();
126 
127             ExceptionAssert.ThrowsDisposed(part, () =>
128             {
129                 var definitions = part.ExportDefinitions;
130             });
131         }
132 
133         [Fact]
OnComposed_WhenDisposed_ShouldThrowObjectDisposed()134         public void OnComposed_WhenDisposed_ShouldThrowObjectDisposed()
135         {
136             var part = CreateDefaultDisposablePart();
137             ((IDisposable)part).Dispose();
138 
139             ExceptionAssert.ThrowsDisposed(part, () =>
140             {
141                 part.Activate();
142             });
143         }
144 
145         [Fact]
OnComposed_MissingPostImportsOnInstance_ShouldThrowComposition()146         public void OnComposed_MissingPostImportsOnInstance_ShouldThrowComposition()
147         {
148             var part = CreatePart(new MySharedPartExport());
149 
150             // Dev10:484204 - This used to cause a failure but after we made
151             // ReflectionComposablePart internal we needed to back remove this
152             // validation for post imports to make declarative composition work.
153             //part.Activate().VerifyFailure(CompositionIssueId.ImportNotSetOnPart);
154             part.Activate();
155         }
156 
157         [Fact]
OnComposed_ProperlyComposed_ShouldSucceed()158         public void OnComposed_ProperlyComposed_ShouldSucceed()
159         {
160             var import = new TrivialImporter();
161             var export = new TrivialExporter();
162 
163             var part = CreatePart(import);
164 
165             var importDef = part.ImportDefinitions.First();
166             part.SetImport(importDef, CreateSimpleExports(export));
167             part.Activate();
168             Assert.True(export.done, "OnImportsSatisfied should have been called");
169         }
170 
171         [Fact]
OnComposed_UnhandledExceptionThrowInOnImportsSatisfied_ShouldThrowComposablePart()172         public void OnComposed_UnhandledExceptionThrowInOnImportsSatisfied_ShouldThrowComposablePart()
173         {
174             var part = CreatePart(typeof(ExceptionDuringINotifyImport));
175             var definition = part.ImportDefinitions.First();
176             part.SetImport(definition, CreateSimpleExports(21));
177 
178             CompositionAssert.ThrowsPart<NotImplementedException>(RetryMode.DoNotRetry, () =>
179             {
180                 part.Activate();
181             });
182         }
183 
184         [Fact]
SetImport_WhenDisposed_ShouldThrowObjectDisposed()185         public void SetImport_WhenDisposed_ShouldThrowObjectDisposed()
186         {
187             var part = CreateDefaultDisposablePart();
188             var definition = part.ImportDefinitions.First();
189 
190             ((IDisposable)part).Dispose();
191 
192             ExceptionAssert.ThrowsDisposed(part, () =>
193             {
194                 part.SetImport(definition, Enumerable.Empty<Export>());
195             });
196         }
197 
198         [Fact]
SetImport_NullAsImportDefinitionArgument_ShouldThrowArgumentNull()199         public void SetImport_NullAsImportDefinitionArgument_ShouldThrowArgumentNull()
200         {
201             var part = CreateDefaultPart();
202 
203             Assert.Throws<ArgumentNullException>("definition", () =>
204             {
205                 part.SetImport((ImportDefinition)null, Enumerable.Empty<Export>());
206             });
207         }
208 
209         [Fact]
SetImport_NullAsExportsArgument_ShouldThrowArgumentNull()210         public void SetImport_NullAsExportsArgument_ShouldThrowArgumentNull()
211         {
212             var part = CreatePart(typeof(MySharedPartExport));
213             var import = part.ImportDefinitions.First();
214 
215             Assert.Throws<ArgumentNullException>("exports", () =>
216             {
217                 part.SetImport(import, (IEnumerable<Export>)null);
218             });
219         }
220 
221         [Fact]
SetImport_ExportsArrayWithNullElementAsExportsArgument_ShouldThrowArgument()222         public void SetImport_ExportsArrayWithNullElementAsExportsArgument_ShouldThrowArgument()
223         {
224             var part = CreatePart(typeof(MySharedPartExport));
225             var definition = part.ImportDefinitions.First();
226 
227             Assert.Throws<ArgumentException>("exports", () =>
228             {
229                 part.SetImport(definition, new Export[] { null });
230             });
231         }
232 
233         [Fact]
SetImport_WrongDefinitionAsDefinitionArgument_ShouldThrowArgument()234         public void SetImport_WrongDefinitionAsDefinitionArgument_ShouldThrowArgument()
235         {
236             var part = CreateDefaultPart();
237 
238             var definition = ImportDefinitionFactory.Create();
239 
240             Assert.Throws<ArgumentException>("definition", () =>
241             {
242                 part.SetImport(definition, Enumerable.Empty<Export>());
243             });
244         }
245 
246         [Fact]
SetImport_SetNonRecomposableDefinitionAsDefinitionArgumentAfterOnComposed_ShouldThrowInvalidOperation()247         public void SetImport_SetNonRecomposableDefinitionAsDefinitionArgumentAfterOnComposed_ShouldThrowInvalidOperation()
248         {
249             var part = CreatePartWithNonRecomposableImport();
250             var definition = part.ImportDefinitions.First();
251 
252             part.SetImport(definition, Enumerable.Empty<Export>());
253             part.Activate();
254 
255             ExceptionAssert.Throws<InvalidOperationException>(() =>
256             {
257                 part.SetImport(definition, Enumerable.Empty<Export>());
258             });
259         }
260 
261         [Fact]
SetImport_ZeroOrOneDefinitionAsDefinitionArgumentAndTwoExportsAsExportsArgument_ShouldThrowArgument()262         public void SetImport_ZeroOrOneDefinitionAsDefinitionArgumentAndTwoExportsAsExportsArgument_ShouldThrowArgument()
263         {
264             var part = CreatePartWithZeroOrOneImport();
265             var definition = part.ImportDefinitions.First();
266 
267             var exports = ExportFactory.Create("Import", 2);
268 
269             Assert.Throws<ArgumentException>("exports", () =>
270             {
271                 part.SetImport(definition, exports);
272             });
273         }
274 
275         [Fact]
SetImport_ExactlyOneDefinitionAsDefinitionArgumentAndTwoExportsAsExportsArgument_ShouldThrowArgument()276         public void SetImport_ExactlyOneDefinitionAsDefinitionArgumentAndTwoExportsAsExportsArgument_ShouldThrowArgument()
277         {
278             var part = CreatePartWithExactlyOneImport();
279             var definition = part.ImportDefinitions.First();
280 
281             var exports = ExportFactory.Create("Import", 2);
282 
283             Assert.Throws<ArgumentException>("exports", () =>
284             {
285                 part.SetImport(definition, exports);
286             });
287         }
288 
289         [Fact]
SetImport_ExactlyOneDefinitionAsDefinitionArgumentAndEmptyExportsAsExportsArgument_ShouldThrowArgument()290         public void SetImport_ExactlyOneDefinitionAsDefinitionArgumentAndEmptyExportsAsExportsArgument_ShouldThrowArgument()
291         {
292             var part = CreatePartWithExactlyOneImport();
293             var definition = part.ImportDefinitions.First();
294 
295             var exports = Enumerable.Empty<Export>();
296 
297             Assert.Throws<ArgumentException>("exports", () =>
298             {
299                 part.SetImport(definition, exports);
300             });
301         }
302 
303         [Fact]
SetImport_WrongTypeExportGiven_ShouldThrowComposablePart()304         public void SetImport_WrongTypeExportGiven_ShouldThrowComposablePart()
305         {
306             var part = CreatePart(new MySharedPartExport());
307             var import = part.ImportDefinitions.First();
308 
309             CompositionAssert.ThrowsPart(() =>
310            {
311                part.SetImport(import, CreateSimpleExports("21"));
312            });
313         }
314 
315         [Fact]
SetImport_SetPostValueAndSetAgainOnInstance_ShouldSetProperty()316         public void SetImport_SetPostValueAndSetAgainOnInstance_ShouldSetProperty()
317         {
318             var import = new MySharedPartExport();
319             var part = CreatePart(import);
320             var importDef = part.ImportDefinitions.First();
321 
322             part.SetImport(importDef, CreateSimpleExports(21));
323 
324             Assert.NotEqual(import.Value, 21);
325             part.Activate();
326 
327             Assert.Equal(import.Value, 21);
328 
329             part.SetImport(importDef, CreateSimpleExports(42));
330 
331             Assert.NotEqual(import.Value, 42);
332 
333             part.Activate();
334 
335             Assert.Equal(import.Value, 42);
336         }
337 
338         [Fact]
GetExportedValue_WhenDisposed_ShouldThrowObjectDisposed()339         public void GetExportedValue_WhenDisposed_ShouldThrowObjectDisposed()
340         {
341             var part = CreateDefaultDisposablePart();
342             var definition = part.ExportDefinitions.First();
343 
344             ((IDisposable)part).Dispose();
345 
346             ExceptionAssert.ThrowsDisposed(part, () =>
347             {
348                 part.GetExportedValue(definition);
349             });
350         }
351 
352         [Fact]
GetExportedValue_NullAsDefinitionArgument_ShouldThrowArgumentNull()353         public void GetExportedValue_NullAsDefinitionArgument_ShouldThrowArgumentNull()
354         {
355             var part = CreateDefaultPart();
356 
357             Assert.Throws<ArgumentNullException>("definition", () =>
358             {
359                 part.GetExportedValue((ExportDefinition)null);
360             });
361         }
362 
363         [Fact]
GetExportedValue_WrongDefinitionAsDefinitionArgument_ShouldThrowArgument()364         public void GetExportedValue_WrongDefinitionAsDefinitionArgument_ShouldThrowArgument()
365         {
366             var part = CreateDefaultPart();
367             var definition = ExportDefinitionFactory.Create();
368 
369             Assert.Throws<ArgumentException>("definition", () =>
370             {
371                 part.GetExportedValue(definition);
372             });
373         }
374 
375         [Fact]
GetExportedValue_MissingPrerequisiteImport_ShouldThrowInvalidOperation()376         public void GetExportedValue_MissingPrerequisiteImport_ShouldThrowInvalidOperation()
377         {
378             var part = CreatePart(typeof(SimpleConstructorInjectedObject));
379             var definition = part.ExportDefinitions.First();
380 
381             ExceptionAssert.Throws<InvalidOperationException>(() =>
382             {
383                 part.GetExportedValue(definition);
384             });
385         }
386 
387         [Fact]
388         [ActiveIssue(484204)]
GetExportedValue_MissingPostImports_ShouldThrowComposition()389         public void GetExportedValue_MissingPostImports_ShouldThrowComposition()
390         {
391             var part = CreatePart(typeof(MySharedPartExport));
392 
393             // Signal that the composition should be finished
394             part.Activate();
395 
396             var definition = part.ExportDefinitions.First();
397 
398             // Dev10:484204 - This used to cause a failure but after we made
399             // ReflectionComposablePart internal we needed to back remove this
400             // validation for post imports to make declarative composition work.
401             CompositionAssert.ThrowsError(ErrorId.ImportNotSetOnPart, () =>
402             {
403                 part.GetExportedValue(definition);
404             });
405         }
406 
407         [Fact]
GetExportedValue_NoConstructorOnDefinition_ShouldThrowComposablePart()408         public void GetExportedValue_NoConstructorOnDefinition_ShouldThrowComposablePart()
409         {
410             var part = CreatePart(typeof(ClassWithNoMarkedOrDefaultConstructor));
411 
412             var definition = part.ExportDefinitions.First();
413 
414             CompositionAssert.ThrowsPart(() =>
415             {
416                 part.GetExportedValue(definition);
417             });
418         }
419 
420         [Fact]
GetExportedValue_UnhandledExceptionThrowInConstructor_ShouldThrowComposablePart()421         public void GetExportedValue_UnhandledExceptionThrowInConstructor_ShouldThrowComposablePart()
422         {
423             var part = CreatePart(typeof(ExportWithExceptionDuringConstruction));
424 
425             var definition = part.ExportDefinitions.First();
426 
427             CompositionAssert.ThrowsPart<NotImplementedException>(() =>
428             {
429                 part.GetExportedValue(definition);
430             });
431         }
432 
433         [Fact]
GetExportedValue_GetObjectAfterSetPreImport_ShouldGetValue()434         public void GetExportedValue_GetObjectAfterSetPreImport_ShouldGetValue()
435         {
436             var part = CreatePart(typeof(SimpleConstructorInjectedObject));
437 
438             var import = part.ImportDefinitions.First();
439             part.SetImport(import, CreateSimpleExports(21));
440 
441             part.Activate();
442 
443             var definition = part.ExportDefinitions.First();
444             var exportObject = (SimpleConstructorInjectedObject)part.GetExportedValue(definition);
445 
446             Assert.Equal(21, exportObject.CISimpleValue);
447         }
448 
449         [Fact]
GetExportedValue_GetObjectAfterSetPostImport_ShouldGetValue()450         public void GetExportedValue_GetObjectAfterSetPostImport_ShouldGetValue()
451         {
452             var part = CreatePart(typeof(MySharedPartExport));
453 
454             var import = part.ImportDefinitions.First();
455             part.SetImport(import, CreateSimpleExports(21));
456 
457             part.Activate();
458 
459             var definition = part.ExportDefinitions.First();
460             var exportObject = (MySharedPartExport)part.GetExportedValue(definition);
461 
462             Assert.NotNull(exportObject);
463             Assert.Equal(21, exportObject.Value);
464         }
465 
466         [Fact]
GetExportedValue_CallMultipleTimes_ShouldReturnSame()467         public void GetExportedValue_CallMultipleTimes_ShouldReturnSame()
468         {
469             var part = CreatePart(typeof(MySharedPartExport));
470 
471             var import = part.ImportDefinitions.First();
472             part.SetImport(import, CreateSimpleExports(21));
473 
474             part.Activate();
475 
476             var definition = part.ExportDefinitions.First();
477             var exportedValue1 = part.GetExportedValue(definition);
478             var exportedValue2 = part.GetExportedValue(definition);
479 
480             Assert.Same(exportedValue1, exportedValue2);
481         }
482 
483         [Fact]
GetExportedValue_FromStaticClass_ShouldReturnExport()484         public void GetExportedValue_FromStaticClass_ShouldReturnExport()
485         {
486             var part = CreatePart(typeof(StaticExportClass));
487 
488             var definition = part.ExportDefinitions.First();
489 
490             var exportObject = (string)part.GetExportedValue(definition);
491 
492             Assert.Equal("StaticString", exportObject);
493         }
494 
495         [Fact]
GetExportedValue_OptionalPostNotGiven_ShouldReturnValidObject()496         public void GetExportedValue_OptionalPostNotGiven_ShouldReturnValidObject()
497         {
498             var part = CreatePart(typeof(ClassWithOptionalPostImport));
499             part.Activate();
500 
501             var definition = part.ExportDefinitions.First();
502             var exportObject = (ClassWithOptionalPostImport)part.GetExportedValue(definition);
503 
504             Assert.Null(exportObject.Formatter);
505         }
506 
507         [Fact]
GetExportedValue_OptionalPreNotGiven_ShouldReturnValidObject()508         public void GetExportedValue_OptionalPreNotGiven_ShouldReturnValidObject()
509         {
510             var part = CreatePart(typeof(ClassWithOptionalPreImport));
511             part.Activate();
512 
513             var definition = part.ExportDefinitions.First();
514 
515             var exportedValue = (ClassWithOptionalPreImport)part.GetExportedValue(definition);
516             Assert.Null(exportedValue.Formatter);
517         }
518 
519         [Fact]
520         [ActiveIssue(25498, TestPlatforms.AnyUnix)] // System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types.Retrieve the LoaderExceptions property for more information.
ICompositionElementDisplayName_ShouldReturnTypeDisplayName()521         public void ICompositionElementDisplayName_ShouldReturnTypeDisplayName()
522         {
523             var expectations = Expectations.GetAttributedTypes();
524             foreach (var e in expectations)
525             {
526                 var part = (ICompositionElement)CreatePart(e);
527 
528                 Assert.Equal(e.GetDisplayName(), part.DisplayName);
529             }
530         }
531 
532         [Fact]
533         [ActiveIssue(25498, TestPlatforms.AnyUnix)] // System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
ToString_ShouldReturnICompositionElementDisplayName()534         public void ToString_ShouldReturnICompositionElementDisplayName()
535         {
536             var expectations = Expectations.GetAttributedTypes();
537             foreach (var e in expectations)
538             {
539                 var part = (ICompositionElement)CreatePart(e);
540 
541                 Assert.Equal(part.DisplayName, part.ToString());
542             }
543         }
544 
545         [PartNotDiscoverable]
546         public class PropertyExporter
547         {
548             [Export]
549             public object Property { get { return new object(); } }
550         }
551 
552         [PartNotDiscoverable]
553         public class FieldExporter
554         {
555             [Export]
556             public object Field = null;
557         }
558 
559         [PartNotDiscoverable]
560         public class MethodExporter
561         {
562             [Export("Method")]
Method()563             public void Method() { }
564         }
565 
566         [PartNotDiscoverable]
567         [Export]
568         public class TypeExporter
569         {
570         }
571 
572         [Fact]
GetExportedObjectAlwaysReturnsSameReference_ForProperty()573         public void GetExportedObjectAlwaysReturnsSameReference_ForProperty()
574         {
575             var cp = CreatePart(new PropertyExporter());
576             var ed = cp.ExportDefinitions.Single();
577             var eo1 = cp.GetExportedValue(ed);
578             var eo2 = cp.GetExportedValue(ed);
579             Assert.Same(eo1, eo2);
580         }
581 
582         [Fact]
GetExportedObjectAlwaysReturnsSameReference_ForField()583         public void GetExportedObjectAlwaysReturnsSameReference_ForField()
584         {
585             var exporter = new FieldExporter();
586             var cp = CreatePart(new FieldExporter());
587             var ed = cp.ExportDefinitions.Single();
588 
589             exporter.Field = new object();
590             var eo1 = cp.GetExportedValue(ed);
591             exporter.Field = new object();
592             var eo2 = cp.GetExportedValue(ed);
593             Assert.Same(eo1, eo2);
594         }
595 
596         [Fact]
GetExportedObjectAlwaysReturnsSameReference_ForMethod()597         public void GetExportedObjectAlwaysReturnsSameReference_ForMethod()
598         {
599             var cp = CreatePart(new MethodExporter());
600             var ed = cp.ExportDefinitions.Single();
601             var eo1 = cp.GetExportedValue(ed);
602             var eo2 = cp.GetExportedValue(ed);
603             Assert.Same(eo1, eo2);
604         }
605 
606         [Fact]
GetExportedObjectAlwaysReturnsSameReference_ForType()607         public void GetExportedObjectAlwaysReturnsSameReference_ForType()
608         {
609             var cp = CreatePart(new TypeExporter());
610             var ed = cp.ExportDefinitions.Single();
611             var eo1 = cp.GetExportedValue(ed);
612             var eo2 = cp.GetExportedValue(ed);
613             Assert.Same(eo1, eo2);
614         }
615 
616         [PartNotDiscoverable]
617         public class MethodWithoutContractName
618         {
619             [Export]
MethodWithoutContractNameNotAllowed()620             public void MethodWithoutContractNameNotAllowed()
621             {
622             }
623         }
624 
625         public interface IContract
626         {
627         }
628 
629         [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
630         public class CustomImportAttributeInvalidTarget : ImportAttribute
631         {
CustomImportAttributeInvalidTarget()632             public CustomImportAttributeInvalidTarget()
633                 : base(typeof(IContract))
634             {
635             }
636         }
637 
638         [PartNotDiscoverable]
639         public class ImportWithCustomImport
640         {
641             [CustomImport]
642             IContract ImportWithCustomAttributeImport { get; set; }
643         }
644 
645         [PartNotDiscoverable]
646         public class ImportWithCustomImportInvalidTarget
647         {
648             [CustomImportAttributeInvalidTarget]
InvalidImport()649             void InvalidImport() { }
650         }
651 
652         [Fact]
ImportDefinitions_ImportWithCustomAttributeImports()653         public void ImportDefinitions_ImportWithCustomAttributeImports()
654         {
655             var part = CreatePart(typeof(ImportWithCustomImport));
656             Assert.Equal(part.ImportDefinitions.Count(), 1);
657             ContractBasedImportDefinition import = part.ImportDefinitions.First() as ContractBasedImportDefinition;
658             Assert.NotNull(import);
659 
660             Assert.Equal(AttributedModelServices.GetContractName(typeof(IContract)), import.ContractName);
661             Assert.Equal(AttributedModelServices.GetTypeIdentity(typeof(IContract)), import.RequiredTypeIdentity);
662         }
663 
664         [Fact]
ImportDefinitions_ImportWithCustomImportInvalidTarget_ShouldbeIgnored()665         public void ImportDefinitions_ImportWithCustomImportInvalidTarget_ShouldbeIgnored()
666         {
667             var part = CreatePart(typeof(ImportWithCustomImportInvalidTarget));
668             Assert.Equal(part.ImportDefinitions.Count(), 0);
669         }
670 
671         [PartNotDiscoverable]
672         public class ImportManyWithCustomImportMany
673         {
674             [CustomImportMany]
675             IContract ImportManyWithCustomAttributeImportMany { get; set; }
676         }
677 
678         [PartNotDiscoverable]
679         public class ImportManyWithCustomImportManyInvalidTarget
680         {
681             [CustomImportMany]
InvalidImportMany()682             void InvalidImportMany() { }
683         }
684 
685         [Fact]
ImportDefinitions_ImportManyWithCustomAttributeImportManys()686         public void ImportDefinitions_ImportManyWithCustomAttributeImportManys()
687         {
688             var part = CreatePart(typeof(ImportManyWithCustomImportMany));
689             Assert.Equal(part.ImportDefinitions.Count(), 1);
690             ContractBasedImportDefinition import = part.ImportDefinitions.First() as ContractBasedImportDefinition;
691             Assert.NotNull(import);
692 
693             Assert.Equal(AttributedModelServices.GetContractName(typeof(IContract)), import.ContractName);
694             Assert.Equal(AttributedModelServices.GetTypeIdentity(typeof(IContract)), import.RequiredTypeIdentity);
695         }
696 
697         [Fact]
ImportDefinitions_ImportManyWithCustomImportManyInvalidTarget_ShouldbeIgnored()698         public void ImportDefinitions_ImportManyWithCustomImportManyInvalidTarget_ShouldbeIgnored()
699         {
700             var part = CreatePart(typeof(ImportManyWithCustomImportManyInvalidTarget));
701             Assert.Equal(part.ImportDefinitions.Count(), 0);
702         }
703 
704         [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
705         public class CustomImportingConstructorAttribute : ImportingConstructorAttribute
706         {
CustomImportingConstructorAttribute()707             public CustomImportingConstructorAttribute()
708                 : base()
709             {
710             }
711         }
712 
713         [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = true, Inherited = false)]
714         public class CustomImportingConstructorAllowMultipleAttribute : ImportingConstructorAttribute
715         {
CustomImportingConstructorAllowMultipleAttribute()716             public CustomImportingConstructorAllowMultipleAttribute()
717                 : base()
718             {
719             }
720         }
721 
722         [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
723         public class CustomImportingConstructorInvalidTargetAttribute : ImportingConstructorAttribute
724         {
CustomImportingConstructorInvalidTargetAttribute()725             public CustomImportingConstructorInvalidTargetAttribute()
726                 : base()
727             {
728             }
729         }
730 
731         [PartNotDiscoverable]
732         public class ImportingConstructorWithCustomImportingConstructor
733         {
734             [CustomImportingConstructor]
ImportingConstructorWithCustomImportingConstructor([Import] IContract argument)735             ImportingConstructorWithCustomImportingConstructor([Import] IContract argument) { }
736         }
737 
738         [PartNotDiscoverable]
739         public class ImportingConstructorWithCustomImportingConstructorAllowMultiple
740         {
741             [CustomImportingConstructorAllowMultiple]
742             [CustomImportingConstructorAllowMultiple]
ImportingConstructorWithCustomImportingConstructorAllowMultiple([Import] IContract argument)743             ImportingConstructorWithCustomImportingConstructorAllowMultiple([Import] IContract argument) { }
744         }
745 
746         [PartNotDiscoverable]
747         public class ImportingConstructorWithCustomImportingConstructorInvalidTarget
748         {
749             [CustomImportingConstructorInvalidTarget]
InvalidImportingConstructor()750             void InvalidImportingConstructor() { }
751         }
752 
753         [Fact]
ImportDefinitions_ImportingConstructorWithCustomAttributeImportingConstructors()754         public void ImportDefinitions_ImportingConstructorWithCustomAttributeImportingConstructors()
755         {
756             var part = CreatePart(typeof(ImportingConstructorWithCustomImportingConstructor));
757             Assert.Equal(part.ImportDefinitions.Count(), 1);
758             ContractBasedImportDefinition import = part.ImportDefinitions.First() as ContractBasedImportDefinition;
759             Assert.NotNull(import);
760 
761             Assert.Equal(AttributedModelServices.GetContractName(typeof(IContract)), import.ContractName);
762             Assert.Equal(AttributedModelServices.GetTypeIdentity(typeof(IContract)), import.RequiredTypeIdentity);
763         }
764 
765         [Fact]
ImportDefinitions_ImportingConstructorWithCustomAttributeImportingConstructorsWithAllowMultiple_ShouldNotThrowInvalidOperation()766         public void ImportDefinitions_ImportingConstructorWithCustomAttributeImportingConstructorsWithAllowMultiple_ShouldNotThrowInvalidOperation()
767         {
768             var part = CreatePart(typeof(ImportingConstructorWithCustomImportingConstructorAllowMultiple));
769 
770             Assert.Equal(part.ImportDefinitions.Count(), 1);
771             ContractBasedImportDefinition import = part.ImportDefinitions.First() as ContractBasedImportDefinition;
772             Assert.NotNull(import);
773 
774             Assert.Equal(AttributedModelServices.GetContractName(typeof(IContract)), import.ContractName);
775             Assert.Equal(AttributedModelServices.GetTypeIdentity(typeof(IContract)), import.RequiredTypeIdentity);
776         }
777 
778         [Fact]
ImportDefinitions_ImportingConstructorWithCustomImportingConstructorInvalidTarget_ShouldbeIgnored()779         public void ImportDefinitions_ImportingConstructorWithCustomImportingConstructorInvalidTarget_ShouldbeIgnored()
780         {
781             var part = CreatePart(typeof(ImportingConstructorWithCustomImportingConstructorInvalidTarget));
782             Assert.Equal(part.ImportDefinitions.Count(), 0);
783         }
784 
CreateSimpleExports(object value)785         private Export[] CreateSimpleExports(object value)
786         {
787             var export = ExportFactory.Create("NoContract", () => value);
788 
789             return new Export[] { export };
790         }
791 
CreatePartWithExport()792         private ReflectionComposablePart CreatePartWithExport()
793         {
794             return CreatePart(typeof(StaticExportClass));
795         }
796 
CreatePartWithNonRecomposableImport()797         private ReflectionComposablePart CreatePartWithNonRecomposableImport()
798         {
799             return CreatePart(typeof(SingleImportWithAllowDefault));
800         }
801 
CreatePartWithZeroOrOneImport()802         private ReflectionComposablePart CreatePartWithZeroOrOneImport()
803         {
804             return CreatePart(typeof(SingleImportWithAllowDefault));
805         }
806 
CreatePartWithExactlyOneImport()807         private ReflectionComposablePart CreatePartWithExactlyOneImport()
808         {
809             return CreatePart(typeof(SingleImport));
810         }
811 
CreateDefaultPart()812         private ReflectionComposablePart CreateDefaultPart()
813         {
814             return CreatePart(new object());
815         }
816 
817         [PartNotDiscoverable]
818         [Export]
819         public class DisposablePart : IDisposable
820         {
821             [Import(AllowDefault = true)]
822             public int Foo { get; set; }
823 
Dispose()824             public void Dispose() { }
825         }
826 
CreateDefaultDisposablePart()827         private ReflectionComposablePart CreateDefaultDisposablePart()
828         {
829             return CreatePart(typeof(DisposablePart));
830         }
831 
CreatePart(object instance)832         private ReflectionComposablePart CreatePart(object instance)
833         {
834             if (instance is Type)
835             {
836                 var definition = PartDefinitionFactory.CreateAttributed((Type)instance);
837 
838                 return (ReflectionComposablePart)definition.CreatePart();
839             }
840             else
841             {
842                 var definition = PartDefinitionFactory.CreateAttributed(instance.GetType());
843 
844                 return new ReflectionComposablePart(definition, instance);
845             }
846         }
847     }
848 }
849