Skip to content

Commit

Permalink
Merge pull request #53 from martindevans/stack_tests
Browse files Browse the repository at this point in the history
UnsafeStack Tests
  • Loading branch information
genaray authored Dec 11, 2023
2 parents 979f9f3 + 135166c commit 01644ad
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 15 deletions.
155 changes: 152 additions & 3 deletions Arch.LowLevel.Tests/UnsafeStackTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,171 @@ namespace Arch.LowLevel.Tests;
[TestFixture]
public class UnsafeStackTest
{

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is capable of adding itemss.
/// Checks if <see cref="UnsafeStack{T}"/> checks for invalid capacity on construction.
/// </summary>
[Test]
public void UnsafeStackInvalidCapacity()
{
Throws<ArgumentOutOfRangeException>(() => new UnsafeStack<int>(-9));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is capable of adding items.
/// </summary>
[Test]
public void UnsafeStackAdd()
{
using var stack = new UnsafeStack<int>(8);

That(stack.IsFull, Is.False);
That(stack.IsEmpty, Is.True);

stack.Push(1);
stack.Push(2);
stack.Push(3);

That(stack.IsFull, Is.False);
That(stack.IsEmpty, Is.False);

That(stack.Count, Is.EqualTo(3));
That(stack.Peek(), Is.EqualTo(3));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is can be converted to a span
/// </summary>
[Test]
public void UnsafeStackAsSpan()
{
using var stack = new UnsafeStack<int>(8);

stack.Push(1);
stack.Push(2);
stack.Push(3);

var span = stack.AsSpan();

stack.Pop();
stack.Push(4);

That(span.Length, Is.EqualTo(3));

CollectionAssert.AreEqual(span.ToArray(), new[] { 1, 2, 4 });
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is capable of adding items even past the initial capacity
/// </summary>
[Test]
public void UnsafeStackAddBeyondCapacity()
{
using var stack = new UnsafeStack<int>(4);
That(stack.Capacity, Is.EqualTo(4));

stack.Push(1);
stack.Push(2);
stack.Push(3);
stack.Push(4);
That(stack.IsFull, Is.True);
stack.Push(5);
stack.Push(6);
stack.Push(7);

That(stack.Count, Is.EqualTo(7));
That(stack.Peek(), Is.EqualTo(7));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}.EnsureCapacity"/> expands capacity
/// </summary>
[Test]
public void UnsafeStackEnsureCapacityExpands()
{
using var stack = new UnsafeStack<int>(10);
That(stack.Capacity, Is.EqualTo(10));

stack.EnsureCapacity(11);

That(stack.Capacity, Is.GreaterThanOrEqualTo(11));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}.EnsureCapacity"/> cannot shrink the capacity
/// </summary>
[Test]
public void UnsafeStackEnsureCapacityCannotShrink()
{
using var stack = new UnsafeStack<int>(10);
That(stack.Capacity, Is.EqualTo(10));

stack.EnsureCapacity(1);

That(stack.Capacity, Is.EqualTo(10));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}.EnsureCapacity"/> can add a massive amount of new capacity
/// </summary>
[Test]
public void UnsafeStackEnsureCapacityExpandsALot()
{
using var stack = new UnsafeStack<int>(10);
That(stack.Capacity, Is.EqualTo(10));

stack.EnsureCapacity(10000);

That(stack.Capacity, Is.GreaterThanOrEqualTo(10000));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}.TrimExcess"/> can remove unused capacity
/// </summary>
[Test]
public void UnsafeStackTrimExcessShrinks()
{
using var stack = new UnsafeStack<int>(10);
That(stack.Capacity, Is.EqualTo(10));

stack.TrimExcess();

That(stack.Capacity, Is.LessThan(10));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}.TrimExcess"/> does not expand
/// </summary>
[Test]
public void UnsafeStackTrimExcessNeverExpands()
{
using var stack = new UnsafeStack<int>(2);

stack.TrimExcess();

That(stack.Capacity, Is.LessThanOrEqualTo(2));
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is capable of being cleared.
/// </summary>
[Test]
public void UnsafeStackClear()
{
using var stack = new UnsafeStack<int>(8);
stack.Push(1);
stack.Push(2);
stack.Push(3);

That(stack.Count, Is.EqualTo(3));
That(stack.Peek(), Is.EqualTo(3));

stack.Clear();

That(stack.Count, Is.EqualTo(0));
Throws<InvalidOperationException>(() => stack.Peek());
Throws<InvalidOperationException>(() => stack.Pop());
}

/// <summary>
/// Checks if <see cref="UnsafeStack{T}"/> is capable of peeking itemss.
/// </summary>
Expand Down
21 changes: 9 additions & 12 deletions Arch.LowLevel/UnsafeStack.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace Arch.LowLevel;
Expand Down Expand Up @@ -51,7 +49,7 @@ public UnsafeStack(int capacity = DefaultCapacity)
/// <summary>
/// The amount of items in the stack.
/// </summary>
public int Count
public readonly int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _count;
Expand All @@ -60,7 +58,7 @@ public int Count
/// <summary>
/// The total capacity of this stack.
/// </summary>
public int Capacity
public readonly int Capacity
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _capacity;
Expand All @@ -69,7 +67,7 @@ public int Capacity
/// <summary>
/// If this stack is empty.
/// </summary>
public bool IsEmpty
public readonly bool IsEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _count == 0;
Expand All @@ -78,7 +76,7 @@ public bool IsEmpty
/// <summary>
/// If this stack is full.
/// </summary>
public bool IsFull
public readonly bool IsFull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _count >= _capacity;
Expand Down Expand Up @@ -204,9 +202,8 @@ public void Dispose()
/// Converts this <see cref="UnsafeStack{T}"/> instance into a <see cref="Span{T}"/>.
/// </summary>
/// <returns>A new instance of <see cref="Span{T}"/>.</returns>
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> AsSpan()
public readonly Span<T> AsSpan()
{
return new Span<T>(_stack, Count);
}
Expand All @@ -216,7 +213,7 @@ public Span<T> AsSpan()
/// </summary>
/// <returns>A new <see cref="UnsafeEnumerator{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeReverseEnumerator<T> GetEnumerator()
public readonly UnsafeReverseEnumerator<T> GetEnumerator()
{
return new UnsafeReverseEnumerator<T>(_stack, Count);
}
Expand All @@ -226,7 +223,7 @@ public UnsafeReverseEnumerator<T> GetEnumerator()
/// </summary>
/// <returns>The new <see cref="IEnumerable{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
IEnumerator<T> IEnumerable<T>.GetEnumerator()
readonly IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new ReverseEnumerator<T>(_stack, Count);
}
Expand All @@ -236,7 +233,7 @@ IEnumerator<T> IEnumerable<T>.GetEnumerator()
/// </summary>
/// <returns>The new <see cref="IEnumerator"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
IEnumerator IEnumerable.GetEnumerator()
readonly IEnumerator IEnumerable.GetEnumerator()
{
return new ReverseEnumerator<T>(_stack, Count);
}
Expand All @@ -246,7 +243,7 @@ IEnumerator IEnumerable.GetEnumerator()
/// </summary>
/// <returns>The string.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString()
public readonly override string ToString()
{
var items = new StringBuilder();
foreach (ref var item in this)
Expand Down

0 comments on commit 01644ad

Please sign in to comment.