test(core): add debugger and watchpoint tests
This commit is contained in:
1 parent
a72e1d6e07
commit
86feaab0dd
2 files changed
+216
No files matched your search
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user