Testing¶
The test suite lives in tests/, outside the pplx_export package, and runs
fully offline. Its API-shaped inputs are deterministic simulated data committed
under tests/fixtures/; tests do not depend on live services or a real
user-level configuration.
This page owns the current test-module inventory and the contributor workflow. For the regression design, see Test system architecture. For the input data contract, see Test fixtures.
1. Running the tests¶
uv run pytest tests
pytest is a declared development dependency. The suite guarantees:
- Zero network — simulated inputs are checked in; network-facing paths are
covered with fakes,
tmp_path, andmonkeypatch. - No real user configuration — before importing any production module,
tests/conftest.pycreates a process-local temporary configuration and overridesPPLX_EXPORT_CONFIG. Each test then receives its own placeholderalice/bobconfiguration and restores the process-local placeholder afterward. Subprocess regressions verify that a missing or broken caller configuration cannot break test collection. - Fast feedback — on 2026-07-25 the project observed 435 tests collected
from 32
test_*.pymodules and ran the full suite in roughly 13–25 seconds across local verification runs. Counts are a dated repository snapshot and will grow.
Useful selections:
| Command | Effect |
|---|---|
uv run pytest tests |
full suite |
uv run pytest tests/test_units.py |
one module |
uv run pytest tests -k snapshot |
tests whose node id matches snapshot |
uv run pytest tests -x -q |
stop at the first failure, quiet output |
uv run pytest --collect-only -q |
refresh the collected-case count |
2. Current module inventory¶
Inventory synchronized with the repository on 2026-07-27:
| Functional family | Modules | Purpose |
|---|---|---|
| Render snapshots | test_render_snapshots.py |
re-render all simulated full-mode and reduced-scenario fixtures, then compare committed products byte-for-byte |
| Core and shared utilities | test_units.py |
state, throttling, planning, normalization, asset naming, mode detection, safe paths, and cross-cutting regressions |
| Documentation contracts, skills, and localization | test_agent_skills.pytest_audit_docs.pytest_translate_docs.py |
repository-local skill contracts plus isolated miniature-repository tests for the read-only documentation auditor and machine-translation pipeline |
| Configuration, authentication, and bootstrap | test_config_external.pytest_cookie_profiles.pytest_credential.pytest_init.py |
external configuration isolation, cookie-source profiles, credential selection, and initialization |
| Rendering and workflow semantics | test_interruptions.pytest_stub_workflows.pytest_answer_variants.pytest_answer_variant_logging.pytest_relations.py |
workflow attribution, interruption states, answer variants, audit logging, and relation edges |
| Offline archive and index maintenance | test_search_mode_backfill.pytest_sync_deleted.pytest_status.py |
enrichment, resume/idempotency behavior, cross-account deletion detection, terminal states, and the offline state-account/change report tiers |
| Review regressions | 16 test_fix_*.py modules listed below |
fixes derived from review findings; module names retain review lineage |
2.1 Review-regression lineage¶
Review identifiers explain why a regression exists; they are not the test suite's primary architecture. The mapping is deliberately many-to-many: one module may cover several findings, and a finding may also add cases to an existing topical module.
| Lineage | Dedicated modules |
|---|---|
| N review | test_fix_n01_inline_assets.py, test_fix_n02_spaces_link.py, test_fix_n03_n12.py, test_fix_n04_cookies.py, test_fix_n05_n06_n09.py, test_fix_n07_usage_checkpoint.py, test_fix_n08_throttle_overflow.py, test_fix_n10_table_header.py, test_fix_n11_batch_total.py |
| V3 review | test_fix_v301_nested_sources_text.py, test_fix_v305_export_products.py |
| V4 review | test_fix_v401_thread_dir_migration.py, test_fix_v402_manifest_count.py, test_fix_v403_handle_assets_idempotency.py, test_fix_v405_ask_post_steps.py |
| V5 review | test_fix_v5_review.py, plus focused additions to existing topical modules |
| V6 review | test_fix_v6_atomic_writes.py |
The module docstrings remain the authoritative explanation of each finding's old behavior, corrected behavior, and regression boundary.
3. How snapshot tests reuse the production re-render path¶
Snapshot tests do not implement a parallel renderer:
render_fixtureintests/conftest.pycopies a fixture's simulatedraw_entries.json, optionalraw_blocks.json, andthread.jsoninto a temporary directory.- It calls
pplx_export.commands.rerender_cmd.rerender, the same function used bypplx-export re-render. - The
renderedfixture factory returns the fresh output and the fixture's committedgolden/directory. - Tests compare
conversation.mdand everyturns/turn_*.mdbyte-for-byte.
Content invariants supplement byte equality: answers must not collapse to the
empty (无) placeholder, and dict-repr residue such as {'type': ... must not
leak into rendered text.
4. Adding a test¶
- Existing logic — add a test to the matching topical module. Use
tmp_path, fakes, andmonkeypatch; never access the network or real~/.config. - Bug regression — prefer the matching topical module. Create a
test_fix_<lineage>_<slug>.pymodule when retaining review lineage materially improves traceability; do not assume one module per finding. - Render regression — add or reduce a simulated fixture, regenerate its
golden products with the maintenance tool, then register it in
test_render_snapshots.pyor add scenario-specific assertions.
Follow the neighboring style: type annotations,
from __future__ import annotations, and bilingual module docstrings.
5. See also¶
- Test fixtures — simulated inputs, golden products, and the maintenance contract
- Test system architecture — test layers and regression guarantees
- Offline operations — the production re-render path used by snapshot tests