Skip to content

Instantly share code, notes, and snippets.

@MichalStrehovsky
Last active August 7, 2018 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MichalStrehovsky/482e1818df7e01363a27bfb0cbd3c837 to your computer and use it in GitHub Desktop.
Save MichalStrehovsky/482e1818df7e01363a27bfb0cbd3c837 to your computer and use it in GitHub Desktop.
// 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