Skip to content

test(pdf): #204 extract PdfAuditor page-grid geometry to pure method + 9 tests - #562

Merged
jsboige merged 1 commit into
masterfrom
test/pdfauditor-geometry-contract
Jun 20, 2026
Merged

test(pdf): #204 extract PdfAuditor page-grid geometry to pure method + 9 tests#562
jsboige merged 1 commit into
masterfrom
test/pdfauditor-geometry-contract

Conversation

@jsboige

@jsboige jsboige commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What

Extract the inline A4-based page-grid arithmetic from PdfAuditor.GetExpectedImageOrder into a pure, deterministic method ComputeAuditPageGeometry, so the audit's layout contract is unit-testable without a PDF render. Output-neutral — the call site preserves the exact computation, no behavior change.

Part of the #204 output-neutral extraction lane (cont. po-2024): the matrice ClassMap is closed (#561), SVG disambiguation is pinned (#560). A targeted audit (Explore + code read) found one real gap left: the audit computed its page-grid geometry inline, with only a code comment guarding the assumption.

Why

GetExpectedImageOrder chunked the deck into page-sized groups using geometry derived from:

  • hardcoded PageSizes.A4 (comment: "Assuming A4 for calculation, needs to be dynamic if possible")
  • no page margin subtracted
  • no header band reserved

…all of which diverge from the renderer (PrintAndPlayDocument.ComputePageGeometry, which resolves the actual docConfig.PageSize and subtracts margin + header). The audit's NbCardsPerPage is therefore systematically larger than the renderer's whenever the document is not plain A4-without-header — chunking the deck into pages of the wrong capacity and silently producing false audit mismatches or false passes, with no signal beyond the PDF render. This arithmetic had zero unit coverage.

Changes

PdfAuditor.cs — extraction (output-neutral):

  • New ComputeAuditPageGeometry(cardWidthPoints, cardHeightPoints, configuredNbColumns) pure static method + AuditPageGeometry readonly struct (NbColumns, NbRows, NbCardsPerPage).
  • GetExpectedImageOrder calls it (same arithmetic, same result).
  • XML doc explicitly documents the divergence from the renderer + flags it for a separate behavior-change PR.

PdfAuditorPageGeometryContractTests.cs — 9 contract tests pinning the real contract:

  1. Configured columns honored when > 0
  2. Zero config → floor(A4w / cardW)
  3. Negative config → same fallback (the > 0 guard)
  4. Floor truncation, not rounding (the fragile bit — Math.Round would regress)
  5. Rows = floor(A4h / cardH)
  6. Cards-per-page = rows × cols
  7. Cards-per-page with configured columns
  8. Hardcoded A4 observable (column count derived from A4, never from actual page size)
  9. Divergence pin — audit capacity (96) exceeds renderer capacity (84, headered) by the one header row; documents the latent bug

No-Pendulum

The latent bug is documented and pinned, NOT fixed. A behavior change (route the audit through ComputePageGeometry, or accept margin/header inputs) belongs in its own PR — this one is strictly output-neutral extraction + contract pinning, matching the lane discipline (#553/#556/#560).

Verification

  • dotnet test --filter PdfAuditorPageGeometryContractTests9/9 pass
  • Full suite → 438/0/5 (baseline 429 + 9). 0 regression.
  • Build: 0 error (only preexisting nullable warnings).

…+ 9 tests

Extract the inline A4-based page-grid arithmetic from
GetExpectedImageOrder (nbColumns/nbRows/nbCardsPerPage) into the pure,
determinatic ComputeAuditPageGeometry so the audit's layout contract is
unit-testable without a PDF render — output-neutral (call site preserves
the exact computation).

9 contract tests pin the contract: configured-columns honored, zero/
negative config fallback to floor(A4/card), floor truncation not
rounding, rows = floor(A4h/cardH), cards-per-page = rows×cols, hardcoded
A4 (observable), and a DIVERGENCE pin documenting the latent correctness
bug vs the renderer.

Latent bug documented, NOT fixed (No-Pendulum — a behavior change belongs
in its own PR): the audit hardcodes PageSizes.A4 and ignores the page
margin + header band that the renderer (ComputePageGeometry) subtracts,
so its NbCardsPerPage is systematically larger than the renderer's
whenever the document is not plain A4-without-header — silently producing
false audit mismatches or false passes. The divergence test pins the
renderer value (84 cards, headered) vs the audit value (96) so the gap
is observable and fixable in isolation.

Suite 438/0/5 (baseline 429 + 9).

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

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw] Refactor-correctness pass — extraction is behavior-preserving, method is pure, tests are genuine.

  • Output-neutral confirmed. The moved arithmetic is byte-identical: same PageSizes.A4 constant, same guards (configuredNbColumns > 0), same (int) truncation casts, same nbRows * nbColumns. Call site passes the exact values (cardWidthPoints, cardHeightPoints, docConfig.NbColumns) that were inlined. The only structural change is nbRows now surfaces on the struct (previously used only as a local to derive nbCardsPerPage) — no runtime difference.
  • Pure method. ComputeAuditPageGeometry(float, float, int)AuditPageGeometry struct: no I/O, no PDF render, no DateTime.Now/random, deterministic. Genuinely unit-testable.
  • Tests are real assertions, not tautologies. Cross-checked Columns_FloorTruncation: A4 595.2756/100 = 5.95 → (int) truncates to 5 (not 6 with rounding) — a genuine floor-vs-round edge case. CardsPerPage_IsRowsTimesColumns: 11×8 = 88, verified manually. The divergence test correctly pins the latent A4-vs-renderer bug as observable (audit 96 > renderer 84 with header) without fixing it — appropriate scope for an output-neutral PR.
  • Minor: the using static workaround for the namespace/class name collision (Argumentum.AssetConverter.PdfAuditor.PdfAuditor) is a legitimate C# quirk, well-commented in the test file.

No concerns blocking merge. Good extraction — fragile inline geometry now pinned by 9 contract tests.

@jsboige
jsboige merged commit 6acb9de into master Jun 20, 2026
3 checks passed
@jsboige
jsboige deleted the test/pdfauditor-geometry-contract branch June 20, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants