| title | Testing Strategy |
|---|---|
| audience | developers, contributors |
| prerequisites | repository structure |
| related | workflows/quality-assurance.md, workflows/contributing.md |
| status | maintained |
| publication | draft |
The canonical ownership and command map is
../../tests/README.md. The Fortran feature index is
../../tests/fortran/README.md. Maintainers
record the active migration gates in
docs/developer/roadmap/fortran-test-suite-cleanup-checklist.md.
Tests first answer which native input contract they exercise:
tests/docs/owns documentation metadata, navigation, examples, and content;tests/tools/owns maintainer commands and CI support scripts;tests/workflows/owns exceptional automation-safety checks;tests/fortran/owns Fortran input and semantic.pyiwrapper behavior;
Within Fortran, user-visible behavior is feature first and pipeline stage second:
tests/fortran/<documented-feature>/<owning-stage>/
This makes a documentation feature independently navigable:
python3 -m pytest -q tests/fortran/arrays
python3 -m pytest -q tests/fortran/derived_types
python3 -m pytest -q tests/fortran/source_parsing
python3 -m pytest -q tests/fortran/command_line_interface
python3 -m pytest -q tests/fortran/pyi_contracts/calls_and_resultsUse tests/fortran/infrastructure/ only for a cross-feature mechanism with no
honest public-capability owner. Public Fortran parsing, preprocessing,
command-line behavior, and semantic-IR conversion have the explicit
source_parsing/, source_preprocessing/, command_line_interface/, and
semantic_ir/ owners. Generic internal policy dispatch, typed-plan mechanics,
compiler construction, and runtime-handle plumbing may remain infrastructure.
Ordinary regressions stay with their feature and stage. Minimized,
cross-feature parser interactions discovered in real-world sources belong in
tests/fortran/source_parsing/parsing/.
Treat a full third-party parser corpus as temporary evidence. Use contextual line/branch coverage and named model assertions to identify what it uniquely proves, replace those facts with minimized regressions, and delete the upstream snapshot once the focused suite subsumes it. Aggregate coverage alone is not a reason to keep hundreds of sources. A temporary corpus may be staged outside the authoritative test tree while it is being reduced.
Stage tests answer where a fact, policy decision, mechanism, or diagnostic is owned. Use the earliest stage that can prove the invariant:
- parsing for source-model facts and parser diagnostics;
- probes or preprocessing for compiler facts and source processing;
- semantics for IR construction;
- policy for ownership, transfer, destruction, writeback, nullability, projection, storage, getter/setter, and Python-exposure decisions;
- wrapper code generation for typed-plan dispatch and emitted mechanisms;
- compiling or pipeline for commands, native inputs, artifacts, and build transitions; and
- runtime for shared execution mechanisms that are not complete feature journeys.
End-to-end tests answer whether a supported public feature survives the whole
journey. They start from user-owned Fortran source or an intentional .pyi,
generate wrappers, compile and link an extension, import it from an isolated
build directory, call the public Python surface, and verify visible behavior.
Successful compilation or import without a public call is insufficient.
Feature end-to-end tests live below the owning feature's end_to_end/
directory and carry fortran_end_to_end. Full-library integration nodes carry
real_library. The complete correctness examples under examples/blas/ and
examples/lapack/ use both markers and run only in the dedicated BLAS/LAPACK
lane.
The opt-in numerical showcases under
tests/fortran/building_shared_library/end_to_end/real_libraries/ locate a
sibling checkout or an explicitly configured source directory, build the real
library sources, call representative generated routines, and compare against
independently known numerical answers. PRIK_FFTPACK_SOURCE_DIR and
PRIK_MINPACK_SOURCE_DIR override the default sibling fftpack/src and
minpack/src locations. The tests skip when the corresponding checkout is
absent.
Put an unsupported case at its first decisive stage and assert a stable prik diagnostic. Do not force a known policy rejection through compilation merely to observe a compiler failure.
Error cases stay with their owning feature. The Error Handling feature owns
only behavior that is itself an error-handling contract, such as native-status
projection, exception type/message behavior, cleanup on failure, and public
diagnostic routing. tests/fortran/CONTRACT_COVERAGE.md indexes negative
evidence and terminal stages across all features.
Keep fixtures beside their final behavioral owner:
- parser-only sources with parsing;
- semantic/policy setup with that stage;
- complete native projects below feature-local
end_to_end/fixtures/; - edited
.pyibelow the edit family it proves; - minimized real-world parser interactions with source parsing; and
- the authoritative full BLAS source set below
examples/blas/native/, shared by the correctness example, full-library integration, LAPACK CI build, and build comparison tooling; - the authoritative Reference LAPACK implementation corpus below
examples/lapack/native/, shared by its correctness example and full-library integration.
Generate build products and temporary contracts in temporary directories.
Compiler capability probes must also run with a temporary working directory so
side products such as Fortran .mod files cannot escape into the repository
root merely because the primary object or executable has an explicit output
path. Check in generated .pyi only where exact generation text,
imports, placement, or package shape is the invariant.
For BLAS behavior, source examples/blas/build_all.sh, then run
python3 -m pytest -q examples/blas/tests or one of its named test functions.
The aggregate script sources the exact documented build_prik.sh and
build_f2py.sh sequences. This compiles the sorted 155-source implementation
once and builds each wrapper once; the direct f2py script compiles the
committed reviewed blas.pyf and links the native artifact produced by the
PRIK script.
Documentation source markers require the displayed commands to remain
byte-for-byte equal to the executed scripts. test_routine_coverage.py audits
the parsed source inventory, f2py signature drift, both export sets, visible
named tests, and terminal outcomes. The dedicated CI lane explicitly adds
examples/blas/ci/full_surface.py to the same pytest invocation and does not
rebuild its wrappers afterward. User-run correctness tests and maintainer-only
audits therefore have separate directories.
For LAPACK behavior, the dedicated lane sources examples/lapack/build_all.sh
and then runs python3 -m pytest -q examples/lapack/tests. The aggregate
script sources the exact documented build_prik.sh and build_f2py.sh
sequences. The complete native corpus is compiled once, each wrapper is built
once, and the direct f2py script compiles the committed reviewed lapack.pyf
against the native artifact produced by the PRIK script while testing the
127-routine SciPy 1.18.0 float64 inventory. Documentation source markers keep
the displayed commands equal to the executed scripts. The inventory audit
fails on SciPy drift, signature drift, missing sources or exports, missing
explicitly named tests, and divergent documentation claims. CI explicitly
adds examples/lapack/ci/full_surface.py
to the same pytest invocation, reusing the complete PRIK extension to require
all 2,066 procedure exports, including module namespaces, and run a
non-inventory runtime smoke call. User-run
correctness tests and maintainer-only audits have separate directories.
The complete examples/ tree is a copyable execution boundary. Example code
may depend on an installed prik and its documented external toolchain, but it
must not import repository-only helpers from tests/. The workflow must source
the documented build scripts through build_all.sh before starting pytest,
rather than run a second build test that repeats native compilation or wrapper
construction.
Every maintained test and checked fixture has one behavioral owner. Directory layout, exact file inventories, and the current organization of the tests are maintainer conventions rather than executable product contracts. Do not add tests whose only purpose is to make an intentional reorganization fail. Add a structural check only for a concrete, unusually costly risk that cannot be protected by a behavior test. Cross-feature product mechanics require an explicit infrastructure owner; documentation and maintainer tools use their named top-level feature owners.
A test has one of two navigation shapes after language ownership is known:
- user-visible behavior lives under
tests/fortran/<documented-feature>/<owning-stage>/; or - a genuinely internal mechanism lives under
tests/fortran/infrastructure/<production-package>/test_<production-module>.py.
For example, semantic-policy internals use
infrastructure/semantics/test_ownership.py and
test_policy_completion.py; wrapper internals use
infrastructure/codegen/test_plan.py, test_planner.py, and
tests/fortran/infrastructure/pipeline/test_wrapper_generator.py. Other internal owners mirror prik/compiler/,
prik/contracts/, prik/pipeline/, prik/runtime/, and the remaining source
packages when they have real internal tests. Do not create empty mirror
directories or combine multiple production owners in generic backend or policy
collection modules. A retained direct-execution example
under if __name__ == "__main__" is maintained by the same dedicated test
module.
Documentation tests are grouped by invariant rather than by Markdown page.
Generic metadata, navigation, source-marker, link, and executable-example
validators stay parameterized over applicable pages. Page-specific content
contracts live in a module named for the documentation area they protect.
Workflow checks belong under tests/workflows/ only when they
protect concrete behavior or release safety; they should not duplicate or
freeze the current CI organization. Tests for maintainer tools and workflow
safety and all blocking static-analysis checks run through the tracked pre-push
hook for early feedback, together with the fast publication and user-content
documentation checks and one compiled scalar-wrapper test that exercises the
public source-build path through a native call. They remain in GitHub Actions
for shared enforcement. Enable the hook once per clone with
git config core.hooksPath .githooks.
Test support contains reusable construction or assertion behavior, not an
alternate import surface for production code. Tests import pytest, Python
standard-library names, and production symbols from their real owners; support
modules do not re-export them merely to shorten imports.
Run the narrowest owning directory first. After moving or splitting tests, run collection before execution and compare node IDs, parametrized suffixes, markers, skips, and xfails. Then run every destination touched by the move.
For code or test changes, run the complete static-analysis suite documented in
AGENTS.md. Documentation-only changes use the focused documentation checks
and whitespace check.
Do not run the complete coverage workflow after each feature. The migration
records one CI-equivalent baseline and one final new-suite-only comparison.
Both use COVERAGE_PROCESS_START=pyproject.toml, combine subprocess data with
python3 -m coverage combine, and retain per-file executed line and branch
data. LAPACK remains CI-only unless a maintainer explicitly requests a local
run.
Regenerate broad fixture sets only after a focused test explains the intended change. Update the narrowest affected owner:
python3 tests/fortran/source_parsing/parsing/generate_parser_goldens.py \
tests/fortran/source_parsing/parsing/fixtures/general/basic_subroutine.f90
python3 tests/fortran/semantic_ir/semantics/generate_semantic_fixtures.py
WRAPPER_UPDATE_PYI_FIXTURES=1 python3 -m pytest -q \
tests/fortran/semantic_pyi_format/pipeline/test_contract_package_generation.pyInclude regenerated artifacts only when the parser, semantic IR, or public contract representation intentionally changed. Never regenerate a broad set to hide uncertainty or unrelated drift.