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