Files
hcie-rust-v3.05/hcie-tile/tests/tile_tests.rs
T
Your Name 8447b2d796
mandatory-regression-gate / deterministic-tests (push) Has been cancelled
mandatory-regression-gate / protected-performance-path (push) Has been cancelled
Refactor code structure for improved readability and maintainability
2026-07-23 15:34:05 +03:00

323 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use hcie_tile::*;
/// Integration tests for hcie-tile sparse tile storage.
///
/// Covers: tile creation, pixel read/write, tile key mapping,
/// sparse storage behavior, from_dense / to_dense roundtrip,
/// update_tiles_in_region, composite_into, edge cases.
// ---------------------------------------------------------------------------
// Tile (single 256×256 block) tests
// ---------------------------------------------------------------------------
#[test]
fn new_transparent_tile_is_all_zeros() {
let tile = Tile::new_transparent();
assert_eq!(tile.pixels.len(), TILE_BYTES);
// Spot-check a few positions
assert_eq!(tile.pixels[0], 0);
assert_eq!(tile.pixels[3], 0);
assert_eq!(tile.pixels[TILE_BYTES - 1], 0);
}
#[test]
fn new_blank_tile_is_white_and_opaque() {
let tile = Tile::new_blank();
assert_eq!(tile.pixels.len(), TILE_BYTES);
// Every pixel should be [255, 255, 255, 255]
for i in 0..10 {
let base = i * 4;
assert_eq!(tile.pixels[base], 255, "R should be 255 at pixel {}", i);
assert_eq!(tile.pixels[base + 1], 255, "G should be 255 at pixel {}", i);
assert_eq!(tile.pixels[base + 2], 255, "B should be 255 at pixel {}", i);
assert_eq!(tile.pixels[base + 3], 255, "A should be 255 at pixel {}", i);
}
}
// ---------------------------------------------------------------------------
// TiledLayer creation
// ---------------------------------------------------------------------------
#[test]
fn new_tiled_layer_has_correct_dimensions() {
let tl = TiledLayer::new(512, 256);
assert_eq!(tl.width(), 512);
assert_eq!(tl.height(), 256);
}
#[test]
fn new_tiled_layer_has_zero_tiles() {
let tl = TiledLayer::new(512, 256);
assert_eq!(tl.tile_count(), 0, "empty layer should have no allocated tiles");
}
#[test]
fn from_dense_size_matches() {
let pixels = vec![255u8; 64 * 64 * 4];
let tl = TiledLayer::from_dense(&pixels, 64, 64);
assert_eq!(tl.width(), 64);
assert_eq!(tl.height(), 64);
}
#[test]
fn from_dense_creates_tiles_for_non_transparent_data() {
let pixels = vec![255u8; 256 * 256 * 4]; // fully opaque, exactly one tile
let tl = TiledLayer::from_dense(&pixels, 256, 256);
assert_eq!(tl.tile_count(), 1, "fully opaque 256x256 should produce exactly 1 tile");
}
#[test]
fn from_dense_prunes_transparent_tiles() {
let pixels = vec![0u8; 256 * 256 * 4]; // fully transparent, exactly one tile
let tl = TiledLayer::from_dense(&pixels, 256, 256);
assert_eq!(
tl.tile_count(),
0,
"fully transparent layer should have no allocated tiles"
);
}
// ---------------------------------------------------------------------------
// Tile key mapping
// ---------------------------------------------------------------------------
#[test]
fn tile_key_maps_pixel_zero_to_zero_zero() {
let key = TiledLayer::tile_key(0, 0);
assert_eq!(key, (0, 0));
}
#[test]
fn tile_key_maps_pixel_255_to_0() {
let key = TiledLayer::tile_key(255, 255);
assert_eq!(key, (0, 0));
}
#[test]
fn tile_key_maps_pixel_256_to_1() {
let key = TiledLayer::tile_key(256, 256);
assert_eq!(key, (1, 1));
}
#[test]
fn tile_key_maps_large_coordinates() {
let key = TiledLayer::tile_key(1000, 2000);
assert_eq!(key, (1000 / TILE_SIZE, 2000 / TILE_SIZE));
}
// ---------------------------------------------------------------------------
// Pixel read/write
// ---------------------------------------------------------------------------
#[test]
fn get_pixel_outside_allocated_tile_returns_transparent() {
let tl = TiledLayer::new(512, 512);
let pixel = tl.get_pixel(100, 100);
assert_eq!(pixel, [0, 0, 0, 0], "unwritten pixel should be transparent");
}
#[test]
fn set_pixel_and_get_pixel_roundtrip() {
let mut tl = TiledLayer::new(64, 64);
tl.set_pixel(10, 10, [255, 128, 64, 200]);
let pixel = tl.get_pixel(10, 10);
assert_eq!(pixel, [255, 128, 64, 200]);
}
#[test]
fn set_pixel_out_of_bounds_is_noop() {
let mut tl = TiledLayer::new(64, 64);
tl.set_pixel(100, 100, [255, 0, 0, 255]); // outside layer bounds
assert_eq!(tl.tile_count(), 0, "out-of-bounds set should not create tiles");
}
#[test]
fn set_pixel_auto_creates_tile() {
let mut tl = TiledLayer::new(256, 256);
tl.set_pixel(0, 0, [255, 0, 0, 255]);
assert_eq!(tl.tile_count(), 1, "setting a pixel should create the containing tile");
}
#[test]
fn get_pixel_written_twice_returns_last_value() {
let mut tl = TiledLayer::new(64, 64);
tl.set_pixel(5, 5, [10, 20, 30, 40]);
tl.set_pixel(5, 5, [50, 60, 70, 80]);
assert_eq!(tl.get_pixel(5, 5), [50, 60, 70, 80]);
}
// ---------------------------------------------------------------------------
// to_dense roundtrip
// ---------------------------------------------------------------------------
#[test]
fn to_dense_returns_correct_size() {
let tl = TiledLayer::new(64, 64);
let dense = tl.to_dense();
assert_eq!(dense.len(), (64 * 64 * 4) as usize);
}
#[test]
fn to_dense_after_set_pixel_preserves_value() {
let mut tl = TiledLayer::new(16, 16);
tl.set_pixel(7, 8, [100, 150, 200, 250]);
let dense = tl.to_dense();
let idx = ((8 * 16 + 7) * 4) as usize;
assert_eq!(dense[idx], 100);
assert_eq!(dense[idx + 1], 150);
assert_eq!(dense[idx + 2], 200);
assert_eq!(dense[idx + 3], 250);
}
#[test]
fn from_dense_to_dense_roundtrip() {
let original = vec![42u8; 128 * 128 * 4];
let tl = TiledLayer::from_dense(&original, 128, 128);
let result = tl.to_dense();
assert_eq!(original, result, "from_dense → to_dense should be identity");
}
#[test]
fn from_dense_to_dense_roundtrip_transparent() {
let original = vec![0u8; 128 * 128 * 4];
let tl = TiledLayer::from_dense(&original, 128, 128);
let result = tl.to_dense();
assert_eq!(original, result, "transparent from_dense → to_dense should be identity");
}
// ---------------------------------------------------------------------------
// update_tiles_in_region
// ---------------------------------------------------------------------------
#[test]
fn update_tiles_in_region_writes_pixels() {
let mut tl = TiledLayer::new(64, 64);
let mut pixels = vec![0u8; 64 * 64 * 4];
// Set a block of pixels to red
for y in 10..20 {
for x in 10..20 {
let idx = ((y * 64 + x) * 4) as usize;
pixels[idx] = 255;
pixels[idx + 3] = 255;
}
}
tl.update_tiles_in_region(&pixels, 64, 0, 0, 64, 64);
assert_eq!(tl.get_pixel(15, 15), [255, 0, 0, 255], "updated pixel should be red");
assert_eq!(tl.get_pixel(0, 0), [0, 0, 0, 0], "pixel outside update region stays unchanged");
}
#[test]
fn update_tiles_in_region_partial_update() {
let mut tl = TiledLayer::new(256, 256);
let mut pixels = vec![0u8; 64 * 64 * 4];
for i in (0..pixels.len()).step_by(4) {
pixels[i] = 255;
pixels[i + 3] = 255;
}
// Update only the sub-region (0,0)-(64,64)
tl.update_tiles_in_region(&pixels, 64, 0, 0, 64, 64);
assert_eq!(tl.get_pixel(32, 32), [255, 0, 0, 255]);
assert_eq!(tl.get_pixel(100, 100), [0, 0, 0, 0], "pixels outside region should be zero");
}
// ---------------------------------------------------------------------------
// composite_into
// ---------------------------------------------------------------------------
#[test]
fn composite_into_copies_pixels() {
let mut tl = TiledLayer::new(32, 32);
tl.set_pixel(5, 5, [100, 150, 200, 255]);
let mut output = vec![0u8; 32 * 32 * 4];
tl.composite_into(&mut output, 32, 32, 0, 0, 32, 32);
let idx = ((5 * 32 + 5) * 4) as usize;
assert_eq!(output[idx], 100);
assert_eq!(output[idx + 1], 150);
assert_eq!(output[idx + 2], 200);
assert_eq!(output[idx + 3], 255);
}
#[test]
fn composite_into_respects_region_bounds() {
let mut tl = TiledLayer::new(64, 64);
tl.set_pixel(30, 30, [255, 0, 0, 255]);
let mut output = vec![0u8; 64 * 64 * 4];
// Composite only the top-left 16×16 region
tl.composite_into(&mut output, 64, 64, 0, 0, 16, 16);
// Pixel at (30,30) is outside the region and should not be copied
let idx = ((30 * 64 + 30) * 4) as usize;
assert_eq!(
output[idx..idx + 4],
[0, 0, 0, 0],
"pixel outside region should not appear in output"
);
}
// ---------------------------------------------------------------------------
// Edge cases
// ---------------------------------------------------------------------------
#[test]
fn zero_sized_layer_has_no_tiles() {
let tl = TiledLayer::new(0, 0);
assert_eq!(tl.tile_count(), 0);
assert_eq!(tl.width(), 0);
assert_eq!(tl.height(), 0);
}
#[test]
fn very_large_layer_does_not_panic() {
let tl = TiledLayer::new(4096, 4096);
assert_eq!(tl.width(), 4096);
assert_eq!(tl.height(), 4096);
}
#[test]
fn tile_count_increases_with_written_area() {
let mut tl = TiledLayer::new(512, 512);
assert_eq!(tl.tile_count(), 0);
// Write one pixel in two different tiles
tl.set_pixel(0, 0, [1, 1, 1, 1]);
assert_eq!(tl.tile_count(), 1);
tl.set_pixel(300, 300, [2, 2, 2, 2]);
assert_eq!(tl.tile_count(), 2, "pixels in different tiles should create two tiles");
}
#[test]
fn tiles_are_independent() {
let mut tl = TiledLayer::new(512, 512);
tl.set_pixel(0, 0, [10, 20, 30, 40]);
tl.set_pixel(300, 300, [50, 60, 70, 80]);
assert_eq!(tl.get_pixel(0, 0), [10, 20, 30, 40]);
assert_eq!(tl.get_pixel(300, 300), [50, 60, 70, 80]);
// neighboring pixel should be untouched
assert_eq!(tl.get_pixel(1, 0), [0, 0, 0, 0]);
}
// ---------------------------------------------------------------------------
// Serde roundtrip (if Tile is Serialize/Deserialize)
// ---------------------------------------------------------------------------
#[test]
fn tile_serde_json_roundtrip() {
let tile = Tile::new_blank();
let json = serde_json::to_string(&tile).expect("serialize tile");
let restored: Tile = serde_json::from_str(&json).expect("deserialize tile");
assert_eq!(tile.pixels, restored.pixels, "JSON serde roundtrip should preserve pixels");
}
#[test]
fn tile_bincode_roundtrip() {
let tile = Tile::new_blank();
let bytes = bincode::serialize(&tile).expect("serialize tile via bincode");
let restored: Tile = bincode::deserialize(&bytes).expect("deserialize tile via bincode");
assert_eq!(tile.pixels, restored.pixels, "bincode serde roundtrip should preserve pixels");
}