chrome_for_testing/api/
channel.rs1use rootcause::{Report, report};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::fmt::{Debug, Display};
4use std::str::FromStr;
5
6#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
8#[error("Invalid channel: '{value}'. Channel names must not be empty.")]
9pub struct ParseChannelError {
10 value: String,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum Channel {
16 Stable,
18
19 Beta,
22
23 Dev,
26
27 Canary,
30
31 Other(String),
33}
34
35impl Serialize for Channel {
36 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37 where
38 S: Serializer,
39 {
40 serializer.serialize_str(self.as_str())
41 }
42}
43
44impl<'de> Deserialize<'de> for Channel {
45 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46 where
47 D: Deserializer<'de>,
48 {
49 String::deserialize(deserializer)?
50 .parse()
51 .map_err(serde::de::Error::custom)
52 }
53}
54
55impl Display for Channel {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(match self {
58 Channel::Stable => "Stable",
59 Channel::Beta => "Beta",
60 Channel::Dev => "Dev",
61 Channel::Canary => "Canary",
62 Channel::Other(name) => name,
63 })
64 }
65}
66
67impl FromStr for Channel {
68 type Err = Report<ParseChannelError>;
69
70 fn from_str(s: &str) -> Result<Self, Self::Err> {
71 match s {
72 "Stable" | "stable" => Ok(Channel::Stable),
73 "Beta" | "beta" => Ok(Channel::Beta),
74 "Dev" | "dev" => Ok(Channel::Dev),
75 "Canary" | "canary" => Ok(Channel::Canary),
76 "" => Err(report!(ParseChannelError {
77 value: s.to_owned(),
78 })),
79 name => Ok(Channel::Other(name.to_owned())),
80 }
81 }
82}
83
84impl Channel {
85 #[must_use]
88 pub fn is_known(&self) -> bool {
89 match self {
90 Channel::Stable | Channel::Beta | Channel::Dev | Channel::Canary => true,
91 Channel::Other(_) => false,
92 }
93 }
94
95 #[must_use]
97 pub fn as_str(&self) -> &str {
98 match self {
99 Channel::Stable => "Stable",
100 Channel::Beta => "Beta",
101 Channel::Dev => "Dev",
102 Channel::Canary => "Canary",
103 Channel::Other(name) => name,
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use assertr::prelude::*;
112
113 fn channels() -> [(&'static str, Channel); 10] {
114 [
115 ("Stable", Channel::Stable),
116 ("stable", Channel::Stable),
117 ("Beta", Channel::Beta),
118 ("beta", Channel::Beta),
119 ("Dev", Channel::Dev),
120 ("dev", Channel::Dev),
121 ("Canary", Channel::Canary),
122 ("canary", Channel::Canary),
123 ("Unknown", Channel::Other("Unknown".to_owned())),
124 ("unknown", Channel::Other("unknown".to_owned())),
125 ]
126 }
127
128 #[test]
129 fn parse_empty_string_fails() {
130 let err = "".parse::<Channel>().unwrap_err();
131
132 assert_that!(err.current_context()).is_equal_to(ParseChannelError {
133 value: String::new(),
134 });
135 }
136
137 #[test]
138 fn parse_channels() {
139 for (test, expected) in channels() {
140 assert_that!(test.parse::<Channel>())
141 .is_ok()
142 .is_equal_to(expected.clone());
143 }
144 }
145
146 #[test]
147 fn deserialize_channels() {
148 for (test, expected) in channels() {
149 assert_that!(serde_json::from_str::<Channel>(&format!(r#""{test}""#)))
150 .is_ok()
151 .is_equal_to(expected);
152 }
153 }
154
155 #[test]
156 fn serialized_channels() {
157 fn capitalize_first(s: &str) -> String {
158 s.chars()
159 .take(1)
160 .flat_map(|f| f.to_uppercase())
161 .chain(s.chars().skip(1))
162 .collect()
163 }
164
165 for (expected, channel) in channels() {
166 assert_that!(serde_json::to_string(&channel))
167 .is_ok()
168 .is_equal_to(format!(
169 r#""{}""#,
170 match channel {
171 Channel::Other(_) => expected.to_owned(),
172 _ => capitalize_first(expected),
173 }
174 ));
175 }
176 }
177}