unity_version/version/
release_type.rs

1use serde::{Deserialize, Serialize};
2use std::{cmp::Ordering, fmt, str::FromStr};
3use thiserror::Error;
4
5#[derive(PartialEq, Eq, Ord, Hash, Debug, Clone, Copy, Serialize, Deserialize)]
6#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
7pub enum ReleaseType {
8    Alpha,
9    Beta,
10    Patch,
11    Final,
12}
13
14impl PartialOrd for ReleaseType {
15    fn partial_cmp(&self, other: &ReleaseType) -> Option<Ordering> {
16        Some(self.cmp(other))
17    }
18}
19
20impl fmt::Display for ReleaseType {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        if f.alternate() {
23            match *self {
24                ReleaseType::Final => write!(f, "final"),
25                ReleaseType::Patch => write!(f, "patch"),
26                ReleaseType::Beta => write!(f, "beta"),
27                ReleaseType::Alpha => write!(f, "alpha"),
28            }
29        } else {
30            match *self {
31                ReleaseType::Final => write!(f, "f"),
32                ReleaseType::Patch => write!(f, "p"),
33                ReleaseType::Beta => write!(f, "b"),
34                ReleaseType::Alpha => write!(f, "a"),
35            }
36        }
37    }
38}
39
40impl Default for ReleaseType {
41    fn default() -> ReleaseType {
42        ReleaseType::Final
43    }
44}
45
46#[derive(Debug, Error, PartialEq)]
47pub enum ReleaseTypeError {
48    #[error("Unknown release type: {0}")]
49    UnknownType(String),
50
51    #[error("Invalid release type character: {0}")]
52    InvalidCharacter(char),
53}
54
55impl FromStr for ReleaseType {
56    type Err = ReleaseTypeError;
57
58    fn from_str(s: &str) -> Result<Self, Self::Err> {
59        match s {
60            "a" => Ok(ReleaseType::Alpha),
61            "b" => Ok(ReleaseType::Beta),
62            "p" => Ok(ReleaseType::Patch),
63            "f" => Ok(ReleaseType::Final),
64            _ => Err(ReleaseTypeError::UnknownType(s.to_string())),
65        }
66    }
67}
68
69impl TryFrom<char> for ReleaseType {
70    type Error = ReleaseTypeError;
71
72    fn try_from(value: char) -> Result<Self, Self::Error> {
73        match value {
74            'f' => Ok(ReleaseType::Final),
75            'b' => Ok(ReleaseType::Beta),
76            'a' => Ok(ReleaseType::Alpha),
77            'p' => Ok(ReleaseType::Patch),
78            _ => Err(ReleaseTypeError::InvalidCharacter(value)),
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    use proptest::prelude::*;
88
89    #[test]
90    fn should_return_final_when_given_f_as_input() {
91        let result = ReleaseType::try_from('f');
92        assert_eq!(result, Ok(ReleaseType::Final));
93    }
94    #[test]
95    fn should_return_alpha_when_given_a_as_input() {
96        let result = ReleaseType::try_from('a');
97        assert_eq!(result, Ok(ReleaseType::Alpha));
98    }
99    #[test]
100    fn should_return_beta_when_given_b_as_input() {
101        let result = ReleaseType::try_from('b');
102        assert_eq!(result, Ok(ReleaseType::Beta));
103    }
104    #[test]
105    fn should_return_patch_when_given_p_as_input() {
106        let result = ReleaseType::try_from('p');
107        assert_eq!(result, Ok(ReleaseType::Patch));
108    }
109    #[test]
110    fn should_return_error_when_given_empty_input() {
111        let result = ReleaseType::try_from(' ');
112        assert_eq!(result, Err(ReleaseTypeError::InvalidCharacter(' ')));
113    }
114
115    #[test]
116    fn should_return_correct_to_string_value() {
117        assert_eq!(ReleaseType::Final.to_string(), "f");
118        assert_eq!(ReleaseType::Patch.to_string(), "p");
119        assert_eq!(ReleaseType::Alpha.to_string(), "a");
120        assert_eq!(ReleaseType::Beta.to_string(), "b");
121    }
122    #[test]
123    fn should_format_using_correct_alternative_format() {
124        assert_eq!(&format!("{:#}", ReleaseType::Final), "final");
125        assert_eq!(&format!("{:#}", ReleaseType::Patch), "patch");
126        assert_eq!(&format!("{:#}", ReleaseType::Beta), "beta");
127        assert_eq!(&format!("{:#}", ReleaseType::Alpha), "alpha");
128    }
129
130    proptest! {
131        #[test]
132        fn from_str_does_not_crash(s in "\\PC*") {
133            let _r = ReleaseType::from_str(&s);
134        }
135
136        #[test]
137        fn from_str_supports_all_valid_cases(s in "(a|b|f|p)") {
138            ReleaseType::from_str(&s).unwrap();
139        }
140    }
141}