summaryrefslogtreecommitdiffstats
path: root/CLI/rust/src/game_of_life/opts.rs
blob: 9f612c113847657a4475f4836515d240649a8b22 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/// Clap validators module
///
/// Used for validating different CLI args (like width, height and delay)
/// Ref: https://docs.rs/clap/3.0.0-beta.2/clap/struct.Arg.html#method.validator
pub(crate) mod validators {
    use terminal_size::{terminal_size, Height, Width};

    /// Validator to check if width configuration can be used
    ///
    /// The maximum width allowed is the current terminal window width
    pub(crate) fn is_fitting_term_width(val: &str) -> Result<(), String> {
        let (Width(term_width), Height(_)) = terminal_size().unwrap();
        match val.parse::<u16>() {
            Ok(n) if n > 0 && n <= term_width => Ok(()),
            Ok(_) => Err(format!(
                "must be between 1 and {} (current terminal width)",
                term_width
            )),
            Err(e) => Err(e.to_string()),
        }
    }

    #[cfg(test)]
    mod is_fitting_term_width {
        use super::*;

        #[test]
        fn positive_value() {
            assert!(is_fitting_term_width("13").is_ok());
        }


        #[test]
        fn value_too_large() {
            assert!(is_fitting_term_width("1337").is_err());
        }

        #[test]
        fn negative_value() {
            assert!(is_fitting_term_width("-13").is_err());
        }

        #[test]
        fn string_value() {
            assert!(is_fitting_term_width("not a number").is_err());
        }
    }

    /// Validator to check if height configuration can be used
    ///
    /// The maximum height allowed is the current terminal window height - 2
    /// The last 2 lines are used for status reporting (seed/input) and space
    /// for ease of use
    pub(crate) fn is_fitting_term_height(val: &str) -> Result<(), String> {
        let (Width(_), Height(term_height)) = terminal_size().unwrap();
        let term_height = term_height - 2;
        match val.parse::<u16>() {
            Ok(n) if n > 0 && n <= term_height => Ok(()),
            Ok(_) => Err(format!(
                "must be between 1 and {} (current terminal height)",
                term_height
            )),
            Err(e) => Err(e.to_string()),
        }
    }

    #[cfg(test)]
    mod is_fitting_term_height {
        use super::*;

        #[test]
        fn positive_value() {
            assert!(is_fitting_term_height("13").is_ok());
        }


        #[test]
        fn value_too_large() {
            assert!(is_fitting_term_height("1337").is_err());
        }

        #[test]
        fn negative_value() {
            assert!(is_fitting_term_height("-13").is_err());
        }

        #[test]
        fn string_value() {
            assert!(is_fitting_term_height("not a number").is_err());
        }
    }

    /// Validator to check if delay value is positive
    pub(crate) fn is_positive(val: &str) -> Result<(), String> {
        match val.parse::<i16>() {
            Ok(n) if n.is_positive() => Ok(()),
            Ok(_) => Err(String::from("must be postive value (so far)")),
            Err(e) => Err(e.to_string()),
        }
    }

    #[cfg(test)]
    mod is_positive {
        use super::*;

        #[test]
        fn positive_value() {
            assert!(is_positive("1337").is_ok());
        }

        #[test]
        fn negative_value() {
            assert!(is_positive("-1337").is_err());
        }

        #[test]
        fn string_value() {
            assert!(is_positive("not a number").is_err());
        }
    }
}