hqx 0.1.1

high-quality pixel-art image magnification (2x/3x/4x upscaling)
Documentation
//! Property tests for invariants that hold for any input.
//!
//! These check shape and structural guarantees rather than exact pixels:
//! output sizing, solid-color identity, determinism, init-free idempotence,
//! and corner replication.

use proptest::prelude::*;

/// A small random image: dimensions plus pixels.
fn image() -> impl Strategy<Value = (usize, usize, Vec<u32>)> {
    (1usize..=8, 1usize..=8).prop_flat_map(|(w, h)| {
        prop::collection::vec(any::<u32>(), w * h).prop_map(move |px| (w, h, px))
    })
}

proptest! {
    #[test]
    fn output_length_is_scale_squared((w, h, px) in image()) {
        for (scale, run) in scalers() {
            let mut dst = vec![0u32; scale * scale * w * h];
            run(&px, &mut dst, w as u32, h as u32);
            prop_assert_eq!(dst.len(), scale * scale * w * h);
        }
    }

    #[test]
    fn solid_input_yields_solid_output(color in any::<u32>(), w in 1usize..=6, h in 1usize..=6) {
        let px = vec![color; w * h];
        for (scale, run) in scalers() {
            let mut dst = vec![0u32; scale * scale * w * h];
            run(&px, &mut dst, w as u32, h as u32);
            prop_assert!(dst.iter().all(|&p| p == color), "scale {}", scale);
        }
    }

    #[test]
    fn scaling_is_deterministic((w, h, px) in image()) {
        for (scale, run) in scalers() {
            let mut a = vec![0u32; scale * scale * w * h];
            let mut b = vec![0u32; scale * scale * w * h];
            run(&px, &mut a, w as u32, h as u32);
            run(&px, &mut b, w as u32, h as u32);
            prop_assert_eq!(a, b);
        }
    }

    #[test]
    fn extreme_corners_copy_source_corners((w, h, px) in image()) {
        for (scale, run) in scalers() {
            let dw = w * scale;
            let dh = h * scale;
            let mut dst = vec![0u32; dw * dh];
            run(&px, &mut dst, w as u32, h as u32);
            prop_assert_eq!(dst[0], px[0]);
            prop_assert_eq!(dst[dw - 1], px[w - 1]);
            prop_assert_eq!(dst[(dh - 1) * dw], px[(h - 1) * w]);
            prop_assert_eq!(dst[dh * dw - 1], px[h * w - 1]);
        }
    }
}

type Scaler = fn(&[u32], &mut [u32], u32, u32);

fn scalers() -> Vec<(usize, Scaler)> {
    vec![
        (2, hqx::hq2x as Scaler),
        (3, hqx::hq3x as Scaler),
        (4, hqx::hq4x as Scaler),
    ]
}