ryo-executor 0.1.0

[experimental] Mutation execution engine for RYO - parallel execution, conflict detection, workspace management
Documentation
//! MatchArmConverter: Converts MutationSpec::AddMatchArm, RemoveMatchArm, and ReplaceMatchArm

use crate::engine::ASTRegApply;
use crate::executor::registry::converters::ResolveTargetSymbol;
use crate::executor::registry::{ConvertError, MutationConverter};
use crate::executor::spec::MutationSpec;
use ryo_analysis::AnalysisContext;
use ryo_mutations::{AddMatchArmMutation, RemoveMatchArmMutation, ReplaceMatchArmMutation};

/// Converter for AddMatchArm, RemoveMatchArm, and ReplaceMatchArm mutations
#[derive(Debug, Clone, Default)]
pub struct MatchArmConverter;

impl MatchArmConverter {
    pub fn new() -> Self {
        Self
    }
}

// MatchArmConverter uses the default implementation of ResolveTargetSymbol
impl ResolveTargetSymbol for MatchArmConverter {}

impl MutationConverter for MatchArmConverter {
    fn spec_kinds(&self) -> &'static [&'static str] {
        &["AddMatchArm", "RemoveMatchArm", "ReplaceMatchArm"]
    }

    fn convert_v2(
        &self,
        spec: &MutationSpec,
        ctx: &AnalysisContext,
    ) -> Result<Vec<Box<dyn ASTRegApply>>, ConvertError> {
        match spec {
            MutationSpec::AddMatchArm {
                target,
                enum_name,
                pattern,
                body,
            } => {
                let fn_id = self.resolve_target_symbol(target, ctx)?;

                let mutation = AddMatchArmMutation::new(
                    fn_id,
                    enum_name.clone(),
                    pattern.clone(),
                    body.clone(),
                );
                Ok(vec![Box::new(mutation)])
            }
            MutationSpec::RemoveMatchArm {
                target,
                enum_name,
                pattern,
            } => {
                let fn_id = self.resolve_target_symbol(target, ctx)?;

                let mutation =
                    RemoveMatchArmMutation::new(fn_id, enum_name.clone(), pattern.clone());
                Ok(vec![Box::new(mutation)])
            }
            MutationSpec::ReplaceMatchArm {
                target,
                enum_name,
                old_pattern,
                new_pattern,
                new_body,
            } => {
                let fn_id = self.resolve_target_symbol(target, ctx)?;

                let mutation = ReplaceMatchArmMutation::new(
                    fn_id,
                    enum_name.clone(),
                    old_pattern.clone(),
                    new_pattern.clone(),
                    new_body.clone(),
                );
                Ok(vec![Box::new(mutation)])
            }
            _ => Err(ConvertError::TypeMismatch {
                expected: "AddMatchArm, RemoveMatchArm, or ReplaceMatchArm",
                actual: spec.kind_name().to_string(),
            }),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::executor::spec::MutationTargetSymbol;
    use ryo_analysis::SymbolPath;

    #[test]
    fn test_match_arm_converter_spec_kinds() {
        let converter = MatchArmConverter::new();
        assert_eq!(
            converter.spec_kinds(),
            &["AddMatchArm", "RemoveMatchArm", "ReplaceMatchArm"]
        );
    }

    #[test]
    fn test_match_arm_converter_can_handle() {
        let converter = MatchArmConverter::new();

        let spec = MutationSpec::AddMatchArm {
            target: MutationTargetSymbol::ByPath(Box::new(
                SymbolPath::parse("test_crate::handlers::process_status").unwrap(),
            )),
            enum_name: "Status".to_string(),
            pattern: "Status::Cancelled".to_string(),
            body: "todo!()".to_string(),
        };
        assert!(converter.can_handle(&spec));
    }
}