mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-13 06:12:17 -06:00
test: add tons of tests for all easy submodules
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
use anyhow::Result;
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::{Canvas, RenderTarget};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::texture::sprite::{AtlasTile, SpriteAtlas};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AnimatedTextureError {
|
||||
#[error("Frame duration must be positive, got {0}")]
|
||||
InvalidFrameDuration(f32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnimatedTexture {
|
||||
tiles: Vec<AtlasTile>,
|
||||
frame_duration: f32,
|
||||
@@ -13,13 +20,17 @@ pub struct AnimatedTexture {
|
||||
}
|
||||
|
||||
impl AnimatedTexture {
|
||||
pub fn new(tiles: Vec<AtlasTile>, frame_duration: f32) -> Self {
|
||||
Self {
|
||||
pub fn new(tiles: Vec<AtlasTile>, frame_duration: f32) -> Result<Self, AnimatedTextureError> {
|
||||
if frame_duration <= 0.0 {
|
||||
return Err(AnimatedTextureError::InvalidFrameDuration(frame_duration));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
tiles,
|
||||
frame_duration,
|
||||
current_frame: 0,
|
||||
time_bank: 0.0,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, dt: f32) {
|
||||
@@ -38,4 +49,145 @@ impl AnimatedTexture {
|
||||
let mut tile = *self.current_tile();
|
||||
tile.render(canvas, atlas, dest)
|
||||
}
|
||||
|
||||
// Helper methods for testing
|
||||
pub fn current_frame(&self) -> usize {
|
||||
self.current_frame
|
||||
}
|
||||
|
||||
pub fn time_bank(&self) -> f32 {
|
||||
self.time_bank
|
||||
}
|
||||
|
||||
pub fn frame_duration(&self) -> f32 {
|
||||
self.frame_duration
|
||||
}
|
||||
|
||||
pub fn tiles_len(&self) -> usize {
|
||||
self.tiles.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use glam::U16Vec2;
|
||||
use sdl2::pixels::Color;
|
||||
|
||||
impl AtlasTile {
|
||||
fn mock(id: u32) -> Self {
|
||||
AtlasTile {
|
||||
pos: U16Vec2::new(0, 0),
|
||||
size: U16Vec2::new(16, 16),
|
||||
color: Some(Color::RGB(id as u8, 0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_animated_texture() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2), AtlasTile::mock(3)];
|
||||
let texture = AnimatedTexture::new(tiles.clone(), 0.1).unwrap();
|
||||
|
||||
assert_eq!(texture.current_frame(), 0);
|
||||
assert_eq!(texture.time_bank(), 0.0);
|
||||
assert_eq!(texture.frame_duration(), 0.1);
|
||||
assert_eq!(texture.tiles_len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_animated_texture_zero_duration() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let result = AnimatedTexture::new(tiles, 0.0);
|
||||
assert!(result.is_err());
|
||||
assert!(matches!(result.unwrap_err(), AnimatedTextureError::InvalidFrameDuration(0.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_animated_texture_negative_duration() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let result = AnimatedTexture::new(tiles, -0.1);
|
||||
assert!(result.is_err());
|
||||
assert!(matches!(
|
||||
result.unwrap_err(),
|
||||
AnimatedTextureError::InvalidFrameDuration(-0.1)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tick_no_frame_change() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Tick with less than frame duration
|
||||
texture.tick(0.05);
|
||||
assert_eq!(texture.current_frame(), 0);
|
||||
assert_eq!(texture.time_bank(), 0.05);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tick_single_frame_change() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Tick with exactly frame duration
|
||||
texture.tick(0.1);
|
||||
assert_eq!(texture.current_frame(), 1);
|
||||
assert_eq!(texture.time_bank(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tick_multiple_frame_changes() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2), AtlasTile::mock(3)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Tick with 2.5 frame durations
|
||||
texture.tick(0.25);
|
||||
assert_eq!(texture.current_frame(), 2);
|
||||
assert!((texture.time_bank() - 0.05).abs() < 0.001);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tick_wrap_around() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Advance to last frame
|
||||
texture.tick(0.1);
|
||||
assert_eq!(texture.current_frame(), 1);
|
||||
|
||||
// Advance again to wrap around
|
||||
texture.tick(0.1);
|
||||
assert_eq!(texture.current_frame(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_current_tile() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Should return first tile initially
|
||||
assert_eq!(texture.current_tile().color.unwrap().r, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_current_tile_after_frame_change() {
|
||||
let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Advance one frame
|
||||
texture.tick(0.1);
|
||||
assert_eq!(texture.current_tile().color.unwrap().r, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_tile_animation() {
|
||||
let tiles = vec![AtlasTile::mock(1)];
|
||||
let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap();
|
||||
|
||||
// Should stay on same frame
|
||||
texture.tick(0.1);
|
||||
assert_eq!(texture.current_frame(), 0);
|
||||
assert_eq!(texture.current_tile().color.unwrap().r, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user