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