gitignore_template_generator/http_client/
api.rs1pub use crate::http_client::impls::{MockClient, UreqClient};
2
3#[derive(Clone, PartialEq, Debug)]
4pub struct ProgramError {
5 pub message: String,
6 pub exit_status: i32,
7 pub styled_message: Option<String>,
8 pub error_kind: Option<ErrorKind>,
9}
10
11#[derive(Clone, PartialEq, Debug)]
12pub enum ErrorKind {
13 VersionInfos,
14 HelpInfos,
15 AuthorInfos,
16 Other,
17}
18
19pub trait HttpClient {
20 fn get(&self, url: &str) -> Result<String, ProgramError>;
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26 use crate::constant;
27 use mockito::Server;
28
29 mod ureq_client {
30 use super::*;
31
32 mod get {
33 use super::*;
34
35 mod success {
36 use super::*;
37
38 #[test]
39 fn it_fetches_data_as_string_when_200_response() {
40 let mut mock_server = Server::new();
41 let mock_body = "gitignore template for rust";
42 let mock_uri = "/api/rust";
43 let mock = mock_server
44 .mock("GET", mock_uri)
45 .with_status(200)
46 .with_body(mock_body)
47 .create();
48
49 let server_url = mock_server.url();
50 let http_client = UreqClient::default();
51
52 let actual =
53 http_client.get(&format!("{server_url}{mock_uri}"));
54 let expected: Result<String, ProgramError> =
55 Ok(String::from(mock_body));
56
57 mock.assert();
58 assert_eq!(actual, expected);
59 }
60
61 #[test]
62 fn it_fetches_data_as_string_from_given_server_url_when_200() {
63 let mut mock_server = Server::new();
64 let mock_body = "gitignore template for rust";
65 let mock_uri = "/api/rust";
66 let mock = mock_server
67 .mock("GET", mock_uri)
68 .with_status(200)
69 .with_body(mock_body)
70 .create();
71
72 let server_url = mock_server.url();
73 let http_client = UreqClient { server_url };
74
75 let actual = http_client.get(mock_uri);
76 let expected: Result<String, ProgramError> =
77 Ok(String::from(mock_body));
78
79 mock.assert();
80 assert_eq!(actual, expected);
81 }
82 }
83
84 mod failure {
85 use super::*;
86
87 #[test]
88 fn it_fails_with_api_call_error_when_400_response() {
89 let mut mock_server = Server::new();
90 let mock_body = "error response";
91 let mock_uri = "/api/rust";
92 let mock = mock_server
93 .mock("GET", mock_uri)
94 .with_status(400)
95 .with_body(mock_body)
96 .create();
97
98 let server_url = mock_server.url();
99 let http_client = UreqClient::default();
100
101 let actual =
102 http_client.get(&format!("{server_url}{mock_uri}"));
103 let expected: Result<String, ProgramError> =
104 Err(ProgramError {
105 message: constant::error_messages::API_CALL_FAILURE
106 .replace(
107 "{error}",
108 constant::error_messages::HTTP_400,
109 ),
110 exit_status: constant::exit_status::GENERIC,
111 styled_message: None,
112 error_kind: None,
113 });
114
115 mock.assert();
116 assert_eq!(actual, expected);
117 }
118
119 #[test]
120 fn it_fails_with_body_parsing_error_when_invalid_body() {
121 let mut mock_server = Server::new();
122 let mock_body = vec![0, 159, 146, 150];
123 let mock_uri = "/api/rust";
124 let mock = mock_server
125 .mock("GET", mock_uri)
126 .with_status(200)
127 .with_body(mock_body)
128 .create();
129
130 let server_url = mock_server.url();
131 let http_client = UreqClient::default();
132
133 let actual =
134 http_client.get(&format!("{server_url}{mock_uri}"));
135 let expected: Result<String, ProgramError> =
136 Err(ProgramError {
137 message: String::from(
138 constant::error_messages::BODY_PARSING_ISSUE,
139 ),
140 exit_status:
141 constant::exit_status::BODY_PARSING_ISSUE,
142 styled_message: None,
143 error_kind: None,
144 });
145
146 mock.assert();
147 assert_eq!(actual, expected);
148 }
149 }
150 }
151 }
152
153 mod mock_client {
154 use super::*;
155
156 mod get {
157 use super::*;
158
159 mod success {
160 use super::*;
161
162 #[test]
163 fn it_returns_ok_mocked_response() {
164 let result_content = "success response";
165 let http_client = MockClient {
166 response: Ok(String::from(result_content)),
167 };
168
169 let actual = http_client.get("/api/rust");
170 let expected: Result<String, ProgramError> =
171 Ok(String::from(result_content));
172
173 assert_eq!(actual, expected);
174 }
175
176 #[test]
177 fn it_returns_error_mocked_response() {
178 let result_content = "error response";
179 let http_client = MockClient {
180 response: Err(ProgramError {
181 message: String::from(result_content),
182 exit_status: constant::exit_status::GENERIC,
183 styled_message: None,
184 error_kind: None,
185 }),
186 };
187
188 let actual = http_client.get("/api/rust");
189 let expected: Result<String, ProgramError> =
190 Err(ProgramError {
191 message: String::from(result_content),
192 exit_status: constant::exit_status::GENERIC,
193 styled_message: None,
194 error_kind: None,
195 });
196
197 assert_eq!(actual, expected);
198 }
199 }
200 }
201 }
202}