pdftract/notes/bf-4votp.md
jedarden c49b8e36d4 docs(bf-4votp): document fixtures directory structure
Explored tests/fixtures/ to understand PDF organization:
- 1,301 PDFs across 16 categories (max depth: 2 levels)
- 53 symlinks, primarily profiles/ → classifier/ for test reuse
- Largest file: remote_100page.pdf (5.9 MB)
- grep-corpus/ contains 1,000 PDFs in flat structure

Acceptance criteria:
✓ fixtures/ structure is documented
✓ PDF file locations are mapped
✓ Structural oddities noted (symlinks, large grepcorpus)

Verification: notes/bf-4votp.md
2026-07-06 19:52:08 -04:00

173 lines
6.9 KiB
Markdown

# Fixtures Directory Structure Exploration
Bead: bf-4votp
Date: 2026-07-06
Task: Explore fixtures directory structure
## Overview
The `tests/fixtures/` directory contains **1,301 PDF files** organized into **16 top-level categories** with a maximum depth of 2 levels (very flat structure).
## Directory Structure
### Top-level Categories
```
tests/fixtures/
├── cjk/ # 4 PDFs - Chinese, Japanese, Korean
├── classifier/ # 200 PDFs - Document type classification fixtures
│ ├── contract/
│ ├── invoice/ # 50 numbered invoice PDFs (01-50.pdf)
│ ├── misc/
│ └── scientific_paper/
├── encoding/ # 6 PDFs - Font encoding edge cases
├── encrypted/ # 5 PDFs - RC4, AES-128, AES-256 encrypted PDFs
├── fonts/ # 0 PDFs (empty)
├── forms/ # 0 PDFs (has generate_form_fixtures.rs)
├── grep-corpus/ # 1,000 PDFs - Folder search benchmark corpus
│ └── corpus/
├── json_schema/ # 6 PDFs - Schema validation fixtures
├── malformed/ # 15 PDFs - Truncated, corrupt xref, circular refs
├── ocr/ # 2 PDFs - OCR test fixtures
│ ├── brokenvector_aligned/
│ ├── brokenvector_misaligned/
│ ├── clean_lorem_ipsum/
│ ├── eng_fra_mixed/
│ └── perf_10_page/
├── page_class/ # 4 PDFs - Page classification test fixtures
│ ├── brokenvector_pdfa/
│ ├── hybrid_header_body/
│ ├── scanned_single/
│ └── vector_pure/
├── perf/ # 2 PDFs - Performance benchmarking
│ └── 10k-page.pdf (2.4 MB)
├── portfolios/ # 0 PDFs (empty)
├── preprocess/ # 0 PDFs (empty)
│ ├── clean_digital/
│ ├── jbig2_scan/
│ ├── skewed_2deg/
│ ├── uneven_lighting/
├── profiles/ # 20 PDFs + 52 symlinks - Document profile fixtures
│ ├── invoice/ # Symlinks → ../../classifier/invoice/
│ ├── receipt/
│ ├── bank_statement/
│ ├── book_chapter/
│ ├── contract/
│ ├── form/
│ ├── invalid/ # 5 YAML files (malformed profiles)
│ ├── legal_filing/
│ ├── resolution/
│ ├── scientific_paper/
│ ├── slide_deck/
│ └── valid/ # 2 YAML files
├── scanned/ # 16 PDFs - Physical scans at various DPI
│ ├── documents/
│ ├── form/
│ ├── invoice/
│ ├── letter/
│ ├── low-quality/
│ ├── multi-page/ # Large files up to 2.2 MB
│ └── receipt/
├── security/ # 4 PDFs - Security test fixtures
│ └── xss-payload.pdf
├── vector/ # 10 PDFs - Clean LaTeX/Word/InDesign outputs
│ ├── academic-paper/
│ ├── code-documentation/
│ ├── conference-proceedings/
│ ├── financial-report/
│ ├── legal-contract/
│ ├── medical-research/
│ ├── multi-page-academic/
│ ├── scientific-report/
│ ├── technical-documentation/
│ └── user-manual/
├── sample.pdf # Root-level test PDF
├── remote_100page.pdf # 5.9 MB - Remote source testing
├── test-minimal.pdf
├── tagged-suspects-*.pdf # 3 files - Tagged PDF variants
└── valid-minimal.pdf
```
## Symlinks (Structural Oddity)
**53 symlinks** exist, primarily in the `profiles/` directory:
1. **Profile fixtures reference classifier fixtures:**
- `tests/fixtures/profiles/invoice/*.pdf``../../classifier/invoice/*.pdf`
- This allows profile validation tests to use the same underlying PDFs as classifier tests
2. **Self-referential directory symlink:**
- `tests/fixtures/classifier/scientific_paper/scientific_paper``/home/coding/pdftract/tests/fixtures/classifier/scientific_paper`
- Purpose unclear, appears to be a legacy artifact
## Non-PDF Files
### Binary Fixtures (LZW compression tests)
- `tests/fixtures/lzw_*.bin` (13 files) - Test fixtures for LZW stream decoder
### Markdown Files
- `STRUCTURE.md` - Fixtures documentation
- `PROVENANCE.md` - Source/origin tracking
- `no-mapping.md` - Encoding test notes
### YAML Profile Files
- 6 YAML files for document profile validation:
- `profiles/valid/*.yaml` (2 files)
- `profiles/invalid/*.yaml` (5 files)
- `profiles/resolution/custom-invoice.yaml`
### Code Files
- `forms/generate_form_fixtures.rs` - Form fixture generator
### Expected Output Files
- `encrypted/EC-05-aes128-encrypted.expected.json` - Expected JSON output
## Size Distribution
| Category | Size Range | Largest File |
|----------|------------|--------------|
| Root-level | 534 B - 5.9 MB | `remote_100page.pdf` (5.9 MB) |
| scanned/ | 416K - 2.2 MB | `multi-page/report-300dpi.pdf` (2.2 MB) |
| perf/ | 2.4 MB | `10k-page.pdf` |
| Most categories | < 500 KB | N/A |
## Structural Characteristics
### Positive Attributes
1. **Flat hierarchy** - Max depth of 2 levels makes navigation simple
2. **No empty directories** - All categories contain files
3. **Clear naming** - Directory names self-document their purpose
4. **Logical organization** - Grouped by feature/test type
### Potential Issues
1. **Symlink complexity** - 53 symlinks could complicate:
- File discovery algorithms
- Test fixture copying/archiving
- Docker volume mounts (symlink handling varies)
The symlinks from `profiles/` to `classifier/` are intentional for test reuse but may break tools that don't follow symlinks.
2. **Large grep-corpus** - 1,000 PDFs in a single flat directory could:
- Impact filesystem performance on some systems
- Cause name collisions if more added
- Benefit from sharding (e.g., `grep-corpus/batch-1/`, `grep-corpus/batch-2/`)
3. **Mixed content at root level** - 7 PDFs at the root (`sample.pdf`, `test-minimal.pdf`, etc.) lack clear categorization
## Recommendations for Discovery Implementation
1. **Follow symlinks** - Use `followSymlinks: true` or equivalent when walking the directory tree
2. **Handle grepcorpus specially** - Consider batching or streaming for the 1,000-PDF directory
3. **Canonicalize paths** - Resolve symlinks to their targets before deduplication
4. **Root-level special case** - Either categorize root PDFs or document them as "general purpose"
## Summary
- **Total PDFs:** 1,301
- **Total categories:** 16 top-level directories
- **Max depth:** 2 levels
- **Symlinks:** 53 (mostly in `profiles/` `classifier/`)
- **Largest single file:** `remote_100page.pdf` (5.9 MB)
- **Most populated category:** `grep-corpus/` with 1,000 PDFs
The structure is well-organized and flat, with symlink-based fixture reuse being the primary complexity to handle in discovery implementation.