test: Add snapshot regression tests with PDF fixtures
Add 5 stripped public-domain PDF fixtures and golden markdown snapshots for CI regression testing. Fix non-deterministic output caused by HashMap iteration order in font stats, table heuristics, and rect clustering by adding deterministic tie-breaking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ceb0cf5913
commit
28313e1f2d
@@ -21,9 +21,12 @@ pub(crate) fn calculate_font_stats_from_items(items: &[TextItem]) -> FontStats {
|
||||
}
|
||||
}
|
||||
|
||||
// Break ties by preferring the smaller font size for deterministic output
|
||||
let most_common_size = size_counts
|
||||
.iter()
|
||||
.max_by_key(|(_, count)| *count)
|
||||
.max_by(|(size_a, count_a), (size_b, count_b)| {
|
||||
count_a.cmp(count_b).then_with(|| size_b.cmp(size_a))
|
||||
})
|
||||
.map(|(size, _)| *size as f32 / 10.0)
|
||||
.unwrap_or(12.0);
|
||||
|
||||
@@ -45,9 +48,12 @@ pub(crate) fn calculate_font_stats(lines: &[TextLine]) -> FontStats {
|
||||
}
|
||||
}
|
||||
|
||||
// Break ties by preferring the smaller font size for deterministic output
|
||||
let most_common_size = size_counts
|
||||
.iter()
|
||||
.max_by_key(|(_, count)| *count)
|
||||
.max_by(|(size_a, count_a), (size_b, count_b)| {
|
||||
count_a.cmp(count_b).then_with(|| size_b.cmp(size_a))
|
||||
})
|
||||
.map(|(size, _)| *size as f32 / 10.0)
|
||||
.unwrap_or(12.0);
|
||||
|
||||
|
||||
@@ -654,9 +654,12 @@ fn has_consistent_columns(cells: &[Vec<String>]) -> bool {
|
||||
*count_freq.entry(count).or_insert(0) += 1;
|
||||
}
|
||||
|
||||
// Break ties by preferring higher column count for deterministic output
|
||||
let most_common_count = count_freq
|
||||
.iter()
|
||||
.max_by_key(|(_, freq)| *freq)
|
||||
.max_by(|(count_a, freq_a), (count_b, freq_b)| {
|
||||
freq_a.cmp(freq_b).then_with(|| count_a.cmp(count_b))
|
||||
})
|
||||
.map(|(count, _)| *count)
|
||||
.unwrap_or(0);
|
||||
|
||||
|
||||
@@ -88,10 +88,13 @@ pub(crate) fn cluster_rects(
|
||||
groups.entry(uf.find(i)).or_default().push(i);
|
||||
}
|
||||
|
||||
groups
|
||||
.into_values()
|
||||
.filter(|g| g.len() >= min_size)
|
||||
.collect()
|
||||
// Sort by root index for deterministic output order
|
||||
let mut result: Vec<(usize, Vec<usize>)> = groups
|
||||
.into_iter()
|
||||
.filter(|(_, g)| g.len() >= min_size)
|
||||
.collect();
|
||||
result.sort_by_key(|(root, _)| *root);
|
||||
result.into_iter().map(|(_, g)| g).collect()
|
||||
}
|
||||
|
||||
/// Detect tables from explicit rectangle (`re`) operators in the PDF.
|
||||
|
||||
Reference in New Issue
Block a user