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.
5 using System.Collections.Generic;
6 using System.Composition.Hosting.Core;
7 using System.Globalization;
8 using System.Reflection;
11 namespace System.Composition.Runtime.Tests
13 public class CompositionContractTests
16 [InlineData(typeof(int))]
17 public void Ctor_ContractType(Type contractType)
19 var contract = new CompositionContract(contractType);
20 Assert.Equal(contractType, contract.ContractType);
21 Assert.Null(contract.ContractName);
22 Assert.Null(contract.MetadataConstraints);
26 [InlineData(typeof(int), null)]
27 [InlineData(typeof(object), "contractName")]
28 public void Ctor_ContractType(Type contractType, string contractName)
30 var contract = new CompositionContract(contractType, contractName);
31 Assert.Equal(contractType, contract.ContractType);
32 Assert.Equal(contractName, contract.ContractName);
33 Assert.Null(contract.MetadataConstraints);
36 public static IEnumerable<object[]> Ctor_ContractType_ContractName_MetadataConstraints_TestData()
38 yield return new object[] { typeof(int), null, null };
39 yield return new object[] { typeof(object), "contractName", new Dictionary<string, object> { { "key", "value" } } };
43 [MemberData(nameof(Ctor_ContractType_ContractName_MetadataConstraints_TestData))]
44 public void Ctor_ContractType_MetadataConstraints(Type contractType, string contractName, IDictionary<string, object> metadataConstraints)
46 var contract = new CompositionContract(contractType, contractName, metadataConstraints);
47 Assert.Equal(contractType, contract.ContractType);
48 Assert.Equal(contractName, contract.ContractName);
49 Assert.Equal(metadataConstraints, contract.MetadataConstraints);
53 public void Ctor_NullContractType_ThrowsArgumentNullException()
55 AssertExtensions.Throws<ArgumentNullException>("contractType", () => new CompositionContract(null));
56 AssertExtensions.Throws<ArgumentNullException>("contractType", () => new CompositionContract(null, "contractName"));
57 AssertExtensions.Throws<ArgumentNullException>("contractType", () => new CompositionContract(null, "contractName", new Dictionary<string, object>()));
61 public void Ctor_EmptyMetadataConstraints_ThrowsArgumentOutOfRangeException()
63 AssertExtensions.Throws<ArgumentOutOfRangeException>("metadataConstraints", () => new CompositionContract(typeof(string), "contractName", new Dictionary<string, object>()));
66 public static IEnumerable<object[]> Equals_TestData()
68 yield return new object[] { new CompositionContract(typeof(int)), new CompositionContract(typeof(int)), true };
69 yield return new object[] { new CompositionContract(typeof(int)), new CompositionContract(typeof(string)), false };
70 yield return new object[] { new CompositionContract(typeof(int)), new CompositionContract(typeof(int), "contractName"), false };
71 yield return new object[] { new CompositionContract(typeof(int)), new CompositionContract(typeof(int), null, new Dictionary<string, object> { { "key", "value" } }), false };
73 yield return new object[] { new CompositionContract(typeof(int), "contractName"), new CompositionContract(typeof(int), "contractName"), true };
74 yield return new object[] { new CompositionContract(typeof(int), "contractName"), new CompositionContract(typeof(int), "ContractName"), false };
75 yield return new object[] { new CompositionContract(typeof(int), "contractName"), new CompositionContract(typeof(int)), false };
76 yield return new object[] { new CompositionContract(typeof(int)), new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }), false };
78 yield return new object[]
80 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
81 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
85 yield return new object[]
87 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", 1 } }),
88 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", 1 } }),
92 yield return new object[]
94 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[] { "1", null } } }),
95 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new object[] { "1", null } } }),
99 yield return new object[]
101 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[] { "1", null } } }),
102 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new object[] { "1", new object() } } }),
106 yield return new object[]
108 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
109 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" }, { "key2", "value2" } }),
113 yield return new object[]
115 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" }, { "key2", "value2" } }),
116 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
120 yield return new object[]
122 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
123 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key2", "value" } }),
127 yield return new object[]
129 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
130 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value2" } }),
134 yield return new object[]
136 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[0] } }),
137 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[1] } }),
141 yield return new object[]
143 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[0] } }),
144 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
148 yield return new object[]
150 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new string[0] } }),
151 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new object() } }),
155 yield return new object[]
157 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } }),
158 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
162 yield return new object[]
164 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", "value" } }),
165 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } }),
169 yield return new object[]
171 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", new object[0] } }),
172 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } }),
176 if (!PlatformDetection.IsFullFramework)
178 yield return new object[]
180 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } }),
181 new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } }),
186 yield return new object[] { new CompositionContract(typeof(int)), new object(), false };
187 yield return new object[] { new CompositionContract(typeof(int)), null, false };
191 [MemberData(nameof(Equals_TestData))]
192 public void Equals_Object_ReturnsExpected(CompositionContract contract, object other, bool expected)
194 Assert.Equal(expected, contract.Equals(other));
195 Assert.Equal(contract.GetHashCode(), contract.GetHashCode());
199 public void ChangeType_ValidType_Success()
201 var dictionary = new Dictionary<string, object> { { "key", "value" } };
202 var contract = new CompositionContract(typeof(int), "contractName", dictionary);
203 CompositionContract newContract = contract.ChangeType(typeof(string));
205 Assert.Equal(typeof(int), contract.ContractType);
206 Assert.Equal(typeof(string), newContract.ContractType);
207 Assert.Equal("contractName", newContract.ContractName);
208 Assert.Same(dictionary, newContract.MetadataConstraints);
212 public void ChangeType_NullNewContractType_ThrowsArgumentNullException()
214 var contract = new CompositionContract(typeof(int));
215 AssertExtensions.Throws<ArgumentNullException>("newContractType", () => contract.ChangeType(null));
219 public void TryUnwrapMetadataConstraint_NullConstraints_ReturnsFalse()
221 var contract = new CompositionContract(typeof(int));
222 Assert.False(contract.TryUnwrapMetadataConstraint("constraintName", out int constraintValue, out CompositionContract remainingContract));
223 Assert.Equal(0, constraintValue);
224 Assert.Null(remainingContract);
228 public void TryUnwrapMetadataConstraint_NoSuchConstraintName_ReturnsFalse()
230 var contract = new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "constraint", 1 } });
231 Assert.False(contract.TryUnwrapMetadataConstraint("constraintName", out int constraintValue, out CompositionContract remainingContract));
232 Assert.Equal(0, constraintValue);
233 Assert.Null(remainingContract);
237 public void TryUnwrapMetadataConstraint_IncorrectConstraintNameType_ReturnsFalse()
239 var contract = new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "constraintName", "value" } });
240 Assert.False(contract.TryUnwrapMetadataConstraint("constraintName", out int constraintValue, out CompositionContract remainingContract));
241 Assert.Equal(0, constraintValue);
242 Assert.Null(remainingContract);
246 public void TryUnwrapMetadataConstraint_UnwrapAllConstraints_ReturnsTrue()
248 var originalContract = new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "constraintName1", 1 }, { "constraintName2", 2 } });
249 Assert.True(originalContract.TryUnwrapMetadataConstraint("constraintName1", out int constraintValue1, out CompositionContract remainingContract1));
250 Assert.Equal(1, constraintValue1);
252 Assert.Equal(originalContract.ContractType, remainingContract1.ContractType);
253 Assert.Equal(originalContract.ContractName, remainingContract1.ContractName);
254 Assert.Equal(new Dictionary<string, object> { { "constraintName2", 2 } }, remainingContract1.MetadataConstraints);
255 Assert.NotEqual(originalContract.MetadataConstraints, remainingContract1.MetadataConstraints);
257 Assert.True(remainingContract1.TryUnwrapMetadataConstraint("constraintName2", out int constraintValue2, out CompositionContract remainingContract2));
258 Assert.Equal(2, constraintValue2);
260 Assert.Equal(originalContract.ContractType, remainingContract2.ContractType);
261 Assert.Equal(originalContract.ContractName, remainingContract2.ContractName);
262 Assert.Null(remainingContract2.MetadataConstraints);
263 Assert.NotEqual(originalContract.MetadataConstraints, remainingContract2.MetadataConstraints);
267 public void TryUnwrapMetadataConstraint_NullContractName_ThrowsArgumentNullException()
269 var contract = new CompositionContract(typeof(int));
270 AssertExtensions.Throws<ArgumentNullException>("constraintName", () => contract.TryUnwrapMetadataConstraint(null, out int unusedValue, out CompositionContract unusedContract));
273 public static IEnumerable<object[]> ToString_TestData()
275 yield return new object[] { new CompositionContract(typeof(int)), "Int32" };
276 yield return new object[] { new CompositionContract(typeof(int), "contractName"), "Int32 \"contractName\"" };
277 yield return new object[] { new CompositionContract(typeof(List<>), "contractName", new Dictionary<string, object> { { "key1", "value" }, { "key2", 2 } }), "List`1 \"contractName\" { key1 = \"value\", key2 = 2 }" };
278 yield return new object[] { new CompositionContract(typeof(List<string>), "contractName", new Dictionary<string, object> { { "key1", "value" }, { "key2", 2 } }), "List<String> \"contractName\" { key1 = \"value\", key2 = 2 }" };
282 [MemberData(nameof(ToString_TestData))]
283 public void ToString_Get_ReturnsExpected(CompositionContract contract, string expected)
285 Assert.Equal(expected, contract.ToString());
289 public void ToString_NullValueInDictionary_ThrowsArgumentNullException()
291 var contract = new CompositionContract(typeof(int), "contractName", new Dictionary<string, object> { { "key", null } });
292 AssertExtensions.Throws<ArgumentNullException>("value", () => contract.ToString());
296 public void ToString_NullTypeInGenericTypeArguments_ThrowsArgumentNullException()
298 var contract = new CompositionContract(new SubType() { GenericTypeArgumentsOverride = new Type[] { null } });
299 AssertExtensions.Throws<ArgumentNullException>("type", () => contract.ToString());
302 private class SubType : Type
304 public override Assembly Assembly => throw new NotImplementedException();
305 public override string AssemblyQualifiedName => throw new NotImplementedException();
306 public override Type BaseType => throw new NotImplementedException();
307 public override string FullName => throw new NotImplementedException();
308 public override Guid GUID => throw new NotImplementedException();
309 public override Module Module => throw new NotImplementedException();
310 public override string Namespace => throw new NotImplementedException();
311 public override Type UnderlyingSystemType => throw new NotImplementedException();
313 public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => throw new NotImplementedException();
314 public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException();
315 public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException();
316 public override Type GetElementType() => throw new NotImplementedException();
317 public override EventInfo GetEvent(string name, BindingFlags bindingAttr) => throw new NotImplementedException();
318 public override EventInfo[] GetEvents(BindingFlags bindingAttr) => throw new NotImplementedException();
319 public override FieldInfo GetField(string name, BindingFlags bindingAttr) => throw new NotImplementedException();
320 public override FieldInfo[] GetFields(BindingFlags bindingAttr) => throw new NotImplementedException();
321 public override Type GetInterface(string name, bool ignoreCase) => throw new NotImplementedException();
322 public override Type[] GetInterfaces() => throw new NotImplementedException();
323 public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotImplementedException();
324 public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => throw new NotImplementedException();
325 public override Type GetNestedType(string name, BindingFlags bindingAttr) => throw new NotImplementedException();
326 public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotImplementedException();
327 public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotImplementedException();
328 public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) => throw new NotImplementedException();
329 public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException();
330 protected override TypeAttributes GetAttributeFlagsImpl() => throw new NotImplementedException();
331 protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
332 protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
333 protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) => throw new NotImplementedException();
335 protected override bool HasElementTypeImpl() => throw new NotImplementedException();
336 protected override bool IsArrayImpl() => throw new NotImplementedException();
337 protected override bool IsByRefImpl() => throw new NotImplementedException();
338 protected override bool IsCOMObjectImpl() => throw new NotImplementedException();
339 protected override bool IsPointerImpl() => throw new NotImplementedException();
340 protected override bool IsPrimitiveImpl() => throw new NotImplementedException();
342 public override string Name => "Name`1";
343 public override bool IsConstructedGenericType => true;
344 public Type[] GenericTypeArgumentsOverride { get; set; }
345 public override Type[] GenericTypeArguments => GenericTypeArgumentsOverride;