400 lines
10 KiB
C#
400 lines
10 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
using FluentAssertions;
|
||
|
|
using SqrtSpace.SpaceTime.Collections;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace SqrtSpace.SpaceTime.Tests.Collections;
|
||
|
|
|
||
|
|
public class AdaptiveListTests
|
||
|
|
{
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_StartsAsArray()
|
||
|
|
{
|
||
|
|
// Arrange & Act
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.Add(1);
|
||
|
|
list.Add(2);
|
||
|
|
list.Add(3);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.Count.Should().Be(3);
|
||
|
|
list.CurrentImplementation.Should().Be("List<T>");
|
||
|
|
list[0].Should().Be(1);
|
||
|
|
list[1].Should().Be(2);
|
||
|
|
list[2].Should().Be(3);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_TransitionsToList()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
|
||
|
|
// Act - Add items beyond array threshold
|
||
|
|
for (int i = 0; i < 20; i++) // ArrayThreshold is typically 16
|
||
|
|
{
|
||
|
|
list.Add(i);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.CurrentImplementation.Should().Be("List<T>");
|
||
|
|
list.Count.Should().Be(20);
|
||
|
|
list[10].Should().Be(10);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_TransitionsToSegmented()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
|
||
|
|
// Act - Add items beyond list threshold
|
||
|
|
for (int i = 0; i < 15_000; i++) // ListThreshold is typically 10,000
|
||
|
|
{
|
||
|
|
list.Add(i);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
// Note: AdaptiveList doesn't have SegmentedList implementation
|
||
|
|
// list.CurrentImplementation.Should().Be("SegmentedList");
|
||
|
|
list.Count.Should().Be(15_000);
|
||
|
|
list[7500].Should().Be(7500);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_Insert_InsertsAtCorrectPosition()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<string>();
|
||
|
|
list.Add("first");
|
||
|
|
list.Add("third");
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list.Insert(1, "second");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.Count.Should().Be(3);
|
||
|
|
list[0].Should().Be("first");
|
||
|
|
list[1].Should().Be("second");
|
||
|
|
list[2].Should().Be("third");
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_RemoveAt_RemovesCorrectItem()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list.RemoveAt(2);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.Count.Should().Be(4);
|
||
|
|
list.Should().BeEquivalentTo(new[] { 1, 2, 4, 5 });
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_Remove_RemovesFirstOccurrence()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(new[] { 1, 2, 3, 2, 4 });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var removed = list.Remove(2);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
removed.Should().BeTrue();
|
||
|
|
list.Count.Should().Be(4);
|
||
|
|
list.Should().BeEquivalentTo(new[] { 1, 3, 2, 4 });
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_IndexOf_FindsCorrectIndex()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<string>();
|
||
|
|
list.AddRange(new[] { "apple", "banana", "cherry", "date" });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var index = list.IndexOf("cherry");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
index.Should().Be(2);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_IndexOf_ReturnsNegativeOneForNotFound()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<string>();
|
||
|
|
list.AddRange(new[] { "apple", "banana", "cherry" });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var index = list.IndexOf("date");
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
index.Should().Be(-1);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_Contains_ReturnsTrueForExisting()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(Enumerable.Range(1, 100));
|
||
|
|
|
||
|
|
// Act & Assert
|
||
|
|
list.Contains(50).Should().BeTrue();
|
||
|
|
list.Contains(101).Should().BeFalse();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_Clear_RemovesAllItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(Enumerable.Range(1, 50));
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list.Clear();
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.Count.Should().Be(0);
|
||
|
|
list.CurrentImplementation.Should().Be("List<T>");
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_CopyTo_CopiesAllItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
var array = new int[8];
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list.CopyTo(array, 2);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
array.Should().BeEquivalentTo(new[] { 0, 0, 1, 2, 3, 4, 5, 0 });
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_GetEnumerator_EnumeratesAllItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
var expected = Enumerable.Range(1, 10).ToList();
|
||
|
|
list.AddRange(expected);
|
||
|
|
|
||
|
|
// Act
|
||
|
|
var result = new List<int>();
|
||
|
|
foreach (var item in list)
|
||
|
|
{
|
||
|
|
result.Add(item);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
result.Should().BeEquivalentTo(expected);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_IndexerSet_UpdatesValue()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<string>();
|
||
|
|
list.AddRange(new[] { "one", "two", "three" });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list[1] = "TWO";
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list[1].Should().Be("TWO");
|
||
|
|
list.Count.Should().Be(3);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_IndexOutOfRange_ThrowsException()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(new[] { 1, 2, 3 });
|
||
|
|
|
||
|
|
// Act & Assert
|
||
|
|
var action1 = () => _ = list[-1];
|
||
|
|
action1.Should().Throw<ArgumentOutOfRangeException>();
|
||
|
|
|
||
|
|
var action2 = () => _ = list[3];
|
||
|
|
action2.Should().Throw<ArgumentOutOfRangeException>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_AddRange_AddsMultipleItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
var items = Enumerable.Range(1, 100).ToList();
|
||
|
|
|
||
|
|
// Act
|
||
|
|
list.AddRange(items);
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
list.Count.Should().Be(100);
|
||
|
|
list.Should().BeEquivalentTo(items);
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_DataPersistenceAcrossTransitions()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<string>();
|
||
|
|
var testData = Enumerable.Range(0, 100)
|
||
|
|
.Select(i => $"item{i}")
|
||
|
|
.ToList();
|
||
|
|
|
||
|
|
// Act - Add data forcing transitions
|
||
|
|
foreach (var item in testData)
|
||
|
|
{
|
||
|
|
list.Add(item);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert - Verify all data is preserved
|
||
|
|
list.Count.Should().Be(100);
|
||
|
|
for (int i = 0; i < 100; i++)
|
||
|
|
{
|
||
|
|
list[i].Should().Be($"item{i}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Commented out: AdaptiveList doesn't have Sort() method
|
||
|
|
// [Fact]
|
||
|
|
// public void AdaptiveList_Sort_SortsItems()
|
||
|
|
// {
|
||
|
|
// // Arrange
|
||
|
|
// var list = new AdaptiveList<int>();
|
||
|
|
// var random = new Random(42);
|
||
|
|
// var items = Enumerable.Range(1, 50).OrderBy(_ => random.Next()).ToList();
|
||
|
|
// list.AddRange(items);
|
||
|
|
|
||
|
|
// // Act
|
||
|
|
// list.Sort();
|
||
|
|
|
||
|
|
// // Assert
|
||
|
|
// list.Should().BeInAscendingOrder();
|
||
|
|
// }
|
||
|
|
|
||
|
|
// Commented out: AdaptiveList doesn't have Sort(IComparer<T>) method
|
||
|
|
// [Fact]
|
||
|
|
// public void AdaptiveList_Sort_WithComparer_UsesComparer()
|
||
|
|
// {
|
||
|
|
// // Arrange
|
||
|
|
// var list = new AdaptiveList<string>();
|
||
|
|
// list.AddRange(new[] { "apple", "Banana", "cherry", "Date" });
|
||
|
|
|
||
|
|
// // Act
|
||
|
|
// list.Sort(StringComparer.OrdinalIgnoreCase);
|
||
|
|
|
||
|
|
// // Assert
|
||
|
|
// list.Should().BeEquivalentTo(new[] { "apple", "Banana", "cherry", "Date" });
|
||
|
|
// }
|
||
|
|
|
||
|
|
// Commented out: AdaptiveList doesn't have Reverse() method
|
||
|
|
// [Fact]
|
||
|
|
// public void AdaptiveList_Reverse_ReversesOrder()
|
||
|
|
// {
|
||
|
|
// // Arrange
|
||
|
|
// var list = new AdaptiveList<int>();
|
||
|
|
// list.AddRange(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
|
||
|
|
// // Act
|
||
|
|
// list.Reverse();
|
||
|
|
|
||
|
|
// // Assert
|
||
|
|
// list.Should().BeEquivalentTo(new[] { 5, 4, 3, 2, 1 });
|
||
|
|
// }
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_ToArray_ReturnsArray()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
|
||
|
|
// Act
|
||
|
|
// AdaptiveList doesn't have ToArray(), but we can use LINQ
|
||
|
|
var array = list.ToArray();
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
array.Should().BeEquivalentTo(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
array.Should().BeOfType<int[]>();
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_FindAll_ReturnsMatchingItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(Enumerable.Range(1, 20));
|
||
|
|
|
||
|
|
// Act
|
||
|
|
// AdaptiveList doesn't have FindAll(), use LINQ Where instead
|
||
|
|
var evens = list.Where(x => x % 2 == 0).ToList();
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
evens.Should().HaveCount(10);
|
||
|
|
evens.Should().BeEquivalentTo(new[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 });
|
||
|
|
}
|
||
|
|
|
||
|
|
[Fact]
|
||
|
|
public void AdaptiveList_RemoveAll_RemovesMatchingItems()
|
||
|
|
{
|
||
|
|
// Arrange
|
||
|
|
var list = new AdaptiveList<int>();
|
||
|
|
list.AddRange(Enumerable.Range(1, 10));
|
||
|
|
|
||
|
|
// Act
|
||
|
|
// AdaptiveList doesn't have RemoveAll(), manually remove matching items
|
||
|
|
var toRemove = list.Where(x => x % 2 == 0).ToList();
|
||
|
|
var removed = 0;
|
||
|
|
foreach (var item in toRemove)
|
||
|
|
{
|
||
|
|
if (list.Remove(item))
|
||
|
|
removed++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Assert
|
||
|
|
removed.Should().Be(5);
|
||
|
|
list.Should().BeEquivalentTo(new[] { 1, 3, 5, 7, 9 });
|
||
|
|
}
|
||
|
|
|
||
|
|
// Commented out: AdaptiveList doesn't have Capacity property
|
||
|
|
// [Fact]
|
||
|
|
// public void AdaptiveList_WithInitialCapacity_PreallocatesSpace()
|
||
|
|
// {
|
||
|
|
// // Arrange & Act
|
||
|
|
// var list = new AdaptiveList<int>(100);
|
||
|
|
|
||
|
|
// // Assert
|
||
|
|
// list.Count.Should().Be(0);
|
||
|
|
// list.Capacity.Should().BeGreaterOrEqualTo(100);
|
||
|
|
// }
|
||
|
|
|
||
|
|
// Commented out: AdaptiveList doesn't have TrimExcess() method or Capacity property
|
||
|
|
// [Fact]
|
||
|
|
// public void AdaptiveList_TrimExcess_ReducesCapacity()
|
||
|
|
// {
|
||
|
|
// // Arrange
|
||
|
|
// var list = new AdaptiveList<int>(100);
|
||
|
|
// list.AddRange(new[] { 1, 2, 3, 4, 5 });
|
||
|
|
|
||
|
|
// // Act
|
||
|
|
// list.TrimExcess();
|
||
|
|
|
||
|
|
// // Assert
|
||
|
|
// list.Count.Should().Be(5);
|
||
|
|
// list.Capacity.Should().BeLessThan(100);
|
||
|
|
// }
|
||
|
|
}
|