sharpemu/tests/SharpEmu.Libs.Tests/Agc/AgcResourceOwnerTests.cs

92 lines
3.6 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Buffers.Binary;
using SharpEmu.HLE;
using SharpEmu.Libs.Agc;
using Xunit;
namespace SharpEmu.Libs.Tests.Agc;
public sealed class AgcResourceOwnerTests
{
private const ulong BaseAddress = 0x1_0000_0000;
private const ulong OwnerAddress = BaseAddress + 0x100;
private const ulong NameAddress = BaseAddress + 0x200;
private const ulong RegistrationMemoryAddress = BaseAddress + 0x400;
[Fact]
public void RegisterOwner_DoesNotRequireOptionalResourceRegistryMemory()
{
var memory = new FakeCpuMemory(BaseAddress, 0x2000);
var ctx = new CpuContext(memory, Generation.Gen5);
memory.WriteCString(NameAddress, "GIRender");
ctx[CpuRegister.Rdi] = OwnerAddress;
ctx[CpuRegister.Rsi] = NameAddress;
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_OK, AgcExports.DriverRegisterOwner(ctx));
Assert.NotEqual(0u, ReadUInt32(memory, OwnerAddress));
}
[Fact]
public void RegisterOwner_RespectsExplicitRegistryCapacity()
{
var memory = new FakeCpuMemory(BaseAddress, 0x2000);
var ctx = new CpuContext(memory, Generation.Gen5);
ctx[CpuRegister.Rdi] = RegistrationMemoryAddress;
ctx[CpuRegister.Rsi] = 0x1000;
ctx[CpuRegister.Rdx] = 1;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_OK,
AgcExports.DriverInitResourceRegistration(ctx));
memory.WriteCString(NameAddress, "First");
ctx[CpuRegister.Rdi] = OwnerAddress;
ctx[CpuRegister.Rsi] = NameAddress;
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_OK, AgcExports.DriverRegisterOwner(ctx));
memory.WriteCString(NameAddress, "Second");
ctx[CpuRegister.Rdi] = OwnerAddress + 4;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
AgcExports.DriverRegisterOwner(ctx));
}
private static uint ReadUInt32(FakeCpuMemory memory, ulong address)
{
Span<byte> buffer = stackalloc byte[4];
Assert.True(memory.TryRead(address, buffer));
return BinaryPrimitives.ReadUInt32LittleEndian(buffer);
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void UnregisterOwnerUsesTheSharedRegistryAcrossMemoryWrappers(bool nested)
{
var memory = new FakeCpuMemory(BaseAddress, 0x2000);
memory.WriteCString(NameAddress, "Owner");
var registration = new CpuContext(new MemoryWrapper(memory), Generation.Gen5);
registration[CpuRegister.Rdi] = OwnerAddress;
registration[CpuRegister.Rsi] = NameAddress;
Assert.Equal(0, AgcExports.DriverRegisterOwner(registration));
var owner = ReadUInt32(memory, OwnerAddress);
ICpuMemory removalMemory = new MemoryWrapper(memory);
if (nested)
removalMemory = new MemoryWrapper(removalMemory);
var removal = new CpuContext(removalMemory, Generation.Gen5);
removal[CpuRegister.Rdi] = owner;
Assert.Equal(0, AgcExports.DriverUnregisterOwnerAndResources(removal));
registration[CpuRegister.Rdi] = owner;
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
AgcExports.DriverUnregisterOwnerAndResources(registration));
}
private sealed class MemoryWrapper(ICpuMemory inner) : ICpuMemory, ICpuMemoryWrapper
{
public ICpuMemory Inner => inner;
public bool TryRead(ulong address, Span<byte> destination) => inner.TryRead(address, destination);
public bool TryWrite(ulong address, ReadOnlySpan<byte> source) => inner.TryWrite(address, source);
}
}