Skip to content

Commit

Permalink
Add tests for calling Span APIs via reflection to verify graceful fai…
Browse files Browse the repository at this point in the history
…lures. (dotnet/corefx#28674)

* Add tests for calling Span APIs via reflection to verify graceful failures.

* Add Span reflection tests to verify graceful failures

* Address PR feedback (test cleanup and rename)

* Fix up some test names

* Minor tweak: Reorder the tests

* Exclude running the reflection tests for portable span (netfx)

* Remove unused constant from csproj


Commit migrated from dotnet/corefx@a7b59b0
  • Loading branch information
ahsonkhan authored Mar 31, 2018
1 parent c9fc5f5 commit a6ae2fa
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 0 deletions.
186 changes: 186 additions & 0 deletions src/libraries/System.Memory/tests/Span/Reflection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// 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 Xunit;
using System.Buffers;
using System.Buffers.Binary;
using System.Reflection;
using System.Runtime.InteropServices;
using System.MemoryTests;

namespace System.SpanTests
{
public static partial class SpanTests
{
// Calling Span APIs via Reflection is not supported yet.
// These tests check that using reflection results in graceful failures. See https://github.com/dotnet/coreclr/issues/17296
// These tests are only relevant for fast span.

[Fact]
public static void MemoryExtensions_StaticReturningReadOnlySpan()
{
Type type = typeof(MemoryExtensions);

MethodInfo method = type.GetMethod(nameof(MemoryExtensions.AsSpan), new Type[] { typeof(string) });
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { "Hello" }));

method = type.GetMethod(nameof(MemoryExtensions.AsSpan), new Type[] { typeof(string), typeof(int), typeof(int) });
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { "Hello", 1, 1 }));
}

[Fact]
public static void MemoryExtensions_StaticWithSpanArguments()
{
Type type = typeof(MemoryExtensions);

MethodInfo method = type.GetMethod(nameof(MemoryExtensions.CompareTo));

int result = (int)method.Invoke(null, new object[] { default, default, StringComparison.Ordinal });
Assert.Equal(0, result);
}

[Fact]
public static void BinaryPrimitives_StaticWithSpanArgument()
{
Type type = typeof(BinaryPrimitives);

MethodInfo method = type.GetMethod(nameof(BinaryPrimitives.ReadInt16LittleEndian));
Assert.Throws<TargetInvocationException>(() => method.Invoke(null, new object[] { default }));

method = type.GetMethod(nameof(BinaryPrimitives.TryReadInt16LittleEndian));
bool result = (bool)method.Invoke(null, new object[] { default, null });
Assert.False(result);
}

[Fact]
public static void MemoryMarshal_GenericStaticReturningSpan()
{
Type type = typeof(MemoryMarshal);

int value = 0;
ref int refInt = ref value;

MethodInfo method = type.GetMethod(nameof(MemoryMarshal.CreateSpan)).MakeGenericMethod((refInt.GetType()));
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { null, 0 }));
}

[Fact]
public static void Span_Constructor()
{
Type type = typeof(Span<int>);

ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(int[]) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10] }));

ctor = type.GetConstructor(new Type[] { typeof(int[]), typeof(int), typeof(int) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10], 1, 1 }));

ctor = type.GetConstructor(new Type[] { typeof(void*), typeof(int) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { null, 1 }));
}

[Fact]
public static void Span_Property()
{
Type type = typeof(Span<int>);

PropertyInfo property = type.GetProperty(nameof(Span<int>.Empty));
Assert.Throws<NotSupportedException>(() => property.GetValue(default));
}

[Fact]
public static void Span_StaticOperator()
{
Type type = typeof(Span<int>);

MethodInfo method = type.GetMethod("op_Equality");
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));

method = type.GetMethod("op_Inequality");
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
}

[Fact]
public static void Span_InstanceMethod()
{
Type type = typeof(Span<int>);

MethodInfo method = type.GetMethod(nameof(Span<int>.CopyTo), new Type[] { typeof(Span<int>) });
Assert.Throws<NotSupportedException>(() => method.Invoke(default, new object[] { default }));
}

[Fact]
public static void ReadOnlySpan_Constructor()
{
Type type = typeof(ReadOnlySpan<int>);

ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(int[]) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10] }));

ctor = type.GetConstructor(new Type[] { typeof(int[]), typeof(int), typeof(int) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10], 1, 1 }));

ctor = type.GetConstructor(new Type[] { typeof(void*), typeof(int) });
Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { null, 1 }));
}

[Fact]
public static void ReadOnlySpan_Property()
{
Type type = typeof(ReadOnlySpan<int>);

PropertyInfo property = type.GetProperty(nameof(ReadOnlySpan<int>.Empty));
Assert.Throws<NotSupportedException>(() => property.GetValue(default));
}

[Fact]
public static void ReadOnlySpan_Operator()
{
Type type = typeof(ReadOnlySpan<int>);

MethodInfo method = type.GetMethod("op_Equality");
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));

method = type.GetMethod("op_Inequality");
Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
}

[Fact]
public static void ReadOnlySpan_InstanceMethod()
{
Type type = typeof(ReadOnlySpan<int>);

MethodInfo method = type.GetMethod(nameof(ReadOnlySpan<int>.CopyTo), new Type[] { typeof(Span<int>) });
Assert.Throws<NotSupportedException>(() => method.Invoke(default, new object[] { default }));
}

[Fact]
public static void Memory_PropertyReturningSpan()
{
Type type = typeof(Memory<int>);

PropertyInfo property = type.GetProperty(nameof(Memory<int>.Span));
Assert.Throws<NotSupportedException>(() => property.GetValue(null));
}

[Fact]
public static void ReadOnlyMemory_PropertyReturningReadOnlySpan()
{
Type type = typeof(ReadOnlyMemory<int>);

PropertyInfo property = type.GetProperty(nameof(ReadOnlyMemory<int>.Span));
Assert.Throws<NotSupportedException>(() => property.GetValue(null));
}

[Fact]
public static void MemoryManager_MethodReturningSpan()
{
Type type = typeof(MemoryManager<int>);

MemoryManager<int> manager = new CustomMemoryForTest<int>(new int[10]);
MethodInfo method = type.GetMethod(nameof(MemoryManager<int>.GetSpan), BindingFlags.Public | BindingFlags.Instance);
Assert.Throws<NotSupportedException>(() => method.Invoke(manager, null));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<!-- Tests specific to the fast span -->
<Compile Include="MemoryMarshal\CreateSpan.cs" />
<Compile Include="MemoryMarshal\CreateReadOnlySpan.cs" />
<Compile Include="Span\Reflection.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="AllocationHelper.cs" />
Expand Down

0 comments on commit a6ae2fa

Please sign in to comment.