From f8040bac33b9ef957c93c36ffdc643195f1d6996 Mon Sep 17 00:00:00 2001 From: Ganbarukamo41 Date: Mon, 15 Apr 2019 00:34:34 +0100 Subject: [PATCH] Implement IEquatable to Memory and ReadOnlyMemory (dotnet/corefx#36497) * Implement IEquatable to Memory and ReadOnlyMemory * Add equality tests using IEquatable of ReadOnlyMemory and Memory * Fix and add tests for Memory and ReadOnlyMemory * Fixed where IEquatable interface tests were using object.Equals(object) instead of T.Equals(T) * Added IEquatable interface tests for Memory of different types (char, string) * Fix IEquatable tests for Memory and ReadOnlyMemory * Fix tests that were missed in the previous commit (IEquatable tests calling object.Equals(object)) * Should use ReadOnlyMemory in ReadOnlyMemory tests * Update uapaot baseline for dotnet/corefx#36497 Implementing IEquatable to Memory and ReadOnlyMemory (see dotnet/corefx#32905) * Update uapaot baseline for dotnet/corefx#36497 Implementing IEquatable to Memory and ReadOnlyMemory (see dotnet/corefx#32905) * Remove baselines added to System.Runtime by mistake * Add baselines to System.Memory * Update uapaot baseline for dotnet/corefx#36497 Implementing IEquatable to Memory and ReadOnlyMemory (see dotnet/corefx#32905) * Add removed baselines to System.Runtime again Commit migrated from https://github.com/dotnet/corefx/commit/68920bb0764fb13257f710f44dd08e85e4a35c7c --- .../System.Memory/src/ApiCompatBaseline.uapaot.txt | 4 + .../System.Memory/tests/Memory/Equality.cs | 105 ++++++++++++++++++++ .../System.Memory/tests/ReadOnlyMemory/Equality.cs | 106 +++++++++++++++++++++ src/libraries/System.Runtime/ref/System.Runtime.cs | 4 +- .../src/ApiCompatBaseline.uapaot.txt | 2 + 5 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/libraries/System.Memory/src/ApiCompatBaseline.uapaot.txt diff --git a/src/libraries/System.Memory/src/ApiCompatBaseline.uapaot.txt b/src/libraries/System.Memory/src/ApiCompatBaseline.uapaot.txt new file mode 100644 index 0000000..3630a69 --- /dev/null +++ b/src/libraries/System.Memory/src/ApiCompatBaseline.uapaot.txt @@ -0,0 +1,4 @@ +Compat issues with assembly System.Memory: +CannotRemoveBaseTypeOrInterface : Type 'System.Memory' does not implement interface 'System.IEquatable>' in the implementation but it does in the contract. +CannotRemoveBaseTypeOrInterface : Type 'System.ReadOnlyMemory' does not implement interface 'System.IEquatable>' in the implementation but it does in the contract. +Total issues: 2 diff --git a/src/libraries/System.Memory/tests/Memory/Equality.cs b/src/libraries/System.Memory/tests/Memory/Equality.cs index 86f8d61..da24284 100644 --- a/src/libraries/System.Memory/tests/Memory/Equality.cs +++ b/src/libraries/System.Memory/tests/Memory/Equality.cs @@ -120,6 +120,111 @@ namespace System.MemoryTests Assert.True(readOnlyMemory.Equals(memoryAsObject)); } + [Fact] + public static void EqualityThroughInterface_True() + { + int[] a = { 10, 11, 12, 13, 14 }; + Memory left = new Memory(a, 2, 3); + Memory right = new Memory(a, 2, 3); + IEquatable> leftAsEquatable = left; + IEquatable> rightAsEquatable = right; + + Assert.True(leftAsEquatable.Equals(right)); + Assert.True(rightAsEquatable.Equals(left)); + } + + [Fact] + public static void EqualityThroughInterface_Reflexivity() + { + int[] array = { 42, 43, 44, 45, 46 }; + Memory left = new Memory(array, 2, 3); + IEquatable> leftAsEquatable = left; + + Assert.True(leftAsEquatable.Equals(left)); + } + + [Fact] + public static void EqualityThroughInterface_IncludesLength() + { + int[] array = { 42, 43, 44, 45, 46 }; + Memory baseline = new Memory(array, 2, 3); + Memory equalRangeButLength = new Memory(array, 2, 2); + IEquatable> baselineAsEquatable = baseline; + IEquatable> anotherOneAsEquatable = equalRangeButLength; + + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); + Assert.False(anotherOneAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_IncludesBase() + { + int[] array = { 42, 43, 44, 45, 46 }; + Memory baseline = new Memory(array, 2, 3); + Memory equalLengthButRange = new Memory(array, 1, 3); + IEquatable> baselineAsEquatable = baseline; + IEquatable> anotherOneAsEquatable = equalLengthButRange; + + Assert.False(baselineAsEquatable.Equals(equalLengthButRange)); + Assert.False(anotherOneAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_ComparesRangeNotContent() + { + Memory baseline = new Memory(new [] { 1, 2, 3, 4, 5, 6 }, 2, 3); + Memory duplicate = new Memory(new [] { 1, 2, 3, 4, 5, 6 }, 2, 3); + IEquatable> baselineAsEquatable = baseline; + IEquatable> duplicateAsEquatable = duplicate; + + Assert.False(baselineAsEquatable.Equals(duplicate)); + Assert.False(duplicateAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_Strings() + { + string[] array = { "A", "B", "C", "D", "E", "F" }; + string[] anotherArray = { "A", "B", "C", "D", "E", "F" }; + + Memory baseline = new Memory(array, 2, 3); + IEquatable> baselineAsEquatable = baseline; + Memory equalRangeAndLength = new Memory(array, 2, 3); + Memory equalRangeButLength = new Memory(array, 2, 2); + Memory equalLengthButReference = new Memory(array, 3, 3); + Memory differentArraySegmentAsMemory = new Memory(anotherArray, 2, 3); + + Assert.True(baselineAsEquatable.Equals(baseline)); // Reflexivity + Assert.True(baselineAsEquatable.Equals(equalRangeAndLength)); // Range check & length check + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); // Length check + Assert.False(baselineAsEquatable.Equals(equalLengthButReference)); // Range check + + Assert.True(baseline.Span.SequenceEqual(differentArraySegmentAsMemory.Span)); + Assert.False(baselineAsEquatable.Equals(differentArraySegmentAsMemory)); // Doesn't check for content equality + } + + [Fact] + public static void EqualityThroughInterface_Chars() + { + char[] array = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!' }; + char[] anotherArray = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!' }; + + Memory baseline = new Memory(array, 2, 3); + IEquatable> baselineAsEquatable = baseline; + Memory equalRangeAndLength = new Memory(array, 2, 3); + Memory equalRangeButLength = new Memory(array, 2, 2); + Memory equalLengthButReference = new Memory(array, 3, 3); + Memory differentArraySegmentAsMemory = new Memory(anotherArray, 2, 3); + + Assert.True(baselineAsEquatable.Equals(baseline)); // Reflexivity + Assert.True(baselineAsEquatable.Equals(equalRangeAndLength)); // Range check & length check + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); // Length check + Assert.False(baselineAsEquatable.Equals(equalLengthButReference)); // Range check + + Assert.True(baseline.Span.SequenceEqual(differentArraySegmentAsMemory.Span)); + Assert.False(baselineAsEquatable.Equals(differentArraySegmentAsMemory)); // Doesn't check for content equality + } + [Theory] [MemberData(nameof(ValidArraySegments))] public static void MemoryReferencingSameMemoryAreEqualInEveryAspect(byte[] bytes, int start, int length) diff --git a/src/libraries/System.Memory/tests/ReadOnlyMemory/Equality.cs b/src/libraries/System.Memory/tests/ReadOnlyMemory/Equality.cs index a6a53ee..67fbc7e 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyMemory/Equality.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyMemory/Equality.cs @@ -84,6 +84,112 @@ namespace System.MemoryTests Assert.True(right.Equals(left)); } + [Fact] + public static void EqualityThroughInterface_True() + { + int[] array = { 10, 11, 12, 13, 14 }; + ReadOnlyMemory left = new ReadOnlyMemory(array, 2, 3); + ReadOnlyMemory right = new ReadOnlyMemory(array, 2, 3); + IEquatable> leftAsEquatable = left; + IEquatable> rightAsEquatable = right; + + Assert.True(leftAsEquatable.Equals(right)); + Assert.True(rightAsEquatable.Equals(left)); + } + + [Fact] + public static void EqualityThroughInterface_Reflexivity() + { + int[] array = { 42, 43, 44, 45, 46 }; + ReadOnlyMemory left = new ReadOnlyMemory(array, 2, 3); + IEquatable> leftAsEquatable = left; + + Assert.True(leftAsEquatable.Equals(left)); + } + + [Fact] + public static void EqualityThroughInterface_IncludesLength() + { + int[] array = { 42, 43, 44, 45, 46 }; + ReadOnlyMemory baseline = new ReadOnlyMemory(array, 2, 3); + ReadOnlyMemory equalRangeButLength = new ReadOnlyMemory(array, 2, 2); + IEquatable> baselineAsEquatable = baseline; + IEquatable> anotherOneAsEquatable = equalRangeButLength; + + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); + Assert.False(anotherOneAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_IncludesBase() + { + int[] array = { 42, 43, 44, 45, 46 }; + ReadOnlyMemory baseline = new ReadOnlyMemory(array, 2, 3); + ReadOnlyMemory equalLengthButRange = new ReadOnlyMemory(array, 1, 3); + IEquatable> baselineAsEquatable = baseline; + IEquatable> anotherOneAsEquatable = equalLengthButRange; + + Assert.False(baselineAsEquatable.Equals(equalLengthButRange)); + Assert.False(anotherOneAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_ComparesRangeNotContent() + { + ReadOnlyMemory baseline = new ReadOnlyMemory(new[] { 1, 2, 3, 4, 5, 6 }, 2, 3); + ReadOnlyMemory duplicate = new ReadOnlyMemory(new[] { 1, 2, 3, 4, 5, 6 }, 2, 3); + IEquatable> baselineAsEquatable = baseline; + IEquatable> duplicateAsEquatable = duplicate; + + Assert.False(baselineAsEquatable.Equals(duplicate)); + Assert.False(duplicateAsEquatable.Equals(baseline)); + } + + [Fact] + public static void EqualityThroughInterface_Strings() + { + string[] array = { "A", "B", "C", "D", "E", "F" }; + string[] anotherArray = { "A", "B", "C", "D", "E", "F" }; + + ReadOnlyMemory baseline = new ReadOnlyMemory(array, 2, 3); + IEquatable> baselineAsEquatable = baseline; + ReadOnlyMemory equalRangeAndLength = new ReadOnlyMemory(array, 2, 3); + ReadOnlyMemory equalRangeButLength = new ReadOnlyMemory(array, 2, 2); + ReadOnlyMemory equalLengthButReference = new ReadOnlyMemory(array, 3, 3); + ReadOnlyMemory differentArraySegmentAsMemory = new ReadOnlyMemory(anotherArray, 2, 3); + + Assert.True(baselineAsEquatable.Equals(baseline)); // Reflexivity + Assert.True(baselineAsEquatable.Equals(equalRangeAndLength)); // Range check & length check + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); // Length check + Assert.False(baselineAsEquatable.Equals(equalLengthButReference)); // Range check + + Assert.True(baseline.Span.SequenceEqual(differentArraySegmentAsMemory.Span)); + Assert.False(baselineAsEquatable.Equals(differentArraySegmentAsMemory)); // Doesn't check for content equality + } + + [Fact] + public static void EqualityThroughInterface_Chars() + { + char[] array = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!' }; + string str = new string(array); // To prevent both string literals being interned therefore having same reference + string anotherStr = new string(array); + + ReadOnlyMemory baseline = str.AsMemory(2, 3); + IEquatable> baselineAsEquatable = baseline; + ReadOnlyMemory equalRangeAndLength = str.AsMemory(2, 3); + ReadOnlyMemory equalRangeButLength = str.AsMemory(2, 2); + ReadOnlyMemory equalLengthButReference = str.AsMemory(3, 3); + ReadOnlyMemory differentArraySegmentAsMemory = anotherStr.AsMemory(2, 3); + + Assert.True(baselineAsEquatable.Equals(baseline)); // Reflexivity + Assert.True(baselineAsEquatable.Equals(equalRangeAndLength)); // Range check & length check + Assert.False(baselineAsEquatable.Equals(equalRangeButLength)); // Length check + Assert.False(baselineAsEquatable.Equals(equalLengthButReference)); // Range check + + Assert.True(baseline.Span.SequenceEqual(differentArraySegmentAsMemory.Span)); + Assert.False(baselineAsEquatable.Equals(differentArraySegmentAsMemory)); // Doesn't check for content equality + } + [Theory] [MemberData(nameof(ValidArraySegments))] public static void MemoryReferencingSameMemoryAreEqualInEveryAspect(byte[] bytes, int start, int length) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 294fb2e..6496472 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -1724,7 +1724,7 @@ namespace System public MemberAccessException(string message) { } public MemberAccessException(string message, System.Exception inner) { } } - public readonly partial struct Memory + public readonly partial struct Memory : IEquatable> { private readonly object _dummy; private readonly int _dummyPrimitive; @@ -1995,7 +1995,7 @@ namespace System public RankException(string message) { } public RankException(string message, System.Exception innerException) { } } - public readonly partial struct ReadOnlyMemory + public readonly partial struct ReadOnlyMemory : IEquatable> { private readonly object _dummy; private readonly int _dummyPrimitive; diff --git a/src/libraries/System.Runtime/src/ApiCompatBaseline.uapaot.txt b/src/libraries/System.Runtime/src/ApiCompatBaseline.uapaot.txt index 705a0b4..7e2b2e1 100644 --- a/src/libraries/System.Runtime/src/ApiCompatBaseline.uapaot.txt +++ b/src/libraries/System.Runtime/src/ApiCompatBaseline.uapaot.txt @@ -14,3 +14,5 @@ MembersMustExist : Member 'System.Text.Rune.EncodeToUtf8(System.Span, System.Int32)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'System.Range.GetOffsetAndLength(System.Int32)' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'System.Range.OffsetAndLength' does not exist in the implementation but it does exist in the contract. +CannotRemoveBaseTypeOrInterface : Type 'System.Memory' does not implement interface 'System.IEquatable>' in the implementation but it does in the contract. +CannotRemoveBaseTypeOrInterface : Type 'System.ReadOnlyMemory' does not implement interface 'System.IEquatable>' in the implementation but it does in the contract. -- 2.7.4