open_lark/core/
improved_response_handler.rs

1use log::debug;
2use serde_json::Value;
3use tracing::{info_span, Instrument};
4
5use crate::core::{
6    api_resp::{ApiResponseTrait, BaseResponse, RawResponse, ResponseFormat},
7    error::LarkAPIError,
8    observability::ResponseTracker,
9    SDKResult,
10};
11
12/// 改进的响应处理器,解决双重解析问题
13/// 使用 #[serde(flatten)] 和高级 Serde 特性简化反序列化
14pub struct ImprovedResponseHandler;
15
16impl ImprovedResponseHandler {
17    /// 处理响应的核心方法
18    /// 相比原始实现,这个版本:
19    /// 1. 减少了不必要的JSON解析次数
20    /// 2. 使用更高效的直接反序列化
21    /// 3. 更好的错误处理
22    /// 4. 完整的可观测性支持
23    pub async fn handle_response<T: ApiResponseTrait>(
24        response: reqwest::Response,
25    ) -> SDKResult<BaseResponse<T>> {
26        let format = match T::data_format() {
27            ResponseFormat::Data => "data",
28            ResponseFormat::Flatten => "flatten",
29            ResponseFormat::Binary => "binary",
30        };
31
32        let span = info_span!(
33            "response_handling",
34            format = format,
35            status_code = response.status().as_u16(),
36            content_length = tracing::field::Empty,
37            processing_duration_ms = tracing::field::Empty,
38        );
39
40        async move {
41            let start_time = std::time::Instant::now();
42
43            // 获取内容长度用于监控
44            let content_length = response.content_length();
45            if let Some(length) = content_length {
46                tracing::Span::current().record("content_length", length);
47            }
48
49            let result = match T::data_format() {
50                ResponseFormat::Data => Self::handle_data_response(response).await,
51                ResponseFormat::Flatten => Self::handle_flatten_response(response).await,
52                ResponseFormat::Binary => Self::handle_binary_response(response).await,
53            };
54
55            // 记录处理时间
56            let duration_ms = start_time.elapsed().as_millis() as u64;
57            tracing::Span::current().record("processing_duration_ms", duration_ms);
58
59            result
60        }
61        .instrument(span)
62        .await
63    }
64
65    /// 处理标准数据格式响应
66    /// 使用单次解析而非双重解析,包含详细的可观测性
67    async fn handle_data_response<T: ApiResponseTrait>(
68        response: reqwest::Response,
69    ) -> SDKResult<BaseResponse<T>> {
70        let tracker = ResponseTracker::start("json_data", response.content_length());
71
72        let response_text = response.text().await?;
73        debug!("Raw response: {response_text}");
74
75        // 记录解析阶段开始
76        tracker.parsing_complete();
77
78        // 尝试直接解析为BaseResponse<T>
79        match serde_json::from_str::<BaseResponse<T>>(&response_text) {
80            Ok(base_response) => {
81                tracker.success();
82                Ok(base_response)
83            }
84            Err(direct_parse_err) => {
85                tracing::debug!("Direct parsing failed, attempting structured data extraction");
86
87                // 解析基础JSON结构
88                match serde_json::from_str::<Value>(&response_text) {
89                    Ok(raw_value) => {
90                        let code = raw_value["code"].as_i64().unwrap_or(-1) as i32;
91                        let msg = raw_value["msg"]
92                            .as_str()
93                            .unwrap_or("Unknown error")
94                            .to_string();
95
96                        // 如果响应成功,尝试提取并解析data字段
97                        let data = if code == 0 {
98                            if let Some(data_value) = raw_value.get("data") {
99                                // 尝试解析为期望的类型T
100                                match serde_json::from_value::<T>(data_value.clone()) {
101                                    Ok(parsed_data) => {
102                                        tracing::debug!("Successfully parsed data field as type T");
103                                        Some(parsed_data)
104                                    }
105                                    Err(data_parse_err) => {
106                                        tracing::debug!("Failed to parse data field as type T: {data_parse_err:?}");
107
108                                        // 特殊处理:如果T是CreateMessageResp但data直接是Message,尝试包装
109                                        if std::any::type_name::<T>().contains("CreateMessageResp")
110                                        {
111                                            // 尝试将data值包装为 {"data": data_value} 结构
112                                            let wrapped_value = serde_json::json!({
113                                                "data": data_value
114                                            });
115                                            match serde_json::from_value::<T>(wrapped_value) {
116                                                Ok(wrapped_data) => {
117                                                    tracing::debug!("Successfully parsed data by wrapping Message in CreateMessageResp");
118                                                    Some(wrapped_data)
119                                                }
120                                                Err(_) => {
121                                                    tracing::warn!("Failed to parse even after wrapping, but response contains valid message data");
122                                                    // API调用成功了,数据存在,只是结构不匹配
123                                                    None
124                                                }
125                                            }
126                                        } else {
127                                            None
128                                        }
129                                    }
130                                }
131                            } else {
132                                tracing::debug!("No data field found in successful response");
133                                None
134                            }
135                        } else {
136                            None
137                        };
138
139                        tracker.validation_complete();
140                        tracker.success();
141
142                        Ok(BaseResponse {
143                            raw_response: RawResponse {
144                                code,
145                                msg,
146                                err: None,
147                            },
148                            data,
149                        })
150                    }
151                    Err(fallback_err) => {
152                        let error_msg = format!(
153                            "Failed to parse response. Direct parse error: {}. Fallback parse error: {}",
154                            direct_parse_err, fallback_err
155                        );
156                        tracker.error(&error_msg);
157                        Err(LarkAPIError::IllegalParamError(error_msg))
158                    }
159                }
160            }
161        }
162    }
163
164    /// 处理扁平格式响应
165    /// 对于扁平格式,使用自定义反序列化器,包含可观测性支持
166    async fn handle_flatten_response<T: ApiResponseTrait>(
167        response: reqwest::Response,
168    ) -> SDKResult<BaseResponse<T>> {
169        let tracker = ResponseTracker::start("json_flatten", response.content_length());
170
171        let response_text = response.text().await?;
172        debug!("Raw response: {response_text}");
173
174        // 解析阶段
175        let raw_value: Value = match serde_json::from_str(&response_text) {
176            Ok(value) => {
177                tracker.parsing_complete();
178                value
179            }
180            Err(e) => {
181                let error_msg = format!("Failed to parse JSON: {}", e);
182                tracker.error(&error_msg);
183                return Err(LarkAPIError::IllegalParamError(error_msg));
184            }
185        };
186
187        // 解析原始响应信息
188        let raw_response: RawResponse = match serde_json::from_value(raw_value.clone()) {
189            Ok(response) => response,
190            Err(e) => {
191                let error_msg = format!("Failed to parse raw response: {}", e);
192                tracker.error(&error_msg);
193                return Err(LarkAPIError::IllegalParamError(error_msg));
194            }
195        };
196
197        // 验证和数据解析阶段
198        let data = if raw_response.code == 0 {
199            match serde_json::from_value::<T>(raw_value) {
200                Ok(parsed_data) => {
201                    tracker.validation_complete();
202                    Some(parsed_data)
203                }
204                Err(e) => {
205                    debug!("Failed to parse data for flatten response: {e}");
206                    tracker.validation_complete();
207                    None
208                }
209            }
210        } else {
211            tracker.validation_complete();
212            None
213        };
214
215        tracker.success();
216        Ok(BaseResponse { raw_response, data })
217    }
218
219    /// 处理二进制响应,包含可观测性支持
220    async fn handle_binary_response<T: ApiResponseTrait>(
221        response: reqwest::Response,
222    ) -> SDKResult<BaseResponse<T>> {
223        let tracker = ResponseTracker::start("binary", response.content_length());
224
225        // 获取文件名
226        let file_name = response
227            .headers()
228            .get("Content-Disposition")
229            .and_then(|header| header.to_str().ok())
230            .and_then(Self::extract_filename)
231            .unwrap_or_default();
232
233        // 记录解析阶段完成(文件名提取)
234        tracker.parsing_complete();
235
236        // 获取二进制数据
237        let bytes = match response.bytes().await {
238            Ok(bytes) => {
239                let byte_vec = bytes.to_vec();
240                tracing::debug!("Binary response received: {} bytes", byte_vec.len());
241                byte_vec
242            }
243            Err(e) => {
244                let error_msg = format!("Failed to read binary response: {}", e);
245                tracker.error(&error_msg);
246                return Err(LarkAPIError::RequestError(error_msg));
247            }
248        };
249
250        // 验证阶段 - 使用trait方法创建数据
251        let data = match T::from_binary(file_name.clone(), bytes) {
252            Some(binary_data) => {
253                tracker.validation_complete();
254                Some(binary_data)
255            }
256            None => {
257                tracker.validation_complete();
258                tracing::warn!("Binary data could not be processed for file: {}", file_name);
259                None
260            }
261        };
262
263        tracker.success();
264        Ok(BaseResponse {
265            raw_response: RawResponse {
266                code: 0,
267                msg: "success".to_string(),
268                err: None,
269            },
270            data,
271        })
272    }
273
274    /// 提取文件名的辅助函数
275    fn extract_filename(content_disposition: &str) -> Option<String> {
276        // 支持多种文件名格式
277        for part in content_disposition.split(';') {
278            let part = part.trim();
279
280            // 支持 filename*=UTF-8''filename 格式
281            if let Some(filename) = part.strip_prefix("filename*=UTF-8''") {
282                return Some(filename.to_string());
283            }
284
285            // 支持 filename="filename" 格式
286            if let Some(filename) = part.strip_prefix("filename=") {
287                let filename = filename.trim_matches('"');
288                return Some(filename.to_string());
289            }
290        }
291        None
292    }
293}
294
295/// 优化的BaseResponse,使用更好的serde特性
296#[derive(Debug, serde::Serialize, serde::Deserialize)]
297pub struct OptimizedBaseResponse<T>
298where
299    T: Default,
300{
301    /// 响应状态码
302    pub code: i32,
303    /// 响应消息
304    pub msg: String,
305    /// 错误信息(可选)
306    #[serde(rename = "error", default, skip_serializing_if = "Option::is_none")]
307    pub error: Option<ErrorInfo>,
308    /// 业务数据(可选)
309    #[serde(default, skip_serializing_if = "Option::is_none")]
310    pub data: Option<T>,
311}
312
313impl<T> OptimizedBaseResponse<T>
314where
315    T: Default,
316{
317    /// 检查请求是否成功
318    pub fn is_success(&self) -> bool {
319        self.code == 0
320    }
321
322    /// 获取业务数据,如果请求失败则返回错误
323    pub fn into_data(self) -> Result<T, LarkAPIError> {
324        if self.is_success() {
325            self.data.ok_or_else(|| {
326                LarkAPIError::illegal_param("Response is successful but data is missing")
327            })
328        } else {
329            Err(LarkAPIError::api_error(
330                self.code, self.msg, None, // 这里可以添加request_id如果有的话
331            ))
332        }
333    }
334
335    /// 获取数据的引用
336    pub fn data(&self) -> Option<&T> {
337        self.data.as_ref()
338    }
339
340    /// 检查是否有错误信息
341    pub fn has_error(&self) -> bool {
342        self.error.is_some()
343    }
344}
345
346#[derive(Debug, serde::Serialize, serde::Deserialize)]
347pub struct ErrorInfo {
348    #[serde(rename = "key", default, skip_serializing_if = "Option::is_none")]
349    pub log_id: Option<String>,
350    #[serde(default, skip_serializing_if = "Vec::is_empty")]
351    pub details: Vec<ErrorDetail>,
352}
353
354#[derive(Debug, serde::Serialize, serde::Deserialize)]
355pub struct ErrorDetail {
356    #[serde(default, skip_serializing_if = "Option::is_none")]
357    pub key: Option<String>,
358    #[serde(default, skip_serializing_if = "Option::is_none")]
359    pub value: Option<String>,
360    #[serde(default, skip_serializing_if = "Option::is_none")]
361    pub description: Option<String>,
362}
363
364/// 使用宏简化APIResponseTrait实现
365#[macro_export]
366macro_rules! impl_api_response {
367    ($type:ty, $format:expr) => {
368        impl ApiResponseTrait for $type {
369            fn data_format() -> ResponseFormat {
370                $format
371            }
372        }
373    };
374
375    ($type:ty, $format:expr, binary) => {
376        impl ApiResponseTrait for $type {
377            fn data_format() -> ResponseFormat {
378                $format
379            }
380
381            fn from_binary(file_name: String, body: Vec<u8>) -> Option<Self> {
382                Some(<$type>::from_binary_data(file_name, body))
383            }
384        }
385    };
386}
387
388#[cfg(test)]
389mod tests {
390    use super::*;
391    use crate::core::api_resp::ResponseFormat;
392    use serde::{Deserialize, Serialize};
393
394    #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
395    struct TestData {
396        id: i32,
397        name: String,
398    }
399
400    impl ApiResponseTrait for TestData {
401        fn data_format() -> ResponseFormat {
402            ResponseFormat::Data
403        }
404    }
405
406    #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
407    struct TestFlattenData {
408        id: i32,
409        name: String,
410        code: i32,
411        msg: String,
412    }
413
414    impl ApiResponseTrait for TestFlattenData {
415        fn data_format() -> ResponseFormat {
416            ResponseFormat::Flatten
417        }
418    }
419
420    #[derive(Debug, Serialize, Deserialize, PartialEq, Default, Clone)]
421    struct TestBinaryData {
422        file_name: String,
423        content: Vec<u8>,
424    }
425
426    impl ApiResponseTrait for TestBinaryData {
427        fn data_format() -> ResponseFormat {
428            ResponseFormat::Binary
429        }
430
431        fn from_binary(file_name: String, body: Vec<u8>) -> Option<Self> {
432            Some(TestBinaryData {
433                file_name,
434                content: body,
435            })
436        }
437    }
438
439    // Note: Mock HTTP responses would require a more sophisticated testing setup
440    // The helper functions below are simplified examples of what mock functions might look like
441
442    #[test]
443    fn test_optimized_base_response_success() {
444        let response = OptimizedBaseResponse {
445            code: 0,
446            msg: "success".to_string(),
447            error: None,
448            data: Some(TestData {
449                id: 1,
450                name: "test".to_string(),
451            }),
452        };
453
454        assert!(response.is_success());
455        assert!(response.data().is_some());
456        assert_eq!(response.data().unwrap().id, 1);
457        assert!(!response.has_error());
458    }
459
460    #[test]
461    fn test_optimized_base_response_error() {
462        let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
463            code: 400,
464            msg: "Bad Request".to_string(),
465            error: Some(ErrorInfo {
466                log_id: Some("log123".to_string()),
467                details: vec![],
468            }),
469            data: None,
470        };
471
472        assert!(!response.is_success());
473        assert!(response.has_error());
474        assert!(response.data().is_none());
475    }
476
477    #[test]
478    fn test_optimized_base_response_into_data_success() {
479        let response = OptimizedBaseResponse {
480            code: 0,
481            msg: "success".to_string(),
482            error: None,
483            data: Some(TestData {
484                id: 1,
485                name: "test".to_string(),
486            }),
487        };
488
489        let data = response.into_data().unwrap();
490        assert_eq!(data.id, 1);
491        assert_eq!(data.name, "test");
492    }
493
494    #[test]
495    fn test_optimized_base_response_into_data_error() {
496        let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
497            code: 400,
498            msg: "Bad Request".to_string(),
499            error: None,
500            data: None,
501        };
502
503        let result = response.into_data();
504        assert!(result.is_err());
505        match result.unwrap_err() {
506            LarkAPIError::ApiError { code, message, .. } => {
507                assert_eq!(code, 400);
508                assert_eq!(message, "Bad Request");
509            }
510            _ => panic!("Expected ApiError"),
511        }
512    }
513
514    #[test]
515    fn test_optimized_base_response_into_data_success_but_no_data() {
516        let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
517            code: 0,
518            msg: "success".to_string(),
519            error: None,
520            data: None,
521        };
522
523        let result = response.into_data();
524        assert!(result.is_err());
525        match result.unwrap_err() {
526            LarkAPIError::IllegalParamError(msg) => {
527                assert!(msg.contains("data is missing"));
528            }
529            _ => panic!("Expected IllegalParamError"),
530        }
531    }
532
533    #[test]
534    fn test_error_info_serialization() {
535        let error_info = ErrorInfo {
536            log_id: Some("test_log_id".to_string()),
537            details: vec![
538                ErrorDetail {
539                    key: Some("field1".to_string()),
540                    value: Some("invalid_value".to_string()),
541                    description: Some("Field is required".to_string()),
542                },
543                ErrorDetail {
544                    key: Some("field2".to_string()),
545                    value: None,
546                    description: Some("Missing field".to_string()),
547                },
548            ],
549        };
550
551        let json = serde_json::to_string(&error_info).unwrap();
552        let deserialized: ErrorInfo = serde_json::from_str(&json).unwrap();
553
554        assert_eq!(deserialized.log_id, error_info.log_id);
555        assert_eq!(deserialized.details.len(), 2);
556        assert_eq!(deserialized.details[0].key, Some("field1".to_string()));
557        assert_eq!(deserialized.details[1].value, None);
558    }
559
560    #[test]
561    fn test_error_detail_optional_fields() {
562        let detail = ErrorDetail {
563            key: None,
564            value: Some("test_value".to_string()),
565            description: None,
566        };
567
568        let json = serde_json::to_string(&detail).unwrap();
569        let deserialized: ErrorDetail = serde_json::from_str(&json).unwrap();
570
571        assert_eq!(deserialized.key, None);
572        assert_eq!(deserialized.value, Some("test_value".to_string()));
573        assert_eq!(deserialized.description, None);
574    }
575
576    #[test]
577    fn test_filename_extraction() {
578        let cases = vec![
579            (
580                "attachment; filename=\"test.txt\"",
581                Some("test.txt".to_string()),
582            ),
583            (
584                "attachment; filename*=UTF-8''test%20file.pdf",
585                Some("test%20file.pdf".to_string()),
586            ),
587            (
588                "attachment; filename=simple.doc",
589                Some("simple.doc".to_string()),
590            ),
591            ("attachment", None),
592            ("", None),
593            ("filename=\"quoted.txt\"", Some("quoted.txt".to_string())),
594            ("filename=unquoted.txt", Some("unquoted.txt".to_string())),
595            (
596                "filename*=UTF-8''unicode%E2%9C%93.txt",
597                Some("unicode%E2%9C%93.txt".to_string()),
598            ),
599            (
600                "attachment; filename=\"spaced file.doc\"; other=value",
601                Some("spaced file.doc".to_string()),
602            ),
603        ];
604
605        for (input, expected) in cases {
606            let result = ImprovedResponseHandler::extract_filename(input);
607            assert_eq!(result, expected, "Failed for input: {input}");
608        }
609    }
610
611    #[test]
612    fn test_filename_extraction_edge_cases() {
613        // Test empty and whitespace-only strings
614        assert_eq!(ImprovedResponseHandler::extract_filename(""), None);
615        assert_eq!(ImprovedResponseHandler::extract_filename("   "), None);
616        assert_eq!(ImprovedResponseHandler::extract_filename(";;;"), None);
617
618        // Test malformed headers - based on implementation behavior
619        assert_eq!(
620            ImprovedResponseHandler::extract_filename("filename="),
621            Some("".to_string())
622        );
623        assert_eq!(
624            ImprovedResponseHandler::extract_filename("filename*="),
625            None
626        ); // Doesn't match UTF-8 prefix, doesn't match filename= exactly
627        assert_eq!(
628            ImprovedResponseHandler::extract_filename("filename=\""),
629            Some("".to_string())
630        );
631
632        // Test with only quotes - the current implementation extracts empty string
633        assert_eq!(
634            ImprovedResponseHandler::extract_filename("filename=\"\""),
635            Some("".to_string())
636        );
637
638        // Test multiple filename directives (should return first valid one)
639        let multi_filename = "filename=\"first.txt\"; filename=\"second.txt\"";
640        assert_eq!(
641            ImprovedResponseHandler::extract_filename(multi_filename),
642            Some("first.txt".to_string())
643        );
644    }
645
646    #[test]
647    fn test_json_parsing_performance() {
648        let json_data = r#"{"code": 0, "msg": "success", "data": {"id": 1, "name": "test"}}"#;
649
650        // 测试直接解析
651        let start = std::time::Instant::now();
652        let _result: Result<OptimizedBaseResponse<TestData>, _> = serde_json::from_str(json_data);
653        let direct_parse_time = start.elapsed();
654
655        // 测试双重解析(原始方法)
656        let start = std::time::Instant::now();
657        let _value: Value = serde_json::from_str(json_data).unwrap();
658        let _result: Result<OptimizedBaseResponse<TestData>, _> = serde_json::from_value(_value);
659        let double_parse_time = start.elapsed();
660
661        println!("Direct parse time: {direct_parse_time:?}");
662        println!("Double parse time: {double_parse_time:?}");
663
664        // 直接解析应该更快(虽然在微基准测试中差异可能很小)
665        // 这里主要是为了展示概念
666    }
667
668    #[test]
669    fn test_api_response_trait_data_format() {
670        assert_eq!(TestData::data_format(), ResponseFormat::Data);
671        assert_eq!(TestFlattenData::data_format(), ResponseFormat::Flatten);
672        assert_eq!(TestBinaryData::data_format(), ResponseFormat::Binary);
673    }
674
675    #[test]
676    fn test_api_response_trait_from_binary() {
677        let file_name = "test.txt".to_string();
678        let content = b"Hello, World!".to_vec();
679
680        let binary_data = TestBinaryData::from_binary(file_name.clone(), content.clone()).unwrap();
681        assert_eq!(binary_data.file_name, file_name);
682        assert_eq!(binary_data.content, content);
683
684        // Test default implementation for non-binary types
685        let default_result = TestData::from_binary("test.txt".to_string(), vec![1, 2, 3]);
686        assert!(default_result.is_none());
687    }
688
689    // Mock tests for response handlers would require a more sophisticated mocking setup
690    // For now, we'll test the logic that doesn't require actual HTTP responses
691
692    #[tokio::test]
693    async fn test_handle_data_response_parsing_logic() {
694        // Test JSON parsing logic without actual HTTP response
695        let test_cases = vec![
696            // Error response with fallback parsing
697            (r#"{"code": 400, "msg": "Bad Request"}"#, true),
698            // Invalid JSON
699            (r#"{"invalid": json"#, false),
700        ];
701
702        for (json, should_succeed) in test_cases {
703            // Test fallback parsing for error responses
704            if json.contains("code") && !json.contains("raw_response") {
705                let fallback_result = serde_json::from_str::<Value>(json);
706                if should_succeed {
707                    assert!(
708                        fallback_result.is_ok(),
709                        "Fallback parsing should succeed for: {}",
710                        json
711                    );
712                    let value = fallback_result.unwrap();
713                    assert!(value["code"].is_i64());
714                    assert!(value["msg"].is_string());
715                }
716            } else if json.contains("invalid") {
717                let parse_result = serde_json::from_str::<Value>(json);
718                assert!(parse_result.is_err(), "Invalid JSON should fail to parse");
719            }
720        }
721    }
722
723    #[tokio::test]
724    async fn test_handle_flatten_response_parsing_logic() {
725        let test_cases = vec![
726            // Success response
727            (
728                r#"{"id": 1, "name": "test", "code": 0, "msg": "success"}"#,
729                0,
730                true,
731            ),
732            // Error response
733            (r#"{"code": 400, "msg": "Bad Request"}"#, 400, false),
734            // Invalid JSON
735            (r#"{"invalid": json"#, -1, false),
736        ];
737
738        for (json, expected_code, should_have_data) in test_cases {
739            if json.contains("invalid") {
740                let parse_result = serde_json::from_str::<Value>(json);
741                assert!(parse_result.is_err(), "Invalid JSON should fail to parse");
742                continue;
743            }
744
745            let value_result = serde_json::from_str::<Value>(json);
746            assert!(value_result.is_ok(), "Valid JSON should parse as Value");
747
748            let value = value_result.unwrap();
749            let raw_response_result = serde_json::from_value::<RawResponse>(value.clone());
750
751            if expected_code >= 0 {
752                assert!(
753                    raw_response_result.is_ok(),
754                    "Should parse RawResponse for: {}",
755                    json
756                );
757                let raw_response = raw_response_result.unwrap();
758                assert_eq!(raw_response.code, expected_code);
759
760                if should_have_data && raw_response.code == 0 {
761                    let data_result = serde_json::from_value::<TestFlattenData>(value);
762                    assert!(
763                        data_result.is_ok(),
764                        "Should parse data for success response"
765                    );
766                }
767            }
768        }
769    }
770
771    #[test]
772    fn test_response_format_display_logic() {
773        let formats = vec![
774            (ResponseFormat::Data, "data"),
775            (ResponseFormat::Flatten, "flatten"),
776            (ResponseFormat::Binary, "binary"),
777        ];
778
779        for (format, expected_str) in formats {
780            let format_str = match format {
781                ResponseFormat::Data => "data",
782                ResponseFormat::Flatten => "flatten",
783                ResponseFormat::Binary => "binary",
784            };
785            assert_eq!(format_str, expected_str);
786        }
787    }
788
789    #[test]
790    fn test_binary_response_logic() {
791        let test_file_name = "test_document.pdf";
792        let test_content = b"PDF content here".to_vec();
793
794        // Test successful binary data creation
795        let binary_data =
796            TestBinaryData::from_binary(test_file_name.to_string(), test_content.clone());
797        assert!(binary_data.is_some());
798
799        let data = binary_data.unwrap();
800        assert_eq!(data.file_name, test_file_name);
801        assert_eq!(data.content, test_content);
802
803        // Test empty content
804        let empty_data = TestBinaryData::from_binary("empty.txt".to_string(), vec![]);
805        assert!(empty_data.is_some());
806        assert_eq!(empty_data.unwrap().content.len(), 0);
807    }
808
809    #[test]
810    fn test_optimized_response_serialization_roundtrip() {
811        let original = OptimizedBaseResponse {
812            code: 0,
813            msg: "success".to_string(),
814            error: Some(ErrorInfo {
815                log_id: Some("test123".to_string()),
816                details: vec![ErrorDetail {
817                    key: Some("validation".to_string()),
818                    value: Some("failed".to_string()),
819                    description: Some("Field validation failed".to_string()),
820                }],
821            }),
822            data: Some(TestData {
823                id: 42,
824                name: "serialization_test".to_string(),
825            }),
826        };
827
828        // Serialize to JSON
829        let json = serde_json::to_string(&original).unwrap();
830
831        // Deserialize back
832        let deserialized: OptimizedBaseResponse<TestData> = serde_json::from_str(&json).unwrap();
833
834        // Verify all fields are preserved
835        assert_eq!(deserialized.code, original.code);
836        assert_eq!(deserialized.msg, original.msg);
837        assert_eq!(deserialized.data, original.data);
838        assert!(deserialized.error.is_some());
839
840        let error = deserialized.error.unwrap();
841        assert_eq!(error.log_id, Some("test123".to_string()));
842        assert_eq!(error.details.len(), 1);
843        assert_eq!(error.details[0].key, Some("validation".to_string()));
844    }
845
846    #[test]
847    fn test_optimized_response_skipped_fields() {
848        // Test response with None values (should be skipped in serialization)
849        let response: OptimizedBaseResponse<TestData> = OptimizedBaseResponse {
850            code: 0,
851            msg: "success".to_string(),
852            error: None,
853            data: None,
854        };
855
856        let json = serde_json::to_string(&response).unwrap();
857
858        // Should not contain "error" or "data" fields when they are None
859        assert!(!json.contains("\"error\""));
860        assert!(!json.contains("\"data\""));
861        assert!(json.contains("\"code\":0"));
862        assert!(json.contains("\"msg\":\"success\""));
863    }
864
865    #[test]
866    fn test_macro_api_response_implementation() {
867        // Test that the macro would work correctly
868        // Since we can't actually invoke the macro in tests easily,
869        // we'll test the pattern it would generate
870
871        #[derive(Debug, Default, Serialize, Deserialize)]
872        struct MacroTestData;
873
874        impl ApiResponseTrait for MacroTestData {
875            fn data_format() -> ResponseFormat {
876                ResponseFormat::Data
877            }
878        }
879
880        assert_eq!(MacroTestData::data_format(), ResponseFormat::Data);
881        assert!(MacroTestData::from_binary("test".to_string(), vec![1, 2, 3]).is_none());
882    }
883
884    #[test]
885    fn test_error_detail_empty_values() {
886        let detail = ErrorDetail {
887            key: Some("".to_string()),
888            value: Some("".to_string()),
889            description: Some("".to_string()),
890        };
891
892        let json = serde_json::to_string(&detail).unwrap();
893        let deserialized: ErrorDetail = serde_json::from_str(&json).unwrap();
894
895        assert_eq!(deserialized.key, Some("".to_string()));
896        assert_eq!(deserialized.value, Some("".to_string()));
897        assert_eq!(deserialized.description, Some("".to_string()));
898    }
899
900    #[test]
901    fn test_content_disposition_header_edge_cases() {
902        let edge_cases = vec![
903            // Case-insensitive filename
904            ("FILENAME=\"test.txt\"", None), // Our implementation is case-sensitive
905            ("Filename=\"test.txt\"", None), // Our implementation is case-sensitive
906            // Multiple spaces
907            (
908                "attachment;  filename=\"test.txt\"",
909                Some("test.txt".to_string()),
910            ),
911            ("attachment; filename =  \"test.txt\"", None), // Space before = is not handled
912            // Special characters in filename
913            (
914                "attachment; filename=\"test-file_v1.2.txt\"",
915                Some("test-file_v1.2.txt".to_string()),
916            ),
917            (
918                "attachment; filename=\"测试文件.txt\"",
919                Some("测试文件.txt".to_string()),
920            ),
921            // Both UTF-8 and regular filename (current implementation returns first match)
922            (
923                "attachment; filename=\"test.txt\"; filename*=UTF-8''better.txt",
924                Some("test.txt".to_string()),
925            ),
926        ];
927
928        for (input, expected) in edge_cases {
929            let result = ImprovedResponseHandler::extract_filename(input);
930            assert_eq!(result, expected, "Failed for input: {}", input);
931        }
932    }
933}
934
935/// 使用示例
936///
937/// 在RequestExecutor中使用改进的响应处理器:
938/// ```rust,ignore
939/// impl RequestExecutor {
940///     pub async fn execute_improved<T: ApiResponseTrait + DeserializeOwned>(
941///         // ... 参数
942///     ) -> SDKResult<OptimizedBaseResponse<T>> {
943///         // ... 构建请求
944///         let response = http_client.send(request).await?;
945///         ImprovedResponseHandler::handle_response(response).await
946///     }
947/// }
948///
949/// // 使用新的响应格式
950/// let result = RequestExecutor::execute_improved::<MessageData>(...).await?;
951///
952/// match result.into_data() {
953///     Ok(data) => println!("Success: {:?}", data),
954///     Err(e) => println!("Error: {:?}", e),
955/// }
956/// ```
957mod usage_examples {}