diff --git a/agb/src/agb_alloc/bump_allocator.rs b/agb/src/agb_alloc/bump_allocator.rs index 98038629..1fe1ef8a 100644 --- a/agb/src/agb_alloc/bump_allocator.rs +++ b/agb/src/agb_alloc/bump_allocator.rs @@ -61,17 +61,22 @@ fn get_data_end() -> usize { (unsafe { &__ewram_data_end }) as *const _ as usize } -#[test_case] -fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) { - let data_end = get_data_end(); +#[cfg(test)] +mod tests { + use super::*; - assert!( - 0x0200_0000 <= data_end, - "data end should be bigger than 0x0200_0000, got {}", - data_end - ); - assert!( - 0x0204_0000 > data_end, - "data end should be smaller than 0x0203_0000" - ); + #[test_case] + fn should_return_data_end_somewhere_in_ewram(_gba: &mut crate::Gba) { + let data_end = get_data_end(); + + assert!( + 0x0200_0000 <= data_end, + "data end should be bigger than 0x0200_0000, got {}", + data_end + ); + assert!( + 0x0204_0000 > data_end, + "data end should be smaller than 0x0203_0000" + ); + } } diff --git a/agb/src/bitarray.rs b/agb/src/bitarray.rs index c237c36c..25c99e16 100644 --- a/agb/src/bitarray.rs +++ b/agb/src/bitarray.rs @@ -22,33 +22,36 @@ impl Bitarray { self.a[index / 32] = self.a[index / 32] & !mask | value_mask } } - -#[test_case] -fn write_and_read(_gba: &mut crate::Gba) { - let mut a: Bitarray<2> = Bitarray::new(); - assert_eq!(a.get(55), Some(false), "expect unset values to be false"); - a.set(62, true); - assert_eq!(a.get(62), Some(true), "expect set value to be true"); - assert_eq!(a.get(120), None, "expect out of range to give None"); -} - -#[test_case] -fn test_everything(_gba: &mut crate::Gba) { - for i in 0..64 { +#[cfg(test)] +mod tests { + use super::*; + #[test_case] + fn write_and_read(_gba: &mut crate::Gba) { let mut a: Bitarray<2> = Bitarray::new(); - a.set(i, true); - for j in 0..64 { - let expected = i == j; - assert_eq!( - a.get(j).unwrap(), - expected, - "set index {} and read {}, expected {} but got {}. u32 of this is {:#b}", - i, - j, - expected, - a.get(j).unwrap(), - a.a[j / 32], - ); + assert_eq!(a.get(55), Some(false), "expect unset values to be false"); + a.set(62, true); + assert_eq!(a.get(62), Some(true), "expect set value to be true"); + assert_eq!(a.get(120), None, "expect out of range to give None"); + } + + #[test_case] + fn test_everything(_gba: &mut crate::Gba) { + for i in 0..64 { + let mut a: Bitarray<2> = Bitarray::new(); + a.set(i, true); + for j in 0..64 { + let expected = i == j; + assert_eq!( + a.get(j).unwrap(), + expected, + "set index {} and read {}, expected {} but got {}. u32 of this is {:#b}", + i, + j, + expected, + a.get(j).unwrap(), + a.a[j / 32], + ); + } } } } diff --git a/agb/src/display/example_logo.rs b/agb/src/display/example_logo.rs index 424a740f..14df97d4 100644 --- a/agb/src/display/example_logo.rs +++ b/agb/src/display/example_logo.rs @@ -19,12 +19,16 @@ pub fn display_logo(gfx: &mut BackgroundDistributor) { back.show(); back.commit(); } +#[cfg(test)] +mod tests { + use super::*; -#[test_case] -fn logo_display(gba: &mut crate::Gba) { - let mut gfx = gba.display.video.tiled0(); + #[test_case] + fn logo_display(gba: &mut crate::Gba) { + let mut gfx = gba.display.video.tiled0(); - display_logo(&mut gfx); + display_logo(&mut gfx); - crate::assert_image_output("gfx/test_logo.png"); + crate::assert_image_output("gfx/test_logo.png"); + } } diff --git a/agb/src/interrupt.rs b/agb/src/interrupt.rs index e6287695..ec364e76 100644 --- a/agb/src/interrupt.rs +++ b/agb/src/interrupt.rs @@ -270,37 +270,6 @@ macro_rules! add_interrupt_handler { }; } -#[test_case] -fn test_vblank_interrupt_handler(_gba: &mut crate::Gba) { - { - let counter = Mutex::new(0); - let counter_2 = Mutex::new(0); - add_interrupt_handler!(Interrupt::VBlank, |key| *counter.lock_with_key(&key) += 1); - add_interrupt_handler!(Interrupt::VBlank, |_| *counter_2.lock() += 1); - - let vblank = VBlank::get(); - - while *counter.lock() < 100 || *counter_2.lock() < 100 { - vblank.wait_for_vblank(); - } - } - - assert_eq!( - interrupt_to_root(Interrupt::VBlank).next.get(), - core::ptr::null(), - "expected the interrupt table for vblank to be empty" - ); -} - -#[test_case] -fn test_interrupt_table_length(_gba: &mut crate::Gba) { - assert_eq!( - unsafe { INTERRUPT_TABLE.len() }, - Interrupt::Gamepak as usize + 1, - "interrupt table should be able to store gamepak interrupt" - ); -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] enum MutexState { Unlocked, @@ -409,3 +378,39 @@ impl Drop for VBlank { interrupt_to_root(Interrupt::VBlank).reduce(); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test_case] + fn test_vblank_interrupt_handler(_gba: &mut crate::Gba) { + { + let counter = Mutex::new(0); + let counter_2 = Mutex::new(0); + add_interrupt_handler!(Interrupt::VBlank, |key| *counter.lock_with_key(&key) += 1); + add_interrupt_handler!(Interrupt::VBlank, |_| *counter_2.lock() += 1); + + let vblank = VBlank::get(); + + while *counter.lock() < 100 || *counter_2.lock() < 100 { + vblank.wait_for_vblank(); + } + } + + assert_eq!( + interrupt_to_root(Interrupt::VBlank).next.get(), + core::ptr::null(), + "expected the interrupt table for vblank to be empty" + ); + } + + #[test_case] + fn test_interrupt_table_length(_gba: &mut crate::Gba) { + assert_eq!( + unsafe { INTERRUPT_TABLE.len() }, + Interrupt::Gamepak as usize + 1, + "interrupt table should be able to store gamepak interrupt" + ); + } +} diff --git a/agb/src/lib.rs b/agb/src/lib.rs index 4127aa80..5f612f8b 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -1,11 +1,12 @@ #![no_std] // This appears to be needed for testing to work #![cfg_attr(test, no_main)] +#![cfg_attr(test, feature(custom_test_frameworks))] +#![cfg_attr(test, test_runner(crate::test_runner))] +#![cfg_attr(test, reexport_test_harness_main = "test_main")] #![deny(clippy::all)] -#![feature(custom_test_frameworks)] #![feature(alloc_error_handler)] -#![test_runner(crate::test_runner)] -#![reexport_test_harness_main = "test_main"] + //! # agb //! `agb` is a library for making games on the Game Boy Advance using the Rust //! programming language. It attempts to be a high level abstraction over the diff --git a/agb/src/number.rs b/agb/src/number.rs index 5983a065..f85f344c 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -334,55 +334,6 @@ impl Num { } } -#[test_case] -fn sqrt(_gba: &mut crate::Gba) { - for x in 1..1024 { - let n: Num = Num::new(x * x); - assert_eq!(n.sqrt(), x.into()); - } -} - -#[test_case] -fn test_macro_conversion(_gba: &mut super::Gba) { - fn test_positive() { - let a: Num = num!(1.5); - let one = A::one() << B; - let b = Num::from_raw(one + (one >> 1)); - - assert_eq!(a, b); - } - - fn test_negative() { - let a: Num = num!(-1.5); - let one = A::one() << B; - let b = Num::from_raw(one + (one >> 1)); - - assert_eq!(a, -b); - } - - fn test_base() { - test_positive::(); - test_positive::(); - test_negative::(); - - if B < 16 { - test_positive::(); - test_positive::(); - test_negative::(); - } - } - // some nice powers of two - test_base::<8>(); - test_base::<4>(); - test_base::<16>(); - // not a power of two - test_base::<10>(); - // an odd number - test_base::<9>(); - // and a prime - test_base::<11>(); -} - impl Num { #[must_use] pub fn abs(self) -> Self { @@ -415,129 +366,6 @@ impl Num { } } -#[test_case] -fn test_numbers(_gba: &mut super::Gba) { - // test addition - let n: Num = 1.into(); - assert_eq!(n + 2, 3.into(), "testing that 1 + 2 == 3"); - - // test multiplication - let n: Num = 5.into(); - assert_eq!(n * 3, 15.into(), "testing that 5 * 3 == 15"); - - // test division - let n: Num = 30.into(); - let p: Num = 3.into(); - assert_eq!(n / 20, p / 2, "testing that 30 / 20 == 3 / 2"); - - assert_ne!(n, p, "testing that 30 != 3"); -} - -#[test_case] -fn test_division_by_one(_gba: &mut super::Gba) { - let one: Num = 1.into(); - - for i in -40..40 { - let n: Num = i.into(); - assert_eq!(n / one, n); - } -} - -#[test_case] -fn test_division_and_multiplication_by_16(_gba: &mut super::Gba) { - let sixteen: Num = 16.into(); - - for i in -40..40 { - let n: Num = i.into(); - let m = n / sixteen; - - assert_eq!(m * sixteen, n); - } -} - -#[test_case] -fn test_division_by_2_and_15(_gba: &mut super::Gba) { - let two: Num = 2.into(); - let fifteen: Num = 15.into(); - let thirty: Num = 30.into(); - - for i in -128..128 { - let n: Num = i.into(); - - assert_eq!(n / two / fifteen, n / thirty); - assert_eq!(n / fifteen / two, n / thirty); - } -} - -#[test_case] -fn test_change_base(_gba: &mut super::Gba) { - let two: Num = 2.into(); - let three: Num = 3.into(); - - assert_eq!(two + three.change_base(), 5.into()); - assert_eq!(three + two.change_base(), 5.into()); -} - -#[test_case] -fn test_rem_returns_sensible_values_for_integers(_gba: &mut super::Gba) { - for i in -50..50 { - for j in -50..50 { - if j == 0 { - continue; - } - - let i_rem_j_normally = i % j; - let i_fixnum: Num = i.into(); - - assert_eq!(i_fixnum % j, i_rem_j_normally.into()); - } - } -} - -#[test_case] -fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut super::Gba) { - let one: Num = 1.into(); - let third = one / 3; - - for i in -50..50 { - for j in -50..50 { - if j == 0 { - continue; - } - - // full calculation in the normal way - let x: Num = third + i; - let y: Num = j.into(); - - let truncated_division: Num = (x / y).trunc().into(); - - let remainder = x - truncated_division * y; - - assert_eq!(x % y, remainder); - } - } -} - -#[test_case] -fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut super::Gba) { - let one: Num = 1.into(); - let third = one / 3; - - for i in -50..50 { - for j in -50..50 { - if j == 0 { - continue; - } - - let x: Num = third + i; - let y: Num = j.into(); - - let rem_euclid = x.rem_euclid(y); - assert!(rem_euclid > 0.into()); - } - } -} - impl Display for Num { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut integral = self.0 >> N; @@ -643,15 +471,6 @@ where } } -#[test_case] -fn test_vector_multiplication_and_division(_gba: &mut super::Gba) { - let a: Vector2D = (1, 2).into(); - let b = a * 5; - let c = b / 5; - assert_eq!(b, (5, 10).into()); - assert_eq!(a, c); -} - #[cfg(feature = "alloc")] #[cfg(test)] mod formatting_tests { @@ -759,15 +578,6 @@ impl Vector2D> { } } -#[test_case] -fn magnitude_accuracy(_gba: &mut crate::Gba) { - let n: Vector2D> = (3, 4).into(); - assert!((n.magnitude() - 5).abs() < num!(0.1)); - - let n: Vector2D> = (3, 4).into(); - assert!((n.magnitude() - 5).abs() < num!(0.1)); -} - impl> From<(P, P)> for Vector2D { fn from(f: (P, P)) -> Self { Vector2D::new(f.0.into(), f.1.into()) @@ -934,12 +744,207 @@ impl Vector2D { } } -#[test_case] -fn test_vector_changing(_gba: &mut super::Gba) { - let v1: Vector2D> = Vector2D::new(1.into(), 2.into()); +#[cfg(test)] +mod tests { + use super::*; - let v2 = v1.trunc(); - assert_eq!(v2.get(), (1, 2)); + #[test_case] + fn sqrt(_gba: &mut crate::Gba) { + for x in 1..1024 { + let n: Num = Num::new(x * x); + assert_eq!(n.sqrt(), x.into()); + } + } - assert_eq!(v1 + v1, (v2 + v2).into()); + #[test_case] + fn test_macro_conversion(_gba: &mut crate::Gba) { + fn test_positive() { + let a: Num = num!(1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, b); + } + + fn test_negative() { + let a: Num = num!(-1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, -b); + } + + fn test_base() { + test_positive::(); + test_positive::(); + test_negative::(); + + if B < 16 { + test_positive::(); + test_positive::(); + test_negative::(); + } + } + // some nice powers of two + test_base::<8>(); + test_base::<4>(); + test_base::<16>(); + // not a power of two + test_base::<10>(); + // an odd number + test_base::<9>(); + // and a prime + test_base::<11>(); + } + + #[test_case] + fn test_numbers(_gba: &mut crate::Gba) { + // test addition + let n: Num = 1.into(); + assert_eq!(n + 2, 3.into(), "testing that 1 + 2 == 3"); + + // test multiplication + let n: Num = 5.into(); + assert_eq!(n * 3, 15.into(), "testing that 5 * 3 == 15"); + + // test division + let n: Num = 30.into(); + let p: Num = 3.into(); + assert_eq!(n / 20, p / 2, "testing that 30 / 20 == 3 / 2"); + + assert_ne!(n, p, "testing that 30 != 3"); + } + + #[test_case] + fn test_division_by_one(_gba: &mut crate::Gba) { + let one: Num = 1.into(); + + for i in -40..40 { + let n: Num = i.into(); + assert_eq!(n / one, n); + } + } + + #[test_case] + fn test_division_and_multiplication_by_16(_gba: &mut crate::Gba) { + let sixteen: Num = 16.into(); + + for i in -40..40 { + let n: Num = i.into(); + let m = n / sixteen; + + assert_eq!(m * sixteen, n); + } + } + + #[test_case] + fn test_division_by_2_and_15(_gba: &mut crate::Gba) { + let two: Num = 2.into(); + let fifteen: Num = 15.into(); + let thirty: Num = 30.into(); + + for i in -128..128 { + let n: Num = i.into(); + + assert_eq!(n / two / fifteen, n / thirty); + assert_eq!(n / fifteen / two, n / thirty); + } + } + + #[test_case] + fn test_change_base(_gba: &mut crate::Gba) { + let two: Num = 2.into(); + let three: Num = 3.into(); + + assert_eq!(two + three.change_base(), 5.into()); + assert_eq!(three + two.change_base(), 5.into()); + } + + #[test_case] + fn test_rem_returns_sensible_values_for_integers(_gba: &mut crate::Gba) { + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + let i_rem_j_normally = i % j; + let i_fixnum: Num = i.into(); + + assert_eq!(i_fixnum % j, i_rem_j_normally.into()); + } + } + } + + #[test_case] + fn test_rem_returns_sensible_values_for_non_integers(_gba: &mut crate::Gba) { + let one: Num = 1.into(); + let third = one / 3; + + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + // full calculation in the normal way + let x: Num = third + i; + let y: Num = j.into(); + + let truncated_division: Num = (x / y).trunc().into(); + + let remainder = x - truncated_division * y; + + assert_eq!(x % y, remainder); + } + } + } + + #[test_case] + fn test_rem_euclid_is_always_positive_and_sensible(_gba: &mut crate::Gba) { + let one: Num = 1.into(); + let third = one / 3; + + for i in -50..50 { + for j in -50..50 { + if j == 0 { + continue; + } + + let x: Num = third + i; + let y: Num = j.into(); + + let rem_euclid = x.rem_euclid(y); + assert!(rem_euclid > 0.into()); + } + } + } + + #[test_case] + fn test_vector_multiplication_and_division(_gba: &mut crate::Gba) { + let a: Vector2D = (1, 2).into(); + let b = a * 5; + let c = b / 5; + assert_eq!(b, (5, 10).into()); + assert_eq!(a, c); + } + + #[test_case] + fn magnitude_accuracy(_gba: &mut crate::Gba) { + let n: Vector2D> = (3, 4).into(); + assert!((n.magnitude() - 5).abs() < num!(0.1)); + + let n: Vector2D> = (3, 4).into(); + assert!((n.magnitude() - 5).abs() < num!(0.1)); + } + + #[test_case] + fn test_vector_changing(_gba: &mut crate::Gba) { + let v1: Vector2D> = Vector2D::new(1.into(), 2.into()); + + let v2 = v1.trunc(); + assert_eq!(v2.get(), (1, 2)); + + assert_eq!(v1 + v1, (v2 + v2).into()); + } } diff --git a/agb/src/syscall.rs b/agb/src/syscall.rs index b4357c58..ddeed8f0 100644 --- a/agb/src/syscall.rs +++ b/agb/src/syscall.rs @@ -151,12 +151,17 @@ pub fn affine_matrix( result } -#[test_case] -fn affine(_gba: &mut crate::Gba) { - // expect identity matrix - let one: Num = 1.into(); +#[cfg(test)] +mod tests { + use super::*; - let aff = affine_matrix(one, one, 0); - assert_eq!(aff.p_a, one.to_raw()); - assert_eq!(aff.p_d, one.to_raw()); + #[test_case] + fn affine(_gba: &mut crate::Gba) { + // expect identity matrix + let one: Num = 1.into(); + + let aff = affine_matrix(one, one, 0); + assert_eq!(aff.p_a, one.to_raw()); + assert_eq!(aff.p_d, one.to_raw()); + } }