uptrakit_web_api_types/
registration.rs1use serde::{Deserialize, Serialize};
2use std::str::FromStr;
3use thiserror::Error;
4
5#[non_exhaustive]
7#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
8#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
9#[cfg_attr(test, derive(strum::EnumIter))]
10#[serde(rename_all = "snake_case")]
11pub enum RegistrationMode {
12 Open,
14 Invite,
16 Closed,
18}
19
20impl RegistrationMode {
21 pub fn as_str(&self) -> &'static str {
22 match self {
23 Self::Open => "open",
24 Self::Invite => "invite",
25 Self::Closed => "closed",
26 }
27 }
28}
29
30impl std::fmt::Display for RegistrationMode {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.write_str(self.as_str())
33 }
34}
35
36#[derive(Debug, Error)]
37#[error("invalid registration mode value")]
38pub struct ParseRegistrationModeError;
39
40impl FromStr for RegistrationMode {
41 type Err = ParseRegistrationModeError;
42
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 match s {
45 "open" => Ok(Self::Open),
46 "invite" => Ok(Self::Invite),
47 "closed" => Ok(Self::Closed),
48 _ => Err(ParseRegistrationModeError),
49 }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 #![expect(
56 clippy::assertions_on_result_states,
57 reason = "test assertions — is_ok/is_err provides readable failure messages"
58 )]
59 use super::*;
60 use strum::IntoEnumIterator;
61
62 #[test]
65 fn serde_round_trip_all_variants() {
66 for mode in RegistrationMode::iter() {
67 let json = serde_json::to_string(&mode).expect("serialization should succeed");
68 let deserialized: RegistrationMode =
69 serde_json::from_str(&json).expect("deserialization should succeed");
70 assert_eq!(deserialized, mode);
71 }
72 }
73
74 #[test]
75 fn serde_serializes_as_snake_case_strings() {
76 assert_eq!(
77 serde_json::to_string(&RegistrationMode::Open).expect("serialization should succeed"),
78 r#""open""#
79 );
80 assert_eq!(
81 serde_json::to_string(&RegistrationMode::Invite).expect("serialization should succeed"),
82 r#""invite""#
83 );
84 assert_eq!(
85 serde_json::to_string(&RegistrationMode::Closed).expect("serialization should succeed"),
86 r#""closed""#
87 );
88 }
89
90 #[test]
91 fn serde_rejects_unknown_variant() {
92 let result = serde_json::from_str::<RegistrationMode>(r#""disabled""#);
93 assert!(result.is_err());
94 }
95
96 #[test]
97 fn serde_rejects_uppercase_variant() {
98 let result = serde_json::from_str::<RegistrationMode>(r#""Open""#);
99 assert!(result.is_err());
100 }
101
102 #[test]
105 fn display_open() {
106 assert_eq!(format!("{}", RegistrationMode::Open), "open");
107 }
108
109 #[test]
110 fn display_invite() {
111 assert_eq!(format!("{}", RegistrationMode::Invite), "invite");
112 }
113
114 #[test]
115 fn display_closed() {
116 assert_eq!(format!("{}", RegistrationMode::Closed), "closed");
117 }
118
119 #[test]
120 fn display_matches_as_str_for_all_variants() {
121 for mode in RegistrationMode::iter() {
122 assert_eq!(format!("{mode}"), mode.as_str());
123 }
124 }
125
126 #[test]
129 fn from_str_open() {
130 let parsed: RegistrationMode = "open".parse().expect("should parse 'open'");
131 assert_eq!(parsed, RegistrationMode::Open);
132 }
133
134 #[test]
135 fn from_str_invite() {
136 let parsed: RegistrationMode = "invite".parse().expect("should parse 'invite'");
137 assert_eq!(parsed, RegistrationMode::Invite);
138 }
139
140 #[test]
141 fn from_str_closed() {
142 let parsed: RegistrationMode = "closed".parse().expect("should parse 'closed'");
143 assert_eq!(parsed, RegistrationMode::Closed);
144 }
145
146 #[test]
147 fn from_str_round_trips_through_as_str() {
148 for mode in RegistrationMode::iter() {
149 let s = mode.as_str();
150 let parsed: RegistrationMode = s
151 .parse()
152 .expect("from_str should succeed for as_str output");
153 assert_eq!(parsed, mode);
154 }
155 }
156
157 #[test]
160 fn from_str_empty_string_fails() {
161 assert!("".parse::<RegistrationMode>().is_err());
162 }
163
164 #[test]
165 fn from_str_uppercase_fails() {
166 assert!("OPEN".parse::<RegistrationMode>().is_err());
167 assert!("Open".parse::<RegistrationMode>().is_err());
168 }
169
170 #[test]
171 fn from_str_unknown_value_fails() {
172 assert!("disabled".parse::<RegistrationMode>().is_err());
173 assert!("public".parse::<RegistrationMode>().is_err());
174 }
175
176 #[test]
177 fn from_str_whitespace_fails() {
178 assert!(" open".parse::<RegistrationMode>().is_err());
179 assert!("open ".parse::<RegistrationMode>().is_err());
180 }
181
182 #[test]
185 fn parse_error_display_message() {
186 let err = ParseRegistrationModeError;
187 assert_eq!(err.to_string(), "invalid registration mode value");
188 }
189}