Repository: dotnet/runtime
File: src/libraries/System.Memory/tests/Span/IndexOfAnyInRange.cs (C#)

Code before:

        [Fact]
        public void MatrixOfLengthsAndOffsets_AnyExcept_FindsValueAtExpectedIndex()
        {
            foreach (int length in Enumerable.Range(1, 40))
            {
                for (int offset = 0; offset < length; offset++)
                {
                    int target = -42;
                    T[] array = Enumerable.Repeat(Create(target), length).ToArray();
                    array[offset] = Create(target - 2);

                    Assert.Equal(offset, IndexOfAnyExceptInRange(array, Create(target), Create(target)));
                    Assert.Equal(offset, IndexOfAnyExceptInRange(array, Create(target - 1), Create(target)));
                    Assert.Equal(offset, IndexOfAnyExceptInRange(array, Create(target), Create(target + 1)));
                    Assert.Equal(offset, IndexOfAnyExceptInRange(array, Create(target - 1), Create(target + 1)));

                    Assert.Equal(offset, LastIndexOfAnyExceptInRange(array, Create(target), Create(target)));
                    Assert.Equal(offset, LastIndexOfAnyExceptInRange(array, Create(target - 1), Create(target)));
                    Assert.Equal(offset, LastIndexOfAnyExceptInRange(array, Create(target), Create(target + 1)));
                    Assert.Equal(offset, LastIndexOfAnyExceptInRange(array, Create(target - 1), Create(target + 1)));
                }
            }
        }

        [Fact]
        public void InvalidRange_HighLessThanLow_ReturnsMinus1()
        {
            // When highInclusive < lowInclusive, the range is invalid and no values should match
            for (int length = 1; length <= 64; length++)
            {
                T[] array = Enumerable.Range(0, length).Select(Create).ToArray();

                // Test with a clearly invalid range where high < low
                T lowInclusive = Create(100);
                T highInclusive = Create(50);

                // IndexOfAnyInRange should return -1 (no match)
                Assert.Equal(-1, IndexOfAnyInRange(array, lowInclusive, highInclusive));

                // LastIndexOfAnyInRange should return -1 (no match)
                Assert.Equal(-1, LastIndexOfAnyInRange(array, lowInclusive, highInclusive));

                // IndexOfAnyExceptInRange should find the first element (all values are outside the invalid range)
                Assert.Equal(0, IndexOfAnyExceptInRange(array, lowInclusive, highInclusive));

                // LastIndexOfAnyExceptInRange should find the last element (all values are outside the invalid range)
                Assert.Equal(length - 1, LastIndexOfAnyExceptInRange(array, lowInclusive, highInclusive));
            }
        }


Review comment (bug):
@copilot, please make this a [Theory] where the lowInclusive and highInclusive values are supplied as arguments. In addition to invoking it with values like 100 and 50 as you already have, please also test values that would flag off-by-one errors, like 100 and 99, as well as negative values if possible.

Also, please ensure there are existing tests that handle the case where lowInclusive == highInclusive. I believe they exist, but if they don't, please add some.

Code after:

                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.LastIndexOfAnyInRange(Span<RefType>.Empty, low, high));
                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.LastIndexOfAnyInRange(ReadOnlySpan<RefType>.Empty, low, high));

                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.IndexOfAnyExceptInRange(Span<RefType>.Empty, low, high));
                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.IndexOfAnyExceptInRange(ReadOnlySpan<RefType>.Empty, low, high));

                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.LastIndexOfAnyExceptInRange(Span<RefType>.Empty, low, high));
                AssertExtensions.Throws<ArgumentNullException>(argName, () => MemoryExtensions.LastIndexOfAnyExceptInRange(ReadOnlySpan<RefType>.Empty, low, high));
            }
        }

        [Fact]
        public void NullPermittedInInput()
        {
            RefType[] array = new[] { null, new RefType { Value = 1 }, null, null, new RefType { Value = 42 }, null };
            RefType low = new RefType { Value = 41 }, high = new RefType { Value = 43 };

            Assert.Equal(4, IndexOfAnyInRange(array, low, high));
            Assert.Equal(4, LastIndexOfAnyInRange(array, low, high));

            Assert.Equal(0, IndexOfAnyExceptInRange(array, low, high));
            Assert.Equal(5, LastIndexOfAnyExceptInRange(array, low, high));
        }
    }

    public class RefType : IComparable<RefType>
    {
        public int Value { get; set; }
        public int CompareTo(RefType? other) => other is null ? 1 : Value.CompareTo(other.Value);
    }

    public abstract class IndexOfAnyInRangeTests<T>
        where T : IComparable<T>
    {
        protected abstract T Create(int value);

        [Fact]
        public void EmptyInput_ReturnsMinus1()
        {
            T[] array = Array.Empty<T>();
            T low = Create(0);
            T high = Create(255);

            Assert.Equal(-1, IndexOfAnyInRange(array, low, high));
            Assert.Equal(-1, LastIndexOfAnyInRange(array, low, high));
            Assert.Equal(-1, IndexOfAnyExceptInRange(array, low, high));
            Assert.Equal(-1, LastIndexOfAnyExceptInRange(array, low, high));
        }

        [Fact]