pdfcraft/apps/pdfcraft-cli/tests/edit.rs

94 lines
4.1 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.

//! `edit` must reject options it does not know instead of writing an unchanged copy (#133).
use std::path::PathBuf;
use std::process::Command;
const BIN: &str = env!("CARGO_BIN_EXE_pdfcraft-cli");
/// A one-page 200×300 pt PDF.
fn fixture() -> Vec<u8> {
let objs: Vec<Vec<u8>> = vec![
b"<< /Type /Catalog /Pages 2 0 R >>".to_vec(),
b"<< /Type /Pages /Kids [3 0 R] /Count 1 /MediaBox [0 0 200 300] >>".to_vec(),
b"<< /Type /Page /Parent 2 0 R >>".to_vec(),
];
let mut out = b"%PDF-1.7\n".to_vec();
let mut offsets = Vec::new();
for (i, o) in objs.iter().enumerate() {
offsets.push(out.len());
out.extend_from_slice(format!("{} 0 obj\n", i + 1).as_bytes());
out.extend_from_slice(o);
out.extend_from_slice(b"\nendobj\n");
}
let xref = out.len();
out.extend_from_slice(format!("xref\n0 {}\n0000000000 65535 f \n", objs.len() + 1).as_bytes());
for o in offsets {
out.extend_from_slice(format!("{o:010} 00000 n \n").as_bytes());
}
out.extend_from_slice(format!("trailer\n<< /Size {} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n", objs.len() + 1).as_bytes());
out
}
fn tmp(test: &str, name: &str) -> PathBuf {
let d = std::env::temp_dir().join(format!("pdfcraft-cli-edit-{test}-{}", std::process::id()));
std::fs::create_dir_all(&d).unwrap();
d.join(name)
}
/// The page rotation `pdfcraft-cli info` reports for the first page, via the inspector.
fn first_page_rotation(path: &std::path::Path) -> u16 {
let bytes = std::sync::Arc::new(std::fs::read(path).unwrap());
pdfcraft_render::inspect(bytes, None).unwrap().pages[0].rotation
}
#[test]
fn a_misspelled_option_fails_and_writes_nothing() {
let input = tmp("typo", "in.pdf");
std::fs::write(&input, fixture()).unwrap();
let output = tmp("typo", "typo.pdf");
let out = Command::new(BIN).args(["edit", input.to_str().unwrap(), "--out", output.to_str().unwrap(), "--rotat", "1:90"]).output().unwrap();
assert!(!out.status.success(), "an unknown option must not exit 0");
let stderr = String::from_utf8_lossy(&out.stderr);
assert!(stderr.contains("unknown option") && stderr.contains("--rotat"), "the option must be named: {stderr}");
assert!(stderr.contains("--rotate"), "the accepted options must be listed: {stderr}");
assert!(!output.exists(), "no output may be written for a rejected command line");
}
#[test]
fn an_option_without_its_value_fails() {
let input = tmp("novalue", "in.pdf");
std::fs::write(&input, fixture()).unwrap();
let output = tmp("novalue", "out.pdf");
let out = Command::new(BIN).args(["edit", input.to_str().unwrap(), "--out", output.to_str().unwrap(), "--title"]).output().unwrap();
assert!(!out.status.success());
assert!(String::from_utf8_lossy(&out.stderr).contains("--title needs a value"));
assert!(!output.exists());
}
#[test]
fn a_second_input_file_fails() {
let input = tmp("stray", "in.pdf");
std::fs::write(&input, fixture()).unwrap();
let output = tmp("stray", "out.pdf");
let out = Command::new(BIN).args(["edit", input.to_str().unwrap(), "other.pdf", "--out", output.to_str().unwrap()]).output().unwrap();
assert!(!out.status.success());
assert!(String::from_utf8_lossy(&out.stderr).contains("unexpected argument \"other.pdf\""));
assert!(!output.exists());
}
#[test]
fn the_documented_options_still_edit_and_save() {
let input = tmp("ok", "in.pdf");
std::fs::write(&input, fixture()).unwrap();
for (name, extra) in [("incremental.pdf", Vec::new()), ("full.pdf", vec!["--full"])] {
let output = tmp("ok", name);
let mut args = vec!["edit", input.to_str().unwrap(), "--out", output.to_str().unwrap(), "--rotate", "1:90", "--title", "Rotated"];
args.extend(extra);
let out = Command::new(BIN).args(&args).output().unwrap();
assert!(out.status.success(), "{name}: {}", String::from_utf8_lossy(&out.stderr));
assert_eq!(first_page_rotation(&output), 90, "{name}");
let info = pdfcraft_render::inspect(std::sync::Arc::new(std::fs::read(&output).unwrap()), None).unwrap();
assert_eq!(info.title.as_deref(), Some("Rotated"), "{name}");
}
}