Last active
August 7, 2018 08:41
-
-
Save MichalStrehovsky/482e1818df7e01363a27bfb0cbd3c837 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Licensed to the .NET Foundation under one or more agreements. | |
// The .NET Foundation licenses this file to you under the MIT license. | |
// See the LICENSE file in the project root for more information. | |
using System; | |
using System.Reflection; | |
using System.Runtime.CompilerServices; | |
public class InvokeRefReturnNetcoreTests | |
{ | |
public static void TestRefReturnPropertyGetValue() | |
{ | |
TestRefReturnInvoke(false, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke('a', (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((byte)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((sbyte)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((ushort)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((short)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((ulong)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((long)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((uint)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((int)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(42.0f, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(42.0, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((IntPtr)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((UIntPtr)42, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(232953453454m, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(Mine.One, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke("Hello", (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(new object(), (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke(new int[0], (p, t) => p.GetValue(t)); | |
TestRefReturnInvoke((object)null, (p, t) => p.GetValue(t)); | |
} | |
public static void TestRefReturnMethodInvoke() | |
{ | |
TestRefReturnInvoke(false, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke('a', (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((byte)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((sbyte)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((ushort)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((short)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((ulong)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((long)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((uint)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((int)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(42.0f, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(42.0, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((IntPtr)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((UIntPtr)42, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(232953453454m, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(Mine.One, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke("Hello", (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(new object(), (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke(new int[0], (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
TestRefReturnInvoke((object)null, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>())); | |
} | |
public static void TestRefReturnNullable() | |
{ | |
TestRefReturnInvokeNullable<int>(42); | |
TestRefReturnInvokeNullable<Mine>(Mine.One); | |
TestRefReturnInvokeNullable<BigStruct>(new BigStruct { X = 987, D = 543 }); | |
} | |
public static void TestRefReturnNullableNoValue() | |
{ | |
TestRefReturnInvokeNullable<int>(default(int?)); | |
TestRefReturnInvokeNullable<Mine>(default(Mine?)); | |
TestRefReturnInvokeNullable<BigStruct>(default(BigStruct?)); | |
} | |
public static void TestNullRefReturnInvoke() | |
{ | |
TestNullRefReturnInvoke(false); | |
TestNullRefReturnInvoke('a'); | |
TestNullRefReturnInvoke((byte)42); | |
TestNullRefReturnInvoke((sbyte)42); | |
TestNullRefReturnInvoke((ushort)42); | |
TestNullRefReturnInvoke((short)42); | |
TestNullRefReturnInvoke((ulong)42); | |
TestNullRefReturnInvoke((long)42); | |
TestNullRefReturnInvoke((uint)42); | |
TestNullRefReturnInvoke((int)42); | |
TestNullRefReturnInvoke(42.0f); | |
TestNullRefReturnInvoke(42.0); | |
TestNullRefReturnInvoke((IntPtr)42); | |
TestNullRefReturnInvoke((UIntPtr)42); | |
TestNullRefReturnInvoke(232953453454m); | |
TestNullRefReturnInvoke(Mine.One); | |
TestNullRefReturnInvoke("Hello"); | |
TestNullRefReturnInvoke(new BigStruct { X = 123, D = 456 }); | |
TestNullRefReturnInvoke(new object()); | |
TestNullRefReturnInvoke(new int[0]); | |
TestNullRefReturnInvoke((object)null); | |
} | |
public static unsafe void TestRefReturnOfPointer() | |
{ | |
int* expected = (int*)0x1122334455667788; | |
TestClassIntPointer tc = new TestClassIntPointer(expected); | |
if (string.Empty.Length > 0) | |
{ | |
((IntPtr)tc.RefReturningProp).ToString(); | |
} | |
PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.RefReturningProp)); | |
object rv = p.GetValue(tc); | |
Assert.True(rv is Pointer); | |
int* actual = (int*)(Pointer.Unbox(rv)); | |
Assert.Equal((IntPtr)expected, (IntPtr)actual); | |
} | |
public static unsafe void TestNullRefReturnOfPointer() | |
{ | |
TestClassIntPointer tc = new TestClassIntPointer(null); | |
if (string.Empty.Length > 0) | |
{ | |
((IntPtr)tc.NullRefReturningProp).ToString(); | |
} | |
PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp)); | |
Assert.NotNull(p); | |
Assert.Throws<NullReferenceException>(() => p.GetValue(tc)); | |
} | |
public static unsafe void TestByRefLikeRefReturn() | |
{ | |
if (string.Empty.Length > 0) | |
{ | |
TestClass<int>.ByRefLikeRefReturningMethod(null); | |
} | |
ByRefLike brl = new ByRefLike(); | |
ByRefLike* pBrl = &brl; | |
MethodInfo mi = typeof(TestClass<int>).GetMethod(nameof(TestClass<int>.ByRefLikeRefReturningMethod)); | |
try | |
{ | |
// Don't use Assert.Throws because that will make a lambda and invalidate the pointer | |
object o = mi.Invoke(null, new object[] { Pointer.Box(pBrl, typeof(ByRefLike*)) }); | |
Assert.Fail(); | |
} | |
catch (NotSupportedException) | |
{ | |
} | |
} | |
private static void TestNullRefReturnInvoke<T>(T value) | |
{ | |
TestClass<T> tc = new TestClass<T>(value); | |
if (String.Empty.Length > 0) | |
{ | |
tc.NullRefReturningProp.ToString(); | |
} | |
PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.NullRefReturningProp)); | |
Assert.NotNull(p); | |
Assert.Throws<NullReferenceException>(() => p.GetValue(tc)); | |
} | |
private static void TestRefReturnInvoke<T>(T value, Func<PropertyInfo, TestClass<T>, object> invoker) | |
{ | |
TestClass<T> tc = new TestClass<T>(value); | |
if (String.Empty.Length > 0) | |
{ | |
tc.RefReturningProp.ToString(); | |
} | |
PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.RefReturningProp)); | |
object rv = invoker(p, tc); | |
if (rv != null) | |
{ | |
Assert.Equal(typeof(T), rv.GetType()); | |
} | |
if (typeof(T).IsValueType) | |
{ | |
Assert.Equal(value, rv); | |
} | |
else | |
{ | |
Assert.Same(value, rv); | |
} | |
} | |
private static void TestRefReturnInvokeNullable<T>(T? nullable) where T : struct | |
{ | |
TestClass<T?> tc = new TestClass<T?>(nullable); | |
if (string.Empty.Length > 0) | |
{ | |
tc.RefReturningProp.ToString(); | |
} | |
PropertyInfo p = typeof(TestClass<T?>).GetProperty(nameof(TestClass<T?>.RefReturningProp)); | |
object rv = p.GetValue(tc); | |
if (rv != null) | |
{ | |
Assert.Equal(typeof(T), rv.GetType()); | |
} | |
if (nullable.HasValue) | |
{ | |
Assert.Equal(nullable.Value, rv); | |
} | |
else | |
{ | |
Assert.Null(rv); | |
} | |
} | |
enum Mine { One = 2018 } | |
struct BigStruct { public ulong X, Y, Z, W, A, B, C, D; } | |
public ref struct ByRefLike { } | |
private sealed class TestClass<T> | |
{ | |
private T _value; | |
public TestClass(T value) { _value = value; } | |
public ref T RefReturningProp => ref _value; | |
public unsafe ref T NullRefReturningProp => ref Unsafe.AsRef<T>((void*)null); | |
public static unsafe ref ByRefLike ByRefLikeRefReturningMethod(ByRefLike* a) => ref *a; | |
} | |
private sealed unsafe class TestClassIntPointer | |
{ | |
private int* _value; | |
public TestClassIntPointer(int* value) { _value = value; } | |
public ref int* RefReturningProp => ref _value; | |
public unsafe ref int* NullRefReturningProp => ref *(int**)null; | |
} | |
public static void Main() | |
{ | |
TestRefReturnPropertyGetValue(); | |
TestRefReturnMethodInvoke(); | |
TestRefReturnNullable(); | |
TestRefReturnNullableNoValue(); | |
TestRefReturnOfPointer(); | |
TestNullRefReturnOfPointer(); | |
TestNullRefReturnInvoke(); | |
TestByRefLikeRefReturn(); | |
} | |
class Assert | |
{ | |
public static void Equal<T>(T expected, T actual) | |
{ | |
if (object.ReferenceEquals(expected, actual)) | |
return; | |
if ((object)expected == null || (object)actual == null) | |
throw new Exception(); | |
if (!expected.Equals(actual)) | |
throw new Exception(); | |
} | |
public static void Same<T>(T expected, T actual) | |
{ | |
if (!object.ReferenceEquals(expected, actual)) | |
throw new Exception(); | |
} | |
public static void Null(object x) | |
{ | |
if (x != null) | |
throw new Exception(); | |
} | |
public static void NotNull(object x) | |
{ | |
if (x == null) | |
throw new Exception(); | |
} | |
public static void True(bool x) | |
{ | |
if (!x) | |
throw new Exception(); | |
} | |
public static void Fail() | |
{ | |
throw new Exception(); | |
} | |
public static void Throws<T>(Action a) | |
{ | |
try | |
{ | |
a(); | |
} | |
catch (Exception ex) | |
{ | |
if (ex.GetType() != typeof(T)) | |
throw new Exception(); | |
return; | |
} | |
throw new Exception(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment