From 79c84e436d521f347997245724772693979e9f3e Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 18 May 2015 15:17:53 +0200 Subject: Add ready to run tests Add tests to verify ready to run handles versioning correctly. --- tests/src/readytorun/app.config | 39 ++++ tests/src/readytorun/main.cs | 325 +++++++++++++++++++++++++++++++ tests/src/readytorun/mainv1.csproj | 59 ++++++ tests/src/readytorun/mainv2.csproj | 59 ++++++ tests/src/readytorun/packages.config | 13 ++ tests/src/readytorun/test.cs | 363 +++++++++++++++++++++++++++++++++++ tests/src/readytorun/testv1.csproj | 41 ++++ tests/src/readytorun/testv2.csproj | 41 ++++ 8 files changed, 940 insertions(+) create mode 100644 tests/src/readytorun/app.config create mode 100644 tests/src/readytorun/main.cs create mode 100644 tests/src/readytorun/mainv1.csproj create mode 100644 tests/src/readytorun/mainv2.csproj create mode 100644 tests/src/readytorun/packages.config create mode 100644 tests/src/readytorun/test.cs create mode 100644 tests/src/readytorun/testv1.csproj create mode 100644 tests/src/readytorun/testv2.csproj (limited to 'tests') diff --git a/tests/src/readytorun/app.config b/tests/src/readytorun/app.config new file mode 100644 index 0000000000..7f13fbce41 --- /dev/null +++ b/tests/src/readytorun/app.config @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/src/readytorun/main.cs b/tests/src/readytorun/main.cs new file mode 100644 index 0000000000..8604a3ef96 --- /dev/null +++ b/tests/src/readytorun/main.cs @@ -0,0 +1,325 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +#if CORECLR +using System.Runtime.Loader; +#endif +using System.Reflection; +using System.IO; + +class InstanceFieldTest : MyClass +{ + public int Value; +} + +class InstanceFieldTest2 : InstanceFieldTest +{ + public int Value2; +} + +[StructLayout(LayoutKind.Sequential)] +class InstanceFieldTestWithLayout : MyClassWithLayout +{ + public int Value; +} + +class GrowingBase +{ + MyGrowingStruct s; +} + +class InheritingFromGrowingBase : GrowingBase +{ + public int x; +} + +class Program +{ + static void TestVirtualMethodCalls() + { + var o = new MyClass(); + Assert.AreEqual(o.VirtualMethod(), "Virtual method result"); + + var iface = (IMyInterface)o; + Assert.AreEqual(iface.InterfaceMethod(" "), "Interface result"); + Assert.AreEqual(MyClass.TestInterfaceMethod(iface, "+"), "Interface+result"); + } + + static void TestMovedVirtualMethods() + { + var o = new MyChildClass(); + + Assert.AreEqual(o.MovedToBaseClass(), "MovedToBaseClass"); + Assert.AreEqual(o.ChangedToVirtual(), "ChangedToVirtual"); + + o = null; + + try + { + o.MovedToBaseClass(); + } + catch (NullReferenceException) + { + try + { + o.ChangedToVirtual(); + } + catch (NullReferenceException) + { + return; + } + } + + Assert.AreEqual("NullReferenceException", "thrown"); + } + + + static void TestConstrainedMethodCalls() + { + using (MyStruct s = new MyStruct()) + { + ((Object)s).ToString(); + } + } + + static void TestConstrainedMethodCalls_Unsupported() + { + MyStruct s = new MyStruct(); + s.ToString(); + } + + static void TestInterop() + { + // Verify both intra-module and inter-module PInvoke interop + MyClass.GetTickCount(); + MyClass.TestInterop(); + } + + static void TestStaticFields() + { + MyClass.StaticObjectField = 894; + MyClass.StaticLongField = 4392854; + MyClass.StaticNullableGuidField = new Guid("0D7E505F-E767-4FEF-AEEC-3243A3005673"); + MyClass.ThreadStaticStringField = "Hello"; + MyClass.ThreadStaticIntField = 735; + MyClass.ThreadStaticDateTimeField = new DateTime(2011, 1, 1); + + MyClass.TestStaticFields(); + +#if false // TODO: Enable once LDFTN is supported + Task.Run(() => { + MyClass.ThreadStaticStringField = "Garbage"; + MyClass.ThreadStaticIntField = 0xBAAD; + MyClass.ThreadStaticDateTimeField = DateTime.Now; + }).Wait(); +#endif + + Assert.AreEqual(MyClass.StaticObjectField, 894 + 12345678 /* + 1234 */); + Assert.AreEqual(MyClass.StaticLongField, (long)(4392854 * 456 /* * 45 */)); + Assert.AreEqual(MyClass.StaticNullableGuidField, null); + Assert.AreEqual(MyClass.ThreadStaticStringField, "HelloWorld"); + Assert.AreEqual(MyClass.ThreadStaticIntField, 735/78); + Assert.AreEqual(MyClass.ThreadStaticDateTimeField, new DateTime(2011, 1, 1) + new TimeSpan(123)); + } + + static void TestPreInitializedArray() + { + var a = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 }; + + int sum = 0; + foreach (var e in a) sum += e; + Assert.AreEqual(sum, 1023); + } + + static void TestMultiDimmArray() + { + var a = new int[2,3,4]; + a[0,1,2] = a[0,0,0] + a[1,1,1]; + a.ToString(); + } + + static void TestGenericVirtualMethod() + { + var o = new MyGeneric(); + Assert.AreEqual(o.GenericVirtualMethod>(), + "System.StringSystem.ObjectProgramSystem.Collections.Generic.IEnumerable`1[System.String]"); + } + + static void TestMovedGenericVirtualMethod() + { + var o = new MyChildGeneric(); + + Assert.AreEqual(o.MovedToBaseClass(), typeof(List).ToString()); + Assert.AreEqual(o.ChangedToVirtual(), typeof(List).ToString()); + + o = null; + + try + { + o.MovedToBaseClass(); + } + catch (NullReferenceException) + { + try + { + o.ChangedToVirtual(); + } + catch (NullReferenceException) + { + return; + } + } + + Assert.AreEqual("NullReferenceException", "thrown"); + } + + static void TestInstanceFields() + { + var t = new InstanceFieldTest2(); + t.Value = 123; + t.Value2 = 234; + t.InstanceField = 345; + + Assert.AreEqual(typeof(InstanceFieldTest).GetRuntimeField("Value").GetValue(t), 123); + Assert.AreEqual(typeof(InstanceFieldTest2).GetRuntimeField("Value2").GetValue(t), 234); + Assert.AreEqual(typeof(MyClass).GetRuntimeField("InstanceField").GetValue(t), 345); + } + + static void TestInstanceFieldsWithLayout() + { + var t = new InstanceFieldTestWithLayout(); + t.Value = 123; + + Assert.AreEqual(typeof(InstanceFieldTestWithLayout).GetRuntimeField("Value").GetValue(t), 123); + } + + static void TestInheritingFromGrowingBase() + { + var o = new InheritingFromGrowingBase(); + o.x = 6780; + Assert.AreEqual(typeof(InheritingFromGrowingBase).GetRuntimeField("x").GetValue(o), 6780); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestGrowingStruct() + { + MyGrowingStruct s = MyGrowingStruct.Construct(); + MyGrowingStruct.Check(ref s); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestChangingStruct() + { + MyChangingStruct s = MyChangingStruct.Construct(); + s.x++; + MyChangingStruct.Check(ref s); + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void TestChangingHFAStruct() + { + MyChangingHFAStruct s = MyChangingHFAStruct.Construct(); + MyChangingHFAStruct.Check(s); + } + +#if CORECLR + class MyLoadContext : AssemblyLoadContext + { + public MyLoadContext() + { + } + + public void TestMultipleLoads() + { +#if V2 + string testVersion = "2"; +#else + string testVersion = "1"; +#endif + Assembly a = LoadFromAssemblyPath(Path.Combine(Directory.GetCurrentDirectory(), "NI", "testv" + testVersion + ".ni.dll")); + Assert.AreEqual(AssemblyLoadContext.GetLoadContext(a), this); + } + + protected override Assembly Load(AssemblyName an) + { + throw new NotImplementedException(); + } + } + + static void TestMultipleLoads() + { + try + { + new MyLoadContext().TestMultipleLoads(); + } + catch (FileLoadException e) + { + Assert.AreEqual(e.ToString().Contains("Native image cannot be loaded multiple times"), true); + return; + } + + Assert.AreEqual("FileLoadException", "thrown"); + } +#endif + + static void TestFieldLayoutNGenMixAndMatch() + { + // This test is verifying consistent field layout when ReadyToRun images are combined with NGen images + // "ngen install /nodependencies main.exe" to exercise the interesting case + var o = new ByteChildClass(67); + Assert.AreEqual(o.ChildByte, (byte)67); + } + + static void RunAllTests() + { + TestVirtualMethodCalls(); + TestMovedVirtualMethods(); + + TestConstrainedMethodCalls(); + + TestConstrainedMethodCalls_Unsupported(); + + TestInterop(); + + TestStaticFields(); + + TestPreInitializedArray(); + + TestMultiDimmArray(); + + TestGenericVirtualMethod(); + TestMovedGenericVirtualMethod(); + + TestInstanceFields(); + + TestInstanceFieldsWithLayout(); + + TestInheritingFromGrowingBase(); + + TestGrowingStruct(); + TestChangingStruct(); + TestChangingHFAStruct(); + +#if CORECLR + TestMultipleLoads(); +#endif + + TestFieldLayoutNGenMixAndMatch(); + } + + static int Main() + { + // Run all tests 3x times to exercise both slow and fast paths work + for (int i = 0; i < 3; i++) + RunAllTests(); + + Console.WriteLine("PASSED"); + return Assert.HasAssertFired ? 1 : 100; + } +} diff --git a/tests/src/readytorun/mainv1.csproj b/tests/src/readytorun/mainv1.csproj new file mode 100644 index 0000000000..cc47339ea2 --- /dev/null +++ b/tests/src/readytorun/mainv1.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + mainv1 + 2.0 + {7DECC55A-B584-4456-83BA-6C42A5B3B3CB} + exe + Properties + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + true + 7a9bfb7d + $(DefineConstants);STATIC;CORECLR + + + + + + + + + False + + + + + {F74F55A1-DFCF-4C7C-B462-E96E1D0BB667} + + + + + + + + + + + + + + + $(TargetDir)\testv1.dll + + + + <_CLRTestPreCommands> + + + diff --git a/tests/src/readytorun/mainv2.csproj b/tests/src/readytorun/mainv2.csproj new file mode 100644 index 0000000000..d52265385c --- /dev/null +++ b/tests/src/readytorun/mainv2.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + mainv2 + 2.0 + {840300BB-0DD2-4BD3-A3C1-51C92DD4ADAD} + exe + Properties + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + true + 7a9bfb7d + $(DefineConstants);STATIC;CORECLR;V2 + + + + + + + + + False + + + + + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + + + + + + + + + + + + + + + $(TargetDir)\testv2.dll + + + + <_CLRTestPreCommands> + + + diff --git a/tests/src/readytorun/packages.config b/tests/src/readytorun/packages.config new file mode 100644 index 0000000000..a1da6980b1 --- /dev/null +++ b/tests/src/readytorun/packages.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/src/readytorun/test.cs b/tests/src/readytorun/test.cs new file mode 100644 index 0000000000..19347689f4 --- /dev/null +++ b/tests/src/readytorun/test.cs @@ -0,0 +1,363 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +public static class Assert +{ + public static bool HasAssertFired; + + public static void AreEqual(Object actual, Object expected) + { + if (!(actual == null && expected == null) && !actual.Equals(expected)) + { + Console.WriteLine("Not equal!"); + Console.WriteLine("actual = " + actual.ToString()); + Console.WriteLine("expected = " + expected.ToString()); + HasAssertFired = true; + } + } +} + +public interface IMyInterface +{ +#if V2 + // Adding new methods to interfaces is incompatible change, but we will make sure that it works anyway + void NewInterfaceMethod(); +#endif + + string InterfaceMethod(string s); +} + +public class MyClass : IMyInterface +{ +#if V2 + public int _field1; + public int _field2; + public int _field3; +#endif + public int InstanceField; + +#if V2 + public static Object StaticObjectField2; + + [ThreadStatic] public static String ThreadStaticStringField2; + + [ThreadStatic] public static int ThreadStaticIntField; + + public static Nullable StaticNullableGuidField; + + public static Object StaticObjectField; + + [ThreadStatic] public static int ThreadStaticIntField2; + + public static long StaticLongField; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField2; + + public static long StaticLongField2; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField; + + public static Nullable StaticNullableGuidField2; + + [ThreadStatic] public static String ThreadStaticStringField; +#else + public static Object StaticObjectField; + + public static long StaticLongField; + + public static Nullable StaticNullableGuidField; + + [ThreadStatic] public static String ThreadStaticStringField; + + [ThreadStatic] public static int ThreadStaticIntField; + + [ThreadStatic] public static DateTime ThreadStaticDateTimeField; +#endif + + public MyClass() + { + } + +#if V2 + public virtual void NewVirtualMethod() + { + } + + public virtual void NewInterfaceMethod() + { + throw new Exception(); + } +#endif + + public virtual string VirtualMethod() + { + return "Virtual method result"; + } + + public virtual string InterfaceMethod(string s) + { + return "Interface" + s + "result"; + } + + public static string TestInterfaceMethod(IMyInterface i, string s) + { + return i.InterfaceMethod(s); + } + + public static void TestStaticFields() + { + StaticObjectField = (int)StaticObjectField + 12345678; + + StaticLongField *= 456; + + Assert.AreEqual(StaticNullableGuidField, new Guid("0D7E505F-E767-4FEF-AEEC-3243A3005673")); + StaticNullableGuidField = null; + + ThreadStaticStringField += "World"; + + ThreadStaticIntField /= 78; + + ThreadStaticDateTimeField = ThreadStaticDateTimeField + new TimeSpan(123); + + MyGeneric.ThreadStatic = new Object(); + +#if false // TODO: Enable once LDFTN is supported + // Do some operations on static fields on a different thread to verify that we are not mixing thread-static and non-static + Task.Run(() => { + + StaticObjectField = (int)StaticObjectField + 1234; + + StaticLongField *= 45; + + ThreadStaticStringField = "Garbage"; + + ThreadStaticIntField = 0xBAAD; + + ThreadStaticDateTimeField = DateTime.Now; + + }).Wait(); +#endif + } + + [DllImport("api-ms-win-core-sysinfo-l1-1-0.dll")] + public extern static int GetTickCount(); + + static public void TestInterop() + { + GetTickCount(); + } + +#if V2 + public string MovedToBaseClass() + { + return "MovedToBaseClass"; + } +#endif + +#if V2 + public virtual string ChangedToVirtual() + { + return null; + } +#else + public string ChangedToVirtual() + { + return "ChangedToVirtual"; + } +#endif + +} + +public class MyChildClass : MyClass +{ + public MyChildClass() + { + } + +#if !V2 + public string MovedToBaseClass() + { + return "MovedToBaseClass"; + } +#endif + +#if V2 + public override string ChangedToVirtual() + { + return "ChangedToVirtual"; + } +#endif +} + + +public struct MyStruct : IDisposable +{ + int x; + +#if V2 + void IDisposable.Dispose() + { + } +#else + public void Dispose() + { + } +#endif +} + +public class MyGeneric +{ + [ThreadStatic] public static Object ThreadStatic; + + public MyGeneric() + { + } + + public virtual string GenericVirtualMethod() + { + return typeof(T).ToString() + typeof(U).ToString() + typeof(V).ToString() + typeof(W).ToString(); + } + +#if V2 + public string MovedToBaseClass() + { + typeof(Dictionary).ToString(); + return typeof(List).ToString(); + } +#endif + +#if V2 + public virtual string ChangedToVirtual() + { + return null; + } +#else + public string ChangedToVirtual() + { + return typeof(List).ToString(); + } +#endif +} + +public class MyChildGeneric : MyGeneric +{ + public MyChildGeneric() + { + } + +#if !V2 + public string MovedToBaseClass() + { + return typeof(List).ToString(); + } +#endif + +#if V2 + public override string ChangedToVirtual() + { + typeof(Dictionary).ToString(); + return typeof(List).ToString(); + } +#endif +} + +[StructLayout(LayoutKind.Sequential)] +public class MyClassWithLayout +{ +#if V2 + public int _field1; + public int _field2; + public int _field3; +#endif +} + +public struct MyGrowingStruct +{ + int x; + int y; +#if V2 + Object o1; + Object o2; +#endif + + static public MyGrowingStruct Construct() + { + return new MyGrowingStruct() { x = 111, y = 222 }; + } + + public static void Check(ref MyGrowingStruct s) + { + Assert.AreEqual(s.x, 111); + Assert.AreEqual(s.y, 222); + } +} + +public struct MyChangingStruct +{ +#if V2 + public int y; + public int x; +#else + public int x; + public int y; +#endif + + static public MyChangingStruct Construct() + { + return new MyChangingStruct() { x = 111, y = 222 }; + } + + public static void Check(ref MyChangingStruct s) + { + Assert.AreEqual(s.x, 112); + Assert.AreEqual(s.y, 222); + } +} + +public struct MyChangingHFAStruct +{ +#if V2 + float x; + float y; +#else + int x; + int y; +#endif + static public MyChangingHFAStruct Construct() + { + return new MyChangingHFAStruct() { x = 12, y = 23 }; + } + + public static void Check(MyChangingHFAStruct s) + { +#if V2 + Assert.AreEqual(s.x, 12.0f); + Assert.AreEqual(s.y, 23.0f); +#else + Assert.AreEqual(s.x, 12); + Assert.AreEqual(s.y, 23); +#endif + } +} + +public class ByteBaseClass : List +{ + public byte BaseByte; +} +public class ByteChildClass : ByteBaseClass +{ + public byte ChildByte; + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public ByteChildClass(byte value) + { + ChildByte = 67; + } +} diff --git a/tests/src/readytorun/testv1.csproj b/tests/src/readytorun/testv1.csproj new file mode 100644 index 0000000000..041f92e7f8 --- /dev/null +++ b/tests/src/readytorun/testv1.csproj @@ -0,0 +1,41 @@ + + + + + Debug + AnyCPU + testv1 + 2.0 + {F74F55A1-DFCF-4C7C-B462-E96E1D0BB667} + library + Properties + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + true + 7a9bfb7d + $(DefineConstants);STATIC;CORECLR + + + + + + + + + False + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/src/readytorun/testv2.csproj b/tests/src/readytorun/testv2.csproj new file mode 100644 index 0000000000..8771df06b5 --- /dev/null +++ b/tests/src/readytorun/testv2.csproj @@ -0,0 +1,41 @@ + + + + + Debug + AnyCPU + testv2 + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + library + Properties + 512 + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + true + 7a9bfb7d + $(DefineConstants);STATIC;CORECLR;V2 + + + + + + + + + False + + + + + + + + + + + + + + -- cgit v1.2.3