sharpemu/tests/SharpEmu.Libs.Tests/Memory/GpuMemory/PageMaskTests.cs

106 lines
3.4 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE.GpuMemory;
using Xunit;
namespace SharpEmu.Libs.Tests.Memory.GpuMemory;
public sealed class PageMaskTests
{
[Fact]
public void RangeQueryPreservesBitsAndUsesExclusiveEnd()
{
var mask = new PageMask();
Assert.False(mask.AnyInRange(0, TrackerLayout.PagesPerBlock));
for (var pageIndex = 0; pageIndex < TrackerLayout.PagesPerBlock; pageIndex++)
{
mask.Set(pageIndex);
Assert.True(mask.AnyInRange(pageIndex, pageIndex + 1));
Assert.True(mask.AnyInRange(0, TrackerLayout.PagesPerBlock));
Assert.False(mask.AnyInRange(0, pageIndex));
Assert.False(mask.AnyInRange(pageIndex + 1, TrackerLayout.PagesPerBlock));
Assert.True(mask.Get(pageIndex));
mask.Unset(pageIndex);
Assert.True(mask.None);
}
mask.Fill();
for (var pageIndex = 0; pageIndex < TrackerLayout.PagesPerBlock; pageIndex++)
Assert.True(mask.AnyInRange(pageIndex, pageIndex + 1));
}
[Fact]
public void RangeQueryMatchesCopiedMasksAcrossAllPageBoundaries()
{
var mask = new PageMask();
foreach (var page in new[] { 0, 63, 64, 127, 512, 700, 1023 }) mask.Set(page);
for (var start = 0; start <= TrackerLayout.PagesPerBlock; start++)
{
for (var end = start; end <= TrackerLayout.PagesPerBlock; end++)
Assert.Equal(new PageMask(mask, start, end).Any, mask.AnyInRange(start, end));
}
Assert.False(mask.AnyInRange(0, TrackerLayout.PagesPerBlock + 1));
Assert.False(mask.AnyInRange(-1, 1));
Assert.False(mask.AnyInRange(10, 9));
}
[Fact]
public void SetAndGet_TrackSingleBits()
{
var mask = new PageMask();
mask.Set(0);
mask.Set(63);
mask.Set(64);
mask.Set(1023);
Assert.True(mask.Get(0));
Assert.True(mask.Get(63));
Assert.True(mask.Get(64));
Assert.True(mask.Get(1023));
Assert.False(mask.Get(1));
Assert.False(mask.Get(65));
}
[Fact]
public void SetRange_CrossesWordBoundaries()
{
var mask = new PageMask();
mask.SetRange(60, 200);
Assert.False(mask.Get(59));
Assert.True(mask.Get(60));
Assert.True(mask.Get(127));
Assert.True(mask.Get(128));
Assert.True(mask.Get(199));
Assert.False(mask.Get(200));
Assert.Equal((60, 200), mask.FindFirstSetRange());
Assert.Equal((60, 200), mask.FindLastSetRange());
}
[Fact]
public void SetRange_IgnoresEmptyOrOutOfBoundsInput()
{
var mask = new PageMask();
mask.SetRange(5, 5);
mask.SetRange(10, 1025);
Assert.Equal((1024, 1024), mask.FindFirstSetRange());
Assert.Equal((0, 0), mask.FindLastSetRange());
}
[Fact]
public void FirstAndLastRange_FindSeparateRuns()
{
var mask = new PageMask();
mask.SetRange(2, 4);
mask.SetRange(700, 1024);
Assert.Equal((2, 4), mask.FindFirstSetRange());
Assert.Equal((700, 1024), mask.FindFirstSetRangeFrom(4));
Assert.Equal((700, 1024), mask.FindLastSetRange());
Assert.Equal((2, 4), mask.FindLastSetRangeBefore(700));
Assert.Equal((1024, 1024), mask.FindFirstSetRangeFrom(1024));
Assert.Equal((0, 0), mask.FindLastSetRangeBefore(2));
}
}