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}