1use serde_json::Value;
2use tracing::debug;
3use tracing::{info_span, Instrument};
4
5use crate::{
6 api::{ApiResponseTrait, BaseResponse, RawResponse, Response, ResponseFormat},
7 content_disposition,
8 error::{network_error, validation_error},
9 observability::ResponseTracker,
10 SDKResult,
11};
12use serde::Deserialize;
13use std::any::Any;
14
15#[cfg(test)]
16use crate::error::{CoreError, ErrorCategory, ErrorCode, ErrorContext};
17
18pub struct ImprovedResponseHandler;
21
22impl ImprovedResponseHandler {
23 pub async fn handle_response<T: ApiResponseTrait + for<'de> Deserialize<'de>>(
30 response: reqwest::Response,
31 ) -> SDKResult<Response<T>> {
32 let format = match T::data_format() {
33 ResponseFormat::Data => "data",
34 ResponseFormat::Flatten => "flatten",
35 ResponseFormat::Binary => "binary",
36 ResponseFormat::Text => "text",
37 ResponseFormat::Custom => "custom",
38 };
39
40 let span = info_span!(
41 "response_handling",
42 format = format,
43 status_code = response.status().as_u16(),
44 content_length = tracing::field::Empty,
45 processing_duration_ms = tracing::field::Empty,
46 );
47
48 async move {
49 let start_time = std::time::Instant::now();
50
51 let content_length = response.content_length();
53 if let Some(length) = content_length {
54 tracing::Span::current().record("content_length", length);
55 }
56
57 let result = match T::data_format() {
58 ResponseFormat::Data => Self::handle_data_response(response).await,
59 ResponseFormat::Flatten => Self::handle_flatten_response(response).await,
60 ResponseFormat::Binary => Self::handle_binary_response(response).await,
61 ResponseFormat::Text => Self::handle_data_response(response).await, ResponseFormat::Custom => Self::handle_data_response(response).await, };
64
65 let duration_ms = start_time.elapsed().as_millis() as u64;
67 tracing::Span::current().record("processing_duration_ms", duration_ms);
68
69 result
70 }
71 .instrument(span)
72 .await
73 }
74
75 async fn handle_data_response<T: ApiResponseTrait + for<'de> Deserialize<'de>>(
78 response: reqwest::Response,
79 ) -> SDKResult<Response<T>> {
80 let tracker = ResponseTracker::start("json_data", response.content_length());
81
82 let response_text = response.text().await?;
83 debug!("Raw response: {response_text}");
84
85 tracker.parsing_complete();
87
88 match serde_json::from_str::<Response<T>>(&response_text) {
90 Ok(base_response) => {
91 tracker.success();
92 Ok(base_response)
93 }
94 Err(direct_parse_err) => {
95 tracing::debug!("Direct parsing failed, attempting structured data extraction");
96
97 match serde_json::from_str::<Value>(&response_text) {
99 Ok(raw_value) => {
100 let code = raw_value["code"].as_i64().unwrap_or(-1) as i32;
101 let msg = raw_value["msg"]
102 .as_str()
103 .unwrap_or("Unknown error")
104 .to_string();
105
106 let data = if code == 0 {
108 if let Some(data_value) = raw_value.get("data") {
109 match serde_json::from_value::<T>(data_value.clone()) {
111 Ok(parsed_data) => {
112 tracing::debug!("Successfully parsed data field as type T");
113 Some(parsed_data)
114 }
115 Err(data_parse_err) => {
116 tracing::debug!(
117 "Failed to parse data field as type T: {data_parse_err:?}"
118 );
119 None
122 }
123 }
124 } else {
125 tracing::debug!("No data field found in successful response");
126 None
127 }
128 } else {
129 None
130 };
131
132 tracker.validation_complete();
133 tracker.success();
134
135 Ok(BaseResponse {
136 raw_response: RawResponse {
137 code,
138 msg,
139 request_id: None,
140 data: None,
141 error: None,
142 },
143 data,
144 })
145 }
146 Err(fallback_err) => {
147 let error_msg = format!(
148 "Failed to parse response. Direct parse error: {}. Fallback parse error: {}",
149 direct_parse_err, fallback_err
150 );
151 tracker.error(&error_msg);
152 Err(validation_error("api_response", error_msg))
153 }
154 }
155 }
156 }
157 }
158
159 async fn handle_flatten_response<T: ApiResponseTrait + for<'de> Deserialize<'de>>(
162 response: reqwest::Response,
163 ) -> SDKResult<Response<T>> {
164 let tracker = ResponseTracker::start("json_flatten", response.content_length());
165
166 let response_text = response.text().await?;
167 debug!("Raw response: {response_text}");
168
169 let raw_value: Value = match serde_json::from_str(&response_text) {
171 Ok(value) => {
172 tracker.parsing_complete();
173 value
174 }
175 Err(e) => {
176 let error_msg = format!("Failed to parse JSON: {}", e);
177 tracker.error(&error_msg);
178 return Err(validation_error("base_response", error_msg));
179 }
180 };
181
182 let raw_response: RawResponse = match serde_json::from_value(raw_value.clone()) {
184 Ok(response) => response,
185 Err(e) => {
186 let error_msg = format!("Failed to parse raw response: {}", e);
187 tracker.error(&error_msg);
188 return Err(validation_error("response", error_msg));
189 }
190 };
191
192 let data = if raw_response.code == 0 {
194 match serde_json::from_value::<T>(raw_value) {
195 Ok(parsed_data) => {
196 tracker.validation_complete();
197 Some(parsed_data)
198 }
199 Err(e) => {
200 debug!("Failed to parse data for flatten response: {e}");
201 tracker.validation_complete();
202 None
203 }
204 }
205 } else {
206 tracker.validation_complete();
207 None
208 };
209
210 tracker.success();
211 Ok(BaseResponse { raw_response, data })
212 }
213
214 async fn handle_binary_response<T: ApiResponseTrait>(
216 response: reqwest::Response,
217 ) -> SDKResult<Response<T>> {
218 let tracker = ResponseTracker::start("binary", response.content_length());
219
220 let _file_name = response
222 .headers()
223 .get("Content-Disposition")
224 .and_then(|header| header.to_str().ok())
225 .and_then(content_disposition::extract_filename)
226 .unwrap_or_default();
227
228 tracker.parsing_complete();
230
231 let bytes = match response.bytes().await {
233 Ok(bytes) => {
234 let byte_vec = bytes.to_vec();
235 tracing::debug!("Binary response received: {} bytes", byte_vec.len());
236 byte_vec
237 }
238 Err(e) => {
239 let error_msg = format!("Failed to read binary response: {}", e);
240 tracker.error(&error_msg);
241 return Err(network_error(error_msg));
242 }
243 };
244
245 let data: Option<T> = {
248 let any: Box<dyn Any> =
249 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<Vec<u8>>() {
250 Box::new(bytes)
251 } else if std::any::TypeId::of::<T>() == std::any::TypeId::of::<String>() {
252 let s = String::from_utf8_lossy(&bytes).to_string();
253 Box::new(s)
254 } else {
255 Box::new(())
257 };
258
259 any.downcast::<T>().ok().map(|boxed| *boxed)
260 };
261
262 tracker.success();
263 Ok(BaseResponse {
264 raw_response: RawResponse {
265 code: 0,
266 msg: "success".to_string(),
267 request_id: None,
268 data: None,
269 error: None,
270 },
271 data,
272 })
273 }
274}
275
276#[cfg(test)]
280#[derive(Debug, serde::Serialize, serde::Deserialize)]
281pub struct OptimizedBaseResponse<T>
282where
283 T: Default,
284{
285 pub code: i32,
287 pub msg: String,
289 #[serde(rename = "error", default, skip_serializing_if = "Option::is_none")]
291 pub error: Option<ErrorInfo>,
292 #[serde(default, skip_serializing_if = "Option::is_none")]
294 pub data: Option<T>,
295}
296
297#[cfg(test)]
298impl<T> OptimizedBaseResponse<T>
299where
300 T: Default,
301{
302 pub fn is_success(&self) -> bool {
304 self.code == 0
305 }
306
307 pub fn into_data(self) -> Result<T, CoreError> {
309 if self.is_success() {
310 self.data.ok_or_else(|| {
311 validation_error("data", "Response is successful but data is missing")
312 })
313 } else {
314 let mapped_code = ErrorCode::from_feishu_code(self.code)
316 .unwrap_or_else(|| ErrorCode::from_code(self.code));
317
318 let mut ctx = ErrorContext::new();
320 ctx.add_context("feishu_code", self.code.to_string());
321
322 if let Some(log_id) = self.error.as_ref().and_then(|e| e.log_id.clone()) {
324 ctx.set_request_id(log_id);
325 }
326
327 let status =
329 mapped_code
330 .http_status()
331 .unwrap_or_else(|| match mapped_code.category() {
332 ErrorCategory::RateLimit => 429,
333 ErrorCategory::Authentication
334 | ErrorCategory::Permission
335 | ErrorCategory::Parameter => 400,
336 ErrorCategory::Resource => 404,
337 _ => 500,
338 });
339
340 Err(CoreError::Api(Box::new(crate::error::ApiError {
341 status,
342 endpoint: "unknown_endpoint".into(),
343 message: self.msg,
344 source: None,
345 code: mapped_code,
346 ctx: Box::new(ctx),
347 })))
348 }
349 }
350
351 pub fn data(&self) -> Option<&T> {
353 self.data.as_ref()
354 }
355
356 pub fn has_error(&self) -> bool {
358 self.error.is_some()
359 }
360}
361
362#[cfg(test)]
363#[derive(Debug, serde::Serialize, serde::Deserialize)]
364pub struct ErrorInfo {
365 #[serde(rename = "key", default, skip_serializing_if = "Option::is_none")]
366 pub log_id: Option<String>,
367 #[serde(default, skip_serializing_if = "Vec::is_empty")]
368 pub details: Vec<ErrorDetail>,
369}
370
371#[cfg(test)]
372#[derive(Debug, serde::Serialize, serde::Deserialize)]
373pub struct ErrorDetail {
374 #[serde(default, skip_serializing_if = "Option::is_none")]
375 pub key: Option<String>,
376 #[serde(default, skip_serializing_if = "Option::is_none")]
377 pub value: Option<String>,
378 #[serde(default, skip_serializing_if = "Option::is_none")]
379 pub description: Option<String>,
380}
381
382#[macro_export]
384macro_rules! impl_api_response {
385 ($type:ty, $format:expr) => {
386 impl ApiResponseTrait for $type {
387 fn data_format() -> ResponseFormat {
388 $format
389 }
390 }
391 };
392
393 ($type:ty, $format:expr, binary) => {
394 impl ApiResponseTrait for $type {
395 fn data_format() -> ResponseFormat {
396 $format
397 }
398
399 fn from_binary(file_name: String, body: Vec<u8>) -> Option<Self> {
400 Some(<$type>::from_binary_data(file_name, body))
401 }
402 }
403 };
404}
405
406#[cfg(test)]
407mod tests {
408 use super::*;
409 use crate::api::ResponseFormat;
410 use serde::{Deserialize, Serialize};
411
412 #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
413 struct TestData {
414 id: i32,
415 name: String,
416 }
417
418 impl ApiResponseTrait for TestData {
419 fn data_format() -> ResponseFormat {
420 ResponseFormat::Data
421 }
422 }
423
424 #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
425 struct TestFlattenData {
426 id: i32,
427 name: String,
428 code: i32,
429 msg: String,
430 }
431
432 impl ApiResponseTrait for TestFlattenData {
433 fn data_format() -> ResponseFormat {
434 ResponseFormat::Flatten
435 }
436 }
437
438 #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
439 struct TestBinaryData {
440 file_name: String,
441 content: Vec<u8>,
442 }
443
444 impl ApiResponseTrait for TestBinaryData {
445 fn data_format() -> ResponseFormat {
446 ResponseFormat::Binary
447 }
448 }
449
450 #[test]
454 fn test_optimized_base_response_success() {
455 let response = OptimizedBaseResponse {
456 code: 0,
457 msg: "success".to_string(),
458 error: None,
459 data: Some(TestData {
460 id: 1,
461 name: "test".to_string(),
462 }),
463 };
464
465 assert!(response.is_success());
466 assert!(response.data().is_some());
467 assert_eq!(response.data().unwrap().id, 1);
468 assert!(!response.has_error());
469 }
470
471 #[test]
472 fn test_optimized_base_response_error() {
473 let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
474 code: 400,
475 msg: "Bad Request".to_string(),
476 error: Some(ErrorInfo {
477 log_id: Some("log123".to_string()),
478 details: vec![],
479 }),
480 data: None,
481 };
482
483 assert!(!response.is_success());
484 assert!(response.has_error());
485 assert!(response.data().is_none());
486 }
487
488 #[test]
489 fn test_optimized_base_response_into_data_success() {
490 let response = OptimizedBaseResponse {
491 code: 0,
492 msg: "success".to_string(),
493 error: None,
494 data: Some(TestData {
495 id: 1,
496 name: "test".to_string(),
497 }),
498 };
499
500 let data = response.into_data().unwrap();
501 assert_eq!(data.id, 1);
502 assert_eq!(data.name, "test");
503 }
504
505 #[test]
506 fn test_optimized_base_response_into_data_error() {
507 let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
508 code: 400,
509 msg: "Bad Request".to_string(),
510 error: None,
511 data: None,
512 };
513
514 let result = response.into_data();
515 assert!(result.is_err());
516 match result.unwrap_err() {
517 CoreError::Api(api) => {
518 assert_eq!(api.status, 400);
519 assert_eq!(api.message, "Bad Request");
520 }
521 _ => panic!("Expected ApiError"),
522 }
523 }
524
525 #[test]
526 fn test_optimized_base_response_into_data_success_but_no_data() {
527 let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
528 code: 0,
529 msg: "success".to_string(),
530 error: None,
531 data: None,
532 };
533
534 let result = response.into_data();
535 assert!(result.is_err());
536 match result.unwrap_err() {
537 CoreError::Validation { message, .. } => {
538 assert!(message.contains("data is missing"));
539 }
540 _ => panic!("Expected IllegalParamError"),
541 }
542 }
543
544 #[test]
545 fn test_error_info_serialization() {
546 let error_info = ErrorInfo {
547 log_id: Some("test_log_id".to_string()),
548 details: vec![
549 ErrorDetail {
550 key: Some("field1".to_string()),
551 value: Some("invalid_value".to_string()),
552 description: Some("Field is required".to_string()),
553 },
554 ErrorDetail {
555 key: Some("field2".to_string()),
556 value: None,
557 description: Some("Missing field".to_string()),
558 },
559 ],
560 };
561
562 let json = serde_json::to_string(&error_info).unwrap();
563 let deserialized: ErrorInfo = serde_json::from_str(&json).unwrap();
564
565 assert_eq!(deserialized.log_id, error_info.log_id);
566 assert_eq!(deserialized.details.len(), 2);
567 assert_eq!(deserialized.details[0].key, Some("field1".to_string()));
568 assert_eq!(deserialized.details[1].value, None);
569 }
570
571 #[test]
572 fn test_error_detail_optional_fields() {
573 let detail = ErrorDetail {
574 key: None,
575 value: Some("test_value".to_string()),
576 description: None,
577 };
578
579 let json = serde_json::to_string(&detail).unwrap();
580 let deserialized: ErrorDetail = serde_json::from_str(&json).unwrap();
581
582 assert_eq!(deserialized.key, None);
583 assert_eq!(deserialized.value, Some("test_value".to_string()));
584 assert_eq!(deserialized.description, None);
585 }
586
587 #[test]
588 fn test_filename_extraction() {
589 let cases = vec![
590 (
591 "attachment; filename=\"test.txt\"",
592 Some("test.txt".to_string()),
593 ),
594 (
595 "attachment; filename*=UTF-8''test%20file.pdf",
596 Some("test%20file.pdf".to_string()),
597 ),
598 (
599 "attachment; filename=simple.doc",
600 Some("simple.doc".to_string()),
601 ),
602 ("attachment", None),
603 ("", None),
604 ("filename=\"quoted.txt\"", Some("quoted.txt".to_string())),
605 ("filename=unquoted.txt", Some("unquoted.txt".to_string())),
606 (
607 "filename*=UTF-8''unicode%E2%9C%93.txt",
608 Some("unicode%E2%9C%93.txt".to_string()),
609 ),
610 (
611 "attachment; filename=\"spaced file.doc\"; other=value",
612 Some("spaced file.doc".to_string()),
613 ),
614 ];
615
616 for (input, expected) in cases {
617 let result = crate::content_disposition::extract_filename(input);
618 assert_eq!(result, expected, "Failed for input: {input}");
619 }
620 }
621
622 #[test]
623 fn test_filename_extraction_edge_cases() {
624 assert_eq!(crate::content_disposition::extract_filename(""), None);
626 assert_eq!(crate::content_disposition::extract_filename(" "), None);
627 assert_eq!(crate::content_disposition::extract_filename(";;;"), None);
628
629 assert_eq!(
631 crate::content_disposition::extract_filename("filename="),
632 Some("".to_string())
633 );
634 assert_eq!(
635 crate::content_disposition::extract_filename("filename*="),
636 None
637 );
638 assert_eq!(
639 crate::content_disposition::extract_filename("filename=\""),
640 Some("".to_string())
641 );
642
643 assert_eq!(
645 crate::content_disposition::extract_filename("filename=\"\""),
646 Some("".to_string())
647 );
648
649 let multi_filename = "filename=\"first.txt\"; filename=\"second.txt\"";
651 assert_eq!(
652 crate::content_disposition::extract_filename(multi_filename),
653 Some("first.txt".to_string())
654 );
655 }
656
657 #[test]
658 fn test_json_parsing_performance() {
659 let json_data = r#"{"code": 0, "msg": "success", "data": {"id": 1, "name": "test"}}"#;
660
661 let start = std::time::Instant::now();
663 let _result: Result<OptimizedBaseResponse<TestData>, _> = serde_json::from_str(json_data);
664 let direct_parse_time = start.elapsed();
665
666 let start = std::time::Instant::now();
668 let _value: Value = serde_json::from_str(json_data).unwrap();
669 let _result: Result<OptimizedBaseResponse<TestData>, _> = serde_json::from_value(_value);
670 let double_parse_time = start.elapsed();
671
672 println!("Direct parse time: {direct_parse_time:?}");
673 println!("Double parse time: {double_parse_time:?}");
674
675 }
678
679 #[test]
680 fn test_api_response_trait_data_format() {
681 assert_eq!(TestData::data_format(), ResponseFormat::Data);
682 assert_eq!(TestFlattenData::data_format(), ResponseFormat::Flatten);
683 assert_eq!(TestBinaryData::data_format(), ResponseFormat::Binary);
684 }
685
686 #[test]
687 fn test_api_response_trait_from_binary() {
688 let file_name = "test.txt".to_string();
689 let content = b"Hello, World!".to_vec();
690
691 let binary_data = TestBinaryData {
692 file_name: file_name.clone(),
693 content: content.clone(),
694 };
695 assert_eq!(binary_data.file_name, file_name);
696 assert_eq!(binary_data.content, content);
697
698 let _ = "test.txt".to_string();
701 }
702
703 #[tokio::test]
707 async fn test_handle_data_response_parsing_logic() {
708 let test_cases = vec![
710 (r#"{"code": 400, "msg": "Bad Request"}"#, true),
712 (r#"{"invalid": json"#, false),
714 ];
715
716 for (json, should_succeed) in test_cases {
717 if json.contains("code") && !json.contains("raw_response") {
719 let fallback_result = serde_json::from_str::<Value>(json);
720 if should_succeed {
721 assert!(
722 fallback_result.is_ok(),
723 "Fallback parsing should succeed for: {}",
724 json
725 );
726 let value = fallback_result.unwrap();
727 assert!(value["code"].is_i64());
728 assert!(value["msg"].is_string());
729 }
730 } else if json.contains("invalid") {
731 let parse_result = serde_json::from_str::<Value>(json);
732 assert!(parse_result.is_err(), "Invalid JSON should fail to parse");
733 }
734 }
735 }
736
737 #[tokio::test]
738 async fn test_handle_flatten_response_parsing_logic() {
739 let test_cases = vec![
740 (
742 r#"{"id": 1, "name": "test", "code": 0, "msg": "success"}"#,
743 0,
744 true,
745 ),
746 (r#"{"code": 400, "msg": "Bad Request"}"#, 400, false),
748 (r#"{"invalid": json"#, -1, false),
750 ];
751
752 for (json, expected_code, should_have_data) in test_cases {
753 if json.contains("invalid") {
754 let parse_result = serde_json::from_str::<Value>(json);
755 assert!(parse_result.is_err(), "Invalid JSON should fail to parse");
756 continue;
757 }
758
759 let value_result = serde_json::from_str::<Value>(json);
760 assert!(value_result.is_ok(), "Valid JSON should parse as Value");
761
762 let value = value_result.unwrap();
763 let raw_response_result = serde_json::from_value::<RawResponse>(value.clone());
764
765 if expected_code >= 0 {
766 assert!(
767 raw_response_result.is_ok(),
768 "Should parse RawResponse for: {}",
769 json
770 );
771 let raw_response = raw_response_result.unwrap();
772 assert_eq!(raw_response.code, expected_code);
773
774 if should_have_data && raw_response.code == 0 {
775 let data_result = serde_json::from_value::<TestFlattenData>(value);
776 assert!(
777 data_result.is_ok(),
778 "Should parse data for success response"
779 );
780 }
781 }
782 }
783 }
784
785 #[test]
786 fn test_response_format_display_logic() {
787 let formats = vec![
788 (ResponseFormat::Data, "data"),
789 (ResponseFormat::Flatten, "flatten"),
790 (ResponseFormat::Binary, "binary"),
791 ];
792
793 for (format, expected_str) in formats {
794 let format_str = match format {
795 ResponseFormat::Data => "data",
796 ResponseFormat::Flatten => "flatten",
797 ResponseFormat::Binary => "binary",
798 ResponseFormat::Text => "text",
799 ResponseFormat::Custom => "custom",
800 };
801 assert_eq!(format_str, expected_str);
802 }
803 }
804
805 #[test]
806 fn test_binary_response_logic() {
807 let test_file_name = "test_document.pdf";
808 let test_content = b"PDF content here".to_vec();
809
810 let binary_data = TestBinaryData {
812 file_name: test_file_name.to_string(),
813 content: test_content.clone(),
814 };
815 assert!(binary_data.file_name == test_file_name);
816 assert!(binary_data.content == test_content);
817
818 let empty_data = TestBinaryData {
820 file_name: "empty.txt".to_string(),
821 content: vec![],
822 };
823 assert_eq!(empty_data.content.len(), 0);
824 }
825
826 #[test]
827 fn test_optimized_response_serialization_roundtrip() {
828 let original = OptimizedBaseResponse {
829 code: 0,
830 msg: "success".to_string(),
831 error: Some(ErrorInfo {
832 log_id: Some("test123".to_string()),
833 details: vec![ErrorDetail {
834 key: Some("validation".to_string()),
835 value: Some("failed".to_string()),
836 description: Some("Field validation failed".to_string()),
837 }],
838 }),
839 data: Some(TestData {
840 id: 42,
841 name: "serialization_test".to_string(),
842 }),
843 };
844
845 let json = serde_json::to_string(&original).unwrap();
847
848 let deserialized: OptimizedBaseResponse<TestData> = serde_json::from_str(&json).unwrap();
850
851 assert_eq!(deserialized.code, original.code);
853 assert_eq!(deserialized.msg, original.msg);
854 assert_eq!(deserialized.data, original.data);
855 assert!(deserialized.error.is_some());
856
857 let error = deserialized.error.unwrap();
858 assert_eq!(error.log_id, Some("test123".to_string()));
859 assert_eq!(error.details.len(), 1);
860 assert_eq!(error.details[0].key, Some("validation".to_string()));
861 }
862
863 #[test]
864 fn test_optimized_response_skipped_fields() {
865 let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
867 code: 0,
868 msg: "success".to_string(),
869 error: None,
870 data: None,
871 };
872
873 let json = serde_json::to_string(&response).unwrap();
874
875 assert!(!json.contains("\"error\""));
877 assert!(!json.contains("\"data\""));
878 assert!(json.contains("\"code\":0"));
879 assert!(json.contains("\"msg\":\"success\""));
880 }
881
882 #[test]
883 fn test_macro_api_response_implementation() {
884 #[derive(Debug, Default, Serialize, Deserialize)]
889 struct MacroTestData;
890
891 impl ApiResponseTrait for MacroTestData {
892 fn data_format() -> ResponseFormat {
893 ResponseFormat::Data
894 }
895 }
896
897 assert_eq!(MacroTestData::data_format(), ResponseFormat::Data);
898 }
901
902 #[test]
903 fn test_error_detail_empty_values() {
904 let detail = ErrorDetail {
905 key: Some("".to_string()),
906 value: Some("".to_string()),
907 description: Some("".to_string()),
908 };
909
910 let json = serde_json::to_string(&detail).unwrap();
911 let deserialized: ErrorDetail = serde_json::from_str(&json).unwrap();
912
913 assert_eq!(deserialized.key, Some("".to_string()));
914 assert_eq!(deserialized.value, Some("".to_string()));
915 assert_eq!(deserialized.description, Some("".to_string()));
916 }
917
918 #[test]
919 fn test_content_disposition_header_edge_cases() {
920 let edge_cases = vec![
921 ("FILENAME=\"test.txt\"", None), ("Filename=\"test.txt\"", None), (
926 "attachment; filename=\"test.txt\"",
927 Some("test.txt".to_string()),
928 ),
929 ("attachment; filename = \"test.txt\"", None), (
932 "attachment; filename=\"test-file_v1.2.txt\"",
933 Some("test-file_v1.2.txt".to_string()),
934 ),
935 (
936 "attachment; filename=\"测试文件.txt\"",
937 Some("测试文件.txt".to_string()),
938 ),
939 (
941 "attachment; filename=\"test.txt\"; filename*=UTF-8''better.txt",
942 Some("better.txt".to_string()),
943 ),
944 ];
945
946 for (input, expected) in edge_cases {
947 let result = crate::content_disposition::extract_filename(input);
948 assert_eq!(result, expected, "Failed for input: {}", input);
949 }
950 }
951
952 #[test]
956 fn test_complex_error_response_scenarios() {
957 use serde_json::Value;
958
959 let complex_error = r#"{
961 "code": 400,
962 "msg": "Validation failed",
963 "error": {
964 "log_id": "error_12345",
965 "details": [
966 {
967 "key": "field1",
968 "value": "invalid",
969 "description": "Field must be valid email"
970 },
971 {
972 "key": "field2",
973 "description": "Required field missing"
974 }
975 ]
976 }
977 }"#;
978
979 let parsed: Value = serde_json::from_str(complex_error).unwrap();
980 assert_eq!(parsed["code"], 400);
981 assert_eq!(parsed["msg"], "Validation failed");
982 assert!(parsed["error"]["log_id"].is_string());
983 assert_eq!(parsed["error"]["details"].as_array().unwrap().len(), 2);
984
985 let error_missing_msg = r#"{"code": 500}"#;
987 let parsed_missing: Value = serde_json::from_str(error_missing_msg).unwrap();
988 assert_eq!(parsed_missing["code"], 500);
989 assert!(!parsed_missing["msg"].is_string());
990
991 let invalid_code = r#"{"code": "400", "msg": "Invalid code type"}"#;
993 let parsed_invalid: Value = serde_json::from_str(invalid_code).unwrap();
994 assert!(parsed_invalid["code"].is_string());
995 }
996
997 #[test]
999 fn test_large_response_data_handling() {
1000 use serde_json::Value;
1001
1002 let large_data_list: Vec<String> = (0..1000).map(|i| format!("item_{}", i)).collect();
1004
1005 let large_response = serde_json::json!({
1006 "code": 0,
1007 "msg": "success",
1008 "data": {
1009 "items": large_data_list,
1010 "metadata": {
1011 "total": 1000,
1012 "page": 1
1013 }
1014 }
1015 });
1016
1017 let json_str = serde_json::to_string(&large_response).unwrap();
1018 assert!(json_str.len() > 10000); let parsed: Value = serde_json::from_str(&json_str).unwrap();
1022 assert_eq!(parsed["code"], 0);
1023 assert_eq!(parsed["data"]["items"].as_array().unwrap().len(), 1000);
1024 }
1025
1026 #[test]
1028 fn test_unicode_response_handling() {
1029 use serde_json::json;
1030
1031 let unicode_response = json!({
1032 "code": 0,
1033 "msg": "操作成功",
1034 "data": {
1035 "title": "测试标题",
1036 "description": "这是一个包含中文、English و العربية 的描述",
1037 "tags": ["标签1", "tag2", "العربية", "🚀"]
1038 }
1039 });
1040
1041 let json_str = serde_json::to_string(&unicode_response).unwrap();
1042 let parsed: Value = serde_json::from_str(&json_str).unwrap();
1043
1044 assert_eq!(parsed["msg"], "操作成功");
1045 assert_eq!(parsed["data"]["title"], "测试标题");
1046 assert!(parsed["data"]["description"]
1047 .as_str()
1048 .unwrap()
1049 .contains("中文"));
1050 assert!(parsed["data"]["tags"].as_array().unwrap()[3] == "🚀");
1051 }
1052
1053 #[test]
1055 fn test_memory_efficient_response_processing() {
1056 use std::mem;
1057
1058 let response = OptimizedBaseResponse {
1060 code: 0,
1061 msg: "success".to_string(),
1062 error: None,
1063 data: Some(TestData {
1064 id: 123,
1065 name: "test".to_string(),
1066 }),
1067 };
1068
1069 let response_size = mem::size_of_val(&response);
1070 assert!(response_size > 0);
1071
1072 let empty_response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
1074 code: 0,
1075 msg: "success".to_string(),
1076 error: None,
1077 data: None,
1078 };
1079
1080 let empty_size = mem::size_of_val(&empty_response);
1081 assert!(empty_size > 0);
1083 }
1084
1085 #[test]
1087 fn test_response_parsing_performance() {
1088 use std::time::Instant;
1089
1090 let test_json = r#"{"code": 0, "msg": "success", "data": {"id": 1, "name": "test"}}"#;
1091
1092 let iterations = 1000;
1094 let start = Instant::now();
1095
1096 for _ in 0..iterations {
1097 let _: Result<OptimizedBaseResponse<TestData>, _> = serde_json::from_str(test_json);
1098 }
1099
1100 let direct_time = start.elapsed();
1101
1102 let start = Instant::now();
1104
1105 for _ in 0..iterations {
1106 let value: Value = serde_json::from_str(test_json).unwrap();
1107 let _: Result<Response<TestData>, _> = serde_json::from_value(value);
1108 }
1109
1110 let fallback_time = start.elapsed();
1111
1112 println!(
1114 "Direct parsing: {:?}, Fallback parsing: {:?}",
1115 direct_time, fallback_time
1116 );
1117
1118 assert!(direct_time.as_millis() < 1000); assert!(fallback_time.as_millis() < 1000); let ratio = fallback_time.as_nanos() as f64 / direct_time.as_nanos() as f64;
1125 println!("Performance ratio (fallback/direct): {:.2}x", ratio);
1126 }
1127
1128 #[test]
1130 fn test_concurrent_response_parsing() {
1131 use std::sync::{Arc, Mutex};
1132 use std::thread;
1133
1134 let test_responses = vec![
1135 r#"{"code": 0, "msg": "success", "data": {"id": 1, "name": "test1"}}"#,
1136 r#"{"code": 0, "msg": "success", "data": {"id": 2, "name": "test2"}}"#,
1137 r#"{"code": 400, "msg": "error", "data": null}"#,
1138 r#"{"code": 0, "msg": "success", "data": {"id": 4, "name": "test4"}}"#,
1139 ];
1140
1141 let results = Arc::new(Mutex::new(Vec::new()));
1142 let mut handles = vec![];
1143
1144 for (i, response_json) in test_responses.into_iter().enumerate() {
1145 let results_clone = results.clone();
1146 let handle = thread::spawn(move || {
1147 let parsed: Result<OptimizedBaseResponse<TestData>, _> =
1148 serde_json::from_str(response_json);
1149
1150 results_clone.lock().unwrap().push((i, parsed.is_ok()));
1151 });
1152 handles.push(handle);
1153 }
1154
1155 for handle in handles {
1156 handle.join().unwrap();
1157 }
1158
1159 let results_vec = results.lock().unwrap();
1160 assert_eq!(results_vec.len(), 4);
1161 assert!(results_vec.iter().all(|(_, success)| *success));
1162 }
1163
1164 #[test]
1166 fn test_edge_case_json_structures() {
1167 use serde_json::json;
1168
1169 let null_response = json!({
1171 "code": 0,
1172 "msg": "success",
1173 "data": null
1174 });
1175
1176 let parsed: OptimizedBaseResponse<TestData> =
1177 serde_json::from_value(null_response).unwrap();
1178 assert!(parsed.is_success());
1179 assert!(parsed.data().is_none());
1180
1181 let empty_response = json!({
1183 "code": 0,
1184 "msg": "success",
1185 "data": {
1186 "items": [],
1187 "metadata": {}
1188 }
1189 });
1190
1191 let parsed_value: Value = serde_json::from_value(empty_response).unwrap();
1193 assert_eq!(parsed_value["data"]["items"].as_array().unwrap().len(), 0);
1194 assert!(parsed_value["data"]["metadata"]
1195 .as_object()
1196 .unwrap()
1197 .is_empty());
1198
1199 let extra_fields_response = json!({
1201 "code": 0,
1202 "msg": "success",
1203 "data": {"id": 1, "name": "test"},
1204 "unexpected_field": "should_be_ignored",
1205 "another_unexpected": {"nested": "data"}
1206 });
1207
1208 let parsed_extra: OptimizedBaseResponse<TestData> =
1209 serde_json::from_value(extra_fields_response).unwrap();
1210 assert!(parsed_extra.is_success());
1211 assert!(parsed_extra.data().is_some());
1212 }
1213
1214 #[test]
1216 fn test_response_format_validation() {
1217 let test_cases = vec![
1219 (ResponseFormat::Data, "data", true),
1220 (ResponseFormat::Flatten, "flatten", false),
1221 (ResponseFormat::Binary, "binary", false),
1222 ];
1223
1224 for (format, expected_str, supports_data) in test_cases {
1225 let format_str = match format {
1227 ResponseFormat::Data => "data",
1228 ResponseFormat::Flatten => "flatten",
1229 ResponseFormat::Binary => "binary",
1230 ResponseFormat::Text => "text",
1231 ResponseFormat::Custom => "custom",
1232 };
1233 assert_eq!(format_str, expected_str);
1234
1235 match format {
1237 ResponseFormat::Data => assert!(supports_data),
1238 ResponseFormat::Flatten => assert!(!supports_data),
1239 ResponseFormat::Binary => assert!(!supports_data),
1240 ResponseFormat::Text => assert!(supports_data),
1241 ResponseFormat::Custom => assert!(supports_data),
1242 }
1243 }
1244 }
1245
1246 #[test]
1248 fn test_binary_response_edge_cases() {
1249 let large_binary = vec![0u8; 1_000_000]; let large_binary_data = TestBinaryData {
1252 file_name: "large_file.bin".to_string(),
1253 content: large_binary,
1254 };
1255 assert_eq!(large_binary_data.content.len(), 1_000_000);
1256
1257 let empty_binary_data = TestBinaryData {
1259 file_name: "empty_file.txt".to_string(),
1260 content: vec![],
1261 };
1262 assert!(empty_binary_data.content.is_empty());
1263
1264 let special_filename_data = TestBinaryData {
1266 file_name: "测试文件@#$%.txt".to_string(),
1267 content: b"test content".to_vec(),
1268 };
1269 assert_eq!(special_filename_data.file_name, "测试文件@#$%.txt");
1270 }
1271
1272 #[test]
1274 fn test_complex_error_detail_scenarios() {
1275 let complex_error = ErrorInfo {
1277 log_id: Some("complex_error_123".to_string()),
1278 details: vec![
1279 ErrorDetail {
1280 key: Some("validation".to_string()),
1281 value: Some("email格式不正确".to_string()),
1282 description: Some("邮箱地址格式验证失败".to_string()),
1283 },
1284 ErrorDetail {
1285 key: Some("required_field".to_string()),
1286 value: None,
1287 description: Some("必填字段缺失".to_string()),
1288 },
1289 ErrorDetail {
1290 key: Some("constraint".to_string()),
1291 value: Some("长度超过限制".to_string()),
1292 description: Some("字段长度超出最大限制".to_string()),
1293 },
1294 ],
1295 };
1296
1297 let json = serde_json::to_string(&complex_error).unwrap();
1299 let deserialized: ErrorInfo = serde_json::from_str(&json).unwrap();
1300
1301 assert_eq!(deserialized.log_id, complex_error.log_id);
1302 assert_eq!(deserialized.details.len(), 3);
1303 assert_eq!(
1304 deserialized.details[0].description,
1305 Some("邮箱地址格式验证失败".to_string())
1306 );
1307 assert_eq!(deserialized.details[1].value, None);
1308 assert_eq!(deserialized.details[2].key, Some("constraint".to_string()));
1309 }
1310
1311 #[test]
1313 fn test_response_tracker_integration_simulation() {
1314 let tracker_calls = [
1316 ("start", "json_data", Some(1024)),
1317 ("parsing_complete", "", None),
1318 ("validation_complete", "", None),
1319 ("success", "", None),
1320 ];
1321
1322 assert_eq!(tracker_calls.len(), 4);
1324 assert_eq!(tracker_calls[0].0, "start");
1325 assert_eq!(tracker_calls[0].1, "json_data");
1326 assert_eq!(tracker_calls[0].2, Some(1024));
1327
1328 let error_tracker_calls = [
1330 ("start", "json_flatten", Some(512)),
1331 ("error", "解析失败", None),
1332 ];
1333
1334 assert_eq!(error_tracker_calls.len(), 2);
1335 assert_eq!(error_tracker_calls[1].0, "error");
1336 assert_eq!(error_tracker_calls[1].1, "解析失败");
1337 }
1338
1339 #[test]
1341 fn test_real_world_response_patterns() {
1342 use serde_json::json;
1343
1344 let pagination_response = json!({
1346 "code": 0,
1347 "msg": "success",
1348 "data": {
1349 "items": [
1350 {"id": 1, "name": "item1"},
1351 {"id": 2, "name": "item2"}
1352 ],
1353 "page_token": "next_page_token",
1354 "has_more": true
1355 }
1356 });
1357
1358 let pagination_parsed: Value = serde_json::from_value(pagination_response).unwrap();
1359 assert_eq!(
1360 pagination_parsed["data"]["items"].as_array().unwrap().len(),
1361 2
1362 );
1363 assert!(pagination_parsed["data"]["has_more"].as_bool().unwrap());
1364
1365 let nested_response = json!({
1367 "code": 0,
1368 "msg": "success",
1369 "data": {
1370 "user": {
1371 "id": "user_123",
1372 "profile": {
1373 "name": "张三",
1374 "department": "技术部"
1375 }
1376 },
1377 "permissions": ["read", "write"]
1378 }
1379 });
1380
1381 let nested_parsed: Value = serde_json::from_value(nested_response).unwrap();
1382 assert_eq!(nested_parsed["data"]["user"]["profile"]["name"], "张三");
1383 assert_eq!(
1384 nested_parsed["data"]["permissions"]
1385 .as_array()
1386 .unwrap()
1387 .len(),
1388 2
1389 );
1390
1391 let validation_error_response = json!({
1393 "code": 400,
1394 "msg": "参数验证失败",
1395 "error": {
1396 "log_id": "validation_error_456",
1397 "details": [
1398 {
1399 "field": "email",
1400 "error_code": "INVALID_FORMAT",
1401 "message": "邮箱格式不正确"
1402 }
1403 ]
1404 }
1405 });
1406
1407 let validation_parsed: Value = serde_json::from_value(validation_error_response).unwrap();
1408 assert_eq!(validation_parsed["code"], 400);
1409 assert!(!validation_parsed["error"]["details"]
1410 .as_array()
1411 .unwrap()
1412 .is_empty());
1413 }
1414
1415 #[test]
1417 fn test_optimized_response_performance_characteristics() {
1418 use std::time::Instant;
1419
1420 let start = Instant::now();
1422 let mut responses = Vec::new();
1423
1424 for i in 0..1000 {
1425 responses.push(OptimizedBaseResponse {
1426 code: if i % 10 == 0 { 400 } else { 0 },
1427 msg: if i % 10 == 0 {
1428 "error".to_string()
1429 } else {
1430 "success".to_string()
1431 },
1432 error: if i % 10 == 0 {
1433 Some(ErrorInfo {
1434 log_id: Some(format!("log_{}", i)),
1435 details: vec![],
1436 })
1437 } else {
1438 None
1439 },
1440 data: if i % 10 != 0 {
1441 Some(TestData {
1442 id: i,
1443 name: format!("test_{}", i),
1444 })
1445 } else {
1446 None
1447 },
1448 });
1449 }
1450
1451 let creation_time = start.elapsed();
1452 assert_eq!(responses.len(), 1000);
1453 assert!(creation_time.as_millis() < 100); let start = Instant::now();
1457 let successful_responses: Vec<_> = responses.iter().filter(|r| r.is_success()).collect();
1458
1459 let filter_time = start.elapsed();
1460 assert_eq!(successful_responses.len(), 900);
1461 assert!(filter_time.as_millis() < 10); }
1463}
1464
1465mod usage_examples {}