CI / build-test (push) Failing after 1m8s
Add MrGameEng.AI utility-AI module; format codebase with CSharpier New MrGameEng.AI module (ResponseCurve, Consideration, UtilityAction, UtilityAi selector, Blackboard) plus CSharpier formatting applied across the whole engine. Documents the CSharpier convention in CLAUDE.md. @
162 lines
4.9 KiB
C#
162 lines
4.9 KiB
C#
using MrGameEng.Graphics;
|
|
using Xunit;
|
|
|
|
namespace MrGameEng.Graphics.Tests;
|
|
|
|
public class SpriteBatcherTests
|
|
{
|
|
private static SpriteInstance Instance(byte layer) => new() { Layer = layer };
|
|
|
|
[Fact]
|
|
public void Sort_OrdersByKey_ReturningOriginalIndices()
|
|
{
|
|
var batcher = new SpriteBatcher(initialCapacity: 2);
|
|
|
|
batcher.Submit(Instance(2), SpriteSortKey.Make(2, 0f, 0));
|
|
batcher.Submit(Instance(0), SpriteSortKey.Make(0, 0f, 0));
|
|
batcher.Submit(Instance(1), SpriteSortKey.Make(1, 0f, 0));
|
|
|
|
var order = batcher.Sort();
|
|
|
|
Assert.Equal(3, order.Length);
|
|
Assert.Equal(0, batcher[order[0]].Layer);
|
|
Assert.Equal(1, batcher[order[1]].Layer);
|
|
Assert.Equal(2, batcher[order[2]].Layer);
|
|
}
|
|
|
|
[Fact]
|
|
public void Submit_GrowsBeyondInitialCapacity()
|
|
{
|
|
var batcher = new SpriteBatcher(initialCapacity: 1);
|
|
|
|
for (var i = 0; i < 100; i++)
|
|
{
|
|
batcher.Submit(Instance(0), (ulong)(100 - i));
|
|
}
|
|
|
|
Assert.Equal(100, batcher.Count);
|
|
var order = batcher.Sort();
|
|
Assert.Equal(99, order[0]); // последний сабмит имеет наименьший ключ
|
|
}
|
|
|
|
[Fact]
|
|
public void Sort_IsStable_EqualKeysKeepSubmissionOrder()
|
|
{
|
|
var batcher = new SpriteBatcher();
|
|
var key = SpriteSortKey.Make(1, 5f, 7);
|
|
|
|
for (byte i = 0; i < 50; i++)
|
|
{
|
|
batcher.Submit(Instance(i), key); // одинаковый ключ у всех
|
|
}
|
|
|
|
var order = batcher.Sort();
|
|
|
|
for (var i = 0; i < 50; i++)
|
|
{
|
|
Assert.Equal(i, order[i]);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Sort_IsStable_WithinMixedKeys()
|
|
{
|
|
var batcher = new SpriteBatcher();
|
|
var keyA = SpriteSortKey.Make(0, 0f, 1);
|
|
var keyB = SpriteSortKey.Make(2, 3f, 9);
|
|
|
|
// Чередуем два ключа: внутри каждой группы порядок сабмита должен сохраниться.
|
|
for (byte i = 0; i < 20; i++)
|
|
{
|
|
batcher.Submit(Instance(i), i % 2 == 0 ? keyA : keyB);
|
|
}
|
|
|
|
var order = batcher.Sort();
|
|
|
|
var expectedA = new[] { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 };
|
|
var expectedB = new[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 };
|
|
Assert.Equal(expectedA, order[..10].ToArray());
|
|
Assert.Equal(expectedB, order[10..].ToArray());
|
|
}
|
|
|
|
[Fact]
|
|
public void Sort_LargeRandomSet_FullyOrdered()
|
|
{
|
|
var batcher = new SpriteBatcher(initialCapacity: 16);
|
|
var random = new Random(123);
|
|
var keys = new ulong[5000];
|
|
for (var i = 0; i < keys.Length; i++)
|
|
{
|
|
keys[i] = (ulong)random.NextInt64();
|
|
batcher.Submit(Instance(0), keys[i]);
|
|
}
|
|
|
|
var order = batcher.Sort();
|
|
|
|
for (var i = 1; i < order.Length; i++)
|
|
{
|
|
Assert.True(keys[order[i - 1]] <= keys[order[i]]);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ChunkedSubmit_MergesInChunkOrder_AndCountsCulled()
|
|
{
|
|
var batcher = new SpriteBatcher();
|
|
var key = SpriteSortKey.Make(0, 0f, 0); // одинаковый ключ — порядок задаётся слиянием чанков
|
|
|
|
batcher.BeginChunks([3, 2]);
|
|
|
|
var writer1 = batcher.GetChunkWriter(1); // чанки могут заполняться в любом порядке (параллельно)
|
|
writer1.Add(Instance(10), key);
|
|
writer1.AddCulled();
|
|
batcher.EndChunk(1, in writer1);
|
|
|
|
var writer0 = batcher.GetChunkWriter(0);
|
|
writer0.Add(Instance(1), key);
|
|
writer0.Add(Instance(2), key);
|
|
batcher.EndChunk(0, in writer0);
|
|
|
|
var accepted = batcher.CommitChunks();
|
|
|
|
Assert.Equal(3, accepted);
|
|
Assert.Equal(1, batcher.LastChunkCulled);
|
|
var order = batcher.Sort();
|
|
Assert.Equal(1, batcher[order[0]].Layer); // сначала чанк 0...
|
|
Assert.Equal(2, batcher[order[1]].Layer);
|
|
Assert.Equal(10, batcher[order[2]].Layer); // ...затем чанк 1 — стабильно
|
|
}
|
|
|
|
[Fact]
|
|
public void ChunkedSubmit_GrowsMainArrays_WhenNeeded()
|
|
{
|
|
var batcher = new SpriteBatcher(initialCapacity: 2);
|
|
batcher.BeginChunks([10]);
|
|
|
|
var writer = batcher.GetChunkWriter(0);
|
|
for (byte i = 0; i < 10; i++)
|
|
{
|
|
writer.Add(Instance(i), i);
|
|
}
|
|
|
|
batcher.EndChunk(0, in writer);
|
|
|
|
Assert.Equal(10, batcher.CommitChunks());
|
|
Assert.Equal(10, batcher.Count);
|
|
Assert.Equal(0, batcher[batcher.Sort()[0]].Layer);
|
|
}
|
|
|
|
[Fact]
|
|
public void Clear_ResetsCount_KeepsWorking()
|
|
{
|
|
var batcher = new SpriteBatcher();
|
|
batcher.Submit(Instance(0), 5);
|
|
batcher.Clear();
|
|
|
|
Assert.Equal(0, batcher.Count);
|
|
batcher.Submit(Instance(1), 1);
|
|
Assert.Equal(1, batcher.Count);
|
|
Assert.Equal(1, batcher[batcher.Sort()[0]].Layer);
|
|
}
|
|
}
|