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