use soorat::WindowConfig;
use soorat::color::Color;
use soorat::pipeline::batch_to_vertices;
use soorat::sprite::{Sprite, SpriteBatch};
use soorat::texture::TextureCache;
use soorat::vertex::{Vertex2D, Vertex3D};
#[test]
fn sprite_workflow() {
let mut batch = SpriteBatch::new();
for i in 0..10 {
let sprite = Sprite::new(i as f32 * 50.0, 100.0, 32.0, 32.0)
.with_color(Color::from_rgba8(255, i * 25, 0, 255))
.with_z_order(10 - i as i32);
batch.push(sprite);
}
assert_eq!(batch.len(), 10);
batch.sort_by_z();
assert_eq!(batch.sprites[0].z_order, 1);
assert_eq!(batch.sprites[9].z_order, 10);
}
#[test]
fn color_conversions() {
let hex = Color::from_hex(0x336699FF);
let arr: [f32; 4] = hex.into();
let back: Color = arr.into();
assert!((hex.r - back.r).abs() < 0.01);
assert!((hex.g - back.g).abs() < 0.01);
assert!((hex.b - back.b).abs() < 0.01);
}
#[test]
fn vertex_sizes() {
assert_eq!(std::mem::size_of::<Vertex2D>(), 32);
assert_eq!(std::mem::size_of::<Vertex3D>(), 48);
}
#[test]
fn window_config_integration() {
let cfg = WindowConfig::new("Test Window", 800, 600);
assert!((cfg.aspect_ratio() - 800.0 / 600.0).abs() < 0.01);
assert_eq!(cfg.present_mode(), wgpu::PresentMode::AutoVsync);
}
#[test]
fn vertex_color_interop() {
let color = Color::from_hex(0xFF8040FF);
let v = Vertex2D {
position: [10.0, 20.0],
tex_coords: [0.0, 0.0],
color: color.to_array(),
};
assert_eq!(v.color[0], color.r);
assert_eq!(v.color[1], color.g);
assert_eq!(v.color[2], color.b);
assert_eq!(v.color[3], color.a);
}
#[test]
fn sprite_batch_serde_roundtrip() {
let sprite = Sprite::new(10.0, 20.0, 64.0, 64.0)
.with_color(Color::from_hex(0x336699FF))
.with_rotation(1.57)
.with_texture(42)
.with_z_order(3);
let json = serde_json::to_string(&sprite).unwrap();
let decoded: Sprite = serde_json::from_str(&json).unwrap();
assert_eq!(sprite, decoded);
}
#[test]
fn sprite_to_vertex_quad() {
let sprite = Sprite::new(100.0, 200.0, 50.0, 30.0).with_color(Color::RED);
let color_arr = sprite.color.to_array();
let verts = [
Vertex2D {
position: [sprite.x, sprite.y],
tex_coords: [0.0, 0.0],
color: color_arr,
},
Vertex2D {
position: [sprite.x + sprite.width, sprite.y],
tex_coords: [1.0, 0.0],
color: color_arr,
},
Vertex2D {
position: [sprite.x + sprite.width, sprite.y + sprite.height],
tex_coords: [1.0, 1.0],
color: color_arr,
},
Vertex2D {
position: [sprite.x, sprite.y + sprite.height],
tex_coords: [0.0, 1.0],
color: color_arr,
},
];
let (min_x, min_y, max_x, max_y) = sprite.bounds();
assert_eq!(verts[0].position, [min_x, min_y]);
assert_eq!(verts[2].position, [max_x, max_y]);
let bytes: &[u8] = bytemuck::cast_slice(&verts);
assert_eq!(bytes.len(), 32 * 4);
}
#[test]
fn batch_sort_preserves_all_sprites() {
let mut batch = SpriteBatch::new();
for i in 0..50 {
batch.push(
Sprite::new(i as f32, 0.0, 10.0, 10.0)
.with_z_order(50 - i)
.with_texture(i as u64),
);
}
batch.sort_by_z();
assert_eq!(batch.len(), 50);
let mut ids: Vec<u64> = batch.sprites.iter().map(|s| s.texture_id).collect();
ids.sort();
assert_eq!(ids, (0..50).collect::<Vec<u64>>());
}
#[test]
fn pipeline_batch_to_vertices_integration() {
let mut batch = SpriteBatch::with_capacity(10);
for i in 0..10 {
batch.push(
Sprite::new(i as f32 * 50.0, 100.0, 32.0, 32.0)
.with_color(Color::from_rgba8(255, i * 25, 0, 255))
.with_z_order(10 - i as i32),
);
}
batch.sort_by_z();
let (verts, indices) = batch_to_vertices(&batch);
assert_eq!(verts.len(), 40); assert_eq!(indices.len(), 60);
let max_vert = verts.len() as u16;
for &idx in &indices {
assert!(idx < max_vert, "Index {idx} out of range (max {max_vert})");
}
let bytes: &[u8] = bytemuck::cast_slice(&verts);
assert_eq!(bytes.len(), 32 * 40);
}
#[test]
fn texture_cache_workflow() {
let cache = TextureCache::new();
assert!(cache.is_empty());
assert!(!cache.contains(0));
assert!(!cache.contains(42));
}
#[test]
fn pipeline_index_pattern() {
let mut batch = SpriteBatch::new();
batch.push(Sprite::new(0.0, 0.0, 10.0, 10.0));
batch.push(Sprite::new(20.0, 0.0, 10.0, 10.0));
batch.push(Sprite::new(40.0, 0.0, 10.0, 10.0));
let (_, indices) = batch_to_vertices(&batch);
assert_eq!(&indices[0..6], &[0, 1, 2, 2, 3, 0]);
assert_eq!(&indices[6..12], &[4, 5, 6, 6, 7, 4]);
assert_eq!(&indices[12..18], &[8, 9, 10, 10, 11, 8]);
}
#[test]
fn pipeline_overflow_protection() {
use soorat::pipeline::MAX_SPRITES_PER_BATCH;
let mut batch = SpriteBatch::new();
for i in 0..MAX_SPRITES_PER_BATCH + 100 {
batch.push(Sprite::new(i as f32, 0.0, 1.0, 1.0));
}
let (verts, indices) = batch_to_vertices(&batch);
assert_eq!(verts.len(), MAX_SPRITES_PER_BATCH * 4);
assert_eq!(indices.len(), MAX_SPRITES_PER_BATCH * 6);
let max_idx = *indices.iter().max().unwrap();
assert!(max_idx < u16::MAX);
}