gitignore_template_generator/http_client/
api.rs1use crate::ProgramExit;
2pub use crate::http_client::impls::{
3 MockEndpointHttpClient, MockHttpClient, UreqHttpClient,
4};
5
6pub trait HttpClient {
8 fn get(&self, url: &str) -> Result<String, ProgramExit>;
18}
19
20#[cfg(test)]
21mod tests {
22 use mockito::Server;
23
24 use super::*;
25 use crate::{ExitKind, constant};
26
27 mod ureq_client {
28 use super::*;
29
30 mod get {
31 use super::*;
32
33 mod success {
34 use super::*;
35
36 #[test]
37 fn it_fetches_data_as_string_when_200_response() {
38 let mut mock_server = Server::new();
39 let mock_body = "gitignore template for rust";
40 let mock_uri = "/api/rust";
41 let mock = mock_server
42 .mock("GET", mock_uri)
43 .with_status(200)
44 .with_body(mock_body)
45 .create();
46
47 let server_url = mock_server.url();
48 let http_client = UreqHttpClient::default();
49
50 let actual =
51 http_client.get(&format!("{server_url}{mock_uri}"));
52 let expected: Result<String, ProgramExit> =
53 Ok(String::from(mock_body));
54
55 mock.assert();
56 assert_eq!(actual, expected);
57 }
58
59 #[test]
60 fn it_fetches_data_as_string_from_given_server_url_when_200() {
61 let mut mock_server = Server::new();
62 let mock_body = "gitignore template for rust";
63 let mock_uri = "/api/rust";
64 let mock = mock_server
65 .mock("GET", mock_uri)
66 .with_status(200)
67 .with_body(mock_body)
68 .create();
69
70 let server_url = mock_server.url();
71 let http_client = UreqHttpClient { server_url };
72
73 let actual = http_client.get(mock_uri);
74 let expected: Result<String, ProgramExit> =
75 Ok(String::from(mock_body));
76
77 mock.assert();
78 assert_eq!(actual, expected);
79 }
80 }
81
82 mod failure {
83 use super::*;
84
85 #[test]
86 fn it_fails_with_api_call_error_when_400_response() {
87 let mut mock_server = Server::new();
88 let mock_body = "error response";
89 let mock_uri = "/api/rust";
90 let mock = mock_server
91 .mock("GET", mock_uri)
92 .with_status(400)
93 .with_body(mock_body)
94 .create();
95
96 let server_url = mock_server.url();
97 let http_client = UreqHttpClient::default();
98
99 let actual =
100 http_client.get(&format!("{server_url}{mock_uri}"));
101 let expected: Result<String, ProgramExit> =
102 Err(ProgramExit {
103 message: constant::error_messages::API_CALL_FAILURE
104 .replace(
105 "{error}",
106 constant::error_messages::HTTP_400,
107 ),
108 exit_status: constant::exit_status::GENERIC,
109 styled_message: None,
110 kind: ExitKind::Error,
111 });
112
113 mock.assert();
114 assert_eq!(actual, expected);
115 }
116
117 #[test]
118 fn it_fails_with_body_parsing_error_when_invalid_body() {
119 let mut mock_server = Server::new();
120 let mock_body = vec![0, 159, 146, 150];
121 let mock_uri = "/api/rust";
122 let mock = mock_server
123 .mock("GET", mock_uri)
124 .with_status(200)
125 .with_body(mock_body)
126 .create();
127
128 let server_url = mock_server.url();
129 let http_client = UreqHttpClient::default();
130
131 let actual =
132 http_client.get(&format!("{server_url}{mock_uri}"));
133 let expected: Result<String, ProgramExit> =
134 Err(ProgramExit {
135 message: String::from(
136 constant::error_messages::BODY_PARSING_ISSUE,
137 ),
138 exit_status:
139 constant::exit_status::BODY_PARSING_ISSUE,
140 styled_message: None,
141 kind: ExitKind::Error,
142 });
143
144 mock.assert();
145 assert_eq!(actual, expected);
146 }
147 }
148 }
149 }
150
151 mod mock_client {
152 use super::*;
153
154 mod get {
155 use super::*;
156
157 mod success {
158 use super::*;
159
160 #[test]
161 fn it_returns_ok_mocked_response() {
162 let result_content = "success response";
163 let http_client = MockHttpClient {
164 response: Ok(String::from(result_content)),
165 };
166
167 let actual = http_client.get("/api/rust");
168 let expected: Result<String, ProgramExit> =
169 Ok(String::from(result_content));
170
171 assert_eq!(actual, expected);
172 }
173
174 #[test]
175 fn it_returns_error_mocked_response() {
176 let result_content = "error response";
177 let http_client = MockHttpClient {
178 response: Err(ProgramExit {
179 message: String::from(result_content),
180 exit_status: constant::exit_status::GENERIC,
181 styled_message: None,
182 kind: ExitKind::Error,
183 }),
184 };
185
186 let actual = http_client.get("/api/rust");
187 let expected: Result<String, ProgramExit> =
188 Err(ProgramExit {
189 message: String::from(result_content),
190 exit_status: constant::exit_status::GENERIC,
191 styled_message: None,
192 kind: ExitKind::Error,
193 });
194
195 assert_eq!(actual, expected);
196 }
197 }
198 }
199 }
200
201 mod mock_endpoint_http_client {
202 use super::*;
203
204 mod get {
205 use super::*;
206
207 mod success {
208 use std::collections::HashMap;
209
210 use super::*;
211
212 #[test]
213 fn it_returns_ok_mocked_response_for_given_url() {
214 let rust_result_content = "success rust response";
215 let python_result_content = "success python response";
216 let http_client = MockEndpointHttpClient {
217 response: HashMap::from([
218 (
219 "/api/rust",
220 Ok(String::from(rust_result_content)),
221 ),
222 (
223 "/api/python",
224 Ok(String::from(python_result_content)),
225 ),
226 ]),
227 };
228
229 let actual = http_client.get("/api/rust");
230 let expected: Result<String, ProgramExit> =
231 Ok(String::from(rust_result_content));
232
233 assert_eq!(actual, expected);
234 }
235
236 #[test]
237 fn it_returns_error_mocked_response_for_given_url() {
238 let rust_result_content = "success rust response";
239 let python_result_content = "success python response";
240 let http_client = MockEndpointHttpClient {
241 response: HashMap::from([
242 (
243 "/api/rust",
244 Err(ProgramExit {
245 message: String::from(rust_result_content),
246 exit_status: constant::exit_status::GENERIC,
247 styled_message: None,
248 kind: ExitKind::Error,
249 }),
250 ),
251 (
252 "/api/python",
253 Err(ProgramExit {
254 message: String::from(
255 python_result_content,
256 ),
257 exit_status: constant::exit_status::GENERIC,
258 styled_message: None,
259 kind: ExitKind::Error,
260 }),
261 ),
262 ]),
263 };
264
265 let actual = http_client.get("/api/python");
266 let expected: Result<String, ProgramExit> =
267 Err(ProgramExit {
268 message: String::from(python_result_content),
269 exit_status: constant::exit_status::GENERIC,
270 styled_message: None,
271 kind: ExitKind::Error,
272 });
273
274 assert_eq!(actual, expected);
275 }
276 }
277 }
278 }
279}