// simple stateless harness helpers without custom runner frameworks const std = @import("std"); const testing = std.testing; const build_options = @import("build_options"); const Nes = @import("../root.zig").Nes; pub fn loadRomAlloc(allocator: std.mem.Allocator, relative_path: []const u8) ![]u8 { const base_dir = build_options.nes_test_roms_dir orelse return error.SkipZigTest; var dir = try std.Io.Dir.openDirAbsolute(testing.io, base_dir, .{}); defer dir.close(testing.io); return try dir.readFileAlloc(testing.io, relative_path, allocator, @enumFromInt(10 * 1024 * 1024)); } // runRom asserts progress so test blocks can be concise 1-liners pub fn runRom(relative_path: []const u8, frames: usize) !Nes { if (build_options.nes_test_roms_dir == null) return error.SkipZigTest; const rom_data = try loadRomAlloc(testing.allocator, relative_path); defer testing.allocator.free(rom_data); var nes: Nes = undefined; try nes.init(rom_data); for (0..frames) |_| { nes.runFrame(); } try testing.expect(nes.cpu.cycles > 1_500_000); try testing.expect(nes.bus.ppu.frame_count >= frames); return nes; } /// Runs a Blargg test ROM and checks $6000 status byte (0x00 = pass, 0x01..0x7F = error code). pub fn runBlarggRom(relative_path: []const u8, max_frames: usize) !Nes { if (build_options.nes_test_roms_dir == null) return error.SkipZigTest; const rom_data = try loadRomAlloc(testing.allocator, relative_path); defer testing.allocator.free(rom_data); var nes: Nes = undefined; try nes.init(rom_data); var status: u8 = 0x80; for (0..max_frames) |_| { nes.runFrame(); status = nes.bus.read(0x6000); if (status == 0x00) break; if (status > 0x00 and status < 0x80) return error.BlarggTestFailed; } if (status != 0x00) return error.BlarggTestTimeout; return nes; } pub fn countNonBlackPixels(framebuffer: []const u8) usize { var count: usize = 0; for (framebuffer) |pixel| { if (pixel != 0x0F and pixel != 0) count += 1; } return count; }