Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Strehovský <michals@microsoft.com>2017-12-28 23:07:40 +0300
committerMichal Strehovský <michals@microsoft.com>2017-12-29 14:41:32 +0300
commit2a0ded50fd791bc98b7e881a2c0af083715d9c0c (patch)
tree5f34df67d30b6097b21eb0800f917892ba7660c6
parent3f55a51b0012116bd766c1dd4edf2f09de20f323 (diff)
Add test coverage for the "reflection metadata from use" feature
-rw-r--r--tests/src/Simple/Reflection/Reflection.cs516
-rw-r--r--tests/src/Simple/SimpleTest.targets4
2 files changed, 341 insertions, 179 deletions
diff --git a/tests/src/Simple/Reflection/Reflection.cs b/tests/src/Simple/Reflection/Reflection.cs
index 79b137560..189090b3a 100644
--- a/tests/src/Simple/Reflection/Reflection.cs
+++ b/tests/src/Simple/Reflection/Reflection.cs
@@ -2,278 +2,436 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if MULTIMODULE_BUILD && !DEBUG
+// Some tests won't work if we're using optimizing codegen, but scanner doesn't run.
+// This currently happens in optimized multi-obj builds.
+#define OPTIMIZED_MODE_WITHOUT_SCANNER
+#endif
+
using System;
-using System.Globalization;
using System.Reflection;
-using System.Runtime.CompilerServices;
-public class ReflectionTest
-{
- const int Pass = 100;
- const int Fail = -1;
+[assembly: TestAssembly]
+[module: TestModule]
- public static int Main()
+internal class ReflectionTest
+{
+ private static int Main()
{
- CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
-
- if (TestNames() == Fail)
- return Fail;
+ // Things I would like to test, but we don't fully support yet:
+ // * Interface method is reflectable if we statically called it through a constrained call
+ // * Delegate Invoke method is reflectable if we statically called it
+
+ //
+ // Tests for dependency graph in the compiler
+ //
+#if !OPTIMIZED_MODE_WITHOUT_SCANNER
+ TestContainment.Run();
+ TestInterfaceMethod.Run();
+#endif
+ TestAttributeInheritance.Run();
+ TestStringConstructor.Run();
+ TestAssemblyAndModuleAttributes.Run();
+ TestAttributeExpressions.Run();
+
+ //
+ // Mostly functionality tests
+ //
+ TestCreateDelegate.Run();
+ TestInstanceFields.Run();
+ TestReflectionInvoke.Run();
+
+ return 100;
+ }
- if (TestUnification() == Fail)
- return Fail;
+ class TestReflectionInvoke
+ {
+ internal class InvokeTests
+ {
+ private string _world = "world";
+
+ public InvokeTests() { }
+
+ public InvokeTests(string message) { _world = message; }
+
+#if OPTIMIZED_MODE_WITHOUT_SCANNER
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+#endif
+ public static string GetHello(string name)
+ {
+ return "Hello " + name;
+ }
+
+#if OPTIMIZED_MODE_WITHOUT_SCANNER
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+#endif
+ public static void GetHelloByRef(string name, out string result)
+ {
+ result = "Hello " + name;
+ }
+
+#if OPTIMIZED_MODE_WITHOUT_SCANNER
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+#endif
+ public static string GetHelloGeneric<T>(T obj)
+ {
+ return "Hello " + obj;
+ }
+
+
+#if OPTIMIZED_MODE_WITHOUT_SCANNER
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+#endif
+ public string GetHelloInstance()
+ {
+ return "Hello " + _world;
+ }
+ }
- if (TestTypeOf() == Fail)
- return Fail;
+ public static void Run()
+ {
+ Console.WriteLine(nameof(TestReflectionInvoke));
+
+ // Ensure things we reflect on are in the static callgraph
+ if (string.Empty.Length > 0)
+ {
+ new InvokeTests().ToString();
+ InvokeTests.GetHello(null);
+ InvokeTests.GetHelloGeneric<int>(0);
+ InvokeTests.GetHelloGeneric<double>(0);
+ string unused;
+ InvokeTests.GetHelloByRef(null, out unused);
+ unused.ToString();
+ }
+
+ {
+ MethodInfo helloMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHello");
+ string result = (string)helloMethod.Invoke(null, new object[] { "world" });
+ if (result != "Hello world")
+ throw new Exception();
+ }
+
+ {
+ MethodInfo helloGenericMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloGeneric").MakeGenericMethod(typeof(int));
+ string result = (string)helloGenericMethod.Invoke(null, new object[] { 12345 });
+ if (result != "Hello 12345")
+ throw new Exception();
+ }
+
+ {
+ MethodInfo helloByRefMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloByRef");
+ object[] args = new object[] { "world", null };
+ helloByRefMethod.Invoke(null, args);
+ if ((string)args[1] != "Hello world")
+ throw new Exception();
+ }
+ }
+ }
- if (TestGenericComposition() == Fail)
- return Fail;
+ class TestInstanceFields
+ {
+ public class FieldInvokeSample
+ {
+ public String InstanceField;
+ }
- if (TestReflectionInvoke() == Fail)
- return Fail;
+ public static void Run()
+ {
+ Console.WriteLine(nameof(TestInstanceFields));
- if (TestReflectionFieldAccess() == Fail)
- return Fail;
+ TypeInfo ti = typeof(FieldInvokeSample).GetTypeInfo();
- if (TestCreateDelegate() == Fail)
- return Fail;
+ FieldInfo instanceField = ti.GetDeclaredField("InstanceField");
+ FieldInvokeSample obj = new FieldInvokeSample();
- return Pass;
- }
+ String value = (String)(instanceField.GetValue(obj));
+ if (value != null)
+ throw new Exception();
- private static int TestNames()
- {
- string hello = "Hello";
+ obj.InstanceField = "Hi!";
+ value = (String)(instanceField.GetValue(obj));
+ if (value != "Hi!")
+ throw new Exception();
- Type stringType = hello.GetType();
+ instanceField.SetValue(obj, "Bye!");
+ if (obj.InstanceField != "Bye!")
+ throw new Exception();
- if (stringType.FullName != "System.String")
- {
- Console.WriteLine("Bad name");
- return Fail;
+ value = (String)(instanceField.GetValue(obj));
+ if (value != "Bye!")
+ throw new Exception();
}
-
- return Pass;
}
- private static int TestUnification()
+ class TestCreateDelegate
{
- Console.WriteLine("Testing unification");
+ internal class Greeter
+ {
+ private string _who;
- // ReflectionTest type doesn't have an EEType and is metadata only.
- Type programType = Type.GetType("ReflectionTest");
- TypeInfo programTypeInfo = programType.GetTypeInfo();
+ public Greeter(string who) { _who = who; }
- Type programBaseType = programTypeInfo.BaseType;
+#if OPTIMIZED_MODE_WITHOUT_SCANNER
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
+#endif
+ public string Greet()
+ {
+ return "Hello " + _who;
+ }
+ }
- Type objectType = (new Object()).GetType();
+ delegate string GetHelloInstanceDelegate(Greeter o);
- if (!objectType.Equals(programBaseType))
+ public static void Run()
{
- Console.WriteLine("Unification failed");
- return Fail;
+ Console.WriteLine(nameof(TestCreateDelegate));
+
+ // Ensure things we reflect on are in the static callgraph
+ if (string.Empty.Length > 0)
+ {
+ new Greeter(null).Greet();
+ GetHelloInstanceDelegate d = null;
+ Func<Greeter, string> d2 = d.Invoke;
+ d = d2.Invoke;
+ }
+
+ TypeInfo ti = typeof(Greeter).GetTypeInfo();
+ MethodInfo mi = ti.GetDeclaredMethod(nameof(Greeter.Greet));
+ {
+ var d = (GetHelloInstanceDelegate)mi.CreateDelegate(typeof(GetHelloInstanceDelegate));
+ if (d(new Greeter("mom")) != "Hello mom")
+ throw new Exception();
+ }
+
+ {
+ var d = (Func<Greeter, string>)mi.CreateDelegate(typeof(Func<Greeter, string>));
+ if (d(new Greeter("pop")) != "Hello pop")
+ throw new Exception();
+ }
}
-
- return Pass;
}
- private static int TestTypeOf()
+ class TestAttributeExpressions
{
- Console.WriteLine("Testing typeof()");
+ struct FirstNeverUsedType { }
- Type intType = typeof(int);
+ struct SecondNeverUsedType { }
- if (intType.FullName != "System.Int32")
- {
- Console.WriteLine("Bad name");
- return Fail;
- }
+ class Gen<T> { }
- if (12.GetType() != typeof(int))
+ class TypeAttribute : Attribute
{
- Console.WriteLine("Bad compare");
- return Fail;
- }
+ public Type SomeType { get; set; }
- // This type only has a limited EEType (without a vtable) because it's not constructed.
- if (typeof(UnallocatedType).FullName != "UnallocatedType")
- {
- return Fail;
+ public TypeAttribute() { }
+ public TypeAttribute(Type someType)
+ {
+ SomeType = someType;
+ }
}
- if (typeof(int) != typeof(int))
+ enum MyEnum { }
+
+ class EnumArrayAttribute : Attribute
{
- Console.WriteLine("Bad compare");
- return Fail;
+ public MyEnum[] EnumArray;
}
- return Pass;
- }
-
- private static int TestGenericComposition()
- {
- Console.WriteLine("Testing generic composition");
+ [Type(typeof(FirstNeverUsedType*[,]))]
+ class Holder1 { }
- Type nullableOfIntType = typeof(int?);
+ [Type(SomeType = typeof(Gen<SecondNeverUsedType>))]
+ class Holder2 { }
- string fullName = nullableOfIntType.FullName;
- if (fullName.Contains("System.Nullable`1") && fullName.Contains("System.Int32"))
- return Pass;
-
- return Fail;
- }
+ [EnumArray(EnumArray = new MyEnum[] { 0 })]
+ class Holder3 { }
- internal class InvokeTests
- {
- private string _world = "world";
+ public static void Run()
+ {
+ Console.WriteLine(nameof(TestAttributeExpressions));
- public InvokeTests() { }
+ TypeAttribute attr1 = typeof(Holder1).GetCustomAttribute<TypeAttribute>();
+ if (attr1.SomeType.ToString() != "ReflectionTest+TestAttributeExpressions+FirstNeverUsedType*[,]")
+ throw new Exception();
- public InvokeTests(string message) { _world = message; }
+ TypeAttribute attr2 = typeof(Holder2).GetCustomAttribute<TypeAttribute>();
+ if (attr2.SomeType.ToString() != "ReflectionTest+TestAttributeExpressions+Gen`1[ReflectionTest+TestAttributeExpressions+SecondNeverUsedType]")
+ throw new Exception();
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static string GetHello(string name)
- {
- return "Hello " + name;
+ EnumArrayAttribute attr3 = typeof(Holder3).GetCustomAttribute<EnumArrayAttribute>();
+ if (attr3.EnumArray[0] != 0)
+ throw new Exception();
}
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void GetHelloByRef(string name, out string result)
+ class TestAssemblyAndModuleAttributes
+ {
+ public static void Run()
{
- result = "Hello " + name;
- }
+ Console.WriteLine(nameof(TestAssemblyAndModuleAttributes));
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static string GetHelloGeneric<T>(T obj)
- {
- return "Hello " + obj;
+ // Also tests GetExecutingAssembly
+ var assAttr = Assembly.GetExecutingAssembly().GetCustomAttribute<TestAssemblyAttribute>();
+ if (assAttr == null)
+ throw new Exception();
+
+ // Also tests GetEntryAssembly
+ var modAttr = Assembly.GetEntryAssembly().ManifestModule.GetCustomAttribute<TestModuleAttribute>();
+ if (modAttr == null)
+ throw new Exception();
}
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- public string GetHelloInstance()
+ class TestStringConstructor
+ {
+ public static void Run()
{
- return "Hello " + _world;
+ Console.WriteLine(nameof(TestStringConstructor));
+
+ // Ensure things we reflect on are in the static callgraph
+ if (string.Empty.Length > 0)
+ {
+ new string(new char[] { }, 0, 0);
+ }
+
+ ConstructorInfo ctor = typeof(string).GetConstructor(new Type[] { typeof(char[]), typeof(int), typeof(int) });
+ object str = ctor.Invoke(new object[] { new char[] { 'a' }, 0, 1 });
+ if ((string)str != "a")
+ throw new Exception();
}
}
- private static int TestReflectionInvoke()
+ class TestAttributeInheritance
{
- Console.WriteLine("Testing reflection invoke");
-
- // Dummy code to make sure the reflection targets are compiled.
- if (String.Empty.Length > 0)
+ class BaseAttribute : Attribute
{
- new InvokeTests().ToString();
- InvokeTests.GetHello(null);
- InvokeTests.GetHelloGeneric<int>(0);
- InvokeTests.GetHelloGeneric<double>(0);
- string unused;
- InvokeTests.GetHelloByRef(null, out unused);
- unused.ToString();
+ public string Field;
+ public int Property { get; set; }
}
+ class DerivedAttribute : BaseAttribute { }
+
+ [Derived(Field = "Hello", Property = 100)]
+ class TestType { }
+
+ public static void Run()
{
- MethodInfo helloMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHello");
- string result = (string)helloMethod.Invoke(null, new object[] { "world" });
- if (result != "Hello world")
- return Fail;
+ Console.WriteLine(nameof(TestAttributeInheritance));
+
+ DerivedAttribute attr = typeof(TestType).GetCustomAttribute<DerivedAttribute>();
+ if (attr.Field != "Hello" || attr.Property != 100)
+ throw new Exception();
}
+ }
+ class TestInterfaceMethod
+ {
+ interface IFoo
{
- MethodInfo helloGenericMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloGeneric").MakeGenericMethod(typeof(int));
- string result = (string)helloGenericMethod.Invoke(null, new object[] { 12345 });
- if (result != "Hello 12345")
- return Fail;
+ string Frob(int x);
}
+ class Foo : IFoo
{
- MethodInfo helloGenericMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloGeneric").MakeGenericMethod(typeof(double));
- string result = (string)helloGenericMethod.Invoke(null, new object[] { 3.14 });
- if (result != "Hello 3.14")
- return Fail;
+ public string Frob(int x)
+ {
+ return x.ToString();
+ }
}
+ public static void Run()
{
- MethodInfo helloByRefMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloByRef");
- object[] args = new object[] { "world", null };
- helloByRefMethod.Invoke(null, args);
- if ((string)args[1] != "Hello world")
- return Fail;
- }
+ Console.WriteLine(nameof(TestInterfaceMethod));
- return Pass;
- }
+ // Ensure things we reflect on are in the static callgraph
+ if (string.Empty.Length > 0)
+ {
+ ((IFoo)new Foo()).Frob(1);
+ }
- public class FieldInvokeSample
- {
- public String InstanceField;
+ object result = InvokeTestMethod(typeof(IFoo), "Frob", new Foo(), 42);
+ if ((string)result != "42")
+ throw new Exception();
+ }
}
- private static int TestReflectionFieldAccess()
+ class TestContainment
{
- Console.WriteLine("Testing reflection field access");
-
- if (string.Empty.Length > 0)
+ class NeverUsedContainerType
{
- new FieldInvokeSample().ToString();
+ public class UsedNestedType
+ {
+ public static int CallMe()
+ {
+ return 42;
+ }
+ }
}
- TypeInfo ti = typeof(FieldInvokeSample).GetTypeInfo();
+
+ public static void Run()
{
- FieldInfo instanceField = ti.GetDeclaredField("InstanceField");
- FieldInvokeSample obj = new FieldInvokeSample();
+ Console.WriteLine(nameof(TestContainment));
- String value = (String)(instanceField.GetValue(obj));
- if (value != null)
- return Fail;
+ // Ensure things we reflect on are in the static callgraph
+ if (string.Empty.Length > 0)
+ {
+ NeverUsedContainerType.UsedNestedType.CallMe();
+ }
- obj.InstanceField = "Hi!";
- value = (String)(instanceField.GetValue(obj));
- if (value != "Hi!")
- return Fail;
+ Type neverUsedContainerType = GetTestType(nameof(TestContainment), nameof(NeverUsedContainerType));
+ Type usedNestedType = neverUsedContainerType.GetNestedType(nameof(NeverUsedContainerType.UsedNestedType));
- instanceField.SetValue(obj, "Bye!");
- if (obj.InstanceField != "Bye!")
- return Fail;
+ // Since we called CallMe, it has reflection metadata and it is invokable
+ object o = InvokeTestMethod(usedNestedType, nameof(NeverUsedContainerType.UsedNestedType.CallMe));
+ if ((int)o != 42)
+ throw new Exception();
- value = (String)(instanceField.GetValue(obj));
- if (value != "Bye!")
- return Fail;
+ // We can get a type handle for the nested type (the invoke mapping table needs it)
+ if (!HasTypeHandle(usedNestedType))
+ throw new Exception($"{nameof(NeverUsedContainerType.UsedNestedType)} should have an EEType");
- return Pass;
+ // But the containing type doesn't need an EEType
+ if (HasTypeHandle(neverUsedContainerType))
+ throw new Exception($"{nameof(NeverUsedContainerType)} should not have an EEType");
}
}
- delegate string GetHelloInstanceDelegate(InvokeTests o);
+ #region Helpers
- private static int TestCreateDelegate()
+ private static Type GetTestType(string testName, string typeName)
{
- Console.WriteLine("Testing MethodInfo.CreateDelegate");
+ string fullTypeName = $"{nameof(ReflectionTest)}+{testName}+{typeName}";
+ Type result = Type.GetType(fullTypeName);
+ if (result == null)
+ throw new Exception($"'{fullTypeName}' could not be located");
+ return result;
+ }
- // Dummy code to make sure the reflection targets are compiled.
- if (String.Empty.Length > 0)
- {
- new InvokeTests().GetHelloInstance();
- GetHelloInstanceDelegate d = null;
- Func<InvokeTests, string> d2 = d.Invoke;
- d = d2.Invoke;
- }
+ private static object InvokeTestMethod(Type type, string methodName, object thisObj = null, params object[] param)
+ {
+ MethodInfo method = type.GetMethod(methodName);
+ if (method == null)
+ throw new Exception($"Method '{methodName}' not found on type {type}");
+
+ return method.Invoke(thisObj, param);
+ }
- TypeInfo ti = typeof(InvokeTests).GetTypeInfo();
- MethodInfo mi = ti.GetDeclaredMethod("GetHelloInstance");
+ private static bool HasTypeHandle(Type type)
+ {
+ try
{
- var d = (GetHelloInstanceDelegate)mi.CreateDelegate(typeof(GetHelloInstanceDelegate));
- if (d(new InvokeTests("mom")) != "Hello mom")
- return Fail;
+ RuntimeTypeHandle typeHandle = type.TypeHandle;
}
-
+ catch (Exception)
{
- var d = (Func<InvokeTests, string>)mi.CreateDelegate(typeof(Func<InvokeTests, string>));
- if (d(new InvokeTests("pop")) != "Hello pop")
- return Fail;
+ return false;
}
-
- return Pass;
+ return true;
}
+
+ #endregion
}
-class UnallocatedType { }
+class TestAssemblyAttribute : Attribute { }
+class TestModuleAttribute : Attribute { }
diff --git a/tests/src/Simple/SimpleTest.targets b/tests/src/Simple/SimpleTest.targets
index f222bfc4d..aae948971 100644
--- a/tests/src/Simple/SimpleTest.targets
+++ b/tests/src/Simple/SimpleTest.targets
@@ -50,6 +50,10 @@
<CustomLinkerArg Include="$(AdditionalLinkerFlags)" />
</ItemGroup>
+ <PropertyGroup>
+ <DefineConstants Condition="'$(IlcMultiModule)' == 'true'">MULTIMODULE_BUILD;$(DefineConstants)</DefineConstants>
+ </PropertyGroup>
+
<ItemGroup>
<IlcArg Include="--targetarch=$(Platform)" />
<IlcArg Include="--stacktracedata" />