diff --git a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs index 226313620f88..8ffa4aa85979 100644 --- a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs +++ b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs @@ -20,6 +20,32 @@ public static void TryCopyTo() Assert.Equal(src, dst); } + [Fact] + public static void TryCopyToArraySegmentImplicit() + { + int[] src = { 1, 2, 3 }; + int[] dst = { 5, 99, 100, 101, 10 }; + var segment = new ArraySegment(dst, 1, 3); + + ReadOnlySpan srcSpan = new ReadOnlySpan(src); + bool success = srcSpan.TryCopyTo(segment); + Assert.True(success); + Assert.Equal(src, segment); + } + + [Fact] + public static void TryCopyToEmpty() + { + int[] src = { }; + int[] dst = { 99, 100, 101 }; + + ReadOnlySpan srcSpan = new ReadOnlySpan(src); + bool success = srcSpan.TryCopyTo(dst); + Assert.True(success); + int[] expected = { 99, 100, 101 }; + Assert.Equal(expected, dst); + } + [Fact] public static void TryCopyToLonger() { diff --git a/src/System.Memory/tests/ReadOnlySpan/Equality.cs b/src/System.Memory/tests/ReadOnlySpan/Equality.cs index 5c0b87a719cd..a884be495d16 100644 --- a/src/System.Memory/tests/ReadOnlySpan/Equality.cs +++ b/src/System.Memory/tests/ReadOnlySpan/Equality.cs @@ -89,5 +89,22 @@ public static void EmptySpansNotUnified() Assert.False(left == right); Assert.False(!(left != right)); } + + [Fact] + public static void CannotCallEqualsOnSpan() + { + ReadOnlySpan left = new ReadOnlySpan(new int[0]); + try + { +#pragma warning disable 0618 + bool result = left.Equals(new object()); +#pragma warning restore 0618 + Assert.True(false); + } + catch (Exception ex) + { + Assert.True(ex is NotSupportedException); + } + } } } diff --git a/src/System.Memory/tests/ReadOnlySpan/GetHashCode.cs b/src/System.Memory/tests/ReadOnlySpan/GetHashCode.cs new file mode 100644 index 000000000000..da4b9e9c3acf --- /dev/null +++ b/src/System.Memory/tests/ReadOnlySpan/GetHashCode.cs @@ -0,0 +1,29 @@ +// 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; + +namespace System.SpanTests +{ + public static partial class ReadOnlySpanTests + { + [Fact] + public static void CannotCallGetHashCodeOnSpan() + { + ReadOnlySpan span = new ReadOnlySpan(new int[0]); + + try + { +#pragma warning disable 0618 + int result = span.GetHashCode(); +#pragma warning restore 0618 + Assert.True(false); + } + catch (Exception ex) + { + Assert.True(ex is NotSupportedException); + } + } + } +} diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs index a52b81698db3..8d7fd82a433a 100644 --- a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs +++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs @@ -2,6 +2,7 @@ // 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.Numerics; using Xunit; namespace System.SpanTests @@ -16,10 +17,27 @@ public static void ZeroLengthIndexOf_Byte() Assert.Equal(-1, idx); } + [Fact] + public static void DefaultFilledIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + ReadOnlySpan span = new ReadOnlySpan(a); + + for (int i = 0; i < length; i++) + { + byte target0 = default(byte); + int idx = span.IndexOf(target0); + Assert.Equal(0, idx); + } + } + } + [Fact] public static void TestMatch_Byte() { - for (int length = 0; length < 32; length++) + for (int length = 0; length < byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) @@ -37,15 +55,72 @@ public static void TestMatch_Byte() } } + [Fact] + public static void TestNoMatch_Byte() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + byte target = (byte)rnd.Next(0, 256); + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == target ? (byte)(target + 1) : val; + } + ReadOnlySpan span = new ReadOnlySpan(a); + + int idx = span.IndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentNoMatch_Byte() + { + byte[] array = new byte[4 * Vector.Count]; + for (var i = 0; i < Vector.Count; i++) + { + var span = new ReadOnlySpan(array, i, 3 * Vector.Count); + int idx = span.IndexOf((byte)'1'); + Assert.Equal(-1, idx); + + span = new ReadOnlySpan(array, i, 3 * Vector.Count - 3); + idx = span.IndexOf((byte)'1'); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentMatch_Byte() + { + byte[] array = new byte[4 * Vector.Count]; + for (int i = 0; i < array.Length; i++) + { + array[i] = 5; + } + for (var i = 0; i < Vector.Count; i++) + { + var span = new ReadOnlySpan(array, i, 3 * Vector.Count); + int idx = span.IndexOf(5); + Assert.Equal(0, idx); + + span = new ReadOnlySpan(array, i, 3 * Vector.Count - 3); + idx = span.IndexOf(5); + Assert.Equal(0, idx); + } + } + [Fact] public static void TestMultipleMatch_Byte() { - for (int length = 2; length < 32; length++) + for (int length = 2; length < byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) { - a[i] = (byte)(i + 1); + byte val = (byte)(i + 1); + a[i] = val == 200 ? (byte)201 : val; } a[length - 1] = 200; @@ -60,7 +135,7 @@ public static void TestMultipleMatch_Byte() [Fact] public static void MakeSureNoChecksGoOutOfRange_Byte() { - for (int length = 0; length < 100; length++) + for (int length = 0; length < byte.MaxValue; length++) { byte[] a = new byte[length + 2]; a[0] = 99; diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.byte.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.byte.cs index 5a02f1577679..fa5d6dce35f9 100644 --- a/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.byte.cs +++ b/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.byte.cs @@ -28,6 +28,27 @@ public static void SameSpanSequenceEqual_Byte() Assert.True(b); } + [Fact] + public static void SequenceEqualArrayImplicit_Byte() + { + byte[] a = { 4, 5, 6 }; + ReadOnlySpan first = new ReadOnlySpan(a, 0, 3); + bool b = first.SequenceEqual(a); + Assert.True(b); + } + + [Fact] + public static void SequenceEqualArraySegmentImplicit_Byte() + { + byte[] src = { 1, 2, 3 }; + byte[] dst = { 5, 1, 2, 3, 10 }; + var segment = new ArraySegment(dst, 1, 3); + + ReadOnlySpan first = new ReadOnlySpan(src, 0, 3); + bool b = first.SequenceEqual(segment); + Assert.True(b); + } + [Fact] public static void LengthMismatchSequenceEqual_Byte() { diff --git a/src/System.Memory/tests/Span/Clear.cs b/src/System.Memory/tests/Span/Clear.cs index 93a2981bac21..2c448eaac7c8 100644 --- a/src/System.Memory/tests/Span/Clear.cs +++ b/src/System.Memory/tests/Span/Clear.cs @@ -149,6 +149,21 @@ public static void ClearValueTypeWithoutReferencesLonger() Assert.Equal(expected, actual); } + [Fact] + public static void ClearValueTypeWithoutReferencesPointerSize() + { + long[] actual = new long[15]; + for (int i = 0; i < actual.Length; i++) + { + actual[i] = i + 1; + } + long[] expected = new long[actual.Length]; + + var span = new Span(actual); + span.Clear(); + Assert.Equal(expected, actual); + } + [Fact] public static void ClearReferenceType() { @@ -175,6 +190,17 @@ public static void ClearReferenceTypeLonger() Assert.Equal(expected, actual); } + [Fact] + public static void ClearEnumType() + { + TestEnum[] actual = {TestEnum.e0, TestEnum.e1, TestEnum.e2}; + TestEnum[] expected = {default(TestEnum), default(TestEnum), default(TestEnum) }; + + var span = new Span(actual); + span.Clear(); + Assert.Equal(expected, actual); + } + [Fact] public static void ClearValueTypeWithReferences() { diff --git a/src/System.Memory/tests/Span/CopyTo.cs b/src/System.Memory/tests/Span/CopyTo.cs index 9c895cbdf3b8..080d75f59c93 100644 --- a/src/System.Memory/tests/Span/CopyTo.cs +++ b/src/System.Memory/tests/Span/CopyTo.cs @@ -20,6 +20,32 @@ public static void TryCopyTo() Assert.Equal(src, dst); } + [Fact] + public static void TryCopyToArraySegmentImplicit() + { + int[] src = { 1, 2, 3 }; + int[] dst = { 5, 99, 100, 101, 10 }; + var segment = new ArraySegment(dst, 1, 3); + + Span srcSpan = new Span(src); + bool success = srcSpan.TryCopyTo(segment); + Assert.True(success); + Assert.Equal(src, segment); + } + + [Fact] + public static void TryCopyToEmpty() + { + int[] src = {}; + int[] dst = { 99, 100, 101 }; + + Span srcSpan = new Span(src); + bool success = srcSpan.TryCopyTo(dst); + Assert.True(success); + int[] expected = { 99, 100, 101 }; + Assert.Equal(expected, dst); + } + [Fact] public static void TryCopyToLonger() { diff --git a/src/System.Memory/tests/Span/Equality.cs b/src/System.Memory/tests/Span/Equality.cs index 688682446af1..921a40fbb9b2 100644 --- a/src/System.Memory/tests/Span/Equality.cs +++ b/src/System.Memory/tests/Span/Equality.cs @@ -89,5 +89,23 @@ public static void EmptySpansNotUnified() Assert.False(left == right); Assert.False(!(left != right)); } + + [Fact] + public static void CannotCallEqualsOnSpan() + { + Span left = new Span(new int[0]); + + try + { +#pragma warning disable 0618 + bool result = left.Equals(new object()); +#pragma warning restore 0618 + Assert.True(false); + } + catch (Exception ex) + { + Assert.True(ex is NotSupportedException); + } + } } } diff --git a/src/System.Memory/tests/Span/Fill.cs b/src/System.Memory/tests/Span/Fill.cs index 020500848315..4976bd815f6b 100644 --- a/src/System.Memory/tests/Span/Fill.cs +++ b/src/System.Memory/tests/Span/Fill.cs @@ -2,6 +2,7 @@ // 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.Runtime.InteropServices; using Xunit; namespace System.SpanTests @@ -58,12 +59,20 @@ public static void FillByteUnaligned() [Fact] public static void FillValueTypeWithoutReferences() { - int[] actual = { 1, 2, 3 }; - int[] expected = { 5, 5, 5 }; - - var span = new Span(actual); - span.Fill(5); - Assert.Equal(expected, actual); + const byte fill = 5; + for (int length = 0; length < 32; length++) + { + var expectedFull = new int[length]; + var actualFull = new int[length]; + for (int i = 0; i < length; i++) + { + expectedFull[i] = fill; + actualFull[i] = i; + } + var span = new Span(actualFull); + span.Fill(fill); + Assert.Equal(expectedFull, actualFull); + } } [Fact] @@ -93,5 +102,50 @@ public static void FillValueTypeWithReferences() span.Fill(new TestValueTypeWithReference() { I = 5, S = "d" }); Assert.Equal(expected, actual); } + + [Fact] + public static unsafe void FillNativeBytes() + { + // Arrange + int length = 50; + + byte* ptr = null; + try + { + ptr = (byte*)Marshal.AllocHGlobal((IntPtr)50); + } + // Skipping test if Out-of-Memory, since this test can only be run, if there is enough memory + catch (OutOfMemoryException) + { + Console.WriteLine( + $"Span.Fill test {nameof(FillNativeBytes)} skipped due to {nameof(OutOfMemoryException)}."); + return; + } + + try + { + byte initial = 1; + for (int i = 0; i < length; i++) + { + *(ptr + i) = initial; + } + const byte fill = 5; + var span = new Span(ptr, length); + + // Act + span.Fill(fill); + + // Assert using custom code for perf and to avoid allocating extra memory + for (int i = 0; i < length; i++) + { + var actual = *(ptr + i); + Assert.Equal(fill, actual); + } + } + finally + { + Marshal.FreeHGlobal(new IntPtr(ptr)); + } + } } } diff --git a/src/System.Memory/tests/Span/GetHashCode.cs b/src/System.Memory/tests/Span/GetHashCode.cs new file mode 100644 index 000000000000..2b33b3c16a23 --- /dev/null +++ b/src/System.Memory/tests/Span/GetHashCode.cs @@ -0,0 +1,29 @@ +// 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; + +namespace System.SpanTests +{ + public static partial class SpanTests + { + [Fact] + public static void CannotCallGetHashCodeOnSpan() + { + Span span = new Span(new int[0]); + + try + { +#pragma warning disable 0618 + int result = span.GetHashCode(); +#pragma warning restore 0618 + Assert.True(false); + } + catch (Exception ex) + { + Assert.True(ex is NotSupportedException); + } + } + } +} diff --git a/src/System.Memory/tests/Span/IndexOf.byte.cs b/src/System.Memory/tests/Span/IndexOf.byte.cs index aca94dbcbc5a..214d5262c818 100644 --- a/src/System.Memory/tests/Span/IndexOf.byte.cs +++ b/src/System.Memory/tests/Span/IndexOf.byte.cs @@ -2,6 +2,7 @@ // 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.Numerics; using Xunit; namespace System.SpanTests @@ -16,10 +17,27 @@ public static void ZeroLengthIndexOf_Byte() Assert.Equal(-1, idx); } + [Fact] + public static void DefaultFilledIndexOf_Byte() + { + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + Span span = new Span(a); + + for (int i = 0; i < length; i++) + { + byte target0 = default(byte); + int idx = span.IndexOf(target0); + Assert.Equal(0, idx); + } + } + } + [Fact] public static void TestMatch_Byte() { - for (int length = 0; length < 32; length++) + for (int length = 0; length <= byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) @@ -37,15 +55,72 @@ public static void TestMatch_Byte() } } + [Fact] + public static void TestNoMatch_Byte() + { + var rnd = new Random(42); + for (int length = 0; length <= byte.MaxValue; length++) + { + byte[] a = new byte[length]; + byte target = (byte)rnd.Next(0, 256); + for (int i = 0; i < length; i++) + { + byte val = (byte)(i + 1); + a[i] = val == target ? (byte)(target + 1) : val; + } + Span span = new Span(a); + + int idx = span.IndexOf(target); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentNoMatch_Byte() + { + byte[] array = new byte[4 * Vector.Count]; + for (var i = 0; i < Vector.Count; i++) + { + var span = new Span(array, i, 3 * Vector.Count); + int idx = span.IndexOf((byte)'1'); + Assert.Equal(-1, idx); + + span = new Span(array, i, 3 * Vector.Count - 3); + idx = span.IndexOf((byte)'1'); + Assert.Equal(-1, idx); + } + } + + [Fact] + public static void TestAllignmentMatch_Byte() + { + byte[] array = new byte[4 * Vector.Count]; + for (int i = 0; i < array.Length; i++) + { + array[i] = 5; + } + for (var i = 0; i < Vector.Count; i++) + { + var span = new Span(array, i, 3 * Vector.Count); + int idx = span.IndexOf(5); + Assert.Equal(0, idx); + + span = new Span(array, i, 3 * Vector.Count - 3); + idx = span.IndexOf(5); + Assert.Equal(0, idx); + } + } + [Fact] public static void TestMultipleMatch_Byte() { - for (int length = 2; length < 32; length++) + for (int length = 2; length <= byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) { - a[i] = (byte)(i + 1); + byte val = (byte)(i + 1); + a[i] = val == 200 ? (byte)201 : val; } a[length - 1] = 200; @@ -60,7 +135,7 @@ public static void TestMultipleMatch_Byte() [Fact] public static void MakeSureNoChecksGoOutOfRange_Byte() { - for (int length = 0; length < 100; length++) + for (int length = 0; length <= byte.MaxValue; length++) { byte[] a = new byte[length + 2]; a[0] = 99; diff --git a/src/System.Memory/tests/Span/SequenceEqual.byte.cs b/src/System.Memory/tests/Span/SequenceEqual.byte.cs index 617f21390101..85205875e819 100644 --- a/src/System.Memory/tests/Span/SequenceEqual.byte.cs +++ b/src/System.Memory/tests/Span/SequenceEqual.byte.cs @@ -28,6 +28,27 @@ public static void SameSpanSequenceEqual_Byte() Assert.True(b); } + [Fact] + public static void SequenceEqualArrayImplicit_Byte() + { + byte[] a = { 4, 5, 6 }; + Span first = new Span(a, 0, 3); + bool b = first.SequenceEqual(a); + Assert.True(b); + } + + [Fact] + public static void SequenceEqualArraySegmentImplicit_Byte() + { + byte[] src = { 1, 2, 3 }; + byte[] dst = { 5, 1, 2, 3, 10 }; + var segment = new ArraySegment(dst, 1, 3); + + Span first = new Span(src, 0, 3); + bool b = first.SequenceEqual(segment); + Assert.True(b); + } + [Fact] public static void LengthMismatchSequenceEqual_Byte() { diff --git a/src/System.Memory/tests/Span/TestHelpers.cs b/src/System.Memory/tests/Span/TestHelpers.cs index 1d86cf815783..0e00c970cd50 100644 --- a/src/System.Memory/tests/Span/TestHelpers.cs +++ b/src/System.Memory/tests/Span/TestHelpers.cs @@ -81,6 +81,15 @@ private struct TestValueTypeWithReference public int I; public string S; } + + private enum TestEnum + { + e0, + e1, + e2, + e3, + e4, + } } } diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj index 2e993a78af9c..d1c55c84aa4d 100644 --- a/src/System.Memory/tests/System.Memory.Tests.csproj +++ b/src/System.Memory/tests/System.Memory.Tests.csproj @@ -24,6 +24,7 @@ + @@ -52,6 +53,7 @@ +