Skip to main content

ryo_executor/executor/registry/converters/
match_arm.rs

1//! MatchArmConverter: Converts MutationSpec::AddMatchArm, RemoveMatchArm, and ReplaceMatchArm
2
3use crate::engine::ASTRegApply;
4use crate::executor::registry::converters::ResolveTargetSymbol;
5use crate::executor::registry::{ConvertError, MutationConverter};
6use crate::executor::spec::MutationSpec;
7use ryo_analysis::AnalysisContext;
8use ryo_mutations::{AddMatchArmMutation, RemoveMatchArmMutation, ReplaceMatchArmMutation};
9
10/// Converter for AddMatchArm, RemoveMatchArm, and ReplaceMatchArm mutations
11#[derive(Debug, Clone, Default)]
12pub struct MatchArmConverter;
13
14impl MatchArmConverter {
15    pub fn new() -> Self {
16        Self
17    }
18}
19
20// MatchArmConverter uses the default implementation of ResolveTargetSymbol
21impl ResolveTargetSymbol for MatchArmConverter {}
22
23impl MutationConverter for MatchArmConverter {
24    fn spec_kinds(&self) -> &'static [&'static str] {
25        &["AddMatchArm", "RemoveMatchArm", "ReplaceMatchArm"]
26    }
27
28    fn convert_v2(
29        &self,
30        spec: &MutationSpec,
31        ctx: &AnalysisContext,
32    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
33        match spec {
34            MutationSpec::AddMatchArm {
35                target,
36                enum_name,
37                pattern,
38                body,
39            } => {
40                let fn_id = self.resolve_target_symbol(target, ctx)?;
41
42                let mutation = AddMatchArmMutation::new(
43                    fn_id,
44                    enum_name.clone(),
45                    pattern.clone(),
46                    body.clone(),
47                );
48                Ok(vec![Box::new(mutation)])
49            }
50            MutationSpec::RemoveMatchArm {
51                target,
52                enum_name,
53                pattern,
54            } => {
55                let fn_id = self.resolve_target_symbol(target, ctx)?;
56
57                let mutation =
58                    RemoveMatchArmMutation::new(fn_id, enum_name.clone(), pattern.clone());
59                Ok(vec![Box::new(mutation)])
60            }
61            MutationSpec::ReplaceMatchArm {
62                target,
63                enum_name,
64                old_pattern,
65                new_pattern,
66                new_body,
67            } => {
68                let fn_id = self.resolve_target_symbol(target, ctx)?;
69
70                let mutation = ReplaceMatchArmMutation::new(
71                    fn_id,
72                    enum_name.clone(),
73                    old_pattern.clone(),
74                    new_pattern.clone(),
75                    new_body.clone(),
76                );
77                Ok(vec![Box::new(mutation)])
78            }
79            _ => Err(ConvertError::TypeMismatch {
80                expected: "AddMatchArm, RemoveMatchArm, or ReplaceMatchArm",
81                actual: spec.kind_name().to_string(),
82            }),
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use crate::executor::spec::MutationTargetSymbol;
91    use ryo_analysis::SymbolPath;
92
93    #[test]
94    fn test_match_arm_converter_spec_kinds() {
95        let converter = MatchArmConverter::new();
96        assert_eq!(
97            converter.spec_kinds(),
98            &["AddMatchArm", "RemoveMatchArm", "ReplaceMatchArm"]
99        );
100    }
101
102    #[test]
103    fn test_match_arm_converter_can_handle() {
104        let converter = MatchArmConverter::new();
105
106        let spec = MutationSpec::AddMatchArm {
107            target: MutationTargetSymbol::ByPath(Box::new(
108                SymbolPath::parse("test_crate::handlers::process_status").unwrap(),
109            )),
110            enum_name: "Status".to_string(),
111            pattern: "Status::Cancelled".to_string(),
112            body: "todo!()".to_string(),
113        };
114        assert!(converter.can_handle(&spec));
115    }
116}