ConstructorInjectionTests.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // -----------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // -----------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel.Composition;
  7. using Microsoft.VisualStudio.TestTools.UnitTesting;
  8. using System.ComponentModel.Composition.Factories;
  9. using System.ComponentModel.Composition.UnitTesting;
  10. using System.UnitTesting;
  11. using System.ComponentModel.Composition.AttributedModel;
  12. using System.ComponentModel.Composition.Hosting;
  13. namespace Tests.Integration
  14. {
  15. [TestClass]
  16. public class ConstructorInjectionTests
  17. {
  18. [TestMethod]
  19. public void SimpleConstructorInjection()
  20. {
  21. var container = ContainerFactory.Create();
  22. CompositionBatch batch = new CompositionBatch();
  23. batch.AddPart(PartFactory.CreateAttributed(typeof(SimpleConstructorInjectedObject)));
  24. batch.AddExportedValue("CISimpleValue", 42);
  25. container.Compose(batch);
  26. SimpleConstructorInjectedObject simple = container.GetExportedValue<SimpleConstructorInjectedObject>();
  27. Assert.AreEqual(42, simple.CISimpleValue);
  28. }
  29. public interface IOptionalRef { }
  30. [Export]
  31. public class OptionalExportProvided { }
  32. [Export]
  33. public class AWithOptionalParameter
  34. {
  35. [ImportingConstructor]
  36. public AWithOptionalParameter([Import(AllowDefault = true)]IOptionalRef import,
  37. [Import("ContractThatShouldNotBeFound", AllowDefault = true)]int value,
  38. [Import(AllowDefault=true)]OptionalExportProvided provided)
  39. {
  40. Assert.IsNull(import);
  41. Assert.AreEqual(0, value);
  42. Assert.IsNotNull(provided);
  43. }
  44. }
  45. [TestMethod]
  46. public void OptionalConstructorArgument()
  47. {
  48. var container = GetContainerWithCatalog();
  49. var a = container.GetExportedValue<AWithOptionalParameter>();
  50. // A should verify that it receieved optional arugments properly
  51. Assert.IsNotNull(a);
  52. }
  53. [Export]
  54. public class AWithCollectionArgument
  55. {
  56. private IEnumerable<int> _values;
  57. [ImportingConstructor]
  58. public AWithCollectionArgument([ImportMany("MyConstructorCollectionItem")]IEnumerable<int> values)
  59. {
  60. this._values = values;
  61. }
  62. public IEnumerable<int> Values { get { return this._values; } }
  63. }
  64. [TestMethod]
  65. public void RebindingShouldNotHappenForConstructorArguments()
  66. {
  67. var container = GetContainerWithCatalog();
  68. CompositionBatch batch = new CompositionBatch();
  69. var p1 = batch.AddExportedValue("MyConstructorCollectionItem", 1);
  70. batch.AddExportedValue("MyConstructorCollectionItem", 2);
  71. batch.AddExportedValue("MyConstructorCollectionItem", 3);
  72. container.Compose(batch);
  73. var a = container.GetExportedValue<AWithCollectionArgument>();
  74. EnumerableAssert.AreEqual(a.Values, 1, 2, 3);
  75. batch = new CompositionBatch();
  76. batch.AddExportedValue("MyConstructorCollectionItem", 4);
  77. batch.AddExportedValue("MyConstructorCollectionItem", 5);
  78. batch.AddExportedValue("MyConstructorCollectionItem", 6);
  79. // After rejection changes that are incompatible with existing assumptions are no
  80. // longer silently ignored. The batch attempting to make this change is rejected
  81. // with a ChangeRejectedException
  82. CompositionAssert.ThrowsChangeRejectedError(ErrorId.ImportEngine_PreventedByExistingImport,() =>
  83. {
  84. container.Compose(batch);
  85. });
  86. // The collection which is a constructor import should not be rebound
  87. EnumerableAssert.AreEqual(a.Values, 1, 2, 3);
  88. batch.RemovePart(p1);
  89. // After rejection changes that are incompatible with existing assumptions are no
  90. // longer silently ignored. The batch attempting to make this change is rejected
  91. // with a ChangeRejectedException
  92. CompositionAssert.ThrowsChangeRejectedError(ErrorId.ImportEngine_PreventedByExistingImport, () =>
  93. {
  94. container.Compose(batch);
  95. });
  96. // The collection which is a constructor import should not be rebound
  97. EnumerableAssert.AreEqual(a.Values, 1, 2, 3);
  98. }
  99. [TestMethod]
  100. public void MissingConstructorArgsWithAlreadyCreatedInstance()
  101. {
  102. var container = GetContainerWithCatalog();
  103. CompositionBatch batch = new CompositionBatch();
  104. batch.AddPart(new ClassWithNotFoundConstructorArgs(21));
  105. container.Compose(batch);
  106. }
  107. [TestMethod]
  108. public void MissingConstructorArgsWithTypeFromCatalogMissingArg()
  109. {
  110. var container = GetContainerWithCatalog();
  111. // After rejection part definitions in catalogs whose dependencies cannot be
  112. // satisfied are now silently ignored, turning this into a cardinality
  113. // exception for the GetExportedValue call
  114. ExceptionAssert.Throws<ImportCardinalityMismatchException>(() =>
  115. {
  116. container.GetExportedValue<ClassWithNotFoundConstructorArgs>();
  117. });
  118. }
  119. [TestMethod]
  120. public void MissingConstructorArgsWithWithTypeFromCatalogWithArg()
  121. {
  122. var container = GetContainerWithCatalog();
  123. CompositionBatch batch = new CompositionBatch();
  124. batch.AddExportedValue("ContractThatDoesntExist", 21);
  125. container.Compose(batch);
  126. Assert.IsTrue(container.IsPresent<ClassWithNotFoundConstructorArgs>());
  127. }
  128. [Export]
  129. public class ClassWithNotFoundConstructorArgs
  130. {
  131. [ImportingConstructor]
  132. public ClassWithNotFoundConstructorArgs([Import("ContractThatDoesntExist")]int i)
  133. {
  134. }
  135. }
  136. private CompositionContainer GetContainerWithCatalog()
  137. {
  138. var catalog = new AssemblyCatalog(typeof(ConstructorInjectionTests).Assembly);
  139. return new CompositionContainer(catalog);
  140. }
  141. [Export]
  142. public class InvalidImportManyCI
  143. {
  144. [ImportingConstructor]
  145. public InvalidImportManyCI(
  146. [ImportMany]List<MyExport> exports)
  147. {
  148. }
  149. }
  150. [TestMethod]
  151. public void ImportMany_ConstructorParameter_OnNonAssiganbleType_ShouldThrowCompositionException()
  152. {
  153. var container = ContainerFactory.CreateWithAttributedCatalog(typeof(InvalidImportManyCI));
  154. CompositionAssert.ThrowsError(ErrorId.ImportEngine_PartCannotGetExportedValue,
  155. ErrorId.ImportEngine_PartCannotActivate,
  156. ErrorId.ReflectionModel_ImportManyOnParameterCanOnlyBeAssigned,
  157. () => container.GetExportedValue<InvalidImportManyCI>());
  158. }
  159. }
  160. }