Skip to main content

foundry_config/
mutation.rs

1//! Configuration for mutation testing.
2
3use serde::{Deserialize, Serialize};
4use strum::IntoEnumIterator;
5
6/// Represents each available mutation operator.
7#[derive(
8    Debug,
9    Clone,
10    Copy,
11    PartialEq,
12    Eq,
13    Hash,
14    Serialize,
15    Deserialize,
16    strum::Display,
17    strum::EnumString,
18    strum::EnumIter,
19)]
20#[serde(rename_all = "kebab-case")]
21#[strum(serialize_all = "kebab-case")]
22pub enum MutatorType {
23    Assembly,
24    Assignment,
25    BinaryOp,
26    DeleteExpression,
27    ElimDelegate,
28    FunctionBody,
29    Require,
30    UnaryOp,
31}
32
33impl MutatorType {
34    /// Returns a list of all available mutator types.
35    pub fn all() -> Vec<Self> {
36        Self::iter().collect()
37    }
38
39    /// Returns the operators that are excluded by default.
40    pub const fn default_excluded() -> Vec<Self> {
41        Vec::new()
42    }
43}
44
45/// Configuration for mutation testing.
46#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
47pub struct MutationConfig {
48    /// Re-enable operators that are excluded by default.
49    pub include_operators: Vec<MutatorType>,
50    /// Exclude additional operators beyond the defaults.
51    pub exclude_operators: Vec<MutatorType>,
52    /// Per-mutant wall-clock timeout, in seconds.
53    ///
54    /// When set, each mutant's compile-and-test work is bounded by this
55    /// duration; mutants that exceed it are recorded as `TimedOut`. This is
56    /// the analog of `invariant.timeout` for mutation campaigns.
57    ///
58    /// Note: enforcement is best-effort. Background work for a timed-out
59    /// mutant may continue briefly until the underlying compile / test loop
60    /// reaches a checkpoint, but the worker slot is freed immediately so
61    /// other mutants can proceed. Cleanup backlog is bounded by the configured
62    /// mutation worker count.
63    pub timeout: Option<u32>,
64    /// Override `optimizer_runs` for mutation testing compile-and-test runs.
65    ///
66    /// This lets mutation campaigns use a faster compiler profile without
67    /// changing the project's normal build settings.
68    pub optimizer_runs: Option<u32>,
69    /// Override `via_ir` for mutation testing compile-and-test runs.
70    ///
71    /// This lets mutation campaigns disable the IR pipeline without changing
72    /// the project's normal build settings.
73    pub via_ir: Option<bool>,
74}
75
76impl MutationConfig {
77    /// Returns the list of operators that are currently enabled.
78    ///
79    /// Effective set: `all() - default_excluded - exclude_operators + include_operators`
80    pub fn enabled_operators(&self) -> Vec<MutatorType> {
81        let default_excluded = MutatorType::default_excluded();
82        MutatorType::all()
83            .into_iter()
84            .filter(|op| {
85                let excluded = default_excluded.contains(op) || self.exclude_operators.contains(op);
86                let included = self.include_operators.contains(op);
87                !excluded || included
88            })
89            .collect()
90    }
91}