#![cfg(feature = "ocr")]
mod helpers;
use helpers::extract_uri_document_blocking;
use helpers::*;
use xberg::core::config::{ExtractionConfig, OcrConfig, PageConfig};
use xberg::types::TesseractConfig;
#[test]
fn test_ocr_content_not_doubled() {
if skip_if_missing("images/test_hello_world.png") {
return;
}
let file_path = get_test_file_path("images/test_hello_world.png");
let config = ExtractionConfig {
ocr: Some(OcrConfig {
backend: "tesseract".to_string(),
language: vec!["eng".to_string()],
..Default::default()
}),
pages: Some(PageConfig {
extract_pages: true,
..Default::default()
}),
use_cache: false,
..Default::default()
};
let result = extract_uri_document_blocking(&file_path, None, &config).expect("OCR extraction must succeed");
let content_words: Vec<&str> = result.content.split_whitespace().collect();
if content_words.is_empty() {
return;
}
let pages = result
.pages
.as_ref()
.expect("pages must be populated when extract_pages=true");
assert!(!pages.is_empty(), "at least one page must be present");
let page_content = &pages[0].content;
let page_words: Vec<&str> = page_content.split_whitespace().collect();
if !page_words.is_empty() {
let ratio = content_words.len() as f64 / page_words.len() as f64;
assert!(
ratio <= 1.3,
"content word count ({}) is more than 30% larger than pages[0].content word count ({}). \
This indicates doubled output — word-token dump appended after HOCR text (issue #706). \
ratio = {:.2}",
content_words.len(),
page_words.len(),
ratio,
);
}
if page_content.trim().len() > 4 {
let trimmed = page_content.trim();
let doubled = format!("{trimmed}{trimmed}");
assert!(
!result.content.contains(doubled.as_str()),
"content appears to contain page text concatenated with itself — doubled output (issue #706)",
);
}
}
#[test]
fn test_ocr_page_content_matches_top_level_content() {
if skip_if_missing("images/ocr_image.jpg") {
return;
}
let file_path = get_test_file_path("images/ocr_image.jpg");
let config = ExtractionConfig {
ocr: Some(OcrConfig {
backend: "tesseract".to_string(),
language: vec!["eng".to_string()],
..Default::default()
}),
pages: Some(PageConfig {
extract_pages: true,
..Default::default()
}),
use_cache: false,
..Default::default()
};
let result = extract_uri_document_blocking(&file_path, None, &config).expect("OCR extraction must succeed");
if result.content.trim().is_empty() {
return;
}
let pages = result
.pages
.as_ref()
.expect("pages must be populated when extract_pages=true");
assert!(!pages.is_empty(), "at least one page must be present");
let top_words = result.content.split_whitespace().count();
let page_words = pages[0].content.split_whitespace().count();
if top_words > 0 && page_words > 0 {
let ratio = top_words as f64 / page_words.max(1) as f64;
assert!(
ratio <= 1.3,
"top-level content ({} words) is more than 30% larger than pages[0].content ({} words). \
Indicates word-dump appended to top-level content but missing from page — issue #706.",
top_words,
page_words,
);
}
}
#[test]
fn test_ocr_table_text_not_duplicated_in_content() {
if skip_if_missing("images/simple_table.png") {
return;
}
let file_path = get_test_file_path("images/simple_table.png");
let config = ExtractionConfig {
ocr: Some(OcrConfig {
backend: "tesseract".to_string(),
language: vec!["eng".to_string()],
tesseract_config: Some(TesseractConfig {
enable_table_detection: true,
table_min_confidence: 0.0,
table_column_threshold: 80,
table_row_threshold_ratio: 0.5,
..Default::default()
}),
..Default::default()
}),
force_ocr: false,
use_cache: false,
..Default::default()
};
let result = extract_uri_document_blocking(&file_path, None, &config).expect("OCR extraction must succeed");
assert!(
!result.tables.is_empty(),
"table detection must fire on this fixture for the test to exercise the #1571 path"
);
let table = &result.tables[0];
let mut cell_values: Vec<&str> = table
.cells
.iter()
.flatten()
.map(String::as_str)
.filter(|cell| cell.trim().len() >= 3)
.collect();
cell_values.sort_unstable();
cell_values.dedup();
for cell in cell_values {
let occurrences_in_table_cells = table.cells.iter().flatten().filter(|c| c.as_str() == cell).count();
let occurrences_in_content = result.content.matches(cell).count();
assert!(
occurrences_in_content <= occurrences_in_table_cells,
"table cell {cell:?} appears {occurrences_in_content} times in doc.content but only \
{occurrences_in_table_cells} times among table cells -- its text is duplicated outside \
the table (issue #1571)",
);
}
}