gewe_http/
lib.rs

1pub mod client;
2pub mod contact;
3pub mod favorite;
4pub mod group;
5pub mod login;
6pub mod message;
7pub mod moments;
8pub mod personal;
9pub mod tag;
10pub mod video_account;
11
12pub use client::GeweHttpClient;
13
14#[cfg(test)]
15mod tests {
16    use super::*;
17    use gewe_core::{ApiEnvelope, GeweError};
18    use serde::{Deserialize, Serialize};
19
20    // 测试用的简单结构体
21    #[derive(Debug, Serialize, Deserialize, PartialEq)]
22    struct TestRequest<'a> {
23        #[serde(rename = "appId")]
24        app_id: &'a str,
25        #[serde(rename = "userId")]
26        user_id: Option<&'a str>,
27    }
28
29    #[derive(Debug, Serialize, Deserialize, PartialEq)]
30    struct TestResponse {
31        message: String,
32        count: i32,
33    }
34
35    mod client_tests {
36        use super::*;
37
38        #[test]
39        fn test_client_new() {
40            // 测试创建客户端
41            let result = GeweHttpClient::new("test_token_123", "https://api.example.com");
42            assert!(result.is_ok());
43
44            let client = result.unwrap();
45            assert_eq!(client.base_url, "https://api.example.com");
46        }
47
48        #[test]
49        fn test_client_new_with_trailing_slash() {
50            // 测试带尾部斜杠的 URL
51            let result = GeweHttpClient::new("test_token", "https://api.example.com/");
52            assert!(result.is_ok());
53
54            let client = result.unwrap();
55            assert_eq!(client.base_url, "https://api.example.com/");
56        }
57
58        #[test]
59        fn test_client_new_with_invalid_token() {
60            // 测试无效的 token(包含非 ASCII 换行符)
61            let result = GeweHttpClient::new("invalid\ntoken", "https://api.example.com");
62
63            // 确保返回错误且是 Http 错误
64            assert!(result.is_err());
65            assert!(matches!(result, Err(GeweError::Http(_))));
66        }
67
68        #[test]
69        fn test_endpoint_generation() {
70            let client = GeweHttpClient::new("token", "https://api.example.com")
71                .expect("Failed to create client");
72
73            // 测试基本路径
74            assert_eq!(
75                client.endpoint("gewe/v2/api/login/getLoginQrCode"),
76                "https://api.example.com/gewe/v2/api/login/getLoginQrCode"
77            );
78
79            // 测试带前导斜杠的路径
80            assert_eq!(
81                client.endpoint("/gewe/v2/api/login/getLoginQrCode"),
82                "https://api.example.com/gewe/v2/api/login/getLoginQrCode"
83            );
84
85            // 测试带尾部斜杠的 base_url
86            let client2 = GeweHttpClient::new("token", "https://api.example.com/")
87                .expect("Failed to create client");
88            assert_eq!(
89                client2.endpoint("gewe/v2/api/login/getLoginQrCode"),
90                "https://api.example.com/gewe/v2/api/login/getLoginQrCode"
91            );
92
93            // 测试两者都有斜杠
94            assert_eq!(
95                client2.endpoint("/gewe/v2/api/login/getLoginQrCode"),
96                "https://api.example.com/gewe/v2/api/login/getLoginQrCode"
97            );
98        }
99
100        #[test]
101        fn test_endpoint_with_empty_path() {
102            let client = GeweHttpClient::new("token", "https://api.example.com")
103                .expect("Failed to create client");
104            assert_eq!(client.endpoint(""), "https://api.example.com/");
105        }
106
107        #[test]
108        fn test_client_is_clone() {
109            // 测试客户端可以被克隆
110            let client = GeweHttpClient::new("token", "https://api.example.com")
111                .expect("Failed to create client");
112            let client2 = client.clone();
113
114            assert_eq!(client.base_url, client2.base_url);
115        }
116    }
117
118    mod serialization_tests {
119        use super::*;
120
121        #[test]
122        fn test_request_serialization() {
123            // 测试请求结构体的序列化
124            let req = TestRequest {
125                app_id: "app123",
126                user_id: Some("user456"),
127            };
128
129            let json = serde_json::to_string(&req).expect("Failed to serialize");
130            assert!(json.contains("appId"));
131            assert!(json.contains("app123"));
132            assert!(json.contains("userId"));
133            assert!(json.contains("user456"));
134        }
135
136        #[test]
137        fn test_request_serialization_with_none() {
138            // 测试带 None 的请求序列化
139            let req = TestRequest {
140                app_id: "app123",
141                user_id: None,
142            };
143
144            let json = serde_json::to_string(&req).expect("Failed to serialize");
145            assert!(json.contains("appId"));
146            assert!(json.contains("app123"));
147            // Option::None 会被序列化为 null
148            assert!(json.contains("null"));
149        }
150
151        #[test]
152        fn test_response_deserialization() {
153            // 测试响应结构体的反序列化
154            let json = r#"{"message":"success","count":42}"#;
155            let resp: TestResponse = serde_json::from_str(json).expect("Failed to deserialize");
156
157            assert_eq!(resp.message, "success");
158            assert_eq!(resp.count, 42);
159        }
160
161        #[test]
162        fn test_api_envelope_deserialization_success() {
163            // 测试成功响应的反序列化
164            let json = r#"{
165                "ret": 200,
166                "msg": "success",
167                "data": {
168                    "message": "hello",
169                    "count": 10
170                }
171            }"#;
172
173            let env: ApiEnvelope<TestResponse> =
174                serde_json::from_str(json).expect("Failed to deserialize");
175
176            assert_eq!(env.ret, 200);
177            assert_eq!(env.msg, "success");
178            assert!(env.data.is_some());
179
180            let data = env.data.unwrap();
181            assert_eq!(data.message, "hello");
182            assert_eq!(data.count, 10);
183        }
184
185        #[test]
186        fn test_api_envelope_deserialization_no_data() {
187            // 测试没有 data 字段的响应
188            let json = r#"{
189                "ret": 200,
190                "msg": "success"
191            }"#;
192
193            let env: ApiEnvelope<TestResponse> =
194                serde_json::from_str(json).expect("Failed to deserialize");
195
196            assert_eq!(env.ret, 200);
197            assert_eq!(env.msg, "success");
198            assert!(env.data.is_none());
199        }
200
201        #[test]
202        fn test_api_envelope_deserialization_error() {
203            // 测试错误响应的反序列化
204            let json = r#"{
205                "ret": 400,
206                "msg": "invalid request"
207            }"#;
208
209            let env: ApiEnvelope<TestResponse> =
210                serde_json::from_str(json).expect("Failed to deserialize");
211
212            assert_eq!(env.ret, 400);
213            assert_eq!(env.msg, "invalid request");
214            assert!(env.data.is_none());
215        }
216    }
217
218    mod error_tests {
219        use super::*;
220
221        #[test]
222        fn test_gewe_error_http() {
223            // 测试 HTTP 错误
224            let err = GeweError::Http("connection failed".to_string());
225            assert!(err.to_string().contains("http error"));
226            assert!(err.to_string().contains("connection failed"));
227        }
228
229        #[test]
230        fn test_gewe_error_api() {
231            // 测试 API 错误
232            let err = GeweError::Api {
233                code: 401,
234                message: "unauthorized".to_string(),
235            };
236            assert!(err.to_string().contains("api error"));
237            assert!(err.to_string().contains("401"));
238            assert!(err.to_string().contains("unauthorized"));
239        }
240
241        #[test]
242        fn test_gewe_error_decode() {
243            // 测试解码错误
244            let err = GeweError::Decode("invalid json".to_string());
245            assert!(err.to_string().contains("decode error"));
246            assert!(err.to_string().contains("invalid json"));
247        }
248
249        #[test]
250        fn test_gewe_error_missing_data() {
251            // 测试缺失数据错误
252            let err = GeweError::MissingData;
253            assert!(err.to_string().contains("missing data"));
254        }
255    }
256
257    mod url_building_tests {
258        use super::*;
259
260        #[test]
261        fn test_various_base_url_formats() {
262            // 测试各种 base_url 格式
263            let test_cases = vec![
264                (
265                    "https://api.example.com",
266                    "api/test",
267                    "https://api.example.com/api/test",
268                ),
269                (
270                    "https://api.example.com/",
271                    "api/test",
272                    "https://api.example.com/api/test",
273                ),
274                (
275                    "https://api.example.com",
276                    "/api/test",
277                    "https://api.example.com/api/test",
278                ),
279                (
280                    "https://api.example.com/",
281                    "/api/test",
282                    "https://api.example.com/api/test",
283                ),
284                (
285                    "https://api.example.com/v1",
286                    "login/check",
287                    "https://api.example.com/v1/login/check",
288                ),
289                (
290                    "https://api.example.com/v1/",
291                    "/login/check",
292                    "https://api.example.com/v1/login/check",
293                ),
294            ];
295
296            for (base_url, path, expected) in test_cases {
297                let client =
298                    GeweHttpClient::new("token", base_url).expect("Failed to create client");
299                let result = client.endpoint(path);
300                assert_eq!(
301                    result, expected,
302                    "Failed for base_url='{}', path='{}'",
303                    base_url, path
304                );
305            }
306        }
307
308        #[test]
309        fn test_url_with_port() {
310            // 测试带端口号的 URL
311            let client = GeweHttpClient::new("token", "https://api.example.com:8080")
312                .expect("Failed to create client");
313            assert_eq!(
314                client.endpoint("gewe/api/test"),
315                "https://api.example.com:8080/gewe/api/test"
316            );
317        }
318
319        #[test]
320        fn test_url_with_path_prefix() {
321            // 测试带路径前缀的 base_url
322            let client = GeweHttpClient::new("token", "https://api.example.com/api/v2")
323                .expect("Failed to create client");
324            assert_eq!(
325                client.endpoint("login/check"),
326                "https://api.example.com/api/v2/login/check"
327            );
328        }
329    }
330
331    mod integration_mock_tests {
332        use super::*;
333
334        // 由于实际的 HTTP 请求需要真实服务器,这里我们主要测试请求构建逻辑
335        // 在实际项目中,可以使用 mockito 或 wiremock 等库来模拟 HTTP 服务器
336
337        #[test]
338        fn test_client_timeout_configuration() {
339            // 测试客户端超时配置
340            let client = GeweHttpClient::new("token", "https://api.example.com")
341                .expect("Failed to create client");
342
343            // 虽然我们不能直接访问 timeout 设置,但可以确保客户端创建成功
344            // 在实际使用中,超时设置会在 HTTP 请求时生效
345            assert_eq!(client.base_url, "https://api.example.com");
346        }
347
348        #[test]
349        fn test_multiple_clients() {
350            // 测试创建多个客户端实例
351            let client1 = GeweHttpClient::new("token1", "https://api1.example.com")
352                .expect("Failed to create client");
353            let client2 = GeweHttpClient::new("token2", "https://api2.example.com")
354                .expect("Failed to create client");
355
356            assert_eq!(client1.base_url, "https://api1.example.com");
357            assert_eq!(client2.base_url, "https://api2.example.com");
358        }
359    }
360
361    mod edge_case_tests {
362        use super::*;
363
364        #[test]
365        fn test_empty_token() {
366            // 测试空 token
367            let result = GeweHttpClient::new("", "https://api.example.com");
368            // 空 token 是有效的,只是可能在 API 调用时失败
369            assert!(result.is_ok());
370        }
371
372        #[test]
373        fn test_long_token() {
374            // 测试长 token
375            let long_token = "a".repeat(1000);
376            let result = GeweHttpClient::new(&long_token, "https://api.example.com");
377            assert!(result.is_ok());
378        }
379
380        #[test]
381        fn test_special_characters_in_base_url() {
382            // 测试 base_url 中的特殊字符(URL 编码)
383            let client =
384                GeweHttpClient::new("token", "https://api.example.com/path%20with%20spaces")
385                    .expect("Failed to create client");
386            assert_eq!(
387                client.base_url,
388                "https://api.example.com/path%20with%20spaces"
389            );
390        }
391
392        #[test]
393        fn test_unicode_in_data() {
394            // 测试 Unicode 字符的序列化
395            let req = TestRequest {
396                app_id: "测试应用",
397                user_id: Some("用户123"),
398            };
399
400            let json = serde_json::to_string(&req).expect("Failed to serialize");
401            assert!(json.contains("测试应用"));
402            assert!(json.contains("用户123"));
403        }
404
405        #[test]
406        fn test_api_envelope_with_null_data() {
407            // 测试 data 为 null 的情况
408            let json = r#"{
409                "ret": 200,
410                "msg": "success",
411                "data": null
412            }"#;
413
414            let env: ApiEnvelope<TestResponse> =
415                serde_json::from_str(json).expect("Failed to deserialize");
416
417            assert_eq!(env.ret, 200);
418            assert!(env.data.is_none());
419        }
420    }
421
422    mod path_handling_tests {
423        use super::*;
424
425        #[test]
426        fn test_path_with_query_string() {
427            // 测试带查询字符串的路径(虽然通常使用 POST,但测试边界情况)
428            let client = GeweHttpClient::new("token", "https://api.example.com")
429                .expect("Failed to create client");
430            let endpoint = client.endpoint("api/test?param=value");
431            assert_eq!(endpoint, "https://api.example.com/api/test?param=value");
432        }
433
434        #[test]
435        fn test_path_with_fragment() {
436            // 测试带片段标识符的路径
437            let client = GeweHttpClient::new("token", "https://api.example.com")
438                .expect("Failed to create client");
439            let endpoint = client.endpoint("api/test#section");
440            assert_eq!(endpoint, "https://api.example.com/api/test#section");
441        }
442
443        #[test]
444        fn test_deeply_nested_path() {
445            // 测试深层嵌套的路径
446            let client = GeweHttpClient::new("token", "https://api.example.com")
447                .expect("Failed to create client");
448            let endpoint = client.endpoint("a/b/c/d/e/f/g/h");
449            assert_eq!(endpoint, "https://api.example.com/a/b/c/d/e/f/g/h");
450        }
451
452        #[test]
453        fn test_path_with_multiple_slashes() {
454            // 测试包含多个斜杠的路径
455            let client = GeweHttpClient::new("token", "https://api.example.com")
456                .expect("Failed to create client");
457            // 注意:endpoint 方法只处理前导斜杠,不会清理中间的多余斜杠
458            let endpoint = client.endpoint("api//test///path");
459            assert_eq!(endpoint, "https://api.example.com/api//test///path");
460        }
461    }
462}