1use clap::Parser;
2
3#[derive(Parser, Debug, Clone)]
4#[command(version, about, long_about = None)]
5pub struct Cli {
6 #[arg(short = 'D', long, conflicts_with_all = ["config_file"])]
7 pub device_name: Option<String>,
8 #[arg(short = 'N', long, conflicts_with_all = ["config_file"])]
9 pub number_packages: Option<u64>,
10 #[arg(short = 'B', long, conflicts_with_all = ["config_file"])]
11 pub buffer_size: Option<i32>,
12 #[arg(short = 'C', long, conflicts_with_all = ["device_name", "number_packages", "buffer_size"])]
13 pub config_file: Option<String>,
14 #[arg(short = 'O', long, default_value = "output", conflicts_with_all = ["config_file"])]
15 pub output_directory: Option<String>,
16}
17
18impl Cli {
19 pub fn is_config_missing(&self) -> bool {
20 self.config_file.is_none() &&
21 (
22 self.buffer_size.is_none() ||
23 self.device_name.is_none() ||
24 self.number_packages.is_none()
25 )
26 }
27
28 pub fn missing_fields_message(&self) -> String {
29 let mut missing_fields = Vec::new();
30
31 if self.buffer_size.is_none() {
32 missing_fields.push("buffer_size");
33 }
34 if self.device_name.is_none() {
35 missing_fields.push("device_name");
36 }
37 if self.number_packages.is_none() {
38 missing_fields.push("number_packages");
39 }
40
41 format!("Missing fields: {}. Provide a path to a valid config file or command line arguments for net-agent.\nYou can use config_file to set all these arguments.\nSee --help",
42 missing_fields.join(", "))
43 }
44}
45
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn test_cli_default_values() {
53 let cli = Cli::parse_from(&["test"]);
54
55 assert_eq!(cli.device_name, None);
56 assert_eq!(cli.number_packages, None);
57 assert_eq!(cli.buffer_size, None);
58 assert_eq!(cli.config_file, None);
59 assert_eq!(cli.output_directory, Some("output".to_string()));
60 }
61
62 #[test]
63 fn test_cli_custom_values_long() {
64 let cli = Cli::parse_from(&["test", "--device-name", "eth0", "--number-packages", "100", "--buffer-size", "1024", "--output-directory", "my-output"]);
65
66 assert_eq!(cli.device_name, Some("eth0".to_string()));
67 assert_eq!(cli.number_packages, Some(100));
68 assert_eq!(cli.buffer_size, Some(1024));
69 assert_eq!(cli.config_file, None);
70 assert_eq!(cli.output_directory, Some("my-output".to_string()));
71 }
72
73 #[test]
74 fn test_cli_custom_values_short() {
75 let cli = Cli::parse_from(&["test", "-D", "eth0", "-N", "100", "-B", "1024", "-O", "my-output"]);
76
77 assert_eq!(cli.device_name, Some("eth0".to_string()));
78 assert_eq!(cli.number_packages, Some(100));
79 assert_eq!(cli.buffer_size, Some(1024));
80 assert_eq!(cli.config_file, None);
81 assert_eq!(cli.output_directory, Some("my-output".to_string()));
82 }
83
84 #[test]
85 fn test_panic_lower_case_short() {
86 assert!(Cli::try_parse_from(&["test", "-d", "eth0", "-N", "100", "-B", "1024"]).is_err());
87 }
88
89 #[test]
90 fn test_cli_with_config_and_all_the_other_args() {
91 assert!(Cli::try_parse_from(&["test", "-D", "eth0", "-N", "100", "-B", "1024", "--config-file", "config.toml"]).is_err());
92 }
93
94 #[test]
95 fn test_cli_with_long_config() {
96 let cli = Cli::try_parse_from(&["test", "--config-file", "config.toml"]);
97 assert!(cli.is_ok());
98 let cli = cli.unwrap();
99 assert_eq!(cli.device_name, None);
100 assert_eq!(cli.number_packages, None);
101 assert_eq!(cli.buffer_size, None);
102 assert_eq!(cli.config_file, Some("config.toml".to_string()));
103 assert_eq!(cli.output_directory, Some("output".to_string()));
105 }
106
107 #[test]
108 fn test_cli_with_short_config() {
109 let cli = Cli::try_parse_from(&["test", "-C", "config.toml"]);
110 assert!(cli.is_ok());
111 let cli = cli.unwrap();
112 assert_eq!(cli.device_name, None);
113 assert_eq!(cli.number_packages, None);
114 assert_eq!(cli.buffer_size, None);
115 assert_eq!(cli.config_file, Some("config.toml".to_string()));
116 assert_eq!(cli.output_directory, Some("output".to_string()));
117 }
118}