use std::fmt;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EolAction {
#[default]
Trash,
Delete,
}
impl fmt::Display for EolAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EolAction::Trash => write!(f, "trash"),
EolAction::Delete => write!(f, "delete"),
}
}
}
impl EolAction {
pub fn parse(input: &str) -> Option<Self> {
match input.trim().to_lowercase().as_str() {
"trash" => Some(EolAction::Trash),
"delete" => Some(EolAction::Delete),
_ => None,
}
}
pub fn is_reversible(&self) -> bool {
match self {
EolAction::Trash => true,
EolAction::Delete => false,
}
}
pub fn variants() -> &'static [EolAction] {
&[EolAction::Trash, EolAction::Delete]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_action_is_trash() {
let action = EolAction::default();
assert_eq!(action, EolAction::Trash);
}
#[test]
fn test_copy_and_equality() {
let trash1 = EolAction::Trash;
let trash2 = trash1; assert_eq!(trash1, trash2);
let delete1 = EolAction::Delete;
let delete2 = delete1; assert_eq!(delete1, delete2);
assert_ne!(trash1, delete1);
}
#[test]
fn test_debug_formatting() {
assert_eq!(format!("{:?}", EolAction::Trash), "Trash");
assert_eq!(format!("{:?}", EolAction::Delete), "Delete");
}
#[test]
fn test_display_formatting() {
assert_eq!(EolAction::Trash.to_string(), "trash");
assert_eq!(EolAction::Delete.to_string(), "delete");
assert_eq!(format!("{}", EolAction::Trash), "trash");
assert_eq!(format!("{}", EolAction::Delete), "delete");
}
#[test]
fn test_parse_valid_inputs() {
assert_eq!(EolAction::parse("trash"), Some(EolAction::Trash));
assert_eq!(EolAction::parse("delete"), Some(EolAction::Delete));
assert_eq!(EolAction::parse("TRASH"), Some(EolAction::Trash));
assert_eq!(EolAction::parse("DELETE"), Some(EolAction::Delete));
assert_eq!(EolAction::parse("Trash"), Some(EolAction::Trash));
assert_eq!(EolAction::parse("Delete"), Some(EolAction::Delete));
assert_eq!(EolAction::parse("TrAsH"), Some(EolAction::Trash));
assert_eq!(EolAction::parse("dElEtE"), Some(EolAction::Delete));
assert_eq!(EolAction::parse(" trash "), Some(EolAction::Trash));
assert_eq!(EolAction::parse("\tdelete\n"), Some(EolAction::Delete));
assert_eq!(EolAction::parse(" TRASH "), Some(EolAction::Trash));
}
#[test]
fn test_parse_invalid_inputs() {
assert_eq!(EolAction::parse("invalid"), None);
assert_eq!(EolAction::parse("remove"), None);
assert_eq!(EolAction::parse("destroy"), None);
assert_eq!(EolAction::parse("archive"), None);
assert_eq!(EolAction::parse(""), None);
assert_eq!(EolAction::parse(" "), None);
assert_eq!(EolAction::parse("\t\n"), None);
assert_eq!(EolAction::parse("tras"), None);
assert_eq!(EolAction::parse("delet"), None);
assert_eq!(EolAction::parse("trashh"), None);
assert_eq!(EolAction::parse("deletee"), None);
assert_eq!(EolAction::parse("trash!"), None);
assert_eq!(EolAction::parse("delete?"), None);
assert_eq!(EolAction::parse("trash-delete"), None);
}
#[test]
fn test_parse_edge_cases() {
assert_eq!(EolAction::parse("trash"), Some(EolAction::Trash));
assert_eq!(EolAction::parse("trash123"), None);
assert_eq!(EolAction::parse("123delete"), None);
assert_eq!(EolAction::parse("t@rash"), None);
}
#[test]
fn test_is_reversible() {
assert!(EolAction::Trash.is_reversible());
assert!(!EolAction::Delete.is_reversible());
}
#[test]
fn test_variants() {
let variants = EolAction::variants();
assert_eq!(variants.len(), 2);
assert_eq!(variants[0], EolAction::Trash);
assert_eq!(variants[1], EolAction::Delete);
assert!(variants.contains(&EolAction::Trash));
assert!(variants.contains(&EolAction::Delete));
}
#[test]
fn test_variants_completeness() {
let variants = EolAction::variants();
for variant in variants {
let string_repr = variant.to_string();
let parsed = EolAction::parse(&string_repr);
assert_eq!(parsed, Some(*variant));
}
}
#[test]
fn test_hash_trait() {
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(EolAction::Trash, "safe");
map.insert(EolAction::Delete, "dangerous");
assert_eq!(map.get(&EolAction::Trash), Some(&"safe"));
assert_eq!(map.get(&EolAction::Delete), Some(&"dangerous"));
}
#[test]
fn test_round_trip_conversion() {
let actions = [EolAction::Trash, EolAction::Delete];
for action in actions {
let string_repr = action.to_string();
let parsed = EolAction::parse(&string_repr).expect("Should parse successfully");
assert_eq!(action, parsed);
assert_eq!(string_repr, parsed.to_string());
}
}
#[test]
fn test_safety_properties() {
assert!(
EolAction::Trash.is_reversible(),
"Trash should be reversible for safety"
);
assert!(
!EolAction::Delete.is_reversible(),
"Delete should be irreversible"
);
assert_eq!(
EolAction::default(),
EolAction::Trash,
"Default should be the safer option"
);
}
#[test]
fn test_string_case_insensitive_parsing() {
let test_cases = [
("trash", Some(EolAction::Trash)),
("TRASH", Some(EolAction::Trash)),
("Trash", Some(EolAction::Trash)),
("TrAsH", Some(EolAction::Trash)),
("delete", Some(EolAction::Delete)),
("DELETE", Some(EolAction::Delete)),
("Delete", Some(EolAction::Delete)),
("DeLeTe", Some(EolAction::Delete)),
("invalid", None),
("INVALID", None),
("", None),
];
for (input, expected) in test_cases {
assert_eq!(
EolAction::parse(input),
expected,
"Failed for input: '{input}'"
);
}
}
#[test]
fn test_practical_usage_scenarios() {
let config_value = "delete";
let action = EolAction::parse(config_value).unwrap_or_default();
assert_eq!(action, EolAction::Delete);
let invalid_config = "invalid_action";
let safe_action = EolAction::parse(invalid_config).unwrap_or_default();
assert_eq!(safe_action, EolAction::Trash);
let action = EolAction::Delete;
let log_message = format!("Executing {action} action");
assert_eq!(log_message, "Executing delete action");
let dangerous_action = EolAction::Delete;
if !dangerous_action.is_reversible() {
}
}
#[test]
fn test_error_handling_patterns() {
fn parse_with_error(input: &str) -> Result<EolAction, String> {
EolAction::parse(input)
.ok_or_else(|| format!("Invalid action: '{input}'. Valid options: trash, delete"))
}
assert!(parse_with_error("trash").is_ok());
assert!(parse_with_error("delete").is_ok());
let error = parse_with_error("invalid").unwrap_err();
assert!(error.contains("Invalid action: 'invalid'"));
assert!(error.contains("trash, delete"));
}
}