Skip to main content

fallow_api/mutation/
mod.rs

1//! The dynamic half of mutation testing: the runner protocol, the embedded
2//! companion, the transport, the scheduler and the result model.
3//!
4//! The static half (selection, the test map, pruning, ranking and the
5//! instrumented code) is `fallow_engine::mutation`. The entry points are
6//! [`crate::run_mutation`] and [`crate::plan_mutation`].
7
8pub(crate) mod companion;
9pub(crate) mod discovery;
10pub(crate) mod last_report;
11pub(crate) mod manifest;
12pub(crate) mod node_args;
13pub(crate) mod protocol;
14pub(crate) mod report;
15pub(crate) mod result_cache;
16pub(crate) mod run_dir;
17pub(crate) mod runner_select;
18pub(crate) mod scheduler;
19pub(crate) mod transport;
20pub(crate) mod typecheck;
21pub(crate) mod verdicts;
22pub(crate) mod worktree;
23
24#[cfg(test)]
25#[expect(clippy::unwrap_used, reason = "tests unwrap to keep assertions short")]
26mod e2e_tests;
27
28use std::path::PathBuf;
29use std::time::Duration;
30
31pub use fallow_engine::mutation::Operator;
32pub use last_report::{last_mutation_report_path, save_last_mutation_report};
33pub use report::baseline_blocked_run_error;
34pub use verdicts::{MAX_VERDICT_INPUT_BYTES, apply_mutation_verdicts, validate_mutation_verdicts};
35
36use crate::AnalysisOptions;
37
38/// The code that a mutation run mutates.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum MutationRunScope {
41    /// The added lines against a base ref. `None` detects the base ref the
42    /// same way as `audit`. An explicit `analysis.diff_file` wins over the
43    /// base ref.
44    Changed {
45        /// The base ref.
46        base: Option<String>,
47    },
48    /// Each source file of the project.
49    All,
50    /// The files at these paths, or below these directories. A relative
51    /// path is relative to the project root.
52    Paths(Vec<PathBuf>),
53}
54
55impl Default for MutationRunScope {
56    fn default() -> Self {
57        Self::Changed { base: None }
58    }
59}
60
61/// Options of [`crate::run_mutation`] and [`crate::plan_mutation`].
62#[derive(Debug, Clone, Default)]
63pub struct MutationRunOptions {
64    /// Shared project, config and cache options.
65    pub analysis: AnalysisOptions,
66    /// The code to mutate.
67    pub scope: MutationRunScope,
68    /// The operators to use. `None` uses each operator.
69    pub operators: Option<Vec<Operator>>,
70    /// Keep mutants near a file system, process, network or database sink.
71    /// Only an explicit caller option can set this, never project config,
72    /// because the run has no sandbox copy.
73    pub allow_side_effects: bool,
74    /// The maximum number of covered mutants to run, in rank order. A
75    /// mutant that no dry-run test covers is `no_coverage` and does not
76    /// count. The others become `pending`.
77    pub max_mutants: Option<usize>,
78    /// Run in a dirty git worktree, or outside a git worktree. The run still
79    /// compares the worktree after the run.
80    pub allow_dirty: bool,
81    /// The JavaScript runtime. `None` uses the runtime of the runner from
82    /// `PATH`: `node` for `node:test`, `bun` for `bun test`, and `node`,
83    /// then `bun`, for Vitest.
84    pub runtime: Option<PathBuf>,
85    /// The number of companion processes. `None` uses half the logical
86    /// cores.
87    pub concurrency: Option<usize>,
88    /// The time budget of the run. Mutants that did not start before it
89    /// ends become `pending`.
90    pub time_budget: Option<Duration>,
91    /// The timeout of the companion `init` and the dry run. `None` uses
92    /// 120 seconds.
93    pub runner_timeout: Option<Duration>,
94    /// The files that the caller writes after the run, for example the
95    /// `--output-file` report. The worktree check leaves them out, so an old
96    /// report does not make the worktree dirty. A relative path is relative
97    /// to the process directory, as the caller writes it.
98    pub output_paths: Vec<PathBuf>,
99    /// Type-check each survived mutant through the TypeScript-Go companion
100    /// of `--type-aware`. A survivor whose mutated file does not type-check
101    /// becomes `compile_error` and leaves the score. The run fails before
102    /// the tests start when no trusted companion exists.
103    pub typecheck: bool,
104}