use crate::cli::args::UninstallArgs;
use crate::core::installation;
use crate::types::responses::{InstallationStatus, UninstallResponse};
use crate::utils::formatting::format_uninstall_output;
use anyhow::{Context, Result};
pub async fn execute(args: UninstallArgs) -> Result<String> {
validate_target(&args.target)?;
let result = match args.target.as_str() {
"claude-code" => installation::uninstall_from_claude_code()
.await
.context("Failed to uninstall from Claude Code")?,
"cursor" => installation::uninstall_from_cursor(args.remove_config)
.await
.context("Failed to uninstall from Cursor")?,
_ => {
return Err(anyhow::anyhow!(
"Unsupported uninstallation target: {}. Supported targets: claude-code, cursor",
args.target
));
}
};
let response_data = UninstallResponse {
target: args.target.clone(),
config_path: result.config_path.clone(),
uninstallation_status: if result.success {
InstallationStatus::Success
} else {
InstallationStatus::Partial
},
actions_taken: result.actions_taken.clone(),
files_removed: result.files_removed.clone(),
};
if args.json {
Ok(serde_json::to_string_pretty(&response_data)?)
} else {
Ok(format_uninstall_output(
&args.target,
&result.config_path,
result.success,
&result.actions_taken,
&result.files_removed,
))
}
}
fn validate_target(target: &str) -> Result<()> {
match target {
"claude-code" | "cursor" => Ok(()),
_ => Err(anyhow::anyhow!(
"Unsupported uninstallation target: {}. Supported targets: claude-code, cursor",
target
)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::installation::create_uninstallation_result;
#[test]
fn test_validate_target_valid() {
let valid_targets = vec!["claude-code", "cursor"];
for target in valid_targets {
assert!(
validate_target(target).is_ok(),
"Target '{}' should be valid",
target
);
}
}
#[test]
fn test_validate_target_invalid() {
let invalid_targets = vec!["", "vscode", "claude-desktop"];
for target in invalid_targets {
assert!(
validate_target(target).is_err(),
"Target '{}' should be invalid",
target
);
}
}
#[test]
fn test_execute_invalid_target() {
let args = UninstallArgs {
target: "invalid-target".to_string(),
remove_config: false,
json: false,
};
let validation_result = validate_target(&args.target);
assert!(validation_result.is_err());
assert!(
validation_result
.unwrap_err()
.to_string()
.contains("Unsupported uninstallation target")
);
}
#[test]
fn test_uninstall_args_creation() {
let args = UninstallArgs {
target: "claude-code".to_string(),
remove_config: true,
json: false,
};
assert_eq!(args.target, "claude-code");
assert!(args.remove_config);
}
#[test]
fn test_uninstall_args_default_values() {
let args = UninstallArgs {
target: "cursor".to_string(),
remove_config: false,
json: false,
};
assert_eq!(args.target, "cursor");
assert!(!args.remove_config);
}
#[test]
fn test_create_uninstallation_result() {
let result = create_uninstallation_result(
true,
"/path/to/config.json".to_string(),
vec!["Action 1".to_string(), "Action 2".to_string()],
vec!["file1.json".to_string(), "file2.json".to_string()],
);
assert!(result.success);
assert_eq!(result.config_path, "/path/to/config.json");
assert_eq!(result.actions_taken.len(), 2);
assert_eq!(result.files_removed.len(), 2);
assert_eq!(result.actions_taken[0], "Action 1");
assert_eq!(result.files_removed[0], "file1.json");
}
#[test]
fn test_uninstall_args_with_config_removal() {
let args = UninstallArgs {
target: "cursor".to_string(),
remove_config: true,
json: false,
};
assert_eq!(args.target, "cursor");
assert!(args.remove_config);
}
}