Development¶
The CLI and library live in src/; the user-facing documentation is in docs/.
Build & test¶
cargo test # full test suite (incl. the golden snapshot)
cargo clippy --all-targets -- -D warnings # lint (CI denies warnings)
make release # optimized (native-CPU) build
make docs # build the docs with MkDocs Material
Enable the repo git hooks once per clone. A pre-commit check then blocks common
slips (em-dashes, a leftover dbg!, a conflict marker) before they land:
make hooks # sets core.hooksPath to .githooks
tests/golden.rs freezes the exact eskaks vcf output on the bundled toy genome
(every table, TSV and JSON), so any silent drift fails CI with an exact diff. After
an intended output change, regenerate the snapshot and review the diff before
committing:
BLESS=1 cargo test --test golden
Quality tooling¶
cargo test already runs, beyond the unit and integration suites:
- Property tests (
tests/property_tests.rs, proptest) that assert invariants over generated inputs: the dN/dS models, the diversity statistics (pi is polarization-invariant, Tajima's D is finite-or-NaN), the distribution helpers (Wilson, binomial, Benjamini-Hochberg), and that the VCF and GFF3 parsers never panic on arbitrary bytes. - A docs-code contract (
tests/docs_contract.rs): every pN/pS output column and everyeskaks vcf/eskaks fasta --helpflag must be documented, so the docs cannot silently drift from the binary.
Two deeper tools run out of band. Neither is a PR gate and neither runs on a schedule: their workflows are manual, started from the repository's Actions tab with "Run workflow", so they cost nothing until you ask for them. Locally:
# Coverage-guided fuzzing of the parsers (needs a nightly toolchain + cargo-fuzz).
cargo +nightly fuzz run parse_vcf # or parse_gff3
# Mutation testing: inject bugs and confirm the suite kills them (cargo install cargo-mutants).
cargo mutants --file src/stats/diversity.rs # one module, fast
cargo mutants # whole scientific core (slow)
Mutation testing surfaces test gaps (a surviving mutant is a bug the suite did not
catch); review each survivor, but expect some to be genuinely equivalent mutants
(e.g. flipping || to && between two logically equivalent guards) that no test can
kill.
Source layout¶
src/
├── main.rs # subcommand dispatch + --demo
├── cli.rs # CLI definitions (clap subcommands)
├── run_fasta.rs # `fasta` orchestration (pairwise / lineage / group / window)
├── run_vcf.rs # `vcf` orchestration (pN/pS, diversity, MK, report)
├── input.rs # FASTA reading, validation, stdin
├── compute.rs # ComputeEngine (Nei | Li)
├── genetic_code.rs # 20 NCBI tables
├── stats/ # dist.rs (binomial/Wilson/Fisher, FDR, probit), diversity.rs, accum.rs
├── vcf/, gff.rs # VCF (parse / merge / filter) and GFF3 parsers
├── vcf_analysis/ # per-gene pN/pS, neutrality test, MK, genomic control, diversity
├── report.rs # self-contained interactive HTML report
├── plot/ # SVG generation (bars, histogram, window)
└── models/ # nei.rs, li.rs
eskaks can also be used as a Rust library crate rather than through the CLI; see the FAQ for a minimal example.