mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-24 09:57:08 -06:00
Every tests/*.rs file is its own executable that links the whole crate graph. Move each crate's test files into tests/it/ as modules of one tests/it/main.rs; helper modules under tests/common move with them. These keep their own binary (own process): - engine panic_hunt: a process-wide panic hook counts every panic. - engine text_gamma: changes the process-wide text gamma. - engine smart_filter_stages, mask_cache_purge: assert on global caches. - codecs pnm_peak_memory: reads the process's peak RSS. - photocraft mac_menu_appkit: harness = false.
83 lines
3.2 KiB
Rust
83 lines
3.2 KiB
Rust
use photocraft_codecs::{ChannelLayout, CodecError, Format, SampleType, decode, decode_as};
|
|
|
|
const PAM_GRAY: &[u8] = b"P7\nWIDTH 1\nHEIGHT 1\nDEPTH 1\nMAXVAL 255\nENDHDR";
|
|
const ENDINGS: &[&[u8]] = &[b"\n", b" \n", b"\t \n", b"\r\n", b" \t\r\n"];
|
|
|
|
#[test]
|
|
fn pam_consumes_the_complete_endhdr_line() {
|
|
for ending in ENDINGS {
|
|
let mut bytes = PAM_GRAY.to_vec();
|
|
bytes.extend_from_slice(ending);
|
|
bytes.push(0x80);
|
|
let img = decode(&bytes).unwrap();
|
|
assert_eq!(img.dimensions(), (1, 1));
|
|
assert_eq!(img.layout(), ChannelLayout::Gray);
|
|
assert_eq!(img.data(), &[0x80], "ENDHDR ending {ending:?}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pam_preserves_every_possible_first_raster_byte() {
|
|
// In particular, LF, CR, space, tab and '#' must not be skipped as header syntax.
|
|
for ending in ENDINGS {
|
|
for first in 0..=255u8 {
|
|
let mut bytes = PAM_GRAY.to_vec();
|
|
bytes.extend_from_slice(ending);
|
|
bytes.push(first);
|
|
assert_eq!(decode(&bytes).unwrap().data(), &[first], "ENDHDR ending {ending:?}, raster byte {first}");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pam_crlf_header_preserves_u16_samples_and_alpha() {
|
|
for ending in ENDINGS {
|
|
let mut bytes = b"P7\r\nWIDTH 1\r\nHEIGHT 1\r\nDEPTH 2\r\nMAXVAL 65535\r\nTUPLTYPE GRAYSCALE_ALPHA\r\nENDHDR".to_vec();
|
|
bytes.extend_from_slice(ending);
|
|
bytes.extend_from_slice(b" \n#\r");
|
|
let img = decode(&bytes).unwrap();
|
|
assert_eq!(img.layout(), ChannelLayout::GrayA);
|
|
assert_eq!(img.sample_type(), SampleType::U16);
|
|
assert_eq!(img.to_u16_samples().unwrap(), vec![0x200a, 0x230d], "ENDHDR ending {ending:?}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pam_rejects_unterminated_or_invalid_endhdr_lines() {
|
|
for suffix in [b"".as_slice(), b" ", b"\r", b" \t\r", b" \x80", b" \x80\n\x7f", b"#comment\n\x7f"] {
|
|
let mut bytes = PAM_GRAY.to_vec();
|
|
bytes.extend_from_slice(suffix);
|
|
assert!(matches!(decode_as(Format::Pnm, &bytes), Err(CodecError::Malformed { .. })), "ENDHDR suffix {suffix:?}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn pam_truncation_never_uses_header_whitespace_as_pixels() {
|
|
for ending in ENDINGS {
|
|
let mut bytes = PAM_GRAY.to_vec();
|
|
bytes.extend_from_slice(ending);
|
|
bytes.push(0x80);
|
|
for cut in 0..bytes.len() {
|
|
assert!(decode_as(Format::Pnm, &bytes[..cut]).is_err(), "ENDHDR ending {ending:?}, truncated at {cut}");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn binary_pnm_keeps_its_single_whitespace_separator() {
|
|
for separator in *b" \t\r\n" {
|
|
for first in *b" \t\r\n#" {
|
|
for (header, channels) in [(b"P5\n1 1\n255".as_slice(), 1), (b"P6\n1 1\n255", 3)] {
|
|
let mut bytes = header.to_vec();
|
|
bytes.push(separator);
|
|
bytes.extend(std::iter::repeat_n(first, channels));
|
|
assert_eq!(decode(&bytes).unwrap().data(), vec![first; channels]);
|
|
}
|
|
let mut bytes = b"P4\n8 1".to_vec();
|
|
bytes.extend_from_slice(&[separator, first]);
|
|
let expected: Vec<u8> = (0..8).map(|bit| if first & (0x80 >> bit) == 0 { 255 } else { 0 }).collect();
|
|
assert_eq!(decode(&bytes).unwrap().data(), expected);
|
|
}
|
|
}
|
|
}
|