#![cfg(all(test, feature = "__expert"))]
extern crate alloc;
use alloc::vec::Vec;
use super::api::{CostModel, EncodeRequest, PixelLayout};
use super::config::{InternalParams, LossyConfig, SharpYuvSetting};
const W: u32 = 192;
const H: u32 = 144;
fn synthetic_rgb() -> Vec<u8> {
let mut buf = Vec::with_capacity((W * H * 3) as usize);
let mut state: u32 = 0x1234_5678;
let mut rng = || {
state = state.wrapping_mul(1664525).wrapping_add(1013904223);
(state >> 16) as u8
};
let noise: Vec<u8> = (0..(W * H * 3)).map(|_| rng()).collect();
for y in 0..H {
for x in 0..W {
let mb_x = x / 16;
let mb_y = y / 16;
let band = if mb_y < 3 {
let i = ((y * W + x) * 3) as usize;
[noise[i], noise[i + 1], noise[i + 2]]
} else if mb_y < 5 {
let r = (x * 255 / W) as u8;
let g = (y * 255 / H) as u8;
[r, g, 128]
} else if mb_y < 7 {
let on = ((x / 4) ^ (y / 4)) & 1 != 0;
if on { [240, 30, 30] } else { [20, 200, 220] }
} else {
let anomaly = (mb_x % 4 == 0) && (mb_y == 8);
if anomaly {
let i = ((y * W + x) * 3) as usize;
[noise[i], noise[i + 1], noise[i + 2]]
} else {
[128, 128, 128]
}
};
buf.extend_from_slice(&band);
}
}
buf
}
fn encode(cfg: &LossyConfig, pixels: &[u8]) -> Vec<u8> {
EncodeRequest::lossy(cfg, pixels, PixelLayout::Rgb8, W, H)
.encode()
.expect("encode succeeded")
}
fn baseline_cfg() -> LossyConfig {
LossyConfig::new().with_quality(75.0).with_method(4)
}
#[test]
fn partition_limit_variants_produce_distinct_bytes() {
let rgb = synthetic_rgb();
let baseline = encode(&baseline_cfg(), &rgb);
let with_50 = encode(
&baseline_cfg().with_internal_params(InternalParams {
partition_limit: Some(50),
..Default::default()
}),
&rgb,
);
let with_100 = encode(
&baseline_cfg().with_internal_params(InternalParams {
partition_limit: Some(100),
..Default::default()
}),
&rgb,
);
assert_ne!(
baseline, with_100,
"partition_limit=100 should change emitted bytes vs default"
);
assert!(
with_50 != baseline || with_50 != with_100,
"partition_limit=50 should produce a distinct intermediate result"
);
for bytes in [&baseline, &with_50, &with_100] {
let _ = webp::Decoder::new(bytes).decode().expect("decodable");
}
}
#[test]
fn multi_pass_stats_toggle_changes_bytes() {
let rgb = synthetic_rgb();
let baseline = encode(&baseline_cfg(), &rgb);
let two_pass = encode(
&baseline_cfg().with_internal_params(InternalParams {
multi_pass_stats: Some(true),
..Default::default()
}),
&rgb,
);
assert_ne!(
baseline, two_pass,
"multi_pass_stats=true at m4 must change emitted bytes"
);
}
#[test]
fn smooth_segment_map_toggle_changes_bytes() {
let rgb = synthetic_rgb();
let baseline = encode(&baseline_cfg(), &rgb);
let smoothed = encode(
&baseline_cfg().with_internal_params(InternalParams {
smooth_segment_map: Some(true),
..Default::default()
}),
&rgb,
);
assert_ne!(
baseline, smoothed,
"smooth_segment_map=true must change emitted bytes on multi-segment input"
);
}
#[test]
fn sharp_yuv_variants_encode() {
let rgb = synthetic_rgb();
let off = encode(
&baseline_cfg().with_internal_params(InternalParams {
sharp_yuv: Some(SharpYuvSetting::Off),
..Default::default()
}),
&rgb,
);
let on = encode(
&baseline_cfg().with_internal_params(InternalParams {
sharp_yuv: Some(SharpYuvSetting::On),
..Default::default()
}),
&rgb,
);
let custom = encode(
&baseline_cfg().with_internal_params(InternalParams {
sharp_yuv: Some(SharpYuvSetting::Custom(zenyuv::SharpYuvConfig {
max_iterations: 4,
convergence_threshold: 0.05,
refine_y: false,
})),
..Default::default()
}),
&rgb,
);
let baseline = encode(&baseline_cfg(), &rgb);
assert_eq!(
off, baseline,
"sharp_yuv=Off must match LossyConfig default"
);
assert_ne!(on, baseline, "sharp_yuv=On must change emitted bytes");
assert_ne!(
custom, on,
"Custom sharp_yuv config must differ from On default"
);
for bytes in [&off, &on, &custom] {
let _ = webp::Decoder::new(bytes).decode().expect("decodable");
}
}
#[test]
fn cost_model_variants_differ_at_m4() {
let rgb = synthetic_rgb();
let zw = encode(
&baseline_cfg().with_internal_params(InternalParams {
cost_model: Some(CostModel::ZenwebpDefault),
..Default::default()
}),
&rgb,
);
let parity = encode(
&baseline_cfg().with_internal_params(InternalParams {
cost_model: Some(CostModel::StrictLibwebpParity),
..Default::default()
}),
&rgb,
);
let baseline = encode(&baseline_cfg(), &rgb);
assert_eq!(
zw, baseline,
"cost_model=ZenwebpDefault must match LossyConfig default"
);
assert_ne!(
zw, parity,
"cost_model=StrictLibwebpParity must change emitted bytes vs zenwebp default"
);
}
#[test]
fn with_internal_params_is_idempotent() {
let rgb = synthetic_rgb();
let knobs = InternalParams {
partition_limit: Some(40),
multi_pass_stats: Some(true),
smooth_segment_map: Some(true),
sharp_yuv: Some(SharpYuvSetting::On),
cost_model: Some(CostModel::StrictLibwebpParity),
};
let once = encode(&baseline_cfg().with_internal_params(knobs.clone()), &rgb);
let twice = encode(
&baseline_cfg()
.with_internal_params(knobs.clone())
.with_internal_params(knobs),
&rgb,
);
assert_eq!(
once, twice,
"applying the same InternalParams twice must be idempotent"
);
}
#[test]
fn all_fields_combined_produces_valid_encode() {
let rgb = synthetic_rgb();
let cfg = baseline_cfg().with_internal_params(InternalParams {
partition_limit: Some(60),
multi_pass_stats: Some(true),
smooth_segment_map: Some(true),
sharp_yuv: Some(SharpYuvSetting::On),
cost_model: Some(CostModel::StrictLibwebpParity),
});
let bytes = encode(&cfg, &rgb);
assert!(!bytes.is_empty(), "combined encode produced empty output");
let decoded = webp::Decoder::new(&bytes).decode().expect("decodable");
assert_eq!(decoded.width(), W);
assert_eq!(decoded.height(), H);
}
#[test]
fn default_internal_params_equals_baseline() {
let rgb = synthetic_rgb();
let baseline = encode(&baseline_cfg(), &rgb);
let with_default = encode(
&baseline_cfg().with_internal_params(InternalParams::default()),
&rgb,
);
assert_eq!(
baseline, with_default,
"InternalParams::default() must be a no-op on a fresh LossyConfig"
);
}
#[test]
fn with_internal_params_is_partial_merge_not_reset() {
let rgb = synthetic_rgb();
let baseline = encode(&baseline_cfg(), &rgb);
let merged = encode(
&baseline_cfg()
.with_internal_params(InternalParams {
smooth_segment_map: Some(true),
..Default::default()
})
.with_internal_params(InternalParams::default()),
&rgb,
);
assert_ne!(
baseline, merged,
"Re-applying Default must not reset previously-set fields (partial merge)"
);
let single = encode(
&baseline_cfg().with_internal_params(InternalParams {
smooth_segment_map: Some(true),
..Default::default()
}),
&rgb,
);
assert_eq!(
merged, single,
"Re-applying Default after a real set must equal a single set"
);
}