gitignore_template_generator/http_client/
api.rs

1pub 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}