use std::io::Write;
use std::process::{Command, Stdio};
fn make_tiny_jpeg() -> Vec<u8> {
use image::{DynamicImage, RgbImage};
let img = RgbImage::from_pixel(1, 1, image::Rgb([128u8, 64, 32]));
let dyn_img = DynamicImage::ImageRgb8(img);
let mut buf = Vec::new();
dyn_img
.write_to(
&mut std::io::Cursor::new(&mut buf),
image::ImageFormat::Jpeg,
)
.unwrap();
buf
}
fn sensus_bin() -> std::path::PathBuf {
std::path::PathBuf::from(env!("CARGO_BIN_EXE_sensus"))
}
#[test]
fn pipe_two_frames_output_two_jpegs() {
let frame = make_tiny_jpeg();
let mut two_frames = frame.clone();
two_frames.extend_from_slice(&frame);
let bin = sensus_bin();
let mut child = Command::new(&bin)
.args(["--filter", "protanopia", "--pipe"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn sensus");
child.stdin.take().unwrap().write_all(&two_frames).unwrap();
let output = child.wait_with_output().unwrap();
assert!(
output.status.success(),
"sensus --pipe exited with error: {}",
String::from_utf8_lossy(&output.stderr)
);
let frames = count_jpeg_frames(&output.stdout);
assert_eq!(frames, 2, "expected 2 output frames, got {frames}");
}
#[test]
fn pipe_conflicts_with_input() {
let bin = sensus_bin();
let output = Command::new(&bin)
.args([
"--filter",
"protanopia",
"--pipe",
"--input",
"dummy.png",
"--output",
"/dev/null",
])
.output()
.expect("failed to run sensus");
assert!(
!output.status.success(),
"expected non-zero exit when --pipe and --input are combined"
);
}
fn count_jpeg_frames(data: &[u8]) -> usize {
let mut count = 0;
let mut i = 0;
while i + 1 < data.len() {
if data[i] == 0xFF && data[i + 1] == 0xD8 {
let start = i;
let mut j = start + 2;
while j + 1 < data.len() {
if data[j] == 0xFF && data[j + 1] == 0xD9 {
count += 1;
i = j + 2;
break;
}
j += 1;
}
if j + 1 >= data.len() {
break;
}
} else {
i += 1;
}
}
count
}