test(core): add debugger and watchpoint tests

This commit is contained in:
dualfroz committed 2026-08-28 17:50:57 +02:00
1 parent a72e1d6e07
commit 86feaab0dd
2 files changed
+216

No files matched your search

+115
View File
@@ -0,0 +1,115 @@
using Chip8.Core;
using Xunit;
namespace Chip8.Tests;
public class DebuggerTests
{
[Fact]
public void stepAdvancesProgramCounter()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x6001);
var debugger = new Debugger(machine);
debugger.step();
Assert.Equal(0x202, machine.pc);
Assert.Equal(1, machine.v[0]);
}
[Fact]
public void peekAndDisassembleShowUpcomingInstruction()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0xA300);
var debugger = new Debugger(machine);
Assert.Equal(0xA300, debugger.peekOpcode());
Assert.Equal("LD I, 0x300", debugger.disassembleNext());
}
[Fact]
public void breakpointStopsRunBeforeExecuting()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x6001, 0x6102, 0x6203, 0x1200);
var debugger = new Debugger(machine);
debugger.addBreakpoint(0x204);
var outcome = debugger.run(100);
Assert.Equal(StopReason.Breakpoint, outcome.reason);
Assert.Equal(2, outcome.steps);
Assert.Equal(0x204, machine.pc);
Assert.Equal(1, machine.v[0]);
Assert.Equal(2, machine.v[1]);
Assert.Equal(0, machine.v[2]);
}
[Fact]
public void runWithoutBreakpointReachesStepLimit()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x1200);
var debugger = new Debugger(machine);
var outcome = debugger.run(50);
Assert.Equal(StopReason.StepLimit, outcome.reason);
Assert.Equal(50, outcome.steps);
}
[Fact]
public void runStopsWhenInterpreterExits()
{
var machine = TestHarness.withProgram(Platform.SuperChip, 0x6001, 0x00FD);
var debugger = new Debugger(machine);
var outcome = debugger.run(100);
Assert.Equal(StopReason.Exited, outcome.reason);
Assert.True(machine.exited);
}
[Fact]
public void snapshotCapturesRegistersStackAndTimers()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x2204);
var debugger = new Debugger(machine);
machine.v[5] = 0x9A;
machine.delayTimer = 7;
debugger.step();
var snapshot = debugger.snapshot();
Assert.Equal(0x204, snapshot.pc);
Assert.Equal(1, snapshot.sp);
Assert.Single(snapshot.stack);
Assert.Equal(0x202, snapshot.stack[0]);
Assert.Equal(0x9A, snapshot.v[5]);
Assert.Equal(7, snapshot.delayTimer);
Assert.Contains("PC=0x0204", snapshot.format());
Assert.Contains("V5=9A", snapshot.format());
}
[Fact]
public void snapshotIsNotAliasedToLiveState()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x6001);
var debugger = new Debugger(machine);
var snapshot = debugger.snapshot();
machine.v[0] = 0xFF;
Assert.Equal(0, snapshot.v[0]);
}
[Fact]
public void readMemoryReturnsRequestedWindow()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0xABCD);
var debugger = new Debugger(machine);
var window = debugger.readMemory(0x200, 2);
Assert.Equal(0xAB, window[0]);
Assert.Equal(0xCD, window[1]);
}
[Fact]
public void breakpointCanBeRemoved()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x1200);
var debugger = new Debugger(machine);
debugger.addBreakpoint(0x200);
Assert.True(debugger.hasBreakpoint(0x200));
debugger.removeBreakpoint(0x200);
Assert.False(debugger.hasBreakpoint(0x200));
}
}
+101
View File
@@ -0,0 +1,101 @@
using Chip8.Core;
using Xunit;
namespace Chip8.Tests;
public class WatchpointTests
{
[Fact]
public void memoryWatchStopsWhenTheByteChanges()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0xA400, 0x6005, 0xF055, 0x1206);
var debugger = new Debugger(machine);
debugger.watchMemory(0x400);
RunResult outcome = debugger.run(100);
Assert.Equal(StopReason.Watchpoint, outcome.reason);
Assert.Equal(3, outcome.steps);
Assert.Equal(0x400, outcome.triggeredAddress);
Assert.Equal(5, machine.memory[0x400]);
Assert.Contains("memory 0x0400", debugger.lastWatchDescription);
}
[Fact]
public void registerWatchStopsWhenTheRegisterChanges()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x6005, 0x1202);
var debugger = new Debugger(machine);
debugger.watchRegister(0);
RunResult outcome = debugger.run(50);
Assert.Equal(StopReason.Watchpoint, outcome.reason);
Assert.Equal(1, outcome.steps);
Assert.Contains("V0", debugger.lastWatchDescription);
}
[Fact]
public void unwatchedMemoryDoesNotStop()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0xA400, 0x6005, 0xF055, 0x1206);
var debugger = new Debugger(machine);
debugger.watchMemory(0x400);
debugger.clearWatches();
RunResult outcome = debugger.run(20);
Assert.Equal(StopReason.StepLimit, outcome.reason);
}
[Fact]
public void stepOverRunsThroughACall()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x2204, 0x6042, 0x0000, 0x00EE);
var debugger = new Debugger(machine);
RunResult outcome = debugger.stepOver(100);
Assert.Equal(0x202, machine.pc);
Assert.Equal(0, machine.v[0]);
Assert.Equal(3, outcome.steps);
}
[Fact]
public void stepOverIsASingleStepForNonCalls()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x6005, 0x1202);
var debugger = new Debugger(machine);
debugger.stepOver(100);
Assert.Equal(0x202, machine.pc);
Assert.Equal(5, machine.v[0]);
}
[Fact]
public void runUntilStopsAtTheTargetAddress()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0x7001, 0x1200);
var debugger = new Debugger(machine);
RunResult outcome = debugger.runUntil(0x202, 100);
Assert.Equal(0x202, machine.pc);
Assert.Equal(StopReason.Breakpoint, outcome.reason);
}
[Fact]
public void disassembleWindowDecodesFromProgramCounter()
{
var machine = TestHarness.withProgram(Platform.Chip8, 0xA300, 0x6001, 0x00EE);
var debugger = new Debugger(machine);
var lines = debugger.disassembleWindow(3);
Assert.Equal(3, lines.Count);
Assert.Equal(0x200, lines[0].address);
Assert.Equal("LD I, 0x300", lines[0].mnemonic);
Assert.Equal("RET", lines[2].mnemonic);
}
}