Test cleanup

jsmoo
Nick Krichevsky 2023-04-15 19:42:37 -04:00
parent 321ab461ff
commit 3b6e611768
6 changed files with 175 additions and 164 deletions

View File

@ -89,6 +89,8 @@ mod tests {
#[test]
fn test_get_invalid_address() {
let memory = Memory::new();
#[allow(clippy::match_wild_err_arm)]
match memory.get(0xCC_CC_CC_CC_CC) {
Err(Error::GetInvalidAddress(addr)) => {
assert_eq!(0xCC_CC_CC_CC_CC, addr);
@ -101,6 +103,8 @@ mod tests {
#[test]
fn test_set_invalid_address() {
let mut memory = Memory::new();
#[allow(clippy::match_wild_err_arm)]
match memory.set(0xCC_CC_CC_CC_CC, 100) {
Err(Error::SetInvalidAddress(addr, value)) => {
assert_eq!((0xCC_CC_CC_CC_CC, 100), (addr, value));

View File

@ -3,52 +3,16 @@ use ferris_boi::{
register,
};
use crate::testutil;
use test_case::test_case;
fn set_opposite_of_expected_flags(
processor: &mut Processor,
(zero_flag, sub_flag, half_carry_flag, carry_flag): (u8, u8, u8, u8),
) {
let invert_flag = |value| {
if value == 0 {
1
} else if value == 1 {
0
} else {
panic!("invalid flag value of {value} ")
}
};
processor
.registers
.set_flag_bit(register::Flag::Zero, invert_flag(zero_flag));
processor
.registers
.set_flag_bit(register::Flag::HalfCarry, invert_flag(half_carry_flag));
processor
.registers
.set_flag_bit(register::Flag::Carry, invert_flag(carry_flag));
processor
.registers
.set_flag_bit(register::Flag::Subtract, invert_flag(sub_flag));
struct AdditionOperationFlags {
zero: u8,
half_carry: u8,
carry: u8,
}
macro_rules! assert_flags_eq {
($processor: expr, $(($flag: path, $value: expr)),+ $(,)?) => {
$(
assert_eq!(
$value,
$processor.registers.get_flag_bit($flag),
"{:?} flag had unexpected value",
$flag
);
)+
};
}
#[test]
fn test_add_a_to_itself() {
let mut processor = Processor::default();
@ -104,7 +68,10 @@ fn test_add_register_to_a_flags(
processor.registers.a = a_value;
// Set all the register to the opposite we expect to ensure they all get set
set_opposite_of_expected_flags(&mut processor, (zero_flag, 0, half_carry_flag, carry_flag));
testutil::set_opposite_of_expected_flags(
&mut processor,
(zero_flag, 0, half_carry_flag, carry_flag),
);
processor.registers.set_single_8bit_register(src, src_value);
let data = [opcode, 0x02];
@ -115,7 +82,7 @@ fn test_add_register_to_a_flags(
processor.run(&ins);
assert_flags_eq!(
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, zero_flag),
(register::Flag::Subtract, 0),
@ -173,7 +140,10 @@ fn test_add_hl_addr_to_a_flags(
.expect("expected to set address 0xFF00 but could not");
// Set all the register to the opposite we expect to ensure they all get set
set_opposite_of_expected_flags(&mut processor, (zero_flag, 0, half_carry_flag, carry_flag));
testutil::set_opposite_of_expected_flags(
&mut processor,
(zero_flag, 0, half_carry_flag, carry_flag),
);
let data = [0x86, 0x01];
let (ins, extra_data) =
@ -182,7 +152,7 @@ fn test_add_hl_addr_to_a_flags(
processor.run(&ins);
assert_flags_eq!(
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, zero_flag),
(register::Flag::Subtract, 0),
@ -206,23 +176,25 @@ fn test_add_immediate_to_a_value() {
assert_eq!(69, processor.registers.a);
}
#[test_case(0x00, 0x00, 1, 0, 0; "zero flag for zero value")]
#[test_case(0x00, 0x01, 0, 0, 0; "no zero flag for non-zero value")]
#[test_case(0x0F, 0x01, 0, 1, 0; "half carry flag")]
#[test_case(0x80, 0x80, 0, 0, 1; "full carry flag")]
#[test_case(0xFF, 0x01, 0, 1, 1; "both full and half carry flag")]
fn test_add_immediate_to_a_flags(
a_value: u8,
n: u8,
zero_flag: u8,
half_carry_flag: u8,
carry_flag: u8,
) {
#[test_case(0x00, 0x00, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "zero flag for zero value")]
#[test_case(0x00, 0x01, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no zero flag for non-zero value")]
#[test_case(0x0F, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "half carry flag")]
#[test_case(0x80, 0x80, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 1}; "full carry flag")]
#[test_case(0xFF, 0x01, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "both full and half carry flag")]
fn test_add_immediate_to_a_flags(a_value: u8, n: u8, expected_flags: AdditionOperationFlags) {
let mut processor = Processor::default();
processor.registers.a = a_value;
// Set all the register to the opposite we expect to ensure they all get set
set_opposite_of_expected_flags(&mut processor, (zero_flag, 0, half_carry_flag, carry_flag));
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_flags.zero,
0,
expected_flags.half_carry,
expected_flags.carry,
),
);
let data = [0xC6, n, 0x01];
let (ins, extra_data) =
@ -231,12 +203,12 @@ fn test_add_immediate_to_a_flags(
processor.run(&ins);
assert_flags_eq!(
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, zero_flag),
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, half_carry_flag),
(register::Flag::Carry, carry_flag),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}
@ -280,74 +252,72 @@ fn test_add_with_carry_to_a_value(
// these parameters are like impossible to read but I can't think of a nicer way to do this right now
// B register
#[test_case(0x88, 0x12, 0, register::SingleEightBit::B, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x12, 1, register::SingleEightBit::B, 0x5, 0, 0, 0; "carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x00, 0, register::SingleEightBit::B, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register b")]
#[test_case(0x88, 0x00, 1, register::SingleEightBit::B, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x1, 0, 1, 0; "no carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x1, 0, 1, 0; "carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x0F, 0, 1, 0; "no carry bit, full carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x0F, 0, 1, 0; "carry bit, full carry, register b")]
#[test_case(0x88, 0xFF, 1, register::SingleEightBit::B, 0xFF, 0, 1, 1; "carry bit, both carries, register b")]
#[test_case(0x88, 0x12, 0, register::SingleEightBit::B, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x12, 1, register::SingleEightBit::B, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register b")]
#[test_case(0x88, 0x00, 0, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register b")]
#[test_case(0x88, 0x00, 1, register::SingleEightBit::B, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register b")]
#[test_case(0x88, 0x0F, 0, register::SingleEightBit::B, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register b")]
#[test_case(0x88, 0x0F, 1, register::SingleEightBit::B, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register b")]
#[test_case(0x88, 0xFF, 1, register::SingleEightBit::B, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register b")]
// C register
#[test_case(0x89, 0x12, 0, register::SingleEightBit::C, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x12, 1, register::SingleEightBit::C, 0x5, 0, 0, 0; "carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x00, 0, register::SingleEightBit::C, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register c")]
#[test_case(0x89, 0x00, 1, register::SingleEightBit::C, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x1, 0, 1, 0; "no carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x1, 0, 1, 0; "carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x0F, 0, 1, 0; "no carry bit, full carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x0F, 0, 1, 0; "carry bit, full carry, register c")]
#[test_case(0x89, 0xFF, 1, register::SingleEightBit::C, 0xFF, 0, 1, 1; "carry bit, both carries, register c")]
#[test_case(0x89, 0x12, 0, register::SingleEightBit::C, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x12, 1, register::SingleEightBit::C, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register c")]
#[test_case(0x89, 0x00, 0, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register c")]
#[test_case(0x89, 0x00, 1, register::SingleEightBit::C, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register c")]
#[test_case(0x89, 0x0F, 0, register::SingleEightBit::C, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register c")]
#[test_case(0x89, 0x0F, 1, register::SingleEightBit::C, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register c")]
#[test_case(0x89, 0xFF, 1, register::SingleEightBit::C, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register c")]
// D register
#[test_case(0x8A, 0x12, 0, register::SingleEightBit::D, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x12, 1, register::SingleEightBit::D, 0x5, 0, 0, 0; "carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x00, 0, register::SingleEightBit::D, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register d")]
#[test_case(0x8A, 0x00, 1, register::SingleEightBit::D, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x1, 0, 1, 0; "no carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x1, 0, 1, 0; "carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x0F, 0, 1, 0; "no carry bit, full carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x0F, 0, 1, 0; "carry bit, full carry, register d")]
#[test_case(0x8A, 0xFF, 1, register::SingleEightBit::D, 0xFF, 0, 1, 1; "carry bit, both carries, register d")]
#[test_case(0x8A, 0x12, 0, register::SingleEightBit::D, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x12, 1, register::SingleEightBit::D, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register d")]
#[test_case(0x8A, 0x00, 0, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register d")]
#[test_case(0x8A, 0x00, 1, register::SingleEightBit::D, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register d")]
#[test_case(0x8A, 0x0F, 0, register::SingleEightBit::D, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register d")]
#[test_case(0x8A, 0x0F, 1, register::SingleEightBit::D, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register d")]
#[test_case(0x8A, 0xFF, 1, register::SingleEightBit::D, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register d")]
// E register
#[test_case(0x8B, 0x12, 0, register::SingleEightBit::E, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x12, 1, register::SingleEightBit::E, 0x5, 0, 0, 0; "carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x00, 0, register::SingleEightBit::E, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register e")]
#[test_case(0x8B, 0x00, 1, register::SingleEightBit::E, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x1, 0, 1, 0; "no carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x1, 0, 1, 0; "carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x0F, 0, 1, 0; "no carry bit, full carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x0F, 0, 1, 0; "carry bit, full carry, register e")]
#[test_case(0x8B, 0xFF, 1, register::SingleEightBit::E, 0xFF, 0, 1, 1; "carry bit, both carries, register e")]
#[test_case(0x8B, 0x12, 0, register::SingleEightBit::E, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x12, 1, register::SingleEightBit::E, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register e")]
#[test_case(0x8B, 0x00, 0, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register e")]
#[test_case(0x8B, 0x00, 1, register::SingleEightBit::E, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register e")]
#[test_case(0x8B, 0x0F, 0, register::SingleEightBit::E, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register e")]
#[test_case(0x8B, 0x0F, 1, register::SingleEightBit::E, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register e")]
#[test_case(0x8B, 0xFF, 1, register::SingleEightBit::E, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register e")]
// H register
#[test_case(0x8C, 0x12, 0, register::SingleEightBit::H, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x12, 1, register::SingleEightBit::H, 0x5, 0, 0, 0; "carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x00, 0, register::SingleEightBit::H, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register h")]
#[test_case(0x8C, 0x00, 1, register::SingleEightBit::H, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x1, 0, 1, 0; "no carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x1, 0, 1, 0; "carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x0F, 0, 1, 0; "no carry bit, full carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x0F, 0, 1, 0; "carry bit, full carry, register h")]
#[test_case(0x8C, 0xFF, 1, register::SingleEightBit::H, 0xFF, 0, 1, 1; "carry bit, both carries, register h")]
#[test_case(0x8C, 0x12, 0, register::SingleEightBit::H, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x12, 1, register::SingleEightBit::H, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register h")]
#[test_case(0x8C, 0x00, 0, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register h")]
#[test_case(0x8C, 0x00, 1, register::SingleEightBit::H, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register h")]
#[test_case(0x8C, 0x0F, 0, register::SingleEightBit::H, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register h")]
#[test_case(0x8C, 0x0F, 1, register::SingleEightBit::H, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register h")]
#[test_case(0x8C, 0xFF, 1, register::SingleEightBit::H, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register h")]
// L register
#[test_case(0x8D, 0x12, 0, register::SingleEightBit::L, 0x5, 0, 0, 0; "no carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x12, 1, register::SingleEightBit::L, 0x5, 0, 0, 0; "carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x00, 0, register::SingleEightBit::L, 0x0, 1, 0, 0; "no carry bit set, zero operands result in zero flag set, register l")]
#[test_case(0x8D, 0x00, 1, register::SingleEightBit::L, 0x0, 0, 0, 0; "carry bit set, zero operands result in no zero flag set, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x1, 0, 1, 0; "no carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x1, 0, 1, 0; "carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x0F, 0, 1, 0; "no carry bit, full carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x0F, 0, 1, 0; "carry bit, full carry, register l")]
#[test_case(0x8D, 0xFF, 1, register::SingleEightBit::L, 0xFF, 0, 1, 1; "carry bit, both carries, register l")]
#[test_case(0x8D, 0x12, 0, register::SingleEightBit::L, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "no carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x12, 1, register::SingleEightBit::L, 0x5, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, results in no flags, register l")]
#[test_case(0x8D, 0x00, 0, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 1, half_carry: 0, carry: 0}; "no carry bit set, zero operands result in zero flag set, register l")]
#[test_case(0x8D, 0x00, 1, register::SingleEightBit::L, 0x0, AdditionOperationFlags{zero: 0, half_carry: 0, carry: 0}; "carry bit set, zero operands result in no zero flag set, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x1, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, half carry, register l")]
#[test_case(0x8D, 0x0F, 0, register::SingleEightBit::L, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "no carry bit, full carry, register l")]
#[test_case(0x8D, 0x0F, 1, register::SingleEightBit::L, 0x0F, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 0}; "carry bit, full carry, register l")]
#[test_case(0x8D, 0xFF, 1, register::SingleEightBit::L, 0xFF, AdditionOperationFlags{zero: 0, half_carry: 1, carry: 1}; "carry bit, both carries, register l")]
fn test_add_with_carry_to_a_flags(
opcode: u8,
initial_value: u8,
carry_bit: u8,
operand_register: register::SingleEightBit,
operand: u8,
expected_zero_flag: u8,
expected_half_carry_flag: u8,
expected_carry_flag: u8,
expected_flags: AdditionOperationFlags,
) {
let mut processor = Processor::default();
processor.registers.a = initial_value;
@ -356,13 +326,13 @@ fn test_add_with_carry_to_a_flags(
.set_single_8bit_register(operand_register, operand);
// Set all the register to the opposite we expect to ensure they all get set
set_opposite_of_expected_flags(
testutil::set_opposite_of_expected_flags(
&mut processor,
(
expected_zero_flag,
expected_flags.zero,
0,
expected_half_carry_flag,
expected_carry_flag,
expected_flags.half_carry,
expected_flags.carry,
),
);
@ -377,11 +347,11 @@ fn test_add_with_carry_to_a_flags(
assert_eq!(extra_data, &[0x01]);
processor.run(&ins);
assert_flags_eq!(
testutil::assert_flags_eq!(
processor,
(register::Flag::Zero, expected_zero_flag),
(register::Flag::Zero, expected_flags.zero),
(register::Flag::Subtract, 0),
(register::Flag::HalfCarry, expected_half_carry_flag),
(register::Flag::Carry, expected_carry_flag),
(register::Flag::HalfCarry, expected_flags.half_carry),
(register::Flag::Carry, expected_flags.carry),
);
}

View File

@ -3,6 +3,8 @@ use ferris_boi::{
register,
};
use crate::testutil;
use test_case::test_case;
#[test_case(0x32, 0x64, 0x63)]
@ -93,17 +95,14 @@ fn test_load_effective_address(value: i8, expected_sp: u16) {
0xFF00,
);
#[allow(clippy::cast_sign_loss)]
// The truncation will only happen if |value| > 128 in the branch where we check it's equal to -128
// so we're fine.
#[allow(clippy::cast_possible_truncation)]
let unsigned_value = if value >= 0 {
value as u8
} else if value == i8::MIN {
i16::from(i8::MIN).abs() as u8
i8::MIN.unsigned_abs()
} else {
!(value.abs() as u8) + 1
!(value.unsigned_abs()) + 1
};
let data = [0xF8, unsigned_value, 0x00];
let (ins, extra_data) =
@ -132,16 +131,12 @@ fn test_load_effective_address_flags(starting_sp: u16, add_value: i8, half_carry
let mut processor = Processor::default();
processor.registers.stack_pointer = starting_sp;
#[allow(clippy::cast_sign_loss)]
// The truncation will only happen if |value| > 128 in the branch where we check it's equal to -128
// so we're fine.
#[allow(clippy::cast_possible_truncation)]
let unsigned_value = if add_value >= 0 {
add_value as u8
} else if add_value == i8::MIN {
i16::from(i8::MIN).abs() as u8
i8::MIN.unsigned_abs()
} else {
!(add_value.abs() as u8) + 1
!(add_value.unsigned_abs()) + 1
};
let data = [0xF8, unsigned_value, 0x00];
@ -151,27 +146,12 @@ fn test_load_effective_address_flags(starting_sp: u16, add_value: i8, half_carry
assert_eq!(extra_data, &[0x00]);
processor.run(&ins);
assert_eq!(
half_carry,
processor.registers.get_flag_bit(register::Flag::HalfCarry),
"incorrect half carry bit"
);
assert_eq!(
carry,
processor.registers.get_flag_bit(register::Flag::Carry),
"incorrect carry bit"
);
assert_eq!(
0,
processor.registers.get_flag_bit(register::Flag::Zero),
"incorrect zero bit"
);
assert_eq!(
0,
processor.registers.get_flag_bit(register::Flag::Subtract),
"incorrect subtract bit"
testutil::assert_flags_eq!(
processor,
(register::Flag::HalfCarry, half_carry),
(register::Flag::Carry, carry),
(register::Flag::Zero, 0),
(register::Flag::Subtract, 0),
);
}

View File

@ -196,7 +196,10 @@ fn test_load_immediate_to_memory() {
#[test]
fn test_load_from_immediate_address() {
let mut processor = Processor::default();
processor.memory.set(0xCCDE, 105);
processor
.memory
.set(0xCCDE, 105)
.expect("failed to set memory value");
let data = [0xFA, 0xDE, 0xCC, 0x00];
let (ins, extra_data) =
@ -264,7 +267,10 @@ fn test_load_from_register_address_then_do_arithmetic(
processor
.registers
.set_combined_register(register::Combined::HL, hl_value_before);
processor.memory.set(hl_value_before.into(), 10);
processor
.memory
.set(hl_value_before.into(), 10)
.expect("failed to set memory value");
let data = [opcode, 0x00];
let (ins, extra_data) =
@ -299,7 +305,10 @@ fn test_load_to_io_register_zone_by_immediate() {
#[test]
fn test_load_from_io_register_zone_by_immediate() {
let mut processor = Processor::default();
processor.memory.set(0xFF05, 0xAF);
processor
.memory
.set(0xFF05, 0xAF)
.expect("failed to set memory value");
let data = [0xF0, 0x05, 0x06];
let (ins, extra_data) =

View File

@ -1,3 +1,4 @@
mod arith8;
mod load16;
mod load8;
mod testutil;

47
tests/cpu/testutil.rs Normal file
View File

@ -0,0 +1,47 @@
use ferris_boi::{cpu::Processor, register};
macro_rules! assert_flags_eq {
($processor: expr, $(($flag: path, $value: expr)),+ $(,)?) => {
$(
assert_eq!(
$value,
$processor.registers.get_flag_bit($flag),
"{:?} flag had unexpected value",
$flag
);
)+
};
}
pub(crate) use assert_flags_eq;
pub fn set_opposite_of_expected_flags(
processor: &mut Processor,
(zero_flag, sub_flag, half_carry_flag, carry_flag): (u8, u8, u8, u8),
) {
let invert_flag = |value| {
if value == 0 {
1
} else if value == 1 {
0
} else {
panic!("invalid flag value of {value} ")
}
};
processor
.registers
.set_flag_bit(register::Flag::Zero, invert_flag(zero_flag));
processor
.registers
.set_flag_bit(register::Flag::HalfCarry, invert_flag(half_carry_flag));
processor
.registers
.set_flag_bit(register::Flag::Carry, invert_flag(carry_flag));
processor
.registers
.set_flag_bit(register::Flag::Subtract, invert_flag(sub_flag));
}