pdftract/notes/bf-n5w42.md
jedarden 381ad93112 docs(bf-n5w42): document test failure root cause analysis
Analyzed test failures from bf-1wczm execution. Found:
- No test hangs detected (all modules completed in <1s)
- 11 test failures across 2 modules due to fixture issues
- encoding_recovery: 5 PDF fixtures corrupted (missing /Root reference, 0 pages)
- cjk_encoding: 5 tests failed due to path resolution issues

Proposed fix strategy:
1. Regenerate corrupted PDF fixtures in tests/fixtures/encoding/
2. Fix path resolution using CARGO_MANIFEST_DIR in cjk_encoding.rs
3. Add fixture validation to CI

Closes bf-n5w42.
2026-07-07 00:22:53 -04:00

218 lines
7.3 KiB
Markdown

# Test Failure Root Cause Analysis
**Bead ID:** bf-n5w42
**Date:** 2026-07-07
**Parent:** bf-60vlq
**Dependencies:** bf-1wczm (test execution)
## Executive Summary
Test execution from bead bf-1wczm completed **without any hangs or timeouts**. All 4 test modules terminated cleanly in under 1 second each. However, **11 tests failed across 2 modules** due to fixture issues, not test logic problems.
## Test Modules Summary
| Module | Status | Pass/Fail | Duration |
|--------|--------|-----------|----------|
| `unmapped_glyph_names_config` | ✅ PASS | 4/4 | <1s |
| `encoding_recovery` | FAIL | 1/6 | <1s |
| `cjk_encoding` | FAIL | 0/5 | <1s |
| `cmap_unmapped_glyphs` | PASS | 7/7 | <1s |
**Total:** 12/22 tests passing (54.5%), **0 hangs detected**
## Root Cause Analysis
### Issue 1: encoding_recovery Module - Corrupted PDF Fixtures
**Affected Tests (5 failures):**
- `test_agl_only_fixture`
- `test_fingerprint_match_fixture`
- `test_shape_match_fixture`
- `test_no_mapping_fixture`
- `test_corpus_recovery_rate`
**Error Patterns:**
1. **"No /Root reference in trailer"** (3 tests)
```
called `Result::unwrap()` on an `Err` value:
"Failed to open PDF: No /Root reference in trailer"
```
- Affects: `agl-only.pdf`, `fingerprint-match.pdf`, `shape-match.pdf`
- Root cause: PDF trailer is missing the required `/Root` catalog reference
- PDF structure violation: The trailer must point to the document catalog via `/Root`
2. **"Page index 0 out of bounds (document has 0 pages)"** (2 tests)
```
Failed to extract page: Page index 0 out of bounds (document has 0 pages)
```
- Affects: `no-mapping.pdf`
- Root cause: PDF file has no page tree or empty page count
- Test attempts to extract page 0 but document reports 0 pages
**Fixture Files Location:** `/home/coding/pdftract/tests/fixtures/encoding/`
**Files Requiring Regeneration:**
- `agl-only.pdf`
- `fingerprint-match.pdf`
- `shape-match.pdf`
- `no-mapping.pdf`
**Evidence:** Files exist (confirmed via `ls -la`) but are structurally invalid PDFs.
### Issue 2: cjk_encoding Module - Path Resolution Failure
**Affected Tests (5 failures):**
- `test_all_cjk_fixtures_exist`
- `test_cjk_big5_traditional_chinese`
- `test_cjk_gb18030_chinese`
- `test_cjk_shiftjis_japanese`
- `test_cjk_euckr_korean`
**Error Pattern:**
```
CJK fixture PDF should exist: ../../../tests/fixtures/cjk/cjk-chinese-gb18030.pdf
Failed to open PDF: Failed to open PDF file
```
**Root Cause:** Path resolution failure due to test working directory mismatch
**Test Code Path:** `../../../tests/fixtures/cjk/cjk-chinese-gb18030.pdf`
**Actual File Location:** `/home/coding/pdftract/tests/fixtures/cjk/cjk-chinese-gb18030.pdf`
**Test Working Directory:** `target/debug/deps/` (cargo test default)
The relative path `../../../tests/fixtures/` resolves from `target/debug/deps/` to `tests/fixtures/` in the parent directory, but cargo tests run with the workspace root as cwd in some configurations and target/deps in others. This creates intermittent path resolution failures.
**Files Confirmed to Exist:**
- `cjk-chinese-gb18030.pdf` ✅ (822 bytes)
- `cjk-japanese-shiftjis.pdf` ✅ (822 bytes)
- `cjk-korean-euckr.pdf` ✅ (826 bytes)
- `cjk-tc-big5.pdf` ✅ (814 bytes)
All files are present and non-zero in size, but cannot be found due to path resolution.
## No Test Hangs Detected
Per CLAUDE.md test hygiene requirements, I verified for hangs/timeouts:
✅ All modules completed in <1 second
✅ No process leaks detected
✅ No port conflicts observed
✅ No frozen `cargo test` processes
✅ No orphaned `pdftract mcp` server processes
The test execution was clean and rapid. Failures are immediate assertion panics, not hanging timeouts.
## Proposed Fix Strategy
### Priority 1: Fix encoding_recovery Fixtures
1. **Regenerate corrupted PDFs:**
```bash
cd /home/coding/pdftract/tests/fixtures/encoding/
# Re-run fixture generation scripts
python3 create_unmapped_comprehensive.py
python3 generate_unmapped_glyphs.py
```
2. **Validate regenerated PDFs:**
```bash
# Verify /Root reference exists
pdfgrep -a "Root" agl-only.pdf
# Verify page count > 0
pdfinfo agl-only.pdf | grep "Pages:"
```
3. **Test after regeneration:**
```bash
cargo test -p pdftract-core --test encoding_recovery -- --test-threads=1
```
### Priority 2: Fix cjk_encoding Path Resolution
**Option A: Use CARGO_MANIFEST_DIR (Recommended)**
```rust
// In cjk_encoding.rs
fn get_fixtures() -> Vec<CjkFixture> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let fixture_base = format!("{}/tests/fixtures/cjk", manifest_dir);
vec![
CjkFixture {
name: "chinese-gb18030",
pdf_path: &format!("{}/cjk-chinese-gb18030.pdf", fixture_base),
// ...
},
]
}
```
**Option B: Use find-crate crate for dynamic path resolution**
```rust
use find_crate::{Find, Source};
fn get_fixture_path(fixture_name: &str) -> String {
let pkg = Find::current().expect("find package");
let source = pkg.source;
format!("{}/tests/fixtures/cjk/{}", source, fixture_name)
}
```
**Option C: Use std::path absolute resolution**
```rust
fn get_fixtures() -> Vec<CjkFixture> {
let base = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/cjk");
vec![
CjkFixture {
name: "chinese-gb18030",
pdf_path: base.join("cjk-chinese-gb18030.pdf").to_str().unwrap(),
// ...
},
]
}
```
### Priority 3: Verify Unmapped Glyph Tests
The `cmap_unmapped_glyphs` and `unmapped_glyph_names_config` modules pass cleanly. No action needed.
## Test Hygiene Verification
Per CLAUDE.md test hygiene section, I checked for known failure modes:
- ✅ **Process leaks:** None detected (all processes terminated cleanly)
- ✅ **Port conflicts:** N/A (tests don't bind ports)
- ✅ **Timeout issues:** None (all tests finished instantly)
- ✅ **Orphaned processes:** None (no subprocess spawning in test code)
- ✅ **Undrained pipes:** N/A (no server subprocess spawning)
The test failures are purely fixture/path issues, not the hanging/timeout patterns warned about in CLAUDE.md.
## Recommendations for Parent Bead (bf-60vlq)
1. **Add fixture validation to CI:**
- Run `pdfinfo` on all PDF fixtures before test execution
- Fail fast if fixtures are corrupted
2. **Add path resolution tests:**
- Unit test to verify fixture files are discoverable at test initialization
- Panic early with clear error message if paths fail
3. **Document fixture generation:**
- Add README.md in `tests/fixtures/` explaining how to regenerate fixtures
- Include validation commands
4. **Consider cargo-nextest for hung test detection:**
- Migrate test execution from `cargo test` to `cargo nextest run`
- Leverage `slow-timeout` configuration for automatic hung test termination
- Add `.config/nextest.toml` with per-test timeout settings
## Conclusion
**No test hangs occurred.** All test modules executed rapidly and terminated cleanly. The 11 test failures are due to:
- 5 corrupted PDF fixtures (encoding_recovery)
- 5 path resolution failures (cjk_encoding)
Both issues are fixable with fixture regeneration and path resolution code changes. The underlying test logic for unmapped glyph assertions is working correctly (11/11 tests passing in the 2 passing modules).