test(core): add quirks and save-state tests
This commit is contained in:
1 parent
219c7b895c
commit
dc1d25a0cf
2 files changed
+208
No files matched your search
@@ -0,0 +1,104 @@
|
||||
using Chip8.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Chip8.Tests;
|
||||
|
||||
public class QuirksTests
|
||||
{
|
||||
static Machine drawRowAt(int originX, Quirks quirks)
|
||||
{
|
||||
var machine = new Machine(quirks, 1);
|
||||
machine.memory[0x200] = 0xD0;
|
||||
machine.memory[0x201] = 0x11;
|
||||
machine.i = 0x300;
|
||||
machine.memory[0x300] = 0xFF;
|
||||
machine.v[0] = (byte)originX;
|
||||
machine.v[1] = 0;
|
||||
machine.step();
|
||||
return machine;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void clipQuirkTruncatesSpriteAtRightEdge()
|
||||
{
|
||||
var clipping = new Quirks { clipSprites = true };
|
||||
var machine = drawRowAt(62, clipping);
|
||||
Assert.Equal(2, AsciiScreen.litPixelCount(machine.display));
|
||||
Assert.True(machine.display[62]);
|
||||
Assert.True(machine.display[63]);
|
||||
Assert.False(machine.display[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void wrapQuirkWrapsSpriteAroundRightEdge()
|
||||
{
|
||||
var wrapping = new Quirks { clipSprites = false };
|
||||
var machine = drawRowAt(62, wrapping);
|
||||
Assert.Equal(8, AsciiScreen.litPixelCount(machine.display));
|
||||
Assert.True(machine.display[62]);
|
||||
Assert.True(machine.display[63]);
|
||||
Assert.True(machine.display[0]);
|
||||
Assert.True(machine.display[5]);
|
||||
Assert.False(machine.display[6]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void shiftQuirkSelectsSourceRegister()
|
||||
{
|
||||
var usesVx = TestHarness.withOpcode(0x8016, new Quirks { shiftUsesVy = false });
|
||||
usesVx.v[0] = 0b0000_0100;
|
||||
usesVx.v[1] = 0xFF;
|
||||
usesVx.step();
|
||||
Assert.Equal(0b0000_0010, usesVx.v[0]);
|
||||
|
||||
var usesVy = TestHarness.withOpcode(0x8016, new Quirks { shiftUsesVy = true });
|
||||
usesVy.v[0] = 0x00;
|
||||
usesVy.v[1] = 0b0000_0100;
|
||||
usesVy.step();
|
||||
Assert.Equal(0b0000_0010, usesVy.v[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void loadStoreIncrementQuirkAdvancesIndex()
|
||||
{
|
||||
var noIncrement = TestHarness.withOpcode(0xF255, new Quirks { loadStoreIncrementsI = false });
|
||||
noIncrement.i = 0x300;
|
||||
noIncrement.step();
|
||||
Assert.Equal(0x300, noIncrement.i);
|
||||
|
||||
var increment = TestHarness.withOpcode(0xF255, new Quirks { loadStoreIncrementsI = true });
|
||||
increment.i = 0x300;
|
||||
increment.step();
|
||||
Assert.Equal(0x303, increment.i);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void jumpQuirkSelectsOffsetRegister()
|
||||
{
|
||||
var withV0 = TestHarness.withOpcode(0xB300, new Quirks { jumpWithVx = false });
|
||||
withV0.v[0] = 0x10;
|
||||
withV0.v[3] = 0x20;
|
||||
withV0.step();
|
||||
Assert.Equal(0x310, withV0.pc);
|
||||
|
||||
var withVx = TestHarness.withOpcode(0xB300, new Quirks { jumpWithVx = true });
|
||||
withVx.v[0] = 0x10;
|
||||
withVx.v[3] = 0x20;
|
||||
withVx.step();
|
||||
Assert.Equal(0x320, withVx.pc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void vfResetQuirkClearsFlagOnLogic()
|
||||
{
|
||||
var noReset = TestHarness.withOpcode(0x8011, new Quirks { resetVfOnLogic = false });
|
||||
noReset.v[0xF] = 0x5;
|
||||
noReset.step();
|
||||
Assert.Equal(0x5, noReset.v[0xF]);
|
||||
|
||||
var reset = TestHarness.withOpcode(0x8011, new Quirks { resetVfOnLogic = true });
|
||||
reset.v[0xF] = 0x5;
|
||||
reset.step();
|
||||
Assert.Equal(0, reset.v[0xF]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.IO;
|
||||
using Chip8.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace Chip8.Tests;
|
||||
|
||||
public class SaveStateTests
|
||||
{
|
||||
[Fact]
|
||||
public void loadStateRestoresRegistersMemoryAndDisplay()
|
||||
{
|
||||
var machine = TestHarness.withProgram(Platform.Chip8, 0x7001, 0x1200);
|
||||
machine.step();
|
||||
machine.v[3] = 0xAB;
|
||||
machine.i = 0x321;
|
||||
machine.memory[0x400] = 0x42;
|
||||
machine.display[5] = true;
|
||||
|
||||
byte[] state = machine.saveState();
|
||||
|
||||
machine.v[3] = 0x00;
|
||||
machine.i = 0x000;
|
||||
machine.memory[0x400] = 0x99;
|
||||
machine.display[5] = false;
|
||||
machine.pc = 0x2FF;
|
||||
|
||||
machine.loadState(state);
|
||||
|
||||
Assert.Equal(0xAB, machine.v[3]);
|
||||
Assert.Equal(0x321, machine.i);
|
||||
Assert.Equal(0x42, machine.memory[0x400]);
|
||||
Assert.True(machine.display[5]);
|
||||
Assert.Equal(0x202, machine.pc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void restoreBuildsANewMachineFromState()
|
||||
{
|
||||
var machine = TestHarness.withProgram(Platform.SuperChip, 0x6009);
|
||||
machine.step();
|
||||
byte[] state = machine.saveState();
|
||||
|
||||
Machine restored = Machine.restore(state);
|
||||
|
||||
Assert.Equal(Platform.SuperChip, restored.platform);
|
||||
Assert.Equal(machine.v[0], restored.v[0]);
|
||||
Assert.Equal(machine.pc, restored.pc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void restoredMachineExecutesIdenticallyToTheOriginal()
|
||||
{
|
||||
var original = TestHarness.withProgram(Platform.Chip8, 0x7001, 0x1200);
|
||||
for (int step = 0; step < 20; step++)
|
||||
{
|
||||
original.step();
|
||||
}
|
||||
|
||||
Machine resumed = Machine.restore(original.saveState());
|
||||
for (int step = 0; step < 15; step++)
|
||||
{
|
||||
original.step();
|
||||
resumed.step();
|
||||
}
|
||||
|
||||
Assert.Equal(original.pc, resumed.pc);
|
||||
Assert.Equal(original.v[0], resumed.v[0]);
|
||||
Assert.Equal(original.i, resumed.i);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void xoChipStatePreservesPlanesAndAudio()
|
||||
{
|
||||
var machine = TestHarness.withProgram(Platform.XoChip, 0xF201, 0xA400, 0xD001);
|
||||
machine.memory[0x400] = 0x80;
|
||||
machine.audioPattern[3] = 0xC3;
|
||||
for (int step = 0; step < 3; step++)
|
||||
{
|
||||
machine.step();
|
||||
}
|
||||
Assert.Equal(2, machine.video.colorAt(0, 0));
|
||||
|
||||
Machine restored = Machine.restore(machine.saveState());
|
||||
|
||||
Assert.Equal(2, restored.planeMask);
|
||||
Assert.Equal(2, restored.video.colorAt(0, 0));
|
||||
Assert.Equal(0xC3, restored.audioPattern[3]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void loadStateRejectsAMismatchedPlatform()
|
||||
{
|
||||
var chip8 = new Machine(Quirks.modern(), 1);
|
||||
byte[] state = chip8.saveState();
|
||||
var xoChip = new Machine(null, 1, Platform.XoChip);
|
||||
Assert.Throws<InvalidDataException>(() => xoChip.loadState(state));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void restoreRejectsGarbage()
|
||||
{
|
||||
Assert.Throws<InvalidDataException>(() => Machine.restore(new byte[] { 1, 2, 3, 4, 5 }));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user