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 TypeBuilderSetParent
11     {
SetParent_TestData()12         public static IEnumerable<object[]> SetParent_TestData()
13         {
14             yield return new object[] { TypeAttributes.NotPublic, typeof(EmptyNonGenericClass), typeof(EmptyNonGenericClass) };
15             yield return new object[] { TypeAttributes.NotPublic, typeof(object), typeof(object) };
16             yield return new object[] { TypeAttributes.NotPublic, null, typeof(object) };
17             yield return new object[] { TypeAttributes.Abstract, typeof(EmptyGenericClass<int>), typeof(EmptyGenericClass<int>) };
18             yield return new object[] { TypeAttributes.Interface | TypeAttributes.Abstract, null, null };
19         }
20 
21         [Theory]
22         [MemberData(nameof(SetParent_TestData))]
SetParent(TypeAttributes attributes, Type parent, Type expected)23         public void SetParent(TypeAttributes attributes, Type parent, Type expected)
24         {
25             TypeBuilder type = Helpers.DynamicType(attributes);
26 
27             type.SetParent(parent);
28             Assert.Equal(expected, type.BaseType);
29 
30             TypeInfo createdType = type.CreateTypeInfo();
31             Assert.Equal(expected, createdType.BaseType);
32         }
33 
34         [Fact]
SetParent_TypeCreated_ThrowsInvalidOperationException()35         public void SetParent_TypeCreated_ThrowsInvalidOperationException()
36         {
37             TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic);
38             type.CreateTypeInfo().AsType();
39             Assert.Throws<InvalidOperationException>(() => type.SetParent(typeof(string)));
40         }
41 
42         [Fact]
43         [ActiveIssue(13977)]
SetParent_This_LoopsForever()44         public void SetParent_This_LoopsForever()
45         {
46             TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic);
47             type.SetParent(type.AsType());
48             Assert.Equal(type.AsType(), type.BaseType);
49 
50             Assert.ThrowsAny<Exception>(() => type.CreateTypeInfo());
51         }
52 
53         [Fact]
SetParent_ThisIsInterface_ThrowsTypeLoadExceptionOnLoad()54         public void SetParent_ThisIsInterface_ThrowsTypeLoadExceptionOnLoad()
55         {
56             TypeBuilder type = Helpers.DynamicType(TypeAttributes.Interface | TypeAttributes.Abstract);
57             type.SetParent(typeof(EmptyNonGenericClass));
58             Assert.Throws<TypeLoadException>(() => type.CreateTypeInfo());
59         }
60 
61         [Theory]
62         [InlineData(TypeAttributes.NotPublic)]
63         [InlineData(TypeAttributes.Interface | TypeAttributes.Abstract)]
SetParent_InterfaceType_ThrowsArgumentException(TypeAttributes attributes)64         public void SetParent_InterfaceType_ThrowsArgumentException(TypeAttributes attributes)
65         {
66             TypeBuilder type = Helpers.DynamicType(attributes);
67             AssertExtensions.Throws<ArgumentException>(null, () => type.SetParent(typeof(EmptyNonGenericInterface1)));
68         }
69 
70         [Fact]
SetParent_ByRefType_ThrowsArgumentExceptionOnCreation()71         public void SetParent_ByRefType_ThrowsArgumentExceptionOnCreation()
72         {
73             TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
74 
75             type.SetParent(typeof(int).MakeByRefType());
76             Assert.Equal(typeof(int).MakeByRefType(), type.BaseType);
77 
78             AssertExtensions.Throws<ArgumentException>(null, () => type.CreateTypeInfo());
79         }
80 
81         [Fact]
SetParent_GenericParameter_ThrowsNotSupportedExceptionOnCreation()82         public void SetParent_GenericParameter_ThrowsNotSupportedExceptionOnCreation()
83         {
84             TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic);
85             GenericTypeParameterBuilder genericType = type.DefineGenericParameters("T")[0];
86 
87             type.SetParent(genericType.AsType());
88             Assert.Equal(genericType.AsType(), type.BaseType);
89 
90             Assert.Throws<NotSupportedException>(() => type.CreateTypeInfo());
91         }
92 
93         [Fact]
ParentNotCreated_ThrowsNotSupportedExceptionOnCreation()94         public void ParentNotCreated_ThrowsNotSupportedExceptionOnCreation()
95         {
96             ModuleBuilder module = Helpers.DynamicModule();
97             TypeBuilder type = module.DefineType("Daughter", TypeAttributes.Public);
98             TypeBuilder parentType = module.DefineType("Parent", TypeAttributes.Public);
99 
100             type.SetParent(parentType.AsType());
101             Assert.Equal(parentType.AsType(), type.BaseType);
102 
103             Assert.Throws<NotSupportedException>(() => type.CreateTypeInfo());
104         }
105 
106         [Theory]
107         [InlineData(typeof(void))]
108         [InlineData(typeof(EmptyNonGenericStruct))]
109         [InlineData(typeof(EmptyEnum))]
110         [InlineData(typeof(EmptyGenericStruct<>))]
111         [InlineData(typeof(EmptyGenericStruct<int>))]
112         [InlineData(typeof(SealedClass))]
113         [InlineData(typeof(int?))]
ParentNotInheritable_ThrowsTypeLoadExceptionOnCreation(Type parentType)114         public void ParentNotInheritable_ThrowsTypeLoadExceptionOnCreation(Type parentType)
115         {
116             TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
117 
118             type.SetParent(parentType);
119             Assert.Equal(parentType, type.BaseType);
120 
121             Assert.Throws<TypeLoadException>(() => type.CreateTypeInfo());
122         }
123 
124         [Theory]
125         [InlineData(typeof(string))]
126         [InlineData(typeof(StaticClass))]
127         [InlineData(typeof(int*))]
128         [InlineData(typeof(EmptyNonGenericClass[]))]
ParentHasNoDefaultConstructor_ThrowsNotSupportedExceptionOnCreation(Type parentType)129         public void ParentHasNoDefaultConstructor_ThrowsNotSupportedExceptionOnCreation(Type parentType)
130         {
131             TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
132 
133             type.SetParent(parentType);
134             Assert.Equal(parentType, type.BaseType);
135 
136             Assert.Throws<NotSupportedException>(() => type.CreateTypeInfo());
137         }
138 
139         [Fact]
ParentOpenGenericClass_ThrowsBadImageFormatExceptionOnCreation()140         public void ParentOpenGenericClass_ThrowsBadImageFormatExceptionOnCreation()
141         {
142             TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
143 
144             type.SetParent(typeof(EmptyGenericClass<>));
145             Assert.Equal(typeof(EmptyGenericClass<>), type.BaseType);
146 
147             Assert.Throws<BadImageFormatException>(() => type.CreateTypeInfo());
148         }
149     }
150 }
151