test(datamerge): pin facing-page record placement (#198 no longer reproduces) (#258)

* test(datamerge): pin facing-page record placement (#198)

#198 reported that with `facingPages: true` the merged records after the
first landed at identical coordinates on one spread, leaving a later page
empty. That no longer reproduces: `data.merge` now builds a new document
rather than duplicating pages inside the template, and the three records
land on absolute pages 0, 1 and 2 with no overlap.

Nothing in the engine changed here. These two tests pin the behaviour the
issue asked for, both at the one-record-per-page plan and at the short
block that tiles, so a future refactor of `tile_records` can't quietly
bring the stacking back.

Refs #198

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Merge origin/main; the facing-pages merge tests find each frame's page with page_of_item

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kubuntugamer 2026-10-10 02:35:34 -05:00 committed by GitHub
parent 9e4f69428f
commit a50d279cba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 63 additions and 0 deletions

View File

@ -809,3 +809,66 @@ fn oversized_data_file_is_refused_before_reading() {
assert!(msg.contains("larger than"), "{msg}");
assert_eq!(read_path_capped(&path, 4096).unwrap().len(), 2048);
}
/// #198: with facing pages on, one record per page must not stack the copies at identical
/// coordinates on one spread (leaving a later page empty).
#[test]
fn facing_pages_merge_puts_each_record_on_its_own_page() {
let mut s = Session::new();
exec(&mut s, "file.new", json!({"facingPages": true, "pages": 1, "width": 612, "height": 792}));
select_csv(&mut s, "Title,Clue\nCase 1,Cellar\nCase 2,Attic\nCase 3,Garden\n");
// A block taller than the page's usable height, so only one record fits per page.
text_frame(&mut s, [72.0, 72.0, 540.0, 700.0], "<<Title>> - <<Clue>>", None);
let r = exec(&mut s, "data.merge", json!({}));
assert_eq!(r["records"], 3);
let doc = &s.documents()[s.active_index().unwrap()].doc;
assert_eq!(doc.page_count(), 3, "one page per record");
// Which absolute page each merged frame sits on.
let mut pages_seen = std::collections::BTreeSet::new();
let mut origins = Vec::new();
for sp in &doc.spreads {
for it in &sp.items {
if !matches!(it.content, Content::Text(_)) {
continue;
}
let abs = doc.page_of_item(it.id);
let b = it.bounds();
origins.push((abs, b.x0.round() as i32, b.y0.round() as i32));
if let Some(a) = abs {
pages_seen.insert(a);
}
}
}
assert_eq!(origins.len(), 3, "one text frame per record");
assert_eq!(pages_seen, [0usize, 1, 2].into_iter().collect(), "each record on its own page, none stacked and none left empty: {origins:?}");
}
/// #198's actual repro shape: a short block that tiles several records down one page. With
/// facing pages on they must still land at distinct positions, not on top of each other.
#[test]
fn facing_pages_merge_tiles_short_blocks_without_stacking() {
let mut s = Session::new();
exec(&mut s, "file.new", json!({"facingPages": true, "pages": 1, "width": 612, "height": 792}));
select_csv(&mut s, "Title,Clue\nCase 1,Cellar\nCase 2,Attic\nCase 3,Garden\n");
text_frame(&mut s, [72.0, 72.0, 540.0, 200.0], "<<Title>> - <<Clue>>", None);
let r = exec(&mut s, "data.merge", json!({}));
assert_eq!(r["records"], 3);
let doc = &s.documents()[s.active_index().unwrap()].doc;
let mut origins = Vec::new();
for sp in &doc.spreads {
for it in &sp.items {
if matches!(it.content, Content::Text(_)) {
let abs = doc.page_of_item(it.id);
let b = it.bounds();
origins.push((abs, b.x0.round() as i32, b.y0.round() as i32));
}
}
}
origins.sort();
assert_eq!(origins.len(), 3, "one text frame per record");
let unique: std::collections::BTreeSet<_> = origins.iter().collect();
assert_eq!(unique.len(), 3, "no two records may share a page and coordinates: {origins:?}");
}