File: SpanExtensionsTests.cs
Web Access
Project: src\src\Razor\src\Shared\Microsoft.AspNetCore.Razor.Utilities.Shared.UnitTests\Microsoft.AspNetCore.Razor.Utilities.Shared.UnitTests.csproj (Microsoft.AspNetCore.Razor.Utilities.Shared.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using Xunit;
 
namespace Microsoft.AspNetCore.Razor.Utilities.Shared.Test;
 
public class SpanExtensionsTests
{
    [Fact]
    public void Reversed_Span_BasicEnumeration()
    {
        // Arrange
        Span<int> span = [1, 2, 3, 4, 5];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([5, 4, 3, 2, 1], result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_BasicEnumeration()
    {
        // Arrange
        ReadOnlySpan<int> span = [1, 2, 3, 4, 5];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([5, 4, 3, 2, 1], result);
    }
 
    [Fact]
    public void Reversed_Span_EmptySpan_NoIteration()
    {
        // Arrange
        Span<int> span = [];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Empty(result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_EmptySpan_NoIteration()
    {
        // Arrange
        ReadOnlySpan<int> span = [];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Empty(result);
    }
 
    [Fact]
    public void Reversed_Span_SingleElement()
    {
        // Arrange
        Span<int> span = [42];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([42], result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_SingleElement()
    {
        // Arrange
        ReadOnlySpan<int> span = [42];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([42], result);
    }
 
    [Fact]
    public void Reversed_Span_TwoElements()
    {
        // Arrange
        Span<int> span = [1, 2];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([2, 1], result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_TwoElements()
    {
        // Arrange
        ReadOnlySpan<int> span = [1, 2];
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([2, 1], result);
    }
 
    [Fact]
    public void Reversed_Span_StringElements()
    {
        // Arrange
        Span<string> span = ["first", "second", "third"];
 
        // Act
        var result = new List<string>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(["third", "second", "first"], result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_StringElements()
    {
        // Arrange
        ReadOnlySpan<string> span = ["first", "second", "third"];
 
        // Act
        var result = new List<string>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(["third", "second", "first"], result);
    }
 
    [Fact]
    public void Reversed_Enumerator_Current_ValidAfterMoveNext()
    {
        // Arrange
        Span<int> span = [10, 20, 30];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Act & Assert
        Assert.True(enumerator.MoveNext());
        Assert.Equal(30, enumerator.Current);
 
        Assert.True(enumerator.MoveNext());
        Assert.Equal(20, enumerator.Current);
 
        Assert.True(enumerator.MoveNext());
        Assert.Equal(10, enumerator.Current);
 
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_Enumerator_MoveNext_EmptySpan_ReturnsFalse()
    {
        // Arrange
        Span<int> span = [];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Act & Assert
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_Enumerator_Reset_RestoresInitialState()
    {
        // Arrange
        Span<int> span = [1, 2, 3];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Move through some elements
        Assert.True(enumerator.MoveNext());
        Assert.Equal(3, enumerator.Current);
        Assert.True(enumerator.MoveNext());
        Assert.Equal(2, enumerator.Current);
 
        // Act - Reset
        enumerator.Reset();
 
        // Assert - Should start over
        Assert.True(enumerator.MoveNext());
        Assert.Equal(3, enumerator.Current);
        Assert.True(enumerator.MoveNext());
        Assert.Equal(2, enumerator.Current);
        Assert.True(enumerator.MoveNext());
        Assert.Equal(1, enumerator.Current);
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_Enumerator_Reset_EmptySpan()
    {
        // Arrange
        Span<int> span = [];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Act
        enumerator.Reset();
 
        // Assert
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_Enumerator_Reset_SingleElement()
    {
        // Arrange
        Span<int> span = [42];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Move through the element
        Assert.True(enumerator.MoveNext());
        Assert.Equal(42, enumerator.Current);
        Assert.False(enumerator.MoveNext());
 
        // Act - Reset
        enumerator.Reset();
 
        // Assert - Should start over
        Assert.True(enumerator.MoveNext());
        Assert.Equal(42, enumerator.Current);
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_MultipleEnumerators_Independent()
    {
        // Arrange
        Span<int> span = [1, 2, 3];
        var enumerator1 = span.Reversed.GetEnumerator();
        var enumerator2 = span.Reversed.GetEnumerator();
 
        // Act & Assert - Enumerators should be independent
        Assert.True(enumerator1.MoveNext());
        Assert.Equal(3, enumerator1.Current);
 
        Assert.True(enumerator2.MoveNext());
        Assert.Equal(3, enumerator2.Current);
 
        Assert.True(enumerator1.MoveNext());
        Assert.Equal(2, enumerator1.Current);
 
        // enumerator2 should still be at the first position
        Assert.True(enumerator2.MoveNext());
        Assert.Equal(2, enumerator2.Current);
    }
 
    [Fact]
    public void Reversed_Span_LargeSpan()
    {
        // Arrange
        var array = new int[1000];
        for (var i = 0; i < array.Length; i++)
        {
            array[i] = i;
        }
 
        Span<int> span = array;
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(1000, result.Count);
        Assert.Equal(999, result[0]);
        Assert.Equal(998, result[1]);
        Assert.Equal(0, result[999]);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_LargeSpan()
    {
        // Arrange
        var array = new int[1000];
        for (var i = 0; i < array.Length; i++)
        {
            array[i] = i;
        }
 
        ReadOnlySpan<int> span = array;
 
        // Act
        var result = new List<int>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(1000, result.Count);
        Assert.Equal(999, result[0]);
        Assert.Equal(998, result[1]);
        Assert.Equal(0, result[999]);
    }
 
    [Fact]
    public void Reversed_Span_ReferenceTypes_NullElements()
    {
        // Arrange
        Span<string?> span = ["first", null, "third"];
 
        // Act
        var result = new List<string?>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(["third", null, "first"], result);
    }
 
    [Fact]
    public void Reversed_ReadOnlySpan_ReferenceTypes_NullElements()
    {
        // Arrange
        ReadOnlySpan<string?> span = ["first", null, "third"];
 
        // Act
        var result = new List<string?>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal(["third", null, "first"], result);
    }
 
    [Fact]
    public void Reversed_NestedForeach_Works()
    {
        // Arrange
        Span<int> span1 = [1, 2];
        Span<int> span2 = [3, 4];
 
        // Act
        var result = new List<(int, int)>();
        foreach (var item1 in span1.Reversed)
        {
            foreach (var item2 in span2.Reversed)
            {
                result.Add((item1, item2));
            }
        }
 
        // Assert
        Assert.Equal([(2, 4), (2, 3), (1, 4), (1, 3)], result);
    }
 
    [Fact]
    public void Reversed_ManualEnumerator_Usage()
    {
        // Arrange
        ReadOnlySpan<char> span = ['a', 'b', 'c'];
        var enumerator = span.Reversed.GetEnumerator();
 
        // Act & Assert - Manual enumeration
        var result = new List<char>();
        while (enumerator.MoveNext())
        {
            result.Add(enumerator.Current);
        }
 
        Assert.Equal(['c', 'b', 'a'], result);
 
        // Trying to move next after completion should return false
        Assert.False(enumerator.MoveNext());
    }
 
    [Fact]
    public void Reversed_ValueTypes_StructElements()
    {
        // Arrange
        var point1 = new System.Drawing.Point(1, 2);
        var point2 = new System.Drawing.Point(3, 4);
        var point3 = new System.Drawing.Point(5, 6);
        Span<System.Drawing.Point> span = [point1, point2, point3];
 
        // Act
        var result = new List<System.Drawing.Point>();
        foreach (var item in span.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([point3, point2, point1], result);
    }
 
    [Fact]
    public void Reversed_ImplicitConversion_SpanToReadOnlySpan()
    {
        // Arrange
        Span<int> span = [1, 2, 3];
 
        // Act - Implicit conversion to ReadOnlySpan<T>
        ReadOnlySpan<int> readOnlySpan = span;
        var result = new List<int>();
        foreach (var item in readOnlySpan.Reversed)
        {
            result.Add(item);
        }
 
        // Assert
        Assert.Equal([3, 2, 1], result);
    }
}