Files
lightcraft/crates/raw/tests/robust.rs
T
Andrew FrahnandClaude Opus 5.5 fb097d61be Rename crates to neutral dac-* codename and binaries to app/app-cli
Mechanical rename right after the fork so upstream merges map cleanly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 09:43:50 +11:00

103 lines
3.9 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.
//! Malformed-input robustness: decoding random or corrupted files must never panic.
use dac_raw::{BlackLevel, Cfa, ColorData, DngCompression, DngWriteOptions, Method, OpcodeLists, Orientation, RawData, RawFormat, RawImage, Rect};
use proptest::prelude::*;
fn sample(comp: DngCompression) -> Vec<u8> {
let (w, h) = (24usize, 16usize);
let data: Vec<u16> = (0..w * h).map(|i| (i * 97 % 4000) as u16).collect();
let raw = RawImage {
format: RawFormat::Dng,
width: w,
height: h,
cpp: 1,
data: RawData::U16(data),
cfa: Some(Cfa::bayer("RGGB").unwrap()),
bits: 12,
black: BlackLevel::uniform(64.0),
white: vec![4095.0],
active_area: Rect::new(0, 0, w, h),
crop: Rect::new(0, 0, w, h),
orientation: Orientation::Normal,
color: ColorData::default(),
wb_multipliers: None,
linearized: false,
opcodes: OpcodeLists::default(),
metadata: Default::default(),
};
dac_raw::write_dng(&raw, &DngWriteOptions { compression: comp, ..Default::default() }).unwrap()
}
fn exercise(bytes: &[u8]) {
let _ = dac_raw::probe(bytes);
let _ = dac_raw::embedded_preview(bytes);
if let Ok(img) = dac_raw::decode(bytes)
&& img.width * img.height <= 1 << 16
{
let _ = img.develop(Method::Ahd);
let xy = dac_raw::color::as_shot_white_xy(&img);
let _ = dac_raw::color::camera_transform(&img, xy);
}
}
proptest! {
#![proptest_config(ProptestConfig { cases: 400, .. ProptestConfig::default() })]
#[test]
fn mutated_dngs_never_panic(flips in proptest::collection::vec((any::<usize>(), any::<u8>()), 1..24), cut in any::<usize>(), lj in any::<bool>()) {
let mut data = sample(if lj { DngCompression::Lj92 { tile: 16 } } else { DngCompression::Uncompressed });
for (i, v) in flips {
let n = data.len();
data[i % n] = v;
}
let keep = if cut % 3 == 0 { cut % data.len() } else { data.len() };
exercise(&data[..keep]);
}
#[test]
fn random_tiff_like_bytes_never_panic(mut data in proptest::collection::vec(any::<u8>(), 8..700), kind in 0usize..4) {
let heads: [&[u8]; 4] = [b"II*\0\x08\0\0\0", b"MM\0*\0\0\0\x08", b"II*\0\x10\0\0\0CR\x02\0", b"II+\0\x08\0\0\0"];
let h = heads[kind];
let n = h.len().min(data.len());
data[..n].copy_from_slice(&h[..n]);
exercise(&data);
}
#[test]
fn random_lj92_never_panics(data in proptest::collection::vec(any::<u8>(), 0..400)) {
let mut s = vec![0xff, 0xd8, 0xff, 0xc3, 0, 11, 12, 0, 8, 0, 8, 1, 1, 0x11, 0];
s.extend_from_slice(&data);
let _ = dac_raw::ljpeg::decode(&s, 1 << 20);
}
}
#[test]
fn truncation_at_every_length() {
for comp in [DngCompression::Uncompressed, DngCompression::Lj92 { tile: 16 }] {
let d = sample(comp);
for n in (0..d.len()).step_by(7) {
exercise(&d[..n]);
}
}
}
#[test]
fn hostile_dimensions_are_rejected_quickly() {
// a DNG claiming a 60000 × 60000 16-bit image with 10 bytes of data
use dac_tiff::tags as t;
use dac_tiff::{IfdBuilder, ImageData, TiffWriter, Value};
let mut ifd = IfdBuilder::new();
ifd.set(t::DNG_VERSION, Value::Byte(vec![1, 4, 0, 0]));
ifd.set(t::IMAGE_WIDTH, Value::Long(vec![60000]));
ifd.set(t::IMAGE_LENGTH, Value::Long(vec![60000]));
ifd.set(t::BITS_PER_SAMPLE, Value::Short(vec![16]));
ifd.set(t::PHOTOMETRIC, Value::Short(vec![32803]));
ifd.set(t::CFA_PATTERN_EP, Value::Byte(vec![0, 1, 1, 2]));
ifd.set(t::COMPRESSION, Value::Short(vec![7]));
ifd.set_image(ImageData::Tiles { tile_width: 60000, tile_height: 60000, tiles: vec![vec![0xff, 0xd8, 0xff, 0xd9]] });
let bytes = TiffWriter::default().write(&[ifd]).unwrap();
let t0 = std::time::Instant::now();
assert!(dac_raw::decode(&bytes).is_err());
assert!(t0.elapsed().as_secs_f64() < 2.0);
}