1use std::collections::HashMap;
32
33#[derive(Debug)]
34pub struct URLBuilder {
35 protocol: String,
36 host: String,
37 port: u16,
38 params: HashMap<String, String>,
39 routes: Vec<String>,
40}
41
42impl Default for URLBuilder {
43 fn default() -> Self {
44 Self::new()
45 }
46}
47
48impl URLBuilder {
49 pub fn new() -> URLBuilder {
59 URLBuilder {
60 protocol: String::new(),
61 host: String::new(),
62 port: 0,
63 params: HashMap::new(),
64 routes: Vec::new(),
65 }
66 }
67
68 pub fn build(self) -> String {
88 let base = format!("{}://{}", self.protocol, self.host);
89
90 let mut url_params = String::new();
91 let mut routes = String::new();
92
93 for route in self.routes {
94 routes.push_str(format!("/{}", route).as_str());
95 }
96
97 if !self.params.is_empty() {
98 url_params.push('?');
99
100 for (param, value) in self.params.iter() {
101 url_params.push_str(format!("{}={}&", param, value).as_str());
102 }
103
104 url_params.pop();
106 }
107
108 match self.port {
109 0 => format!("{}{}{}", base, routes, url_params),
110 _ => format!("{}:{}{}{}", base, self.port, routes, url_params),
111 }
112 }
113
114 pub fn add_param(&mut self, param: &str, value: &str) -> &mut Self {
116 self.params.insert(param.to_string(), value.to_string());
117
118 self
119 }
120
121 pub fn set_protocol(&mut self, protocol: &str) -> &mut Self {
123 self.protocol = protocol.to_string();
124
125 self
126 }
127
128 pub fn set_host(&mut self, host: &str) -> &mut Self {
130 self.host = host.to_string();
131
132 self
133 }
134
135 pub fn set_port(&mut self, port: u16) -> &mut Self {
137 self.port = port;
138
139 self
140 }
141
142 pub fn add_route(&mut self, route: &str) -> &mut Self {
144 self.routes.push(route.to_owned());
145
146 self
147 }
148
149 pub fn port(&self) -> u16 {
150 self.port
151 }
152
153 pub fn host(&self) -> &str {
154 &self.host
155 }
156
157 pub fn protocol(&self) -> &str {
158 &self.protocol
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_set_host() {
168 let mut ub = URLBuilder::new();
169 ub.set_host("localhost");
170 assert_eq!("localhost", ub.host());
171 }
172
173 #[test]
174 fn test_set_protocol() {
175 let mut ub = URLBuilder::new();
176 ub.set_protocol("https");
177 assert_eq!("https", ub.protocol());
178 }
179
180 #[test]
181 fn test_set_port() {
182 let mut ub = URLBuilder::new();
183 ub.set_port(8000);
184 assert_eq!(8000, ub.port());
185 }
186
187 #[test]
188 fn create_google_url() {
189 let mut ub = URLBuilder::new();
190 ub.set_protocol("http")
191 .set_host("www.google.com")
192 .set_port(80);
193 let url = ub.build();
194 assert_eq!("http://www.google.com:80", url);
195 }
196
197 #[test]
198 fn create_url_without_port() {
199 let mut ub = URLBuilder::new();
200 ub.set_protocol("http").set_host("google.com");
201 let url = ub.build();
202 assert_eq!("http://google.com", url)
203 }
204
205 #[test]
206 fn create_url_without_port_and_params() {
207 let mut ub = URLBuilder::new();
208 ub.set_protocol("http")
209 .set_host("google.com")
210 .add_param("gcookie", "0xcafe");
211 let url = ub.build();
212 assert_eq!("http://google.com?gcookie=0xcafe", url)
213 }
214
215 #[test]
216 fn create_url_without_port_and_multiple_params() {
217 let mut ub = URLBuilder::new();
218 ub.set_protocol("http")
219 .set_host("google.com")
220 .add_param("gcookie", "0xcafe")
221 .add_param("search", "rust")
222 .add_param("locale", "en-gb");
223 let url = ub.build();
224 assert!(url.contains("gcookie=0xcafe"));
225 assert!(url.contains("search=rust"));
226 assert!(url.contains("locale=en-gb"));
227 }
228
229 #[test]
230 fn create_url_with_routes() {
231 let mut ub = URLBuilder::new();
232 ub.set_protocol("http")
233 .set_host("google.com")
234 .add_route("mail");
235 let url = ub.build();
236 assert_eq!("http://google.com/mail", url)
237 }
238
239 #[test]
240 fn create_url_with_params() {
241 let mut ub = URLBuilder::new();
242 ub.set_protocol("http")
243 .set_host("localhost")
244 .set_port(8000)
245 .add_param("first", "1")
246 .add_param("second", "2")
247 .add_param("third", "3");
248
249 let url = ub.build();
250 assert!(url.contains("first=1"));
251 assert!(url.contains("second=2"));
252 assert!(url.contains("third=3"));
253 }
254
255 #[test]
256 fn create_url_with_ports_routes_and_params() {
257 let mut ub = URLBuilder::new();
258 ub.set_protocol("http")
259 .set_host("localhost")
260 .set_port(8000)
261 .add_route("query")
262 .add_route("chains")
263 .add_param("first", "1")
264 .add_param("second", "2")
265 .add_param("third", "3");
266
267 let url = ub.build();
268 assert!(url.contains("/query"));
269 assert!(url.contains("/chains"));
270 assert!(url.contains("/query/chains"));
271 assert!(url.contains("first=1"));
272 assert!(url.contains("second=2"));
273 assert!(url.contains("third=3"));
274 }
275}