Skip to main content

mabi_cli/
validation.rs

1//! Reusable CLI argument validators.
2//!
3//! Provides `value_parser` compatible functions for clap argument validation.
4//! Each validator returns `Result<T, String>` as required by clap.
5
6/// Validates that a port number is within the usable range (1–65535).
7///
8/// Port 0 is rejected because it causes OS-assigned ephemeral port binding,
9/// which is not meaningful for a simulator that clients need to connect to.
10pub fn parse_port(s: &str) -> Result<u16, String> {
11    let port: u16 = s
12        .parse()
13        .map_err(|_| format!("'{s}' is not a valid port number"))?;
14    if port == 0 {
15        return Err("port must be between 1 and 65535 (port 0 is not allowed)".to_string());
16    }
17    Ok(port)
18}
19
20/// Validates that a count value is at least 1.
21///
22/// Zero-count resources (devices, objects, nodes, groups) produce a server
23/// with nothing to simulate, which is almost certainly a user mistake.
24pub fn parse_nonzero_count(s: &str) -> Result<usize, String> {
25    let n: usize = s
26        .parse()
27        .map_err(|_| format!("'{s}' is not a valid number"))?;
28    if n == 0 {
29        return Err("value must be at least 1".to_string());
30    }
31    Ok(n)
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_parse_port_valid() {
40        assert_eq!(parse_port("1").unwrap(), 1);
41        assert_eq!(parse_port("3671").unwrap(), 3671);
42        assert_eq!(parse_port("65535").unwrap(), 65535);
43    }
44
45    #[test]
46    fn test_parse_port_zero_rejected() {
47        assert!(parse_port("0").is_err());
48    }
49
50    #[test]
51    fn test_parse_port_invalid_string() {
52        assert!(parse_port("abc").is_err());
53        assert!(parse_port("-1").is_err());
54        assert!(parse_port("99999").is_err());
55    }
56
57    #[test]
58    fn test_parse_nonzero_count_valid() {
59        assert_eq!(parse_nonzero_count("1").unwrap(), 1);
60        assert_eq!(parse_nonzero_count("50000").unwrap(), 50000);
61    }
62
63    #[test]
64    fn test_parse_nonzero_count_zero_rejected() {
65        assert!(parse_nonzero_count("0").is_err());
66    }
67
68    #[test]
69    fn test_parse_nonzero_count_invalid() {
70        assert!(parse_nonzero_count("abc").is_err());
71        assert!(parse_nonzero_count("-1").is_err());
72    }
73}