use super::*;
use std::io::Read;
fn make_ines(prg_banks: u8, chr_banks: u8, mapper: u8, flags6: u8, flags7: u8) -> Vec<u8> {
let mut header = [0u8; 16];
header[0..4].copy_from_slice(b"NES\x1A");
header[4] = prg_banks;
header[5] = chr_banks;
header[6] = (flags6 & 0x0F) | ((mapper & 0x0F) << 4);
header[7] = (flags7 & 0x0F) | ((mapper & 0xF0) >> 4);
let mut blob = Vec::from(header);
blob.extend(std::iter::repeat(0xEA).take(prg_banks as usize * 16 * 1024));
blob.extend(std::iter::repeat(0x00).take(chr_banks as usize * 8 * 1024));
blob
}
struct SliceReader<'a>(&'a [u8]);
impl<'a> Read for SliceReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n = buf.len().min(self.0.len());
buf[..n].copy_from_slice(&self.0[..n]);
self.0 = &self.0[n..];
Ok(n)
}
}
#[test]
fn load_nrom_256_horizontal_chr_rom() {
let blob = make_ines(2, 1, 0, 0b0000_0000, 0);
let cart = load_rom(&mut SliceReader(&blob)).expect("NROM-256 should load");
assert!(cart.irq_pin() == false);
}
#[test]
fn load_nrom_128_chr_ram() {
let blob = make_ines(1, 0, 0, 0b0000_0000, 0);
load_rom(&mut SliceReader(&blob)).expect("NROM-128 + CHR RAM should load");
}
#[test]
fn load_uxrom_chr_ram_works() {
let blob = make_ines(8, 0, 2, 0b0000_0001, 0);
load_rom(&mut SliceReader(&blob)).expect("UxROM should load");
}
#[test]
fn load_cnrom_chr_rom_works() {
let blob = make_ines(2, 4, 3, 0b0000_0001, 0);
load_rom(&mut SliceReader(&blob)).expect("CNROM should load");
}
#[test]
fn load_mmc3_256kb_chr_works() {
let blob = make_ines(16, 32, 4, 0b0000_0000, 0);
load_rom(&mut SliceReader(&blob)).expect("MMC3 with 256 KB CHR ROM should load");
}
#[test]
fn load_unsupported_mapper_returns_error() {
let blob = make_ines(2, 1, 7, 0, 0);
let result = load_rom(&mut SliceReader(&blob));
let err = match result {
Ok(_) => panic!("expected error for mapper 7"),
Err(e) => e,
};
match err {
RomError::UnsupportedMapper(n) => assert_eq!(n, 7),
other => panic!("expected UnsupportedMapper(7), got {other:?}"),
}
}
#[test]
fn unsupported_mapper_display_zero_pads_to_three_digits() {
assert_eq!(
format!("{}", RomError::UnsupportedMapper(4)),
"unsupported mapper: 004 (not implemented)"
);
assert_eq!(
format!("{}", RomError::UnsupportedMapper(99)),
"unsupported mapper: 099 (not implemented)"
);
assert_eq!(
format!("{}", RomError::UnsupportedMapper(255)),
"unsupported mapper: 255 (not implemented)"
);
}
#[test]
fn load_rom_without_header_returns_format_error() {
let bogus = b"NOT_A_NES_ROM_AT_ALL_____";
let result = load_rom(&mut SliceReader(bogus.as_slice()));
let err = match result {
Ok(_) => panic!("expected error for non-iNES bytes"),
Err(e) => e,
};
match err {
RomError::RomFormat(msg) => {
assert!(
msg.contains("magic"),
"expected magic-byte error, got: {msg}"
);
}
other => panic!("expected RomFormat, got {other:?}"),
}
}
#[test]
fn load_rom_truncated_returns_io_error() {
let mut header = [0u8; 16];
header[0..4].copy_from_slice(b"NES\x1A");
header[4] = 1; header[5] = 0;
let result = load_rom(&mut SliceReader(header.as_slice()));
let err = match result {
Ok(_) => panic!("expected error for truncated ROM"),
Err(e) => e,
};
match err {
RomError::Io(io_err) => {
assert_eq!(io_err.kind(), std::io::ErrorKind::UnexpectedEof);
}
other => panic!("expected Io(UnexpectedEof), got {other:?}"),
}
}