forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInvokeWithRefLikeArgs.cs
More file actions
155 lines (130 loc) · 5.56 KB
/
Copy pathInvokeWithRefLikeArgs.cs
File metadata and controls
155 lines (130 loc) · 5.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Moq;
using Xunit;
using Xunit.Sdk;
namespace System.Reflection.Tests
{
public class InvokeWithRefLikeArgs
{
[Fact]
public static void MethodReturnsRefToRefStruct_ThrowsNSE()
{
MethodInfo mi = GetMethod(nameof(TestClass.ReturnsRefToRefStruct));
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, null));
}
[Fact]
public static void MethodTakesRefStructAsArg_ThrowsNSE()
{
MethodInfo mi = GetMethod(nameof(TestClass.TakesRefStructAsArg));
object[] args = new object[] { null };
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, args));
}
[Fact]
public static void MethodTakesRefStructAsArgWithDefaultValue_ThrowsNSE()
{
MethodInfo mi = GetMethod(nameof(TestClass.TakesRefStructAsArgWithDefaultValue));
object[] args = new object[] { Type.Missing };
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, args));
}
// Moq heavily utilizes RefEmit, which does not work on most aot workloads
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]
[SkipOnMono("https://github.com/dotnet/runtime/issues/40738")]
public static void MethodTakesRefToRefStructAsArg_ThrowsNSE()
{
// Use a Binder to trick the reflection stack into treating the returned null
// as meaning "use the default value of the ref struct".
Mock<Binder> mockBinder = new Mock<Binder>(MockBehavior.Strict);
Type myRefStructType = typeof(MyRefStruct);
mockBinder.Setup(o => o.ChangeType("hello", myRefStructType.MakeByRefType(), null)).Returns((object)null);
MethodInfo mi = GetMethod(nameof(TestClass.TakesRefToRefStructAsArg));
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, BindingFlags.InvokeMethod, mockBinder.Object, new object[] { "hello" }, null));
}
[Fact]
[SkipOnMono("https://github.com/dotnet/runtime/issues/40738")]
public static void MethodTakesOutToRefStructAsArg_ThrowsNSE()
{
MethodInfo mi = GetMethod(nameof(TestClass.TakesOutToRefStructAsArg));
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, new object[] { null }));
}
[Fact]
public static void PropertyTypedAsRefToRefStruct_AsMethodInfo_ThrowsNSE()
{
MethodInfo mi = GetMethod("get_" + nameof(TestClass.PropertyTypedAsRefToRefStruct));
Assert.Throws<NotSupportedException>(() => mi.Invoke(null, null));
}
[Fact]
public static void PropertyTypedAsRefToRefStruct_AsPropInfo_ThrowsNSE()
{
PropertyInfo pi = typeof(TestClass).GetProperty(nameof(TestClass.PropertyTypedAsRefToRefStruct));
Assert.NotNull(pi);
Assert.Throws<NotSupportedException>(() => pi.GetValue(null));
}
[Fact]
public static void PropertyIndexerWithRefStructArg_ThrowsNSE()
{
PropertyInfo pi = typeof(TestClassWithIndexerWithRefStructArg).GetProperty("Item");
Assert.NotNull(pi);
object obj = new TestClassWithIndexerWithRefStructArg();
object[] args = new object[] { null };
Assert.Throws<NotSupportedException>(() => pi.GetValue(obj, args));
Assert.Throws<NotSupportedException>(() => pi.SetValue(obj, 42, args));
}
private sealed class TestClass
{
private static int _backingField = 42;
public unsafe static ref MyRefStruct ReturnsRefToRefStruct()
{
fixed (int* pInt = &_backingField)
{
return ref *(MyRefStruct*)pInt; // will return a valid ref
}
}
public static void TakesRefStructAsArg(MyRefStruct o)
{
Assert.Equal(0, o.MyInt); // should be default(T)
}
public static void TakesRefStructAsArgWithDefaultValue(MyRefStruct o = default)
{
Assert.Equal(0, o.MyInt); // should be default(T)
}
public static void TakesRefToRefStructAsArg(ref MyRefStruct o)
{
throw new XunitException("Should never be called.");
}
public static void TakesOutToRefStructAsArg(out MyRefStruct o)
{
throw new XunitException("Should never be called.");
}
public static ref MyRefStruct PropertyTypedAsRefToRefStruct
{
get { return ref ReturnsRefToRefStruct(); }
}
}
private static MethodInfo GetMethod(string name)
{
MethodInfo mi = typeof(TestClass).GetMethod(name, BindingFlags.Static | BindingFlags.Public);
Assert.NotNull(mi);
return mi;
}
private sealed class TestClassWithIndexerWithRefStructArg
{
public int this[MyRefStruct o]
{
get
{
Assert.Equal(0, o.MyInt); // should be default(T)
return 42;
}
set
{
Assert.Equal(0, o.MyInt); // should be default(T)
}
}
}
private ref struct MyRefStruct
{
public int MyInt;
}
}
}