#![allow(
clippy::expect_used,
clippy::panic,
reason = "a corpus file that will not open must fail loudly"
)]
use kurbo::Rect;
use pdfrum::Document;
use pdfrum_common::Limits;
use pdfrum_markdown::{
Block, Line, Options, PageInput, document_blocks, page_blocks, page_lines, render, running,
};
fn open(file: &str) -> Document {
let path = format!("{}/../../benches/corpus/{file}", env!("CARGO_MANIFEST_DIR"));
Document::open(&path).expect("the corpus file opens")
}
fn markdown_of(file: &str) -> String {
let doc = open(file);
doc.pages()
.map(|page| {
let graph = page.objects();
let tree = page.structure();
render(&page_blocks(
&graph,
tree.as_ref(),
&doc,
Options::default(),
&Limits::default(),
))
})
.collect()
}
fn counts(markdown: &str) -> (usize, usize) {
let headings = markdown.lines().filter(|l| l.starts_with('#')).count();
let text = markdown
.lines()
.filter(|l| !l.trim().is_empty() && !l.starts_with(['#', '!', '-', '|']))
.count();
(headings, text)
}
#[test]
fn the_products_sheet_keeps_each_feature_item_a_paragraph() {
let md = markdown_of("text_foxit_products.pdf");
let (headings, text) = counts(&md);
assert_eq!(headings, 7, "{md}");
assert!((240..=280).contains(&text), "{text} text lines\n{md}");
for item in [
"XFA Form Filling - XFA (XML Form Architecture) form allows you to leverage existing XFA forms.",
"High Performance - Up to 3 times faster PDF creation from over 200 of the most common office file types and convert multiple files to PDF in a single operation.",
"Redaction - Lets you permanently remove (redact) visible text and images from PDF documents.",
"Email and Phone Support - helps when you need it.",
"System Requirements",
"Operating Systems",
"Windows 7 (32-bit & 64-bit).",
] {
assert!(
md.lines().any(|l| l == item),
"not a paragraph of its own: {item}\n{md}"
);
}
assert!(md.contains(
"Form Design - Easy to use electronic forms design tools to make your office forms work \
harder. Enables you to create or convert static PDF files into professional looking forms."
));
}
#[test]
fn the_guide_keeps_its_tree_paragraphs() {
let md = markdown_of("text_quick_start.pdf");
let (headings, text) = counts(&md);
assert_eq!(headings, 8, "{md}");
assert!((80..=95).contains(&text), "{text} text lines\n{md}");
}
#[test]
fn a_figure_is_the_image_drawn_under_its_marked_content_id() {
let doc = open("text_quick_start.pdf");
let page = doc.page(1u32).expect("page 2 loads");
let graph = page.objects();
let tree = page.structure();
let blocks = page_blocks(
&graph,
tree.as_ref(),
&doc,
Options::default(),
&Limits::default(),
);
let indices: Vec<Option<usize>> = blocks
.iter()
.filter_map(|b| match b {
Block::Image { index, .. } => Some(*index),
_ => None,
})
.collect();
assert_eq!(indices.len(), 13, "{blocks:?}");
assert!(indices.iter().all(Option::is_some), "{indices:?}");
assert_eq!(indices.first().copied().flatten(), Some(12));
assert_eq!(indices.get(1).copied().flatten(), Some(1));
let images = page.images();
assert_eq!(
images.get(12).map(|i| (i.width, i.height)),
Some((1203, 705))
);
assert_eq!(images.get(1).map(|i| (i.width, i.height)), Some((18, 19)));
}
#[test]
fn the_guides_running_title_and_folio_go_when_it_is_read_as_a_document() {
let doc = open("text_quick_start.pdf");
let pages: Vec<_> = doc.pages().collect();
let graphs: Vec<_> = pages.iter().map(pdfrum::Page::objects).collect();
let trees: Vec<_> = pages.iter().map(pdfrum::Page::structure).collect();
let inputs: Vec<PageInput<'_>> = graphs
.iter()
.zip(&trees)
.map(|(page, tree)| PageInput {
page,
tree: tree.as_ref(),
})
.collect();
let md: String = document_blocks(&inputs, &doc, Options::default(), &Limits::default())
.iter()
.map(|blocks| render(blocks))
.collect();
assert!(
!md.lines().any(|l| l == "Foxit MobilePDF"
|| l == "Quick Guide"
|| l.contains("www.foxitsoftware.com")),
"{md}"
);
assert!(md.contains("# Different Views"), "{md}");
let lines: Vec<Vec<Line>> = graphs
.iter()
.map(|g| page_lines(g, &doc, Options::default(), &Limits::default()))
.collect();
let per_page: Vec<(&[Line], Rect)> = lines
.iter()
.zip(&graphs)
.map(|(l, g)| (l.as_slice(), g.crop_box))
.collect();
assert_eq!(per_page.len(), 11);
for (page, mask) in lines.iter().zip(running::mask(&per_page)) {
let dropped: Vec<&str> = page
.iter()
.zip(&mask)
.filter(|(_, gone)| **gone)
.map(|(l, _)| l.text.as_str())
.collect();
assert!(dropped.contains(&"Foxit MobilePDF"), "{dropped:?}");
assert!(dropped.contains(&"Quick Guide"), "{dropped:?}");
assert!(
dropped
.iter()
.any(|t| t.ends_with("/ 11 www.foxitsoftware.com")),
"{dropped:?}"
);
assert_eq!(dropped.len(), 3, "{dropped:?}");
}
let two = per_page.get(1..3).expect("pages 2 and 3");
assert!(running::mask(two).iter().flatten().all(|gone| !gone));
}