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