forge/mutation/mutators/
mutator_registry.rs1use crate::mutation::mutant::Mutant;
2use eyre::Report;
3use foundry_config::MutatorType;
4
5use super::{
6 MutationContext, Mutator, assembly_mutator, assignment_mutator, binary_op_mutator,
7 delete_expression_mutator, elim_delegate_mutator, require_mutator, unary_op_mutator,
8};
9
10pub struct MutatorRegistry {
12 mutators: Vec<Box<dyn Mutator>>,
13}
14
15pub struct MutationGenerationResult {
16 pub mutations: Vec<Mutant>,
17 pub errors: Vec<Report>,
18}
19
20impl MutatorRegistry {
21 #[cfg(test)]
22 pub fn default() -> Self {
23 Self::from_enabled(&MutatorType::all())
24 }
25
26 pub fn from_enabled(enabled: &[MutatorType]) -> Self {
27 let mut registry = Self { mutators: Vec::new() };
28
29 for ty in enabled {
30 match ty {
31 MutatorType::Assembly => {
32 registry.mutators.push(Box::new(assembly_mutator::AssemblyMutator::new()));
33 }
34 MutatorType::Assignment => {
35 registry.mutators.push(Box::new(assignment_mutator::AssignmentMutator));
36 }
37 MutatorType::BinaryOp => {
38 registry.mutators.push(Box::new(binary_op_mutator::BinaryOpMutator));
39 }
40 MutatorType::DeleteExpression => {
41 registry
42 .mutators
43 .push(Box::new(delete_expression_mutator::DeleteExpressionMutator));
44 }
45 MutatorType::ElimDelegate => {
46 registry.mutators.push(Box::new(elim_delegate_mutator::ElimDelegateMutator));
47 }
48 MutatorType::Require => {
49 registry.mutators.push(Box::new(require_mutator::RequireMutator));
50 }
51 MutatorType::UnaryOp => {
52 registry.mutators.push(Box::new(unary_op_mutator::UnaryOpMutator));
53 }
54 }
55 }
56
57 registry
58 }
59
60 #[cfg(test)]
61 pub fn new_with_mutators(mutators: Vec<Box<dyn Mutator>>) -> Self {
62 Self { mutators }
63 }
64
65 pub fn generate_mutations(&self, context: &MutationContext<'_>) -> MutationGenerationResult {
68 let mut mutations = Vec::new();
69 let mut errors = Vec::new();
70 for mutator in self.mutators.iter().filter(|mutator| mutator.is_applicable(context)) {
71 match mutator.generate_mutants(context) {
72 Ok(generated) => mutations.extend(generated),
73 Err(err) => errors.push(err),
74 }
75 }
76 MutationGenerationResult { mutations, errors }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use eyre::{Result, eyre};
83 use solar::ast::Span;
84
85 use super::*;
86
87 struct FailingMutator;
88
89 impl Mutator for FailingMutator {
90 fn generate_mutants(&self, _ctxt: &MutationContext<'_>) -> Result<Vec<Mutant>> {
91 Err(eyre!("synthetic mutator failure"))
92 }
93
94 fn is_applicable(&self, _ctxt: &MutationContext<'_>) -> bool {
95 true
96 }
97 }
98
99 #[test]
100 fn generate_mutations_collects_mutator_errors() {
101 let registry = MutatorRegistry::new_with_mutators(vec![Box::new(FailingMutator)]);
102 let context = MutationContext::builder()
103 .with_path("test.sol".into())
104 .with_span(Span::DUMMY)
105 .build()
106 .unwrap();
107
108 let result = registry.generate_mutations(&context);
109 assert!(result.mutations.is_empty());
110 let err = result.errors.into_iter().next().unwrap();
111 assert!(err.to_string().contains("synthetic mutator failure"));
112 }
113}