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 Xunit; 7 8 namespace System.Reflection.Emit.Tests 9 { 10 public class TypeBuilderDefineProperty 11 { TestData()12 public static IEnumerable<object[]> TestData() 13 { 14 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(int), new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 15 yield return new object[] { "a\0b\0c", PropertyAttributes.HasDefault, typeof(int[]), new Type[] { typeof(int), typeof(double) }, "a", PropertyAttributes.None }; 16 yield return new object[] { "\uD800\uDC00", PropertyAttributes.RTSpecialName, typeof(EmptyNonGenericInterface1), new Type[0], "\uD800\uDC00", PropertyAttributes.None }; 17 yield return new object[] { "привет", PropertyAttributes.SpecialName, typeof(EmptyNonGenericStruct), null, "привет", PropertyAttributes.SpecialName }; 18 yield return new object[] { "class", (PropertyAttributes)(-1), null, new Type[] { typeof(void) }, "class", PropertyAttributes.None }; 19 yield return new object[] { "Test Name With Spaces", (PropertyAttributes)8192, typeof(string), new Type[] { typeof(string) }, "Test Name With Spaces", PropertyAttributes.None }; 20 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(BasicDelegate), new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 21 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(EmptyEnum), new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 22 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(DateTime), new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 23 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(EmptyGenericStruct<int>), new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 24 yield return new object[] { "PropertyName", PropertyAttributes.None, typeof(EmptyGenericStruct<int>).GetGenericArguments()[0], new Type[] { typeof(int) }, "PropertyName", PropertyAttributes.None }; 25 26 // Invalid unicode 27 yield return new object[] { "\uDC00", (PropertyAttributes)0x8000, typeof(EmptyGenericStruct<string>), new Type[] { typeof(EmptyGenericClass<string>) }, "\uFFFD", PropertyAttributes.None }; 28 yield return new object[] { "\uD800", PropertyAttributes.None, typeof(int).MakeByRefType(), new Type[] { typeof(int).MakeByRefType() }, "\uFFFD", PropertyAttributes.None }; 29 yield return new object[] { "1A\0\t\v\r\n\n\uDC81\uDC91", PropertyAttributes.None, typeof(int).MakePointerType(), new Type[] { typeof(int).MakePointerType() }, "1A", PropertyAttributes.None }; 30 } 31 32 [Theory] 33 [MemberData(nameof(TestData))] DefineProperty(string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes, string expectedName, PropertyAttributes expectedPropertyAttributes)34 public void DefineProperty(string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes, string expectedName, PropertyAttributes expectedPropertyAttributes) 35 { 36 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); 37 PropertyBuilder property = type.DefineProperty(name, attributes, returnType, parameterTypes); 38 Assert.Equal(name, property.Name); 39 Assert.Equal(attributes, property.Attributes); 40 Assert.Equal(returnType, property.PropertyType); 41 42 Type createdType = type.CreateTypeInfo().AsType(); 43 Assert.Equal(type.AsType().GetProperties(Helpers.AllFlags), createdType.GetProperties(Helpers.AllFlags)); 44 45 PropertyInfo createdProperty = createdType.GetProperty(expectedName, Helpers.AllFlags); 46 Assert.Equal(expectedName, createdProperty.Name); 47 Assert.Equal(expectedPropertyAttributes, createdProperty.Attributes); 48 Assert.Equal(returnType ?? typeof(void), createdProperty.PropertyType); 49 } 50 51 [Fact] DefineProperty_NullCustomModifiers()52 public void DefineProperty_NullCustomModifiers() 53 { 54 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 55 Type[] parameterTypes = { typeof(int), typeof(double) }; 56 PropertyBuilder property = type.DefineProperty("propertyname", PropertyAttributes.None, typeof(int), null, null, parameterTypes, null, null); 57 58 Assert.Equal("propertyname", property.Name); 59 Assert.Equal(PropertyAttributes.None, property.Attributes); 60 Assert.Equal(typeof(int), property.PropertyType); 61 } 62 63 [Fact] DefineProperty_GetAccessor_NoCustomModifiers()64 public void DefineProperty_GetAccessor_NoCustomModifiers() 65 { 66 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit); 67 type.SetParent(typeof(DefinePropertyClass)); 68 69 PropertyBuilder property = type.DefineProperty("Property", PropertyAttributes.None, CallingConventions.HasThis | CallingConventions.Standard, typeof(int), new Type[0]); 70 71 MethodAttributes methodAttr = MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.ReuseSlot; 72 CallingConventions conventions = CallingConventions.Standard | CallingConventions.HasThis; 73 74 MethodBuilder getMethod = type.DefineMethod("get_Property", methodAttr, conventions, typeof(int), new Type[0]); 75 ILGenerator ilGenerator = getMethod.GetILGenerator(); 76 ilGenerator.Emit(OpCodes.Ldc_I4, 5); 77 ilGenerator.Emit(OpCodes.Ret); 78 property.SetGetMethod(getMethod); 79 80 Type createdType = type.CreateTypeInfo().AsType(); 81 object obj = Activator.CreateInstance(createdType); 82 Assert.Equal(5, createdType.GetProperty("Property").GetGetMethod().Invoke(obj, null)); 83 } 84 85 [Fact] DefineProperty_GetAccessor_NullCustomModifiers()86 public void DefineProperty_GetAccessor_NullCustomModifiers() 87 { 88 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit); 89 type.SetParent(typeof(DefinePropertyClass)); 90 91 PropertyBuilder property = type.DefineProperty("Property", PropertyAttributes.None, CallingConventions.HasThis | CallingConventions.Standard, typeof(int), null, null, null, null, null); 92 93 MethodAttributes methodAttr = MethodAttributes.SpecialName | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.ReuseSlot; 94 CallingConventions conventions = CallingConventions.Standard | CallingConventions.HasThis; 95 96 MethodBuilder getMethod = type.DefineMethod("get_Property", methodAttr, conventions, typeof(int), new Type[0]); 97 ILGenerator ilGenerator = getMethod.GetILGenerator(); 98 ilGenerator.Emit(OpCodes.Ldc_I4, 5); 99 ilGenerator.Emit(OpCodes.Ret); 100 property.SetGetMethod(getMethod); 101 102 Type createdType = type.CreateTypeInfo().AsType(); 103 object obj = Activator.CreateInstance(createdType); 104 Assert.Equal(5, createdType.GetProperty("Property").GetGetMethod().Invoke(obj, null)); 105 } 106 107 [Theory] 108 [InlineData("")] 109 [InlineData("\0")] 110 [InlineData("\0TestProperty")] DefineProperty_InvalidName_ThrowsArgumentException(string name)111 public void DefineProperty_InvalidName_ThrowsArgumentException(string name) 112 { 113 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); 114 AssertExtensions.Throws<ArgumentException>("name", () => type.DefineProperty(name, PropertyAttributes.HasDefault, typeof(int), null, null, new Type[] { typeof(int) }, null, null)); 115 116 AssertExtensions.Throws<ArgumentException>("name", () => type.DefineProperty(name, PropertyAttributes.None, typeof(int), new Type[] { typeof(int) })); 117 } 118 119 [Fact] DefineProperty_NullString_ThrowsArgumentNullException()120 public void DefineProperty_NullString_ThrowsArgumentNullException() 121 { 122 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); 123 AssertExtensions.Throws<ArgumentNullException>("name", () => type.DefineProperty(null, PropertyAttributes.HasDefault, typeof(int), null, null, new Type[] { typeof(int) }, null, null)); 124 125 AssertExtensions.Throws<ArgumentNullException>("name", () => type.DefineProperty(null, PropertyAttributes.None, typeof(int), new Type[] { typeof(int) })); 126 } 127 128 [Fact] DefineProperty_TypeCreated_ThrowsInvalidOperationException()129 public void DefineProperty_TypeCreated_ThrowsInvalidOperationException() 130 { 131 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); 132 type.CreateTypeInfo().AsType(); 133 134 Assert.Throws<InvalidOperationException>(() => type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, typeof(int), null, null, new Type[] { typeof(int) }, null, null)); 135 136 Assert.Throws<InvalidOperationException>(() => type.DefineProperty("TestProperty", PropertyAttributes.None, typeof(int), new Type[] { typeof(int) })); 137 } 138 139 [Fact] DefineProperty_OpenGenericReturnType_ThrowsBadImageFormatExceptionGettingCreatedPropertyType()140 public void DefineProperty_OpenGenericReturnType_ThrowsBadImageFormatExceptionGettingCreatedPropertyType() 141 { 142 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 143 type.DefineProperty("Name", PropertyAttributes.None, typeof(EmptyGenericStruct<>), new Type[0]); 144 145 Type createdType = type.CreateTypeInfo().AsType(); 146 PropertyInfo createdProperty = createdType.GetProperty("Name", BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 147 Assert.Throws<BadImageFormatException>(() => createdProperty.PropertyType); 148 } 149 150 [Fact] DefineProperty_NullParameterType_ThrowsArgumentNullException()151 public void DefineProperty_NullParameterType_ThrowsArgumentNullException() 152 { 153 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 154 AssertExtensions.Throws<ArgumentNullException>("argument", () => type.DefineProperty("Name", PropertyAttributes.None, typeof(void), new Type[] { null })); 155 } 156 157 [Fact] DefineProperty_OpenGenericParameterType_ThrowsBadImageFormatExceptionGettingCreatedPropertyType()158 public void DefineProperty_OpenGenericParameterType_ThrowsBadImageFormatExceptionGettingCreatedPropertyType() 159 { 160 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 161 type.DefineProperty("Name", PropertyAttributes.None, typeof(int), new Type[] { typeof(EmptyGenericStruct<>) }); 162 163 Type createdType = type.CreateTypeInfo().AsType(); 164 PropertyInfo createdProperty = createdType.GetProperty("Name", BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 165 Assert.Throws<BadImageFormatException>(() => createdProperty.PropertyType); 166 } 167 168 [Fact] DefineProperty_DynamicPropertyTypeNotCreated_ThrowsTypeLoadException()169 public void DefineProperty_DynamicPropertyTypeNotCreated_ThrowsTypeLoadException() 170 { 171 ModuleBuilder module = Helpers.DynamicModule(); 172 TypeBuilder type = module.DefineType("Name", TypeAttributes.Public); 173 TypeBuilder propertyType = module.DefineType("PropertyType", TypeAttributes.Public); 174 type.DefineProperty("Name", PropertyAttributes.None, propertyType.AsType(), new Type[0]); 175 176 Type createdType = type.CreateTypeInfo().AsType(); 177 PropertyInfo property = createdType.GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance); 178 Assert.Throws<TypeLoadException>(() => property.PropertyType); 179 180 Type createdPropertyType = propertyType.CreateTypeInfo().AsType(); 181 Assert.Equal(createdPropertyType, property.PropertyType); 182 } 183 184 [Fact] DefineProperty_DynamicParameterTypeNotCreated_ThrowsTypeLoadException()185 public void DefineProperty_DynamicParameterTypeNotCreated_ThrowsTypeLoadException() 186 { 187 ModuleBuilder module = Helpers.DynamicModule(); 188 TypeBuilder type = module.DefineType("Name", TypeAttributes.Public); 189 TypeBuilder propertyType = module.DefineType("PropertyType", TypeAttributes.Public); 190 type.DefineProperty("Name", PropertyAttributes.None, typeof(int), new Type[] { propertyType.AsType() }); 191 192 Type createdType = type.CreateTypeInfo().AsType(); 193 PropertyInfo property = createdType.GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance); 194 Assert.Throws<TypeLoadException>(() => property.PropertyType); 195 196 Type createdPropertyType = propertyType.CreateTypeInfo().AsType(); 197 Assert.Equal(typeof(int), property.PropertyType); 198 } 199 200 [Fact] DefineProperty_CalledMultipleTimes_Works()201 public void DefineProperty_CalledMultipleTimes_Works() 202 { 203 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Class | TypeAttributes.Public); 204 type.DefineProperty("PropertyName", PropertyAttributes.None, typeof(int), new Type[0]); 205 type.DefineProperty("PropertyName", PropertyAttributes.None, typeof(int), new Type[0]); 206 207 Type createdType = type.CreateTypeInfo().AsType(); 208 PropertyInfo[] properties = createdType.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 209 Assert.Equal(1, properties.Length); 210 Assert.Equal("PropertyName", properties[0].Name); 211 } 212 213 [Fact] GetProperty_TypeNotCreated_ThrowsNotSupportedException()214 public void GetProperty_TypeNotCreated_ThrowsNotSupportedException() 215 { 216 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 217 Assert.Throws<NotSupportedException>(() => type.AsType().GetProperty("Any")); 218 } 219 220 [Fact] GetProperty_TypeCreated_ThrowsNotSupportedException()221 public void GetProperty_TypeCreated_ThrowsNotSupportedException() 222 { 223 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 224 type.CreateTypeInfo(); 225 226 Assert.Throws<NotSupportedException>(() => type.AsType().GetProperty("Name")); 227 } 228 229 [Fact] GetProperties_TypeNotCreated_ThrowsNotSupportedException()230 public void GetProperties_TypeNotCreated_ThrowsNotSupportedException() 231 { 232 TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); 233 Assert.Throws<NotSupportedException>(() => type.AsType().GetProperties()); 234 } 235 236 public class DefinePropertyClass 237 { 238 public int Property { get { return 10; } } 239 } 240 } 241 } 242