cron_when/cli/dispatch/
mod.rs

1use crate::cli::actions::Action;
2use anyhow::Result;
3use clap::ArgMatches;
4use std::env;
5use std::path::PathBuf;
6
7/// Convert ArgMatches into an Action
8pub fn handler(matches: &ArgMatches) -> Result<Action> {
9    // Determine verbosity level
10    let verbose = matches.get_count("verbose") > 0;
11
12    // Extract next count if provided
13    let next = matches.get_one::<u32>("next").copied();
14
15    // Extract color flag - check CLI flag first, then environment variable
16    let color = matches.get_flag("color")
17        || env::var("CRON_WHEN_COLOR")
18            .map(|v| v == "1")
19            .unwrap_or(false);
20
21    // Check which mode was requested
22    if matches.get_flag("crontab") {
23        Ok(Action::Crontab { verbose, color })
24    } else if let Some(file_path) = matches.get_one::<String>("file") {
25        Ok(Action::File {
26            path: PathBuf::from(file_path),
27            verbose,
28            color,
29        })
30    } else if let Some(expression) = matches.get_one::<String>("cron") {
31        Ok(Action::Single {
32            expression: expression.clone(),
33            verbose,
34            next,
35            color,
36        })
37    } else {
38        anyhow::bail!(
39            "Please provide a cron expression, use --file, or use --crontab\n\
40             Run with --help for usage information"
41        )
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::cli::commands;
49
50    #[test]
51    fn test_handler_single() {
52        let matches = commands::new().get_matches_from(vec!["cron-when", "*/5 * * * *"]);
53        let action = handler(&matches).unwrap();
54        assert!(matches!(action, Action::Single { .. }));
55    }
56
57    #[test]
58    fn test_handler_file() {
59        let matches = commands::new().get_matches_from(vec!["cron-when", "-f", "test.crontab"]);
60        let action = handler(&matches).unwrap();
61        assert!(matches!(action, Action::File { .. }));
62    }
63
64    #[test]
65    fn test_handler_crontab() {
66        let matches = commands::new().get_matches_from(vec!["cron-when", "--crontab"]);
67        let action = handler(&matches).unwrap();
68        assert!(matches!(
69            action,
70            Action::Crontab {
71                verbose: false,
72                color: false
73            }
74        ));
75    }
76
77    #[test]
78    fn test_handler_verbose() {
79        let matches = commands::new().get_matches_from(vec!["cron-when", "-v", "*/5 * * * *"]);
80        let action = handler(&matches).unwrap();
81        if let Action::Single { verbose, .. } = action {
82            assert!(verbose);
83        } else {
84            panic!("Expected Single action");
85        }
86    }
87
88    #[test]
89    fn test_handler_no_args() {
90        let matches = commands::new().get_matches_from(vec!["cron-when"]);
91        let result = handler(&matches);
92        assert!(result.is_err());
93    }
94
95    #[test]
96    fn test_handler_next() {
97        let matches =
98            commands::new().get_matches_from(vec!["cron-when", "--next", "5", "*/5 * * * *"]);
99        let action = handler(&matches).unwrap();
100        if let Action::Single { next, .. } = action {
101            assert_eq!(next, Some(5));
102        } else {
103            panic!("Expected Single action");
104        }
105    }
106}