#![cfg(feature = "ml")]
#[test]
fn text_layer_matches_no_ocr() {
let bytes = std::fs::read(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../tests/data/pdf/sources/code_and_formula.pdf"
))
.expect("corpus pdf");
let text_layer = docling_pdf::convert_text_layer(&bytes, "code_and_formula.pdf")
.expect("text-layer conversion");
let no_ocr = docling_pdf::convert_with_options(
&bytes,
None,
"code_and_formula.pdf",
true, true, false, false, docling_pdf::EnrichmentOptions::default(),
None,
None,
)
.expect("no_ocr conversion");
let a = text_layer.export_to_markdown();
assert!(!a.trim().is_empty(), "text layer should extract");
assert_eq!(a, no_ocr.export_to_markdown());
}
#[test]
fn scanned_page_extracts_table_and_keeps_chart() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
if std::env::var("PDFIUM_DYNAMIC_LIB_PATH").is_err() {
std::env::set_var("PDFIUM_DYNAMIC_LIB_PATH", root.join(".pdfium/lib"));
}
for needed in [
".pdfium/lib/libpdfium.so",
".models/layout_heron_int8.onnx",
".models/ocr_rec_en.onnx",
".models/tableformer/encoder.onnx",
] {
if !root.join(needed).exists() {
eprintln!("skipping scanned-table e2e: {needed} not found");
return;
}
}
std::env::set_current_dir(&root).expect("chdir to repo root");
let bytes = std::fs::read(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../tests/data/scanned/sources/scanned_chart_table.pdf"
))
.expect("scanned fixture");
let doc =
docling_pdf::convert(&bytes, None, "scanned_chart_table.pdf").expect("scanned conversion");
let md = doc.export_to_markdown();
assert!(
md.contains("<!-- image -->"),
"uncaptioned chart must keep its picture crop:\n{md}"
);
let rows: Vec<&str> = md.lines().filter(|l| l.starts_with('|')).collect();
assert!(
rows.len() >= 9,
"expected a header + 7-row table, got {} pipe rows:\n{md}",
rows.len()
);
for cell in ["Aquifer", "Guarani", "Nubian", "380", "540"] {
assert!(md.contains(cell), "table cell {cell:?} missing:\n{md}");
}
}
#[test]
fn scanned_pdf_yields_empty_document() {
let doc = docling_pdf::convert_text_layer(b"%PDF-1.4\n%%EOF", "scan.pdf").expect("no error");
assert!(doc.nodes.is_empty());
}
#[test]
fn heif_without_feature_reports_clearly() {
let stub = b"\x00\x00\x00\x18ftypheic\0\0\0\0";
let err = docling_pdf::convert_image(stub, "photo.heic").unwrap_err();
let msg = err.to_string();
#[cfg(not(feature = "heif"))]
assert!(msg.contains("--features heif"), "unexpected error: {msg}");
#[cfg(feature = "heif")]
assert!(msg.contains("heif"), "unexpected error: {msg}");
}
#[test]
fn picture_classifier_tells_pictures_apart() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let model = root.join(".models/picture_classifier.onnx");
if !model.exists() {
eprintln!(
"skipping picture-classifier check: {} not found",
model.display()
);
return;
}
std::env::set_var("DOCLING_PICTURE_CLASSIFIER_ONNX", &model);
let mut classifier =
docling_pdf::enrich::PictureClassifier::load_with(1).expect("classifier loads");
for (file, class) in [
(
"latex/sources/2310.06825/images/230927_bars.png",
"bar_chart",
),
(
"latex/sources/1706.03762/Figures/ModalNet-21.png",
"flow_chart",
),
("scanned/sources/qr_bill_example.jpg", "qr_code"),
] {
let img = image::open(root.join("tests/data").join(file))
.expect("fixture image")
.to_rgb8();
let preds = classifier.classify(&img).expect("classify");
let top = &preds[0];
assert!(
top.class_name == class && top.confidence > 0.9,
"{file}: expected {class}, got {} {:.3}",
top.class_name,
top.confidence
);
}
}