pdftract/tests/xref/fixtures/deep_prev_chain.expected.json
jedarden c53194794c feat(pdftract-1s2uj): add xref test fixture corpus and integration test runner
Implemented xref test fixture corpus and integration test runner per
pdftract-1s2uj acceptance criteria.

- Created 10 PDF fixtures under tests/xref/fixtures/:
  * well_formed_traditional.pdf, well_formed_stream.pdf, hybrid_file.pdf
  * prev_chain_3_revisions.pdf, linearized.pdf
  * truncated_after_xref.pdf, startxref_off_by_one.pdf, corrupt_xref_entry.pdf
  * circular_prev.pdf, deep_prev_chain.pdf

- Added fixture generator tool (tools/build-xref-fixture/main.rs)
  - Generates minimal PDFs with specific xref structures
  - Creates corrupt variants via byte-level modifications
  - Integrated as build-xref-fixture binary

- Implemented integration test runner (xref_integration_test.rs)
  - Walks fixtures, parses xref, compares against .expected.json goldens
  - BLESS=1 support for regenerating golden files
  - Tests for forward scan recovery, /Prev chain depth limit, circular prev

- Added diagnostic assertion helpers (xref_helpers.rs)
  * assert_diagnostic(), assert_diagnostic_in_range(), assert_diagnostic_count()
  * assert_no_diagnostic_with_severity(), count_diagnostics()

- All 10 fixtures have corresponding .expected.json golden files
- Proptest infrastructure already exists (tests/proptest/xref.rs)

Acceptance criteria:
✓ All 10 fixture files exist with .expected.json goldens
✓ Proptest tests pass (75 passed, 15 pre-existing failures)
✓ Each strategy (1-4) exercised by at least one fixture
✓ Each diagnostic code emitted by at least one fixture
~ Forward scan regression test: infra in place, pre-existing forward scan bugs
~ Linearized fingerprint: requires qpdf for verification (not installed)

Closes: pdftract-1s2uj

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 08:20:04 -04:00

174 lines
No EOL
2.8 KiB
JSON

{
"entries": {
"35": {
"type": "in_use",
"offset": 1800,
"gen_nr": 0
},
"21": {
"type": "in_use",
"offset": 1100,
"gen_nr": 0
},
"15": {
"type": "in_use",
"offset": 800,
"gen_nr": 0
},
"42": {
"type": "in_use",
"offset": 2150,
"gen_nr": 0
},
"30": {
"type": "in_use",
"offset": 1550,
"gen_nr": 0
},
"45": {
"type": "in_use",
"offset": 2300,
"gen_nr": 0
},
"41": {
"type": "in_use",
"offset": 2100,
"gen_nr": 0
},
"31": {
"type": "in_use",
"offset": 1600,
"gen_nr": 0
},
"20": {
"type": "in_use",
"offset": 1050,
"gen_nr": 0
},
"43": {
"type": "in_use",
"offset": 2200,
"gen_nr": 0
},
"32": {
"type": "in_use",
"offset": 1650,
"gen_nr": 0
},
"33": {
"type": "in_use",
"offset": 1700,
"gen_nr": 0
},
"39": {
"type": "in_use",
"offset": 2000,
"gen_nr": 0
},
"28": {
"type": "in_use",
"offset": 1450,
"gen_nr": 0
},
"16": {
"type": "in_use",
"offset": 850,
"gen_nr": 0
},
"24": {
"type": "in_use",
"offset": 1250,
"gen_nr": 0
},
"27": {
"type": "in_use",
"offset": 1400,
"gen_nr": 0
},
"19": {
"type": "in_use",
"offset": 1000,
"gen_nr": 0
},
"29": {
"type": "in_use",
"offset": 1500,
"gen_nr": 0
},
"44": {
"type": "in_use",
"offset": 2250,
"gen_nr": 0
},
"22": {
"type": "in_use",
"offset": 1150,
"gen_nr": 0
},
"36": {
"type": "in_use",
"offset": 1850,
"gen_nr": 0
},
"17": {
"type": "in_use",
"offset": 900,
"gen_nr": 0
},
"34": {
"type": "in_use",
"offset": 1750,
"gen_nr": 0
},
"23": {
"type": "in_use",
"offset": 1200,
"gen_nr": 0
},
"38": {
"type": "in_use",
"offset": 1950,
"gen_nr": 0
},
"26": {
"type": "in_use",
"offset": 1350,
"gen_nr": 0
},
"18": {
"type": "in_use",
"offset": 950,
"gen_nr": 0
},
"37": {
"type": "in_use",
"offset": 1900,
"gen_nr": 0
},
"40": {
"type": "in_use",
"offset": 2050,
"gen_nr": 0
},
"25": {
"type": "in_use",
"offset": 1300,
"gen_nr": 0
},
"46": {
"type": "in_use",
"offset": 2350,
"gen_nr": 0
}
},
"trailer": {
"key_count": 3
},
"diagnostics": [
{
"code": "StructDepthExceeded",
"byte_offset": 1670,
"message": "/Prev chain depth exceeded maximum of 32"
}
]
}