1use std::collections::HashMap;
2
3use reqwest::Method;
4
5use crate::core::constants::AccessTokenType;
6
7#[derive(Debug, Clone, Default)]
46pub struct ApiRequest {
47 pub(crate) http_method: Method,
52
53 pub api_path: String,
60
61 pub body: Vec<u8>,
73
74 pub query_params: HashMap<&'static str, String>,
90
91 pub path_params: HashMap<String, Vec<String>>,
102
103 pub(crate) supported_access_token_types: Vec<AccessTokenType>,
113
114 pub file: Vec<u8>,
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::core::constants::AccessTokenType;
145 use reqwest::Method;
146
147 #[test]
148 fn test_api_request_creation() {
149 let api_req = ApiRequest {
150 http_method: Method::POST,
151 api_path: "/open-apis/test/v1/endpoint".to_string(),
152 body: b"test body".to_vec(),
153 query_params: HashMap::new(),
154 path_params: HashMap::new(),
155 supported_access_token_types: vec![AccessTokenType::Tenant],
156 file: Vec::new(),
157 };
158
159 assert_eq!(api_req.http_method, Method::POST);
160 assert_eq!(api_req.api_path, "/open-apis/test/v1/endpoint");
161 assert_eq!(api_req.body, b"test body".to_vec());
162 assert!(api_req.query_params.is_empty());
163 assert!(api_req.path_params.is_empty());
164 assert_eq!(
165 api_req.supported_access_token_types,
166 vec![AccessTokenType::Tenant]
167 );
168 assert!(api_req.file.is_empty());
169 }
170
171 #[test]
172 fn test_api_request_default() {
173 let api_req = ApiRequest::default();
174
175 assert_eq!(api_req.http_method, Method::GET);
176 assert!(api_req.api_path.is_empty());
177 assert!(api_req.body.is_empty());
178 assert!(api_req.query_params.is_empty());
179 assert!(api_req.path_params.is_empty());
180 assert!(api_req.supported_access_token_types.is_empty());
181 assert!(api_req.file.is_empty());
182 }
183
184 #[test]
185 fn test_api_request_clone() {
186 let original = ApiRequest {
187 http_method: Method::PUT,
188 api_path: "/open-apis/clone/test".to_string(),
189 body: b"original body".to_vec(),
190 query_params: {
191 let mut params = HashMap::new();
192 params.insert("page_size", "10".to_string());
193 params
194 },
195 path_params: {
196 let mut params = HashMap::new();
197 params.insert("file_id".to_string(), vec!["123".to_string()]);
198 params
199 },
200 supported_access_token_types: vec![AccessTokenType::User, AccessTokenType::Tenant],
201 file: b"file content".to_vec(),
202 };
203
204 let cloned = original.clone();
205
206 assert_eq!(original.http_method, cloned.http_method);
207 assert_eq!(original.api_path, cloned.api_path);
208 assert_eq!(original.body, cloned.body);
209 assert_eq!(original.query_params, cloned.query_params);
210 assert_eq!(original.path_params, cloned.path_params);
211 assert_eq!(
212 original.supported_access_token_types,
213 cloned.supported_access_token_types
214 );
215 assert_eq!(original.file, cloned.file);
216 }
217
218 #[test]
219 fn test_api_request_debug() {
220 let api_req = ApiRequest {
221 http_method: Method::DELETE,
222 api_path: "/debug/test".to_string(),
223 body: b"debug body".to_vec(),
224 ..Default::default()
225 };
226
227 let debug_str = format!("{:?}", api_req);
228
229 assert!(debug_str.contains("ApiRequest"));
230 assert!(debug_str.contains("DELETE"));
231 assert!(debug_str.contains("/debug/test"));
232 }
233
234 #[test]
235 fn test_api_request_with_different_http_methods() {
236 let methods = vec![
237 Method::GET,
238 Method::POST,
239 Method::PUT,
240 Method::DELETE,
241 Method::PATCH,
242 Method::HEAD,
243 Method::OPTIONS,
244 ];
245
246 for method in methods {
247 let api_req = ApiRequest {
248 http_method: method.clone(),
249 ..Default::default()
250 };
251 assert_eq!(api_req.http_method, method);
252 }
253 }
254
255 #[test]
256 fn test_api_request_with_query_params() {
257 let mut api_req = ApiRequest::default();
258
259 api_req.query_params.insert("page_size", "20".to_string());
261 api_req
262 .query_params
263 .insert("page_token", "token123".to_string());
264 api_req
265 .query_params
266 .insert("filter", "status=active".to_string());
267
268 assert_eq!(api_req.query_params.len(), 3);
269 assert_eq!(
270 api_req.query_params.get("page_size"),
271 Some(&"20".to_string())
272 );
273 assert_eq!(
274 api_req.query_params.get("page_token"),
275 Some(&"token123".to_string())
276 );
277 assert_eq!(
278 api_req.query_params.get("filter"),
279 Some(&"status=active".to_string())
280 );
281 }
282
283 #[test]
284 fn test_api_request_with_path_params() {
285 let mut api_req = ApiRequest::default();
286
287 api_req
289 .path_params
290 .insert("user_id".to_string(), vec!["user123".to_string()]);
291 api_req
292 .path_params
293 .insert("file_id".to_string(), vec!["file456".to_string()]);
294 api_req.path_params.insert(
295 "multiple".to_string(),
296 vec!["val1".to_string(), "val2".to_string()],
297 );
298
299 assert_eq!(api_req.path_params.len(), 3);
300 assert_eq!(
301 api_req.path_params.get("user_id"),
302 Some(&vec!["user123".to_string()])
303 );
304 assert_eq!(
305 api_req.path_params.get("file_id"),
306 Some(&vec!["file456".to_string()])
307 );
308 assert_eq!(
309 api_req.path_params.get("multiple"),
310 Some(&vec!["val1".to_string(), "val2".to_string()])
311 );
312 }
313
314 #[test]
315 fn test_api_request_with_different_access_token_types() {
316 let token_types = vec![
317 vec![AccessTokenType::User],
318 vec![AccessTokenType::Tenant],
319 vec![AccessTokenType::App],
320 vec![AccessTokenType::User, AccessTokenType::Tenant],
321 vec![
322 AccessTokenType::User,
323 AccessTokenType::Tenant,
324 AccessTokenType::App,
325 ],
326 ];
327
328 for token_type_vec in token_types {
329 let api_req = ApiRequest {
330 supported_access_token_types: token_type_vec.clone(),
331 ..Default::default()
332 };
333 assert_eq!(api_req.supported_access_token_types, token_type_vec);
334 }
335 }
336
337 #[test]
338 fn test_api_request_with_body_serialization() {
339 let json_data = serde_json::json!({
341 "name": "test file",
342 "parent_id": "folder123"
343 });
344 let json_bytes = serde_json::to_vec(&json_data).unwrap();
345
346 let api_req = ApiRequest {
347 body: json_bytes.clone(),
348 ..Default::default()
349 };
350
351 assert_eq!(api_req.body, json_bytes);
352
353 let deserialized: serde_json::Value = serde_json::from_slice(&api_req.body).unwrap();
355 assert_eq!(deserialized, json_data);
356 }
357
358 #[test]
359 fn test_api_request_with_empty_body() {
360 let api_req = ApiRequest {
361 body: Vec::new(),
362 ..Default::default()
363 };
364
365 assert!(api_req.body.is_empty());
366 }
367
368 #[test]
369 fn test_api_request_with_large_body() {
370 let large_body = vec![0u8; 1024 * 1024]; let api_req = ApiRequest {
372 body: large_body.clone(),
373 ..Default::default()
374 };
375
376 assert_eq!(api_req.body.len(), 1024 * 1024);
377 assert_eq!(api_req.body, large_body);
378 }
379
380 #[test]
381 fn test_api_request_with_file_upload() {
382 let file_content = b"binary file content";
383 let metadata = serde_json::json!({
384 "filename": "test.txt",
385 "size": file_content.len()
386 });
387
388 let api_req = ApiRequest {
389 http_method: Method::POST,
390 api_path: "/upload".to_string(),
391 body: serde_json::to_vec(&metadata).unwrap(),
392 file: file_content.to_vec(),
393 ..Default::default()
394 };
395
396 assert_eq!(api_req.http_method, Method::POST);
397 assert_eq!(api_req.api_path, "/upload");
398 assert!(!api_req.body.is_empty());
399 assert_eq!(api_req.file, file_content.to_vec());
400 }
401
402 #[test]
403 fn test_api_request_with_empty_file() {
404 let api_req = ApiRequest {
405 file: Vec::new(),
406 ..Default::default()
407 };
408
409 assert!(api_req.file.is_empty());
410 }
411
412 #[test]
413 fn test_api_request_with_large_file() {
414 let large_file = vec![1u8; 10 * 1024 * 1024]; let api_req = ApiRequest {
416 file: large_file.clone(),
417 ..Default::default()
418 };
419
420 assert_eq!(api_req.file.len(), 10 * 1024 * 1024);
421 assert_eq!(api_req.file, large_file);
422 }
423
424 #[test]
425 fn test_api_request_multipart_structure() {
426 let metadata = serde_json::json!({
427 "name": "document.pdf",
428 "parent_id": "folder123"
429 });
430 let file_content = b"PDF file binary content";
431
432 let api_req = ApiRequest {
433 http_method: Method::POST,
434 api_path: "/upload/multipart".to_string(),
435 body: serde_json::to_vec(&metadata).unwrap(),
436 file: file_content.to_vec(),
437 supported_access_token_types: vec![AccessTokenType::Tenant],
438 ..Default::default()
439 };
440
441 assert_eq!(api_req.http_method, Method::POST);
443 assert!(!api_req.body.is_empty()); assert!(!api_req.file.is_empty()); assert_eq!(
446 api_req.supported_access_token_types,
447 vec![AccessTokenType::Tenant]
448 );
449 }
450
451 #[test]
452 fn test_api_request_path_variations() {
453 let paths = vec![
454 "/open-apis/drive/v1/files",
455 "/open-apis/drive/v1/files/{file_id}",
456 "/open-apis/contact/v3/users/{user_id}/update",
457 "",
458 "/",
459 "/simple",
460 "/very/deep/nested/path/structure/endpoint",
461 ];
462
463 for path in paths {
464 let api_req = ApiRequest {
465 api_path: path.to_string(),
466 ..Default::default()
467 };
468 assert_eq!(api_req.api_path, path);
469 }
470 }
471
472 #[test]
473 fn test_api_request_special_characters_in_paths() {
474 let special_paths = vec![
475 "/path/with spaces",
476 "/path/with-dashes",
477 "/path/with_underscores",
478 "/path/with.dots",
479 "/path/with@symbols",
480 "/path/with中文字符",
481 "/path/with🚀emoji",
482 ];
483
484 for path in special_paths {
485 let api_req = ApiRequest {
486 api_path: path.to_string(),
487 ..Default::default()
488 };
489 assert_eq!(api_req.api_path, path);
490 }
491 }
492
493 #[test]
494 fn test_api_request_query_params_special_values() {
495 let mut api_req = ApiRequest::default();
496
497 api_req.query_params.insert("empty", "".to_string());
499 api_req
500 .query_params
501 .insert("space", "value with space".to_string());
502 api_req
503 .query_params
504 .insert("special", "value@#$%^&*()".to_string());
505 api_req
506 .query_params
507 .insert("unicode", "中文值🚀".to_string());
508 api_req
509 .query_params
510 .insert("url_encoded", "value%20with%20encoding".to_string());
511
512 assert_eq!(api_req.query_params.len(), 5);
513 assert_eq!(api_req.query_params.get("empty"), Some(&"".to_string()));
514 assert_eq!(
515 api_req.query_params.get("space"),
516 Some(&"value with space".to_string())
517 );
518 assert_eq!(
519 api_req.query_params.get("special"),
520 Some(&"value@#$%^&*()".to_string())
521 );
522 assert_eq!(
523 api_req.query_params.get("unicode"),
524 Some(&"中文值🚀".to_string())
525 );
526 assert_eq!(
527 api_req.query_params.get("url_encoded"),
528 Some(&"value%20with%20encoding".to_string())
529 );
530 }
531
532 #[test]
533 fn test_api_request_path_params_complex() {
534 let mut api_req = ApiRequest::default();
535
536 api_req
538 .path_params
539 .insert("single".to_string(), vec!["one".to_string()]);
540 api_req.path_params.insert(
541 "multiple".to_string(),
542 vec![
543 "first".to_string(),
544 "second".to_string(),
545 "third".to_string(),
546 ],
547 );
548 api_req.path_params.insert("empty".to_string(), vec![]);
549 api_req.path_params.insert(
550 "special".to_string(),
551 vec![
552 "value@#$".to_string(),
553 "中文".to_string(),
554 "🚀emoji".to_string(),
555 ],
556 );
557
558 assert_eq!(api_req.path_params.len(), 4);
559 assert_eq!(
560 api_req.path_params.get("single"),
561 Some(&vec!["one".to_string()])
562 );
563 assert_eq!(
564 api_req.path_params.get("multiple"),
565 Some(&vec![
566 "first".to_string(),
567 "second".to_string(),
568 "third".to_string()
569 ])
570 );
571 assert_eq!(api_req.path_params.get("empty"), Some(&vec![]));
572 assert_eq!(
573 api_req.path_params.get("special"),
574 Some(&vec![
575 "value@#$".to_string(),
576 "中文".to_string(),
577 "🚀emoji".to_string()
578 ])
579 );
580 }
581
582 #[test]
583 fn test_api_request_binary_data_handling() {
584 let binary_data = vec![0, 1, 2, 3, 4, 255, 254, 253];
585 let api_req = ApiRequest {
586 body: binary_data.clone(),
587 file: binary_data.clone(),
588 ..Default::default()
589 };
590
591 assert_eq!(api_req.body, binary_data);
592 assert_eq!(api_req.file, binary_data);
593 }
594
595 #[test]
596 fn test_api_request_memory_efficiency() {
597 let requests: Vec<ApiRequest> = (0..100)
599 .map(|i| ApiRequest {
600 api_path: format!("/api/path/{}", i),
601 body: format!("body_{}", i).into_bytes(),
602 ..Default::default()
603 })
604 .collect();
605
606 assert_eq!(requests.len(), 100);
607
608 for (i, req) in requests.iter().enumerate() {
609 assert_eq!(req.api_path, format!("/api/path/{}", i));
610 assert_eq!(req.body, format!("body_{}", i).into_bytes());
611 }
612 }
613
614 #[test]
615 fn test_api_request_field_independence() {
616 let mut api_req = ApiRequest {
617 http_method: Method::POST,
618 api_path: "/test".to_string(),
619 body: b"test body".to_vec(),
620 ..Default::default()
621 };
622 api_req.query_params.insert("test", "value".to_string());
623 api_req
624 .path_params
625 .insert("id".to_string(), vec!["123".to_string()]);
626 api_req
627 .supported_access_token_types
628 .push(AccessTokenType::User);
629 api_req.file = b"file content".to_vec();
630
631 assert_eq!(api_req.http_method, Method::POST);
633 assert_eq!(api_req.api_path, "/test");
634 assert_eq!(api_req.body, b"test body");
635 assert_eq!(api_req.query_params.len(), 1);
636 assert_eq!(api_req.path_params.len(), 1);
637 assert_eq!(api_req.supported_access_token_types.len(), 1);
638 assert_eq!(api_req.file, b"file content");
639 }
640}