`PageRenderer::new` keeps a failed open as `None`, so `page_count()` is 0 and `text` without `--page` iterated nothing, printed nothing and exited 0 on a password-protected file. When the renderer has no pages, ask `inspect` why and fail with its message (the same wording `info` gives); a document that inspects fine but still renders no pages is reported as unparseable. A genuinely empty document still succeeds. Fixes #132 Co-authored-by: wstock <1394687+wstock@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
parent
11ffedcc98
commit
1e54e709b6
|
|
@ -174,7 +174,18 @@ fn info(args: &[String]) -> Result<(), CliError> {
|
|||
|
||||
fn text(args: &[String]) -> Result<(), CliError> {
|
||||
let path = *positional(args).first().ok_or("text: missing file")?;
|
||||
let mut r = PageRenderer::new(read(path)?, RenderConfig { password: flag(args, "--password").map(Arc::from), ..Default::default() });
|
||||
let password = flag(args, "--password");
|
||||
let bytes = read(path)?;
|
||||
let mut r = PageRenderer::new(bytes.clone(), RenderConfig { password: password.map(Arc::from), ..Default::default() });
|
||||
// A document the renderer could not open (wrong or missing password, unparseable file) has
|
||||
// no pages, and "extract every page" of nothing would print nothing and exit 0 (#132). Ask
|
||||
// `inspect` why instead, so a protected file fails the same way `info` does.
|
||||
if r.page_count() == 0 {
|
||||
let info = inspect(bytes, password).map_err(|e| format!("text: {e}"))?;
|
||||
if !info.pages.is_empty() {
|
||||
return Err("text: the document could not be parsed".into());
|
||||
}
|
||||
}
|
||||
let pages: Vec<usize> = match flag(args, "--page") {
|
||||
Some(p) => vec![p.parse::<usize>().map_err(|_| "bad --page")?.saturating_sub(1)],
|
||||
None => (0..r.page_count()).collect(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//! `text` must fail loudly when a page it was asked for cannot be read (#131).
|
||||
//! `text` must fail loudly when a page it was asked for cannot be read (#131), and when the
|
||||
//! document itself cannot be opened, e.g. a password-protected file without `--password` (#132).
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
|
|
@ -57,3 +58,39 @@ fn text_of_a_readable_document_succeeds() {
|
|||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(stdout.contains("Page 1") && stdout.contains("Page 3"), "{stdout}");
|
||||
}
|
||||
|
||||
/// `three.pdf` encrypted with the open password `openme`, via `run --script`.
|
||||
fn protected_fixture() -> std::path::PathBuf {
|
||||
let src = tmp("to-protect.pdf");
|
||||
std::fs::write(&src, fixture(3)).unwrap();
|
||||
let out_path = tmp("protected.pdf");
|
||||
let script = tmp("protect.json");
|
||||
let steps = serde_json::json!([
|
||||
{ "tool": "doc_open", "args": { "path": src } },
|
||||
{ "tool": "doc_protect", "args": { "doc": 1, "open_password": "openme" } },
|
||||
{ "tool": "doc_save", "args": { "doc": 1, "path": out_path } },
|
||||
]);
|
||||
std::fs::write(&script, steps.to_string()).unwrap();
|
||||
let out = Command::new(BIN).args(["run", "--script", script.to_str().unwrap()]).output().unwrap();
|
||||
assert!(out.status.success(), "protecting the fixture failed: {}", String::from_utf8_lossy(&out.stderr));
|
||||
out_path
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_of_a_protected_document_without_the_password_fails() {
|
||||
let path = protected_fixture();
|
||||
let out = Command::new(BIN).args(["text", path.to_str().unwrap()]).output().unwrap();
|
||||
assert!(!out.status.success(), "a document that cannot be opened must not exit 0");
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(stderr.contains("password"), "the reason must be named: {stderr}");
|
||||
assert!(out.stdout.is_empty(), "{}", String::from_utf8_lossy(&out.stdout));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_of_a_protected_document_with_the_password_succeeds() {
|
||||
let path = protected_fixture();
|
||||
let out = Command::new(BIN).args(["text", path.to_str().unwrap(), "--password", "openme"]).output().unwrap();
|
||||
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
assert!(stdout.contains("Page 1") && stdout.contains("Page 3"), "{stdout}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue