torrust_tracker_deployer_lib/domain/tracker/
protocol.rs1use std::fmt;
7use std::str::FromStr;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub enum Protocol {
28 Udp,
30 Tcp,
32}
33
34#[derive(Debug, Clone, PartialEq)]
36pub enum ProtocolParseError {
37 UnknownProtocol(String),
39}
40
41impl fmt::Display for Protocol {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::Udp => write!(f, "UDP"),
45 Self::Tcp => write!(f, "TCP"),
46 }
47 }
48}
49
50impl FromStr for Protocol {
51 type Err = ProtocolParseError;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 match s.to_uppercase().as_str() {
55 "UDP" => Ok(Self::Udp),
56 "TCP" => Ok(Self::Tcp),
57 _ => Err(ProtocolParseError::UnknownProtocol(s.to_string())),
58 }
59 }
60}
61
62impl fmt::Display for ProtocolParseError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 Self::UnknownProtocol(proto) => {
66 write!(f, "Unknown protocol: '{proto}'. Expected 'UDP' or 'TCP'")
67 }
68 }
69 }
70}
71
72impl std::error::Error for ProtocolParseError {}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 mod protocol_enum {
79 use super::*;
80
81 #[test]
82 fn it_should_display_udp_as_uppercase_string() {
83 assert_eq!(Protocol::Udp.to_string(), "UDP");
84 }
85
86 #[test]
87 fn it_should_display_tcp_as_uppercase_string() {
88 assert_eq!(Protocol::Tcp.to_string(), "TCP");
89 }
90
91 #[test]
92 fn it_should_parse_udp_from_uppercase_string() {
93 assert_eq!("UDP".parse::<Protocol>().unwrap(), Protocol::Udp);
94 }
95
96 #[test]
97 fn it_should_parse_udp_from_lowercase_string() {
98 assert_eq!("udp".parse::<Protocol>().unwrap(), Protocol::Udp);
99 }
100
101 #[test]
102 fn it_should_parse_udp_from_mixed_case_string() {
103 assert_eq!("Udp".parse::<Protocol>().unwrap(), Protocol::Udp);
104 }
105
106 #[test]
107 fn it_should_parse_tcp_from_uppercase_string() {
108 assert_eq!("TCP".parse::<Protocol>().unwrap(), Protocol::Tcp);
109 }
110
111 #[test]
112 fn it_should_parse_tcp_from_lowercase_string() {
113 assert_eq!("tcp".parse::<Protocol>().unwrap(), Protocol::Tcp);
114 }
115
116 #[test]
117 fn it_should_parse_tcp_from_mixed_case_string() {
118 assert_eq!("Tcp".parse::<Protocol>().unwrap(), Protocol::Tcp);
119 }
120
121 #[test]
122 fn it_should_return_error_when_parsing_unknown_protocol() {
123 let result = "HTTP".parse::<Protocol>();
124 assert!(result.is_err());
125 assert_eq!(
126 result.unwrap_err(),
127 ProtocolParseError::UnknownProtocol("HTTP".to_string())
128 );
129 }
130
131 #[test]
132 fn it_should_return_error_when_parsing_empty_string() {
133 let result = "".parse::<Protocol>();
134 assert!(result.is_err());
135 assert_eq!(
136 result.unwrap_err(),
137 ProtocolParseError::UnknownProtocol(String::new())
138 );
139 }
140
141 #[test]
142 fn it_should_be_equal_when_same_protocol() {
143 assert_eq!(Protocol::Udp, Protocol::Udp);
144 assert_eq!(Protocol::Tcp, Protocol::Tcp);
145 }
146
147 #[test]
148 fn it_should_not_be_equal_when_different_protocols() {
149 assert_ne!(Protocol::Udp, Protocol::Tcp);
150 }
151
152 #[test]
153 fn it_should_be_hashable() {
154 use std::collections::HashSet;
155
156 let mut set = HashSet::new();
157 set.insert(Protocol::Udp);
158 set.insert(Protocol::Tcp);
159 set.insert(Protocol::Udp); assert_eq!(set.len(), 2); }
163 }
164
165 mod protocol_parse_error {
166 use super::*;
167
168 #[test]
169 fn it_should_display_helpful_error_message_for_unknown_protocol() {
170 let error = ProtocolParseError::UnknownProtocol("HTTP".to_string());
171 assert_eq!(
172 error.to_string(),
173 "Unknown protocol: 'HTTP'. Expected 'UDP' or 'TCP'"
174 );
175 }
176 }
177}