diff options
| author | crecher <crecher@crecher.net> | 2026-10-13 01:13:13 +0200 |
|---|---|---|
| committer | crecher <crecher@crecher.net> | 2026-10-13 01:13:13 +0200 |
| commit | 99cae5a5a37f41f878a84857361eda47910303ba (patch) | |
| tree | 31c8665ca991f95e09e93bb2e6ec91d81d2427ff /tests/controller_test.go | |
| parent | 96ff6d8eda2ba434682909f4ff4ce350d78b2273 (diff) | |
| download | gones-99cae5a5a37f41f878a84857361eda47910303ba.tar.gz gones-99cae5a5a37f41f878a84857361eda47910303ba.zip | |
sprites!!!!!!
Diffstat (limited to 'tests/controller_test.go')
| -rw-r--r-- | tests/controller_test.go | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/tests/controller_test.go b/tests/controller_test.go new file mode 100644 index 0000000..026e68a --- /dev/null +++ b/tests/controller_test.go @@ -0,0 +1,119 @@ +package tests + +import ( + "testing" + + "crecher.net/gones/v2/cart" + "crecher.net/gones/v2/nes" +) + +func newTestConsole(t *testing.T) *nes.Console { + t.Helper() + c, err := cart.Load("testdata/nestest.nes") + if err != nil { + t.Fatal(err) + } + return nes.New(c) +} + +func strobe(n *nes.Console) { + n.Write(0x4016, 1) + n.Write(0x4016, 0) +} + +func readBits(n *nes.Console, addr uint16, count int) []uint8 { + bits := make([]uint8, count) + for i := range bits { + bits[i] = n.Read(addr) & 1 + } + return bits +} + +func equalBits(a, b []uint8) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +func TestControllerReadsButtonsInOrder(t *testing.T) { + n := newTestConsole(t) + n.SetButtons(0, nes.ButtonA|nes.ButtonStart|nes.ButtonRight) + strobe(n) + + // +---------------------- A + // | +------------------- B + // | | +---------------- Select + // | | | +------------- Start + // | | | | +---------- Up + // | | | | | +------- Down + // | | | | | | +---- Left + // | | | | | | | +- Right + // | | | | | | | | + want := []uint8{1, 0, 0, 1, 0, 0, 0, 1} + if got := readBits(n, 0x4016, 8); !equalBits(got, want) { + t.Errorf("bits = %v, want %v", got, want) + } +} + +func TestControllerReturnsOneAfterEightReads(t *testing.T) { + n := newTestConsole(t) + strobe(n) + readBits(n, 0x4016, 8) + if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 1, 1}) { + t.Errorf("bits after 8 reads = %v, want [1 1 1]", got) + } +} + +func TestControllerStrobeHighKeepsReturningA(t *testing.T) { + n := newTestConsole(t) + n.SetButtons(0, nes.ButtonA) + n.Write(0x4016, 1) + if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 1, 1}) { + t.Errorf("bits = %v, want [1 1 1]", got) + } + + n.SetButtons(0, nes.ButtonB) + if got := readBits(n, 0x4016, 2); !equalBits(got, []uint8{0, 0}) { + t.Errorf("bits after releasing A = %v, want [0 0]", got) + } +} + +func TestControllerLatchesOnStrobe(t *testing.T) { + n := newTestConsole(t) + n.SetButtons(0, nes.ButtonA) + strobe(n) + n.SetButtons(0, 0) // released after the latch, the readout should not change + + want := []uint8{1, 0, 0, 0, 0, 0, 0, 0} + if got := readBits(n, 0x4016, 8); !equalBits(got, want) { + t.Errorf("bits = %v, want %v", got, want) + } +} + +func TestControllerPortsAreIndependentWithSharedStrobe(t *testing.T) { + n := newTestConsole(t) + n.SetButtons(0, nes.ButtonA) + n.SetButtons(1, nes.ButtonSelect) + strobe(n) + + if got := readBits(n, 0x4016, 3); !equalBits(got, []uint8{1, 0, 0}) { + t.Errorf("port 1 bits = %v, want [1 0 0]", got) + } + if got := readBits(n, 0x4017, 3); !equalBits(got, []uint8{0, 0, 1}) { + t.Errorf("port 2 bits = %v, want [0 0 1]", got) + } +} + +func TestControllerReadHasOpenBusBit6(t *testing.T) { + n := newTestConsole(t) + strobe(n) + if got := n.Read(0x4016); got != 0x40 { + t.Errorf("$4016 with nothing pressed = %#02x, want 0x40", got) + } +} |