gewe_core/
lib.rs

1pub mod common;
2pub mod contact;
3pub mod favorite;
4pub mod group;
5pub mod login;
6pub mod message;
7pub mod moments;
8pub mod personal;
9pub mod tag;
10pub mod video_account;
11
12pub use common::*;
13#[allow(ambiguous_glob_reexports)]
14pub use contact::{info::*, manage::*, wecom::*};
15pub use favorite::*;
16#[allow(ambiguous_glob_reexports)]
17pub use group::{admin::*, manage::*, member::*, settings::*};
18pub use login::*;
19pub use message::*;
20#[allow(ambiguous_glob_reexports)]
21pub use moments::{interact::*, manage::*, media::*, publish::*, settings::*, timeline::*};
22pub use personal::{profile::*, safety::*, settings::*};
23pub use tag::*;
24#[allow(ambiguous_glob_reexports)]
25pub use video_account::{
26    common::*, follow::*, interact::*, message::*, profile::*, publish::*, scan::*, search::*,
27};
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32    use serde_json;
33
34    // ===== common.rs tests =====
35    #[test]
36    fn test_app_id_serialize_deserialize() {
37        let app_id = AppId("test_app_123".to_string());
38        let json = serde_json::to_string(&app_id).unwrap();
39        assert_eq!(json, "\"test_app_123\"");
40
41        let deserialized: AppId = serde_json::from_str(&json).unwrap();
42        assert_eq!(deserialized, app_id);
43    }
44
45    #[test]
46    fn test_bot_id_from_string() {
47        let bot_id: BotId = "wxid_test123".to_string().into();
48        assert_eq!(bot_id.0, "wxid_test123");
49    }
50
51    #[test]
52    fn test_bot_id_from_str() {
53        let bot_id: BotId = "wxid_test456".into();
54        assert_eq!(bot_id.0, "wxid_test456");
55    }
56
57    #[test]
58    fn test_bot_id_serialize_deserialize() {
59        let bot_id = BotId("wxid_abc".to_string());
60        let json = serde_json::to_string(&bot_id).unwrap();
61        assert_eq!(json, "\"wxid_abc\"");
62
63        let deserialized: BotId = serde_json::from_str(&json).unwrap();
64        assert_eq!(deserialized, bot_id);
65    }
66
67    #[test]
68    fn test_bot_context_serialize() {
69        let ctx = BotContext {
70            app_id: AppId("app123".to_string()),
71            token: "token456".to_string(),
72            webhook_secret: Some("secret789".to_string()),
73            description: Some("Test bot".to_string()),
74        };
75        let json = serde_json::to_string(&ctx).unwrap();
76        assert!(json.contains("\"appId\":\"app123\""));
77        assert!(json.contains("\"token\":\"token456\""));
78        assert!(json.contains("\"webhookSecret\":\"secret789\""));
79        assert!(json.contains("\"description\":\"Test bot\""));
80    }
81
82    #[test]
83    fn test_bot_context_deserialize() {
84        let json = r#"{"appId":"app123","token":"token456","webhookSecret":"secret","description":"desc"}"#;
85        let ctx: BotContext = serde_json::from_str(json).unwrap();
86        assert_eq!(ctx.app_id.0, "app123");
87        assert_eq!(ctx.token, "token456");
88        assert_eq!(ctx.webhook_secret, Some("secret".to_string()));
89        assert_eq!(ctx.description, Some("desc".to_string()));
90    }
91
92    #[test]
93    fn test_bot_context_optional_fields() {
94        let json = r#"{"appId":"app123","token":"token456"}"#;
95        let ctx: BotContext = serde_json::from_str(json).unwrap();
96        assert_eq!(ctx.webhook_secret, None);
97        assert_eq!(ctx.description, None);
98    }
99
100    #[test]
101    fn test_callback_envelope() {
102        let envelope = CallbackEnvelope {
103            appid: "app123".to_string(),
104            data: "test_data".to_string(),
105        };
106        let json = serde_json::to_string(&envelope).unwrap();
107        assert!(json.contains("\"appid\":\"app123\""));
108        assert!(json.contains("\"data\":\"test_data\""));
109    }
110
111    #[test]
112    fn test_api_envelope_with_data() {
113        let envelope: ApiEnvelope<String> = ApiEnvelope {
114            ret: 200,
115            msg: "success".to_string(),
116            data: Some("result".to_string()),
117        };
118        let json = serde_json::to_string(&envelope).unwrap();
119        assert!(json.contains("\"ret\":200"));
120        assert!(json.contains("\"msg\":\"success\""));
121        assert!(json.contains("\"data\":\"result\""));
122    }
123
124    #[test]
125    fn test_api_envelope_without_data() {
126        let envelope: ApiEnvelope<String> = ApiEnvelope {
127            ret: 400,
128            msg: "error".to_string(),
129            data: None,
130        };
131        let json = serde_json::to_string(&envelope).unwrap();
132        assert!(json.contains("\"ret\":400"));
133        assert!(!json.contains("\"data\""));
134    }
135
136    #[test]
137    fn test_gewe_error_display() {
138        let http_err = GeweError::Http("connection failed".to_string());
139        assert_eq!(format!("{}", http_err), "http error: connection failed");
140
141        let api_err = GeweError::Api {
142            code: 500,
143            message: "server error".to_string(),
144        };
145        assert_eq!(format!("{}", api_err), "api error code=500: server error");
146
147        let decode_err = GeweError::Decode("invalid json".to_string());
148        assert_eq!(format!("{}", decode_err), "decode error: invalid json");
149
150        let missing_err = GeweError::MissingData;
151        assert_eq!(format!("{}", missing_err), "missing data");
152    }
153
154    // ===== login.rs tests =====
155    #[test]
156    fn test_get_login_qr_code_request_serialize() {
157        let req = GetLoginQrCodeRequest {
158            app_id: "app123",
159            r#type: "ipad",
160            region_id: "CN",
161            proxy_ip: Some("127.0.0.1:8080"),
162            ttuid: None,
163            aid: None,
164        };
165        let json = serde_json::to_string(&req).unwrap();
166        assert!(json.contains("\"appId\":\"app123\""));
167        assert!(json.contains("\"type\":\"ipad\""));
168        assert!(json.contains("\"regionId\":\"CN\""));
169        assert!(json.contains("\"proxyIp\":\"127.0.0.1:8080\""));
170    }
171
172    #[test]
173    fn test_get_login_qr_code_response_deserialize() {
174        let json = r#"{"qrData":"data","qrImgBase64":"base64","uuid":"uuid123","appId":"app123"}"#;
175        let resp: GetLoginQrCodeResponse = serde_json::from_str(json).unwrap();
176        assert_eq!(resp.qr_data, "data");
177        assert_eq!(resp.qr_img_base64, "base64");
178        assert_eq!(resp.uuid, "uuid123");
179        assert_eq!(resp.app_id, "app123");
180    }
181
182    #[test]
183    fn test_check_login_request_serialize() {
184        let req = CheckLoginRequest {
185            app_id: "app123",
186            uuid: "uuid456",
187            proxy_ip: None,
188            captch_code: Some("1234"),
189            auto_sliding: Some(true),
190        };
191        let json = serde_json::to_string(&req).unwrap();
192        assert!(json.contains("\"appId\":\"app123\""));
193        assert!(json.contains("\"uuid\":\"uuid456\""));
194        assert!(json.contains("\"captchCode\":\"1234\""));
195        assert!(json.contains("\"autoSliding\":true"));
196    }
197
198    #[test]
199    fn test_check_login_response_deserialize() {
200        let json =
201            r#"{"uuid":"uuid123","status":1,"headImgUrl":"http://img.url","nickName":"test"}"#;
202        let resp: CheckLoginResponse = serde_json::from_str(json).unwrap();
203        assert_eq!(resp.uuid, "uuid123");
204        assert_eq!(resp.status, 1);
205        assert_eq!(resp.head_img_url, Some("http://img.url".to_string()));
206        assert_eq!(resp.nick_name, Some("test".to_string()));
207    }
208
209    #[test]
210    fn test_login_info_deserialize() {
211        let json = r#"{"uin":123456,"wxid":"wxid_test","nickName":"Test","mobile":"13800000000","alias":"test_alias"}"#;
212        let info: LoginInfo = serde_json::from_str(json).unwrap();
213        assert_eq!(info.uin, Some(123456));
214        assert_eq!(info.wxid, Some("wxid_test".to_string()));
215        assert_eq!(info.nick_name, Some("Test".to_string()));
216        assert_eq!(info.mobile, Some("13800000000".to_string()));
217        assert_eq!(info.alias, Some("test_alias".to_string()));
218    }
219
220    #[test]
221    fn test_dialog_login_request_serialize() {
222        let req = DialogLoginRequest {
223            app_id: "app123",
224            region_id: "CN",
225            proxy_ip: None,
226            aid: Some("aid456"),
227        };
228        let json = serde_json::to_string(&req).unwrap();
229        assert!(json.contains("\"appId\":\"app123\""));
230        assert!(json.contains("\"regionId\":\"CN\""));
231        assert!(json.contains("\"aid\":\"aid456\""));
232    }
233
234    #[test]
235    fn test_dialog_login_response_deserialize() {
236        let json = r#"{"appId":"app123","uuid":"uuid456"}"#;
237        let resp: DialogLoginResponse = serde_json::from_str(json).unwrap();
238        assert_eq!(resp.app_id, "app123");
239        assert_eq!(resp.uuid, "uuid456");
240    }
241
242    #[test]
243    fn test_login_by_account_request_serialize() {
244        let req = LoginByAccountRequest {
245            app_id: "app123",
246            proxy_ip: "127.0.0.1:8080",
247            region_id: "CN",
248            account: "user@example.com",
249            password: "password123",
250            step: 1,
251        };
252        let json = serde_json::to_string(&req).unwrap();
253        assert!(json.contains("\"appId\":\"app123\""));
254        assert!(json.contains("\"proxyIp\":\"127.0.0.1:8080\""));
255        assert!(json.contains("\"account\":\"user@example.com\""));
256        assert!(json.contains("\"step\":1"));
257    }
258
259    #[test]
260    fn test_set_callback_request_serialize() {
261        let req = SetCallbackRequest {
262            token: "token123",
263            callback_url: "https://example.com/callback",
264        };
265        let json = serde_json::to_string(&req).unwrap();
266        assert!(json.contains("\"token\":\"token123\""));
267        assert!(json.contains("\"callbackUrl\":\"https://example.com/callback\""));
268    }
269
270    #[test]
271    fn test_check_online_request_serialize() {
272        let req = CheckOnlineRequest { app_id: "app123" };
273        let json = serde_json::to_string(&req).unwrap();
274        assert!(json.contains("\"appId\":\"app123\""));
275    }
276
277    #[test]
278    fn test_reconnection_response_deserialize() {
279        let json =
280            r#"{"uuid":"uuid123","status":1,"headImgUrl":"http://img.url","nickName":"test"}"#;
281        let resp: ReconnectionResponse = serde_json::from_str(json).unwrap();
282        assert_eq!(resp.uuid, "uuid123");
283        assert_eq!(resp.status, 1);
284    }
285
286    #[test]
287    fn test_logout_request_serialize() {
288        let req = LogoutRequest { app_id: "app123" };
289        let json = serde_json::to_string(&req).unwrap();
290        assert!(json.contains("\"appId\":\"app123\""));
291    }
292
293    // ===== tag/mod.rs tests =====
294    #[test]
295    fn test_add_label_request_serialize() {
296        let req = AddLabelRequest {
297            app_id: "app123",
298            label_name: "Friends",
299        };
300        let json = serde_json::to_string(&req).unwrap();
301        assert!(json.contains("\"appId\":\"app123\""));
302        assert!(json.contains("\"labelName\":\"Friends\""));
303    }
304
305    #[test]
306    fn test_label_info_deserialize() {
307        let json = r#"{"labelName":"Friends","labelId":123}"#;
308        let info: LabelInfo = serde_json::from_str(json).unwrap();
309        assert_eq!(info.label_name, "Friends");
310        assert_eq!(info.label_id, 123);
311    }
312
313    #[test]
314    fn test_delete_label_request_serialize() {
315        let req = DeleteLabelRequest {
316            app_id: "app123",
317            label_ids: "1,2,3",
318        };
319        let json = serde_json::to_string(&req).unwrap();
320        assert!(json.contains("\"appId\":\"app123\""));
321        assert!(json.contains("\"labelIds\":\"1,2,3\""));
322    }
323
324    #[test]
325    fn test_list_label_response_deserialize() {
326        let json = r#"{"labelList":[{"labelName":"Friends","labelId":1},{"labelName":"Family","labelId":2}]}"#;
327        let resp: ListLabelResponse = serde_json::from_str(json).unwrap();
328        assert_eq!(resp.label_list.len(), 2);
329        assert_eq!(resp.label_list[0].label_name, "Friends");
330        assert_eq!(resp.label_list[1].label_id, 2);
331    }
332
333    #[test]
334    fn test_modify_label_member_request_serialize() {
335        let req = ModifyLabelMemberRequest {
336            app_id: "app123",
337            label_ids: "1,2",
338            wx_ids: vec!["wxid1", "wxid2"],
339        };
340        let json = serde_json::to_string(&req).unwrap();
341        assert!(json.contains("\"appId\":\"app123\""));
342        assert!(json.contains("\"labelIds\":\"1,2\""));
343        assert!(json.contains("\"wxIds\":[\"wxid1\",\"wxid2\"]"));
344    }
345
346    // ===== contact/info.rs tests =====
347    #[test]
348    fn test_fetch_contacts_list_response_deserialize() {
349        let json = r#"{"friends":["wxid1","wxid2"],"chatrooms":["room1"],"ghs":["gh1"]}"#;
350        let resp: FetchContactsListResponse = serde_json::from_str(json).unwrap();
351        assert_eq!(resp.friends, vec!["wxid1", "wxid2"]);
352        assert_eq!(resp.chatrooms, vec!["room1"]);
353        assert_eq!(resp.ghs, vec!["gh1"]);
354    }
355
356    #[test]
357    fn test_search_contacts_request_serialize() {
358        let req = SearchContactsRequest {
359            app_id: "app123",
360            contacts_info: "test@example.com",
361        };
362        let json = serde_json::to_string(&req).unwrap();
363        assert!(json.contains("\"appId\":\"app123\""));
364        assert!(json.contains("\"contactsInfo\":\"test@example.com\""));
365    }
366
367    #[test]
368    fn test_search_contacts_response_deserialize() {
369        let json = r#"{"v3":"v3data","nickName":"Test","sex":1,"bigHeadImgUrl":"http://big.img","smallHeadImgUrl":"http://small.img"}"#;
370        let resp: SearchContactsResponse = serde_json::from_str(json).unwrap();
371        assert_eq!(resp.v3, "v3data");
372        assert_eq!(resp.nick_name, "Test");
373        assert_eq!(resp.sex, 1);
374    }
375
376    #[test]
377    fn test_get_contact_brief_info_request_serialize() {
378        let req = GetContactBriefInfoRequest {
379            app_id: "app123",
380            wxids: vec!["wxid1", "wxid2"],
381        };
382        let json = serde_json::to_string(&req).unwrap();
383        assert!(json.contains("\"appId\":\"app123\""));
384        assert!(json.contains("\"wxids\":[\"wxid1\",\"wxid2\"]"));
385    }
386
387    #[test]
388    fn test_contact_brief_info_deserialize() {
389        let json = r#"{"userName":"user1","nickName":"Nick","pyInitial":"N","quanPin":"nick","sex":1,"remark":"","remarkPyInitial":"","remarkQuanPin":"","alias":"","country":"CN","bigHeadImgUrl":"http://big.img","smallHeadImgUrl":"http://small.img","labelList":"1,2","province":"BJ","city":"BJ"}"#;
390        let info: ContactBriefInfo = serde_json::from_str(json).unwrap();
391        assert_eq!(info.user_name, "user1");
392        assert_eq!(info.nick_name, "Nick");
393        assert_eq!(info.sex, 1);
394    }
395
396    #[test]
397    fn test_check_relation_request_serialize() {
398        let req = CheckRelationRequest {
399            app_id: "app123",
400            wxids: vec!["wxid1"],
401        };
402        let json = serde_json::to_string(&req).unwrap();
403        assert!(json.contains("\"appId\":\"app123\""));
404    }
405
406    #[test]
407    fn test_contact_relation_status_deserialize() {
408        let json = r#"{"wxid":"wxid123","relation":1}"#;
409        let status: ContactRelationStatus = serde_json::from_str(json).unwrap();
410        assert_eq!(status.wxid, "wxid123");
411        assert_eq!(status.relation, 1);
412    }
413
414    // ===== contact/manage.rs tests =====
415    #[test]
416    fn test_add_contacts_request_serialize() {
417        let req = AddContactsRequest {
418            app_id: "app123",
419            scene: 1,
420            option: 2,
421            v3: "v3data",
422            v4: "v4data",
423            content: "Hello",
424        };
425        let json = serde_json::to_string(&req).unwrap();
426        assert!(json.contains("\"appId\":\"app123\""));
427        assert!(json.contains("\"scene\":1"));
428        assert!(json.contains("\"v3\":\"v3data\""));
429    }
430
431    #[test]
432    fn test_set_friend_remark_request_serialize() {
433        let req = SetFriendRemarkRequest {
434            app_id: "app123",
435            wxid: "wxid456",
436            remark: "Best Friend",
437        };
438        let json = serde_json::to_string(&req).unwrap();
439        assert!(json.contains("\"appId\":\"app123\""));
440        assert!(json.contains("\"wxid\":\"wxid456\""));
441        assert!(json.contains("\"remark\":\"Best Friend\""));
442    }
443
444    #[test]
445    fn test_set_friend_permissions_request_serialize() {
446        let req = SetFriendPermissionsRequest {
447            app_id: "app123",
448            wxid: "wxid456",
449            only_chat: true,
450        };
451        let json = serde_json::to_string(&req).unwrap();
452        assert!(json.contains("\"onlyChat\":true"));
453    }
454
455    #[test]
456    fn test_upload_phone_address_list_request_serialize() {
457        let req = UploadPhoneAddressListRequest {
458            app_id: "app123",
459            phones: vec!["13800000001", "13800000002"],
460            op_type: 1,
461        };
462        let json = serde_json::to_string(&req).unwrap();
463        assert!(json.contains("\"phones\":[\"13800000001\",\"13800000002\"]"));
464        assert!(json.contains("\"opType\":1"));
465    }
466
467    #[test]
468    fn test_delete_friend_request_serialize() {
469        let req = DeleteFriendRequest {
470            app_id: "app123",
471            wxid: "wxid456",
472        };
473        let json = serde_json::to_string(&req).unwrap();
474        assert!(json.contains("\"appId\":\"app123\""));
475        assert!(json.contains("\"wxid\":\"wxid456\""));
476    }
477
478    // ===== contact/wecom.rs tests =====
479    #[test]
480    fn test_search_wecom_request_serialize() {
481        let req = SearchWecomRequest {
482            app_id: "app123",
483            scene: 1,
484            content: "test@company.com",
485        };
486        let json = serde_json::to_string(&req).unwrap();
487        assert!(json.contains("\"scene\":1"));
488        assert!(json.contains("\"content\":\"test@company.com\""));
489    }
490
491    #[test]
492    fn test_search_wecom_response_deserialize() {
493        let json = r#"{"nickName":"Test","sex":1,"signature":"Hello","bigHeadImgUrl":"http://big.img","smallHeadImgUrl":"http://small.img","v3":"v3","v4":"v4"}"#;
494        let resp: SearchWecomResponse = serde_json::from_str(json).unwrap();
495        assert_eq!(resp.nick_name, "Test");
496        assert_eq!(resp.v3, "v3");
497        assert_eq!(resp.v4, "v4");
498    }
499
500    #[test]
501    fn test_wecom_contact_deserialize() {
502        let json = r#"{"userName":"user1","nickName":"Nick","remark":"","bigHeadImg":"http://big","smallHeadImg":"http://small","appId":"app1","descWordingId":"desc1"}"#;
503        let contact: WecomContact = serde_json::from_str(json).unwrap();
504        assert_eq!(contact.user_name, "user1");
505        assert_eq!(contact.nick_name, "Nick");
506    }
507
508    #[test]
509    fn test_wecom_contact_detail_deserialize() {
510        let json = r#"{"userName":"user1","nickName":"Nick","remark":"","bigHeadImg":"http://big","smallHeadImg":"http://small","appId":"app1","descWordingId":"desc1","wording":"work","wordingPinyin":"gong","wordingQuanpin":"gongzuo"}"#;
511        let detail: WecomContactDetail = serde_json::from_str(json).unwrap();
512        assert_eq!(detail.wording, "work");
513    }
514
515    // ===== message/send.rs tests =====
516    #[test]
517    fn test_send_text_request_serialize() {
518        let req = SendTextRequest {
519            app_id: "app123",
520            to_wxid: "wxid456",
521            content: "Hello World",
522            ats: Some("wxid789"),
523        };
524        let json = serde_json::to_string(&req).unwrap();
525        assert!(json.contains("\"appId\":\"app123\""));
526        assert!(json.contains("\"toWxid\":\"wxid456\""));
527        assert!(json.contains("\"content\":\"Hello World\""));
528        assert!(json.contains("\"ats\":\"wxid789\""));
529    }
530
531    #[test]
532    fn test_send_text_response_deserialize() {
533        let json =
534            r#"{"toWxid":"wxid456","createTime":1234567890,"msgId":123,"newMsgId":456,"type":1}"#;
535        let resp: SendTextResponse = serde_json::from_str(json).unwrap();
536        assert_eq!(resp.to_wxid, "wxid456");
537        assert_eq!(resp.create_time, 1234567890);
538        assert_eq!(resp.msg_id, 123);
539        assert_eq!(resp.new_msg_id, 456);
540        assert_eq!(resp.msg_type, 1);
541    }
542
543    #[test]
544    fn test_post_image_request_serialize() {
545        let req = PostImageRequest {
546            app_id: "app123",
547            to_wxid: "wxid456",
548            img_url: "http://example.com/image.jpg",
549        };
550        let json = serde_json::to_string(&req).unwrap();
551        assert!(json.contains("\"imgUrl\":\"http://example.com/image.jpg\""));
552    }
553
554    #[test]
555    fn test_post_image_response_deserialize() {
556        let json = r#"{"toWxid":"wxid456","createTime":1234567890,"msgId":123,"newMsgId":456,"aesKey":"key","fileId":"file1","length":1000,"width":100,"height":200,"md5":"md5hash"}"#;
557        let resp: PostImageResponse = serde_json::from_str(json).unwrap();
558        assert_eq!(resp.aes_key, "key");
559        assert_eq!(resp.width, 100);
560        assert_eq!(resp.height, 200);
561    }
562
563    #[test]
564    fn test_post_voice_request_serialize() {
565        let req = PostVoiceRequest {
566            app_id: "app123",
567            to_wxid: "wxid456",
568            voice_url: "http://example.com/voice.mp3",
569            voice_duration: 5000,
570        };
571        let json = serde_json::to_string(&req).unwrap();
572        assert!(json.contains("\"voiceUrl\":\"http://example.com/voice.mp3\""));
573        assert!(json.contains("\"voiceDuration\":5000"));
574    }
575
576    #[test]
577    fn test_post_video_request_serialize() {
578        let req = PostVideoRequest {
579            app_id: "app123",
580            to_wxid: "wxid456",
581            video_url: "http://example.com/video.mp4",
582            thumb_url: "http://example.com/thumb.jpg",
583            video_duration: 10000,
584        };
585        let json = serde_json::to_string(&req).unwrap();
586        assert!(json.contains("\"videoUrl\":\"http://example.com/video.mp4\""));
587        assert!(json.contains("\"thumbUrl\":\"http://example.com/thumb.jpg\""));
588    }
589
590    #[test]
591    fn test_post_file_request_serialize() {
592        let req = PostFileRequest {
593            app_id: "app123",
594            to_wxid: "wxid456",
595            file_url: "http://example.com/file.pdf",
596            file_name: "document.pdf",
597        };
598        let json = serde_json::to_string(&req).unwrap();
599        assert!(json.contains("\"fileUrl\":\"http://example.com/file.pdf\""));
600        assert!(json.contains("\"fileName\":\"document.pdf\""));
601    }
602
603    #[test]
604    fn test_post_link_request_serialize() {
605        let req = PostLinkRequest {
606            app_id: "app123",
607            to_wxid: "wxid456",
608            title: "Article Title",
609            desc: "Article description",
610            link_url: "http://example.com/article",
611            thumb_url: "http://example.com/thumb.jpg",
612        };
613        let json = serde_json::to_string(&req).unwrap();
614        assert!(json.contains("\"title\":\"Article Title\""));
615        assert!(json.contains("\"linkUrl\":\"http://example.com/article\""));
616    }
617
618    #[test]
619    fn test_post_emoji_request_serialize() {
620        let req = PostEmojiRequest {
621            app_id: "app123",
622            to_wxid: "wxid456",
623            emoji_md5: "md5hash",
624            emoji_size: 1024,
625        };
626        let json = serde_json::to_string(&req).unwrap();
627        assert!(json.contains("\"emojiMd5\":\"md5hash\""));
628        assert!(json.contains("\"emojiSize\":1024"));
629    }
630
631    #[test]
632    fn test_post_app_msg_request_serialize() {
633        let req = PostAppMsgRequest {
634            app_id: "app123",
635            to_wxid: "wxid456",
636            appmsg: "<xml>app message</xml>",
637        };
638        let json = serde_json::to_string(&req).unwrap();
639        assert!(json.contains("\"appmsg\":\"<xml>app message</xml>\""));
640    }
641
642    #[test]
643    fn test_post_mini_app_request_serialize() {
644        let req = PostMiniAppRequest {
645            app_id: "app123",
646            to_wxid: "wxid456",
647            mini_app_id: "miniapp123",
648            display_name: "Mini App",
649            page_path: "/pages/index",
650            cover_img_url: "http://example.com/cover.jpg",
651            title: "Mini App Title",
652            user_name: "gh_miniapp",
653        };
654        let json = serde_json::to_string(&req).unwrap();
655        assert!(json.contains("\"miniAppId\":\"miniapp123\""));
656        assert!(json.contains("\"pagePath\":\"/pages/index\""));
657    }
658
659    #[test]
660    fn test_post_name_card_request_serialize() {
661        let req = PostNameCardRequest {
662            app_id: "app123",
663            to_wxid: "wxid456",
664            nick_name: "Contact Name",
665            name_card_wxid: "wxid_card",
666        };
667        let json = serde_json::to_string(&req).unwrap();
668        assert!(json.contains("\"nickName\":\"Contact Name\""));
669        assert!(json.contains("\"nameCardWxid\":\"wxid_card\""));
670    }
671
672    // ===== message/download.rs tests =====
673    #[test]
674    fn test_download_image_request_serialize() {
675        let req = DownloadImageRequest {
676            app_id: "app123",
677            xml: "<xml>image data</xml>",
678            image_type: 1,
679        };
680        let json = serde_json::to_string(&req).unwrap();
681        assert!(json.contains("\"xml\":\"<xml>image data</xml>\""));
682        assert!(json.contains("\"type\":1"));
683    }
684
685    #[test]
686    fn test_download_image_response_deserialize() {
687        let json = r#"{"fileUrl":"http://example.com/image.jpg"}"#;
688        let resp: DownloadImageResponse = serde_json::from_str(json).unwrap();
689        assert_eq!(resp.file_url, "http://example.com/image.jpg");
690    }
691
692    #[test]
693    fn test_download_voice_request_serialize() {
694        let req = DownloadVoiceRequest {
695            app_id: "app123",
696            xml: "<xml>voice data</xml>",
697            msg_id: 12345,
698        };
699        let json = serde_json::to_string(&req).unwrap();
700        assert!(json.contains("\"msgId\":12345"));
701    }
702
703    #[test]
704    fn test_download_emoji_request_serialize() {
705        let req = DownloadEmojiRequest {
706            app_id: "app123",
707            emoji_md5: "md5hash",
708        };
709        let json = serde_json::to_string(&req).unwrap();
710        assert!(json.contains("\"emojiMd5\":\"md5hash\""));
711    }
712
713    #[test]
714    fn test_download_emoji_response_deserialize() {
715        let json = r#"{"url":"http://example.com/emoji.gif"}"#;
716        let resp: DownloadEmojiResponse = serde_json::from_str(json).unwrap();
717        assert_eq!(resp.url, "http://example.com/emoji.gif");
718    }
719
720    #[test]
721    fn test_download_cdn_request_serialize() {
722        let req = DownloadCdnRequest {
723            app_id: "app123",
724            aes_key: "aeskey",
725            file_id: "fileid",
726            r#type: "image",
727            total_size: "1024",
728            suffix: "jpg",
729        };
730        let json = serde_json::to_string(&req).unwrap();
731        assert!(json.contains("\"aesKey\":\"aeskey\""));
732        assert!(json.contains("\"fileId\":\"fileid\""));
733    }
734
735    // ===== message/forward.rs tests =====
736    #[test]
737    fn test_forward_image_request_serialize() {
738        let req = ForwardImageRequest {
739            app_id: "app123",
740            to_wxid: "wxid456",
741            xml: "<xml>forward data</xml>",
742        };
743        let json = serde_json::to_string(&req).unwrap();
744        assert!(json.contains("\"toWxid\":\"wxid456\""));
745        assert!(json.contains("\"xml\":\"<xml>forward data</xml>\""));
746    }
747
748    #[test]
749    fn test_forward_image_response_deserialize() {
750        let json =
751            r#"{"toWxid":"wxid456","msgId":123,"newMsgId":456,"aesKey":"key","fileId":"file1"}"#;
752        let resp: ForwardImageResponse = serde_json::from_str(json).unwrap();
753        assert_eq!(resp.aes_key, "key");
754        assert_eq!(resp.file_id, "file1");
755    }
756
757    #[test]
758    fn test_forward_mini_app_request_serialize() {
759        let req = ForwardMiniAppRequest {
760            app_id: "app123",
761            to_wxid: "wxid456",
762            xml: "<xml>miniapp</xml>",
763            cover_img_url: "http://example.com/cover.jpg",
764        };
765        let json = serde_json::to_string(&req).unwrap();
766        assert!(json.contains("\"coverImgUrl\":\"http://example.com/cover.jpg\""));
767    }
768
769    // ===== message/revoke.rs tests =====
770    #[test]
771    fn test_revoke_message_request_serialize() {
772        let req = RevokeMessageRequest {
773            app_id: "app123",
774            to_wxid: "wxid456",
775            msg_id: "123",
776            new_msg_id: "456",
777            create_time: "1234567890",
778        };
779        let json = serde_json::to_string(&req).unwrap();
780        assert!(json.contains("\"msgId\":\"123\""));
781        assert!(json.contains("\"newMsgId\":\"456\""));
782        assert!(json.contains("\"createTime\":\"1234567890\""));
783    }
784
785    // ===== group/member.rs tests =====
786    #[test]
787    fn test_invite_member_request_serialize() {
788        let req = InviteMemberRequest {
789            app_id: "app123",
790            chatroom_id: "room456",
791            reason: "Welcome",
792            wxids: vec!["wxid1", "wxid2"],
793        };
794        let json = serde_json::to_string(&req).unwrap();
795        assert!(json.contains("\"chatroomId\":\"room456\""));
796        assert!(json.contains("\"reason\":\"Welcome\""));
797    }
798
799    #[test]
800    fn test_remove_member_request_serialize() {
801        let req = RemoveMemberRequest {
802            app_id: "app123",
803            chatroom_id: "room456",
804            wxids: vec!["wxid1"],
805        };
806        let json = serde_json::to_string(&req).unwrap();
807        assert!(json.contains("\"chatroomId\":\"room456\""));
808    }
809
810    #[test]
811    fn test_get_chatroom_member_list_response_deserialize() {
812        let json = r#"{"chatRoomOwner":"owner1","chatroomMembers":[{"wxid":"wxid1","inviterUserName":"inviter1","bigHeadImgUrl":"http://big.img","smallHeadImgUrl":"http://small.img","inviteTicket":"","memberFlag":0,"nickName":"Nick","remarkName":"","sex":1,"userName":"user1","displayName":""}]}"#;
813        let resp: GetChatroomMemberListResponse = serde_json::from_str(json).unwrap();
814        assert_eq!(resp.chat_room_owner, "owner1");
815        assert_eq!(resp.chatroom_members.len(), 1);
816        assert_eq!(resp.chatroom_members[0].wxid, "wxid1");
817    }
818
819    #[test]
820    fn test_get_chatroom_info_response_deserialize() {
821        let json = r#"{"chatroomId":"room123","nickName":"Group Name","pyInitial":"GN","quanPin":"groupname","sex":0,"chatRoomNotify":1,"chatRoomOwner":"owner1","smallHeadImgUrl":"http://small.img","memberList":[]}"#;
822        let resp: GetChatroomInfoResponse = serde_json::from_str(json).unwrap();
823        assert_eq!(resp.chatroom_id, "room123");
824        assert_eq!(resp.nick_name, "Group Name");
825    }
826
827    // ===== group/admin.rs tests =====
828    #[test]
829    fn test_admin_operate_request_serialize() {
830        let req = AdminOperateRequest {
831            app_id: "app123",
832            chatroom_id: "room456",
833            wxid: "wxid789",
834            is_admin: true,
835        };
836        let json = serde_json::to_string(&req).unwrap();
837        assert!(json.contains("\"isAdmin\":true"));
838    }
839
840    // ===== group/settings.rs tests =====
841    #[test]
842    fn test_set_chatroom_announcement_request_serialize() {
843        let req = SetChatroomAnnouncementRequest {
844            app_id: "app123",
845            chatroom_id: "room456",
846            content: "Important announcement",
847        };
848        let json = serde_json::to_string(&req).unwrap();
849        assert!(json.contains("\"content\":\"Important announcement\""));
850    }
851
852    #[test]
853    fn test_get_chatroom_announcement_response_deserialize() {
854        let json = r#"{"chatRoomAnnouncement":"Hello","sender":"wxid1","createTime":"1234567890","expireTime":"9999999999"}"#;
855        let resp: GetChatroomAnnouncementResponse = serde_json::from_str(json).unwrap();
856        assert_eq!(resp.chat_room_announcement, "Hello");
857        assert_eq!(resp.sender, "wxid1");
858    }
859
860    #[test]
861    fn test_get_chatroom_qr_code_response_deserialize() {
862        let json =
863            r#"{"qrImgBase64":"base64data","headImgBase64":"headbase64","qrUrl":"http://qr.url"}"#;
864        let resp: GetChatroomQrCodeResponse = serde_json::from_str(json).unwrap();
865        assert_eq!(resp.qr_img_base64, "base64data");
866        assert_eq!(resp.qr_url, "http://qr.url");
867    }
868
869    #[test]
870    fn test_save_contract_list_request_serialize() {
871        let req = SaveContractListRequest {
872            app_id: "app123",
873            chatroom_id: "room456",
874            save: true,
875        };
876        let json = serde_json::to_string(&req).unwrap();
877        assert!(json.contains("\"save\":true"));
878    }
879
880    #[test]
881    fn test_pin_chat_request_serialize() {
882        let req = PinChatRequest {
883            app_id: "app123",
884            chatroom_id: "room456",
885            add: true,
886        };
887        let json = serde_json::to_string(&req).unwrap();
888        assert!(json.contains("\"add\":true"));
889    }
890
891    #[test]
892    fn test_set_msg_silence_request_serialize() {
893        let req = SetMsgSilenceRequest {
894            app_id: "app123",
895            chatroom_id: "room456",
896            switch_: true,
897        };
898        let json = serde_json::to_string(&req).unwrap();
899        assert!(json.contains("\"switch\":true"));
900    }
901
902    // ===== personal/profile.rs tests =====
903    #[test]
904    fn test_get_profile_request_serialize() {
905        let req = GetProfileRequest { app_id: "app123" };
906        let json = serde_json::to_string(&req).unwrap();
907        assert!(json.contains("\"appId\":\"app123\""));
908    }
909
910    #[test]
911    fn test_get_profile_response_deserialize() {
912        let json = r#"{"alias":"myalias","wxid":"wxid123","nickName":"Nick","mobile":"138","uin":12345,"sex":1,"province":"BJ","city":"BJ","signature":"Hello","country":"CN","bigHeadImgUrl":"http://big.img","smallHeadImgUrl":"http://small.img","regCountry":"CN","snsBgImg":"http://bg.img"}"#;
913        let resp: GetProfileResponse = serde_json::from_str(json).unwrap();
914        assert_eq!(resp.alias, "myalias");
915        assert_eq!(resp.wxid, "wxid123");
916        assert_eq!(resp.uin, 12345);
917    }
918
919    #[test]
920    fn test_update_profile_request_serialize() {
921        let req = UpdateProfileRequest {
922            app_id: "app123",
923            nick_name: Some("NewNick"),
924            country: Some("CN"),
925            province: Some("BJ"),
926            city: Some("BJ"),
927            sex: Some(1),
928            signature: Some("Hello World"),
929        };
930        let json = serde_json::to_string(&req).unwrap();
931        assert!(json.contains("\"nickName\":\"NewNick\""));
932        assert!(json.contains("\"signature\":\"Hello World\""));
933    }
934
935    #[test]
936    fn test_update_head_img_request_serialize() {
937        let req = UpdateHeadImgRequest {
938            app_id: "app123",
939            head_img_url: "http://example.com/avatar.jpg",
940        };
941        let json = serde_json::to_string(&req).unwrap();
942        assert!(json.contains("\"headImgUrl\":\"http://example.com/avatar.jpg\""));
943    }
944
945    #[test]
946    fn test_get_qr_code_response_deserialize() {
947        let json = r#"{"qrCode":"base64qrdata"}"#;
948        let resp: GetQrCodeResponse = serde_json::from_str(json).unwrap();
949        assert_eq!(resp.qr_code, "base64qrdata");
950    }
951
952    // ===== personal/safety.rs tests =====
953    #[test]
954    fn test_get_safety_info_request_serialize() {
955        let req = GetSafetyInfoRequest { app_id: "app123" };
956        let json = serde_json::to_string(&req).unwrap();
957        assert!(json.contains("\"appId\":\"app123\""));
958    }
959
960    #[test]
961    fn test_safety_device_record_deserialize() {
962        let json =
963            r#"{"uuid":"uuid123","deviceName":"iPhone","deviceType":"iOS","lastTime":1234567890}"#;
964        let record: SafetyDeviceRecord = serde_json::from_str(json).unwrap();
965        assert_eq!(record.uuid, "uuid123");
966        assert_eq!(record.device_name, "iPhone");
967        assert_eq!(record.last_time, 1234567890);
968    }
969
970    #[test]
971    fn test_get_safety_info_response_deserialize() {
972        let json = r#"{"list":[{"uuid":"uuid1","deviceName":"Device1","deviceType":"iOS","lastTime":123}]}"#;
973        let resp: GetSafetyInfoResponse = serde_json::from_str(json).unwrap();
974        assert_eq!(resp.list.len(), 1);
975        assert_eq!(resp.list[0].uuid, "uuid1");
976    }
977
978    // ===== personal/settings.rs tests =====
979    #[test]
980    fn test_privacy_settings_request_serialize() {
981        let req = PrivacySettingsRequest {
982            app_id: "app123",
983            option: 1,
984            open: true,
985        };
986        let json = serde_json::to_string(&req).unwrap();
987        assert!(json.contains("\"option\":1"));
988        assert!(json.contains("\"open\":true"));
989    }
990
991    // ===== favorite/mod.rs tests =====
992    #[test]
993    fn test_sync_favor_request_serialize() {
994        let req = SyncFavorRequest {
995            app_id: "app123",
996            sync_key: Some("key123"),
997        };
998        let json = serde_json::to_string(&req).unwrap();
999        assert!(json.contains("\"syncKey\":\"key123\""));
1000    }
1001
1002    #[test]
1003    fn test_sync_favor_request_without_key() {
1004        let req = SyncFavorRequest {
1005            app_id: "app123",
1006            sync_key: None,
1007        };
1008        let json = serde_json::to_string(&req).unwrap();
1009        assert!(!json.contains("syncKey"));
1010    }
1011
1012    #[test]
1013    fn test_favor_summary_deserialize() {
1014        let json = r#"{"favId":123,"type":1,"flag":0,"updateTime":1234567890}"#;
1015        let summary: FavorSummary = serde_json::from_str(json).unwrap();
1016        assert_eq!(summary.fav_id, 123);
1017        assert_eq!(summary.favor_type, 1);
1018        assert_eq!(summary.update_time, 1234567890);
1019    }
1020
1021    #[test]
1022    fn test_sync_favor_response_deserialize() {
1023        let json =
1024            r#"{"syncKey":"newkey","list":[{"favId":1,"type":1,"flag":0,"updateTime":123}]}"#;
1025        let resp: SyncFavorResponse = serde_json::from_str(json).unwrap();
1026        assert_eq!(resp.sync_key, "newkey");
1027        assert_eq!(resp.list.len(), 1);
1028    }
1029
1030    #[test]
1031    fn test_get_favor_content_request_serialize() {
1032        let req = GetFavorContentRequest {
1033            app_id: "app123",
1034            fav_id: 456,
1035        };
1036        let json = serde_json::to_string(&req).unwrap();
1037        assert!(json.contains("\"favId\":456"));
1038    }
1039
1040    #[test]
1041    fn test_get_favor_content_response_deserialize() {
1042        let json = r#"{"favId":123,"status":1,"flag":0,"updateTime":1234567890,"content":"favorite content"}"#;
1043        let resp: GetFavorContentResponse = serde_json::from_str(json).unwrap();
1044        assert_eq!(resp.fav_id, 123);
1045        assert_eq!(resp.content, "favorite content");
1046    }
1047
1048    #[test]
1049    fn test_delete_favor_request_serialize() {
1050        let req = DeleteFavorRequest {
1051            app_id: "app123",
1052            fav_id: 456,
1053        };
1054        let json = serde_json::to_string(&req).unwrap();
1055        assert!(json.contains("\"favId\":456"));
1056    }
1057
1058    // ===== moments/timeline.rs tests =====
1059    #[test]
1060    fn test_get_self_sns_list_request_serialize() {
1061        let req = GetSelfSnsListRequest {
1062            app_id: "app123",
1063            max_id: Some(12345),
1064            decrypt: Some(true),
1065            first_page_md5: Some("md5hash"),
1066        };
1067        let json = serde_json::to_string(&req).unwrap();
1068        assert!(json.contains("\"appId\":\"app123\""));
1069        assert!(json.contains("\"maxId\":12345"));
1070        assert!(json.contains("\"decrypt\":true"));
1071        assert!(json.contains("\"firstPageMd5\":\"md5hash\""));
1072    }
1073
1074    #[test]
1075    fn test_get_self_sns_list_request_optional_fields() {
1076        let req = GetSelfSnsListRequest {
1077            app_id: "app123",
1078            max_id: None,
1079            decrypt: None,
1080            first_page_md5: None,
1081        };
1082        let json = serde_json::to_string(&req).unwrap();
1083        assert!(!json.contains("maxId"));
1084        assert!(!json.contains("decrypt"));
1085        assert!(!json.contains("firstPageMd5"));
1086    }
1087
1088    #[test]
1089    fn test_get_contacts_sns_list_request_serialize() {
1090        let req = GetContactsSnsListRequest {
1091            app_id: "app123",
1092            wxid: "wxid456",
1093            max_id: Some(67890),
1094            decrypt: Some(false),
1095            first_page_md5: None,
1096        };
1097        let json = serde_json::to_string(&req).unwrap();
1098        assert!(json.contains("\"appId\":\"app123\""));
1099        assert!(json.contains("\"wxid\":\"wxid456\""));
1100        assert!(json.contains("\"maxId\":67890"));
1101    }
1102
1103    #[test]
1104    fn test_get_sns_details_request_serialize() {
1105        let req = GetSnsDetailsRequest {
1106            app_id: "app123",
1107            sns_id: 999,
1108        };
1109        let json = serde_json::to_string(&req).unwrap();
1110        assert!(json.contains("\"appId\":\"app123\""));
1111        assert!(json.contains("\"snsId\":999"));
1112    }
1113
1114    #[test]
1115    fn test_sns_like_entry_deserialize() {
1116        let json =
1117            r#"{"userName":"user1","nickName":"Nick","source":1,"type":2,"createTime":1234567890}"#;
1118        let entry: SnsLikeEntry = serde_json::from_str(json).unwrap();
1119        assert_eq!(entry.user_name, "user1");
1120        assert_eq!(entry.nick_name, "Nick");
1121        assert_eq!(entry.source, 1);
1122        assert_eq!(entry.entry_type, 2);
1123        assert_eq!(entry.create_time, 1234567890);
1124    }
1125
1126    #[test]
1127    fn test_sns_comment_entry_deserialize() {
1128        let json = r#"{"userName":"user2","nickName":"Nick2","source":2,"type":3,"content":"test comment","createTime":9876543210,"commentId":111,"replyCommentId":222,"isNotRichText":1}"#;
1129        let entry: SnsCommentEntry = serde_json::from_str(json).unwrap();
1130        assert_eq!(entry.user_name, "user2");
1131        assert_eq!(entry.content, Some("test comment".to_string()));
1132        assert_eq!(entry.comment_id, Some(111));
1133        assert_eq!(entry.reply_comment_id, Some(222));
1134    }
1135
1136    #[test]
1137    fn test_sns_timeline_item_deserialize() {
1138        let json = r#"{"id":1,"userName":"user1","nickName":"Nick","createTime":123,"snsXml":"<xml>test</xml>","likeCount":10,"commentCount":5,"withUserCount":2}"#;
1139        let item: SnsTimelineItem = serde_json::from_str(json).unwrap();
1140        assert_eq!(item.id, 1);
1141        assert_eq!(item.user_name, "user1");
1142        assert_eq!(item.sns_xml, "<xml>test</xml>");
1143        assert_eq!(item.like_count, 10);
1144        assert_eq!(item.comment_count, 5);
1145    }
1146
1147    #[test]
1148    fn test_sns_list_response_deserialize() {
1149        let json = r#"{"firstPageMd5":"md5","maxId":100,"snsCount":5,"requestTime":123456,"snsList":[{"id":1,"userName":"user1","nickName":"Nick","createTime":123,"snsXml":"<xml>test</xml>","likeCount":10,"commentCount":5,"withUserCount":2}]}"#;
1150        let resp: SnsListResponse = serde_json::from_str(json).unwrap();
1151        assert_eq!(resp.first_page_md5, "md5");
1152        assert_eq!(resp.max_id, 100);
1153        assert_eq!(resp.sns_count, 5);
1154        assert_eq!(resp.sns_list.len(), 1);
1155    }
1156
1157    // ===== moments/media.rs tests =====
1158    #[test]
1159    fn test_upload_sns_image_request_serialize() {
1160        let req = UploadSnsImageRequest {
1161            app_id: "app123",
1162            img_urls: vec!["http://img1.jpg", "http://img2.jpg"],
1163        };
1164        let json = serde_json::to_string(&req).unwrap();
1165        assert!(json.contains("\"appId\":\"app123\""));
1166        assert!(json.contains("\"imgUrls\":["));
1167        assert!(json.contains("\"http://img1.jpg\""));
1168    }
1169
1170    #[test]
1171    fn test_uploaded_sns_image_deserialize() {
1172        let json = r#"{"fileUrl":"http://file.jpg","thumbUrl":"http://thumb.jpg","fileMd5":"md5hash","length":1024,"width":800,"height":600}"#;
1173        let img: UploadedSnsImage = serde_json::from_str(json).unwrap();
1174        assert_eq!(img.file_url, "http://file.jpg");
1175        assert_eq!(img.thumb_url, "http://thumb.jpg");
1176        assert_eq!(img.file_md5, "md5hash");
1177        assert_eq!(img.length, 1024);
1178        assert_eq!(img.width, 800);
1179        assert_eq!(img.height, 600);
1180    }
1181
1182    #[test]
1183    fn test_upload_sns_video_request_serialize() {
1184        let req = UploadSnsVideoRequest {
1185            app_id: "app123",
1186            thumb_url: "http://thumb.jpg",
1187            video_url: "http://video.mp4",
1188        };
1189        let json = serde_json::to_string(&req).unwrap();
1190        assert!(json.contains("\"thumbUrl\":\"http://thumb.jpg\""));
1191        assert!(json.contains("\"videoUrl\":\"http://video.mp4\""));
1192    }
1193
1194    #[test]
1195    fn test_upload_sns_video_response_deserialize() {
1196        let json = r#"{"fileUrl":"http://file.mp4","thumbUrl":"http://thumb.jpg","fileMd5":"md5","length":2048}"#;
1197        let resp: UploadSnsVideoResponse = serde_json::from_str(json).unwrap();
1198        assert_eq!(resp.file_url, "http://file.mp4");
1199        assert_eq!(resp.thumb_url, "http://thumb.jpg");
1200        assert_eq!(resp.file_md5, "md5");
1201        assert_eq!(resp.length, 2048);
1202    }
1203
1204    #[test]
1205    fn test_download_sns_video_request_serialize() {
1206        let req = DownloadSnsVideoRequest {
1207            app_id: "app123",
1208            sns_xml: "<xml>video</xml>",
1209        };
1210        let json = serde_json::to_string(&req).unwrap();
1211        assert!(json.contains("\"snsXml\":\"<xml>video</xml>\""));
1212    }
1213
1214    #[test]
1215    fn test_download_sns_video_response_deserialize() {
1216        let json = r#"{"fileUrl":"http://downloaded.mp4"}"#;
1217        let resp: DownloadSnsVideoResponse = serde_json::from_str(json).unwrap();
1218        assert_eq!(resp.file_url, "http://downloaded.mp4");
1219    }
1220
1221    // ===== moments/interact.rs tests =====
1222    #[test]
1223    fn test_like_sns_request_serialize() {
1224        let req = LikeSnsRequest {
1225            app_id: "app123",
1226            sns_id: 456,
1227            oper_type: 1,
1228            wxid: "wxid789",
1229        };
1230        let json = serde_json::to_string(&req).unwrap();
1231        assert!(json.contains("\"appId\":\"app123\""));
1232        assert!(json.contains("\"snsId\":456"));
1233        assert!(json.contains("\"operType\":1"));
1234        assert!(json.contains("\"wxid\":\"wxid789\""));
1235    }
1236
1237    #[test]
1238    fn test_comment_sns_request_serialize() {
1239        let req = CommentSnsRequest {
1240            app_id: "app123",
1241            sns_id: 456,
1242            oper_type: 1,
1243            wxid: "wxid789",
1244            comment_id: Some("cmt123"),
1245            content: Some("Great post!"),
1246        };
1247        let json = serde_json::to_string(&req).unwrap();
1248        assert!(json.contains("\"snsId\":456"));
1249        assert!(json.contains("\"commentId\":\"cmt123\""));
1250        assert!(json.contains("\"content\":\"Great post!\""));
1251    }
1252
1253    #[test]
1254    fn test_comment_sns_request_without_optional() {
1255        let req = CommentSnsRequest {
1256            app_id: "app123",
1257            sns_id: 456,
1258            oper_type: 2,
1259            wxid: "wxid789",
1260            comment_id: None,
1261            content: None,
1262        };
1263        let json = serde_json::to_string(&req).unwrap();
1264        assert!(!json.contains("commentId"));
1265        assert!(!json.contains("content"));
1266    }
1267
1268    // ===== moments/publish.rs tests =====
1269    #[test]
1270    fn test_sns_audience_serialize() {
1271        let audience = SnsAudience {
1272            allow_wxids: Some(vec!["wxid1", "wxid2"]),
1273            at_wxids: Some(vec!["wxid3"]),
1274            disable_wxids: None,
1275            allow_tag_ids: Some(vec!["tag1"]),
1276            disable_tag_ids: None,
1277            privacy: Some(true),
1278        };
1279        let json = serde_json::to_string(&audience).unwrap();
1280        assert!(json.contains("\"allowWxIds\":[\"wxid1\",\"wxid2\"]"));
1281        assert!(json.contains("\"atWxIds\":[\"wxid3\"]"));
1282        assert!(json.contains("\"privacy\":true"));
1283    }
1284
1285    #[test]
1286    fn test_send_text_sns_request_serialize() {
1287        let req = SendTextSnsRequest {
1288            app_id: "app123",
1289            audience: SnsAudience::default(),
1290            content: "Hello moments!",
1291        };
1292        let json = serde_json::to_string(&req).unwrap();
1293        assert!(json.contains("\"appId\":\"app123\""));
1294        assert!(json.contains("\"content\":\"Hello moments!\""));
1295    }
1296
1297    #[test]
1298    fn test_sns_image_info_serialize() {
1299        let info = SnsImageInfo {
1300            file_url: "http://file.jpg".to_string(),
1301            thumb_url: "http://thumb.jpg".to_string(),
1302            file_md5: "md5".to_string(),
1303            length: Some(1024),
1304            width: 800,
1305            height: 600,
1306        };
1307        let json = serde_json::to_string(&info).unwrap();
1308        assert!(json.contains("\"fileUrl\":\"http://file.jpg\""));
1309        assert!(json.contains("\"width\":800"));
1310    }
1311
1312    #[test]
1313    fn test_send_img_sns_request_serialize() {
1314        let req = SendImgSnsRequest {
1315            app_id: "app123",
1316            audience: SnsAudience::default(),
1317            img_infos: vec![],
1318            content: Some("Image post"),
1319        };
1320        let json = serde_json::to_string(&req).unwrap();
1321        assert!(json.contains("\"imgInfos\":[]"));
1322        assert!(json.contains("\"content\":\"Image post\""));
1323    }
1324
1325    #[test]
1326    fn test_send_video_sns_request_serialize() {
1327        let video_info = SnsVideoInfo {
1328            file_url: "http://video.mp4".to_string(),
1329            thumb_url: "http://thumb.jpg".to_string(),
1330            file_md5: "vmd5".to_string(),
1331            length: Some(2048),
1332        };
1333        let req = SendVideoSnsRequest {
1334            app_id: "app123",
1335            audience: SnsAudience::default(),
1336            content: None,
1337            video_info,
1338        };
1339        let json = serde_json::to_string(&req).unwrap();
1340        assert!(json.contains("\"videoInfo\":{"));
1341        assert!(json.contains("\"fileUrl\":\"http://video.mp4\""));
1342    }
1343
1344    #[test]
1345    fn test_send_url_sns_request_serialize() {
1346        let req = SendUrlSnsRequest {
1347            app_id: "app123",
1348            audience: SnsAudience::default(),
1349            content: Some("Check this out"),
1350            thumb_url: "http://thumb.jpg",
1351            link_url: "http://link.com",
1352            title: "Link Title",
1353            description: "Link description",
1354        };
1355        let json = serde_json::to_string(&req).unwrap();
1356        assert!(json.contains("\"linkUrl\":\"http://link.com\""));
1357        assert!(json.contains("\"title\":\"Link Title\""));
1358    }
1359
1360    #[test]
1361    fn test_forward_sns_request_serialize() {
1362        let req = ForwardSnsRequest {
1363            app_id: "app123",
1364            audience: SnsAudience::default(),
1365            sns_xml: "<xml>forward</xml>",
1366        };
1367        let json = serde_json::to_string(&req).unwrap();
1368        assert!(json.contains("\"snsXml\":\"<xml>forward</xml>\""));
1369    }
1370
1371    #[test]
1372    fn test_send_sns_response_deserialize() {
1373        let json = r#"{"id":123,"userName":"user1","nickName":"Nick","createTime":1234567890}"#;
1374        let resp: SendSnsResponse = serde_json::from_str(json).unwrap();
1375        assert_eq!(resp.id, 123);
1376        assert_eq!(resp.user_name, "user1");
1377        assert_eq!(resp.nick_name, "Nick");
1378        assert_eq!(resp.create_time, 1234567890);
1379    }
1380
1381    // ===== moments/manage.rs tests =====
1382    #[test]
1383    fn test_delete_sns_request_serialize() {
1384        let req = DeleteSnsRequest {
1385            app_id: "app123",
1386            sns_id: 456,
1387        };
1388        let json = serde_json::to_string(&req).unwrap();
1389        assert!(json.contains("\"appId\":\"app123\""));
1390        assert!(json.contains("\"snsId\":456"));
1391    }
1392
1393    // ===== moments/settings.rs tests =====
1394    #[test]
1395    fn test_stranger_visibility_request_serialize() {
1396        let req = StrangerVisibilityRequest {
1397            app_id: "app123",
1398            enabled: true,
1399        };
1400        let json = serde_json::to_string(&req).unwrap();
1401        assert!(json.contains("\"appId\":\"app123\""));
1402        assert!(json.contains("\"enabled\":true"));
1403    }
1404
1405    #[test]
1406    fn test_set_sns_visible_scope_request_serialize() {
1407        let req = SetSnsVisibleScopeRequest {
1408            app_id: "app123",
1409            option: 1,
1410        };
1411        let json = serde_json::to_string(&req).unwrap();
1412        assert!(json.contains("\"option\":1"));
1413    }
1414
1415    #[test]
1416    fn test_set_sns_privacy_request_serialize() {
1417        let req = SetSnsPrivacyRequest {
1418            app_id: "app123",
1419            sns_id: 789,
1420            open: false,
1421        };
1422        let json = serde_json::to_string(&req).unwrap();
1423        assert!(json.contains("\"snsId\":789"));
1424        assert!(json.contains("\"open\":false"));
1425    }
1426
1427    // ===== video_account/message.rs tests =====
1428    #[test]
1429    fn test_send_finder_msg_request_serialize() {
1430        let req = SendFinderMsgRequest {
1431            app_id: "app123",
1432            to_wxid: "wxid456",
1433            id: 789,
1434            username: "finder_user",
1435            nickname: "Finder Nick",
1436            head_url: "http://head.jpg",
1437            nonce_id: "nonce123",
1438            media_type: "video",
1439            width: "1920",
1440            height: "1080",
1441            url: "http://video.mp4",
1442            thumb_url: "http://thumb.jpg",
1443            thumb_url_token: "token123",
1444            description: "Video description",
1445            video_play_len: "60",
1446        };
1447        let json = serde_json::to_string(&req).unwrap();
1448        assert!(json.contains("\"toWxid\":\"wxid456\""));
1449        assert!(json.contains("\"mediaType\":\"video\""));
1450        assert!(json.contains("\"videoPlayLen\":\"60\""));
1451    }
1452
1453    #[test]
1454    fn test_post_private_letter_request_serialize() {
1455        let req = PostPrivateLetterRequest {
1456            app_id: "app123",
1457            content: "Hello!",
1458            to_user_name: "user1",
1459            my_user_name: "myuser",
1460            msg_session_id: "session123",
1461        };
1462        let json = serde_json::to_string(&req).unwrap();
1463        assert!(json.contains("\"content\":\"Hello!\""));
1464        assert!(json.contains("\"toUserName\":\"user1\""));
1465        assert!(json.contains("\"msgSessionId\":\"session123\""));
1466    }
1467
1468    #[test]
1469    fn test_post_private_letter_img_request_serialize() {
1470        let req = PostPrivateLetterImgRequest {
1471            app_id: "app123",
1472            to_user_name: "user1",
1473            my_user_name: "myuser",
1474            msg_session_id: "session123",
1475            img_url: "http://img.jpg",
1476        };
1477        let json = serde_json::to_string(&req).unwrap();
1478        assert!(json.contains("\"imgUrl\":\"http://img.jpg\""));
1479    }
1480
1481    #[test]
1482    fn test_private_letter_response_deserialize() {
1483        let json = r#"{"newMsgId":123456}"#;
1484        let resp: PrivateLetterResponse = serde_json::from_str(json).unwrap();
1485        assert_eq!(resp.new_msg_id, 123456);
1486    }
1487
1488    #[test]
1489    fn test_sync_private_letter_msg_request_serialize() {
1490        let req = SyncPrivateLetterMsgRequest {
1491            app_id: "app123",
1492            key_buff: Some("keybuff123"),
1493        };
1494        let json = serde_json::to_string(&req).unwrap();
1495        assert!(json.contains("\"keyBuff\":\"keybuff123\""));
1496    }
1497
1498    #[test]
1499    fn test_mention_list_request_serialize() {
1500        let req = MentionListRequest {
1501            app_id: "app123",
1502            my_user_name: "myuser",
1503            my_role_type: 1,
1504            req_scene: 2,
1505            last_buff: "buff123",
1506        };
1507        let json = serde_json::to_string(&req).unwrap();
1508        assert!(json.contains("\"myUserName\":\"myuser\""));
1509        assert!(json.contains("\"reqScene\":2"));
1510    }
1511
1512    #[test]
1513    fn test_contact_list_request_serialize() {
1514        let req = ContactListRequest {
1515            app_id: "app123",
1516            my_user_name: "myuser",
1517            my_role_type: 1,
1518            query_info: "query123",
1519        };
1520        let json = serde_json::to_string(&req).unwrap();
1521        assert!(json.contains("\"queryInfo\":\"query123\""));
1522    }
1523
1524    #[test]
1525    fn test_contact_ext_info_deserialize() {
1526        let json = r#"{"country":"CN","province":"BJ","city":"Beijing","sex":1}"#;
1527        let info: ContactExtInfo = serde_json::from_str(json).unwrap();
1528        assert_eq!(info.country, "CN");
1529        assert_eq!(info.province, "BJ");
1530        assert_eq!(info.sex, 1);
1531    }
1532
1533    #[test]
1534    fn test_contact_list_entry_deserialize() {
1535        let json = r#"{"username":"user1","nickname":"Nick","headUrl":"http://head.jpg","signature":"Hi"}"#;
1536        let entry: ContactListEntry = serde_json::from_str(json).unwrap();
1537        assert_eq!(entry.username, Some("user1".to_string()));
1538        assert_eq!(entry.nickname, Some("Nick".to_string()));
1539    }
1540
1541    // ===== video_account/profile.rs tests =====
1542    #[test]
1543    fn test_create_finder_request_serialize() {
1544        let req = CreateFinderRequest {
1545            app_id: "app123",
1546            nick_name: "MyFinder",
1547            head_img: "http://head.jpg",
1548            signature: Some("Hello world"),
1549            sex: Some(1),
1550        };
1551        let json = serde_json::to_string(&req).unwrap();
1552        assert!(json.contains("\"nickName\":\"MyFinder\""));
1553        assert!(json.contains("\"signature\":\"Hello world\""));
1554        assert!(json.contains("\"sex\":1"));
1555    }
1556
1557    #[test]
1558    fn test_create_finder_response_deserialize() {
1559        let json = r#"{"username":"finder_user","nickName":"Nick","headUrl":"http://head.jpg","signature":"Hi","followFlag":0}"#;
1560        let resp: CreateFinderResponse = serde_json::from_str(json).unwrap();
1561        assert_eq!(resp.username, "finder_user");
1562        assert_eq!(resp.nick_name, "Nick");
1563        assert_eq!(resp.follow_flag, 0);
1564    }
1565
1566    #[test]
1567    fn test_update_finder_profile_request_serialize() {
1568        let req = UpdateFinderProfileRequest {
1569            app_id: "app123",
1570            nick_name: Some("NewNick"),
1571            head_img: None,
1572            signature: Some("New signature"),
1573            sex: Some(2),
1574            country: Some("US"),
1575            province: None,
1576            city: None,
1577            my_user_name: "myuser",
1578            my_role_type: 1,
1579        };
1580        let json = serde_json::to_string(&req).unwrap();
1581        assert!(json.contains("\"nickName\":\"NewNick\""));
1582        assert!(json.contains("\"signature\":\"New signature\""));
1583        assert!(!json.contains("headImg"));
1584    }
1585
1586    #[test]
1587    fn test_get_finder_qr_code_request_serialize() {
1588        let req = GetFinderQrCodeRequest {
1589            app_id: "app123",
1590            my_user_name: "myuser",
1591            my_role_type: 1,
1592        };
1593        let json = serde_json::to_string(&req).unwrap();
1594        assert!(json.contains("\"myUserName\":\"myuser\""));
1595    }
1596
1597    #[test]
1598    fn test_get_finder_qr_code_response_deserialize() {
1599        let json = r#"{"qrcodeUrl":"http://qrcode.jpg"}"#;
1600        let resp: GetFinderQrCodeResponse = serde_json::from_str(json).unwrap();
1601        assert_eq!(resp.qrcode_url, "http://qrcode.jpg");
1602    }
1603
1604    #[test]
1605    fn test_finder_alias_info_deserialize() {
1606        let json = r#"{"nickname":"AliasNick","headImgUrl":"http://head.jpg","roleType":2}"#;
1607        let info: FinderAliasInfo = serde_json::from_str(json).unwrap();
1608        assert_eq!(info.nickname, "AliasNick");
1609        assert_eq!(info.role_type, 2);
1610    }
1611
1612    // ===== video_account/follow.rs tests =====
1613    #[test]
1614    fn test_follow_finder_request_serialize() {
1615        let req = FollowFinderRequest {
1616            app_id: "app123",
1617            my_user_name: "myuser",
1618            my_role_type: 1,
1619            to_user_name: "touser",
1620            op_type: 1,
1621            search_info: None,
1622        };
1623        let json = serde_json::to_string(&req).unwrap();
1624        assert!(json.contains("\"myUserName\":\"myuser\""));
1625        assert!(json.contains("\"toUserName\":\"touser\""));
1626        assert!(json.contains("\"opType\":1"));
1627    }
1628
1629    #[test]
1630    fn test_follow_finder_response_deserialize() {
1631        let json = r#"{"username":"user1","nickname":"Nick","headUrl":"http://head.jpg","signature":"Hi","followFlag":1,"auth_info":null,"coverImgUrl":"http://cover.jpg","spamStatus":0,"extFlag":0,"liveStatus":0,"liveCoverImgUrl":"","status":0}"#;
1632        let resp: FollowFinderResponse = serde_json::from_str(json).unwrap();
1633        assert_eq!(resp.username, "user1");
1634        assert_eq!(resp.follow_flag, 1);
1635    }
1636
1637    #[test]
1638    fn test_follow_list_request_serialize() {
1639        let req = FollowListRequest {
1640            app_id: "app123",
1641            my_user_name: "myuser",
1642            my_role_type: 1,
1643            last_buffer: Some("buffer123"),
1644        };
1645        let json = serde_json::to_string(&req).unwrap();
1646        assert!(json.contains("\"lastBuffer\":\"buffer123\""));
1647    }
1648
1649    #[test]
1650    fn test_follow_list_data_deserialize() {
1651        let json = r#"{"contactList":[],"lastBuffer":"buff","continueFlag":1,"followCount":10}"#;
1652        let data: FollowListData = serde_json::from_str(json).unwrap();
1653        assert_eq!(data.last_buffer, "buff");
1654        assert_eq!(data.follow_count, 10);
1655    }
1656
1657    #[test]
1658    fn test_search_follow_request_serialize() {
1659        let req = SearchFollowRequest {
1660            app_id: "app123",
1661            my_user_name: "myuser",
1662            my_role_type: 1,
1663            to_user_name: "touser",
1664            keyword: "search",
1665        };
1666        let json = serde_json::to_string(&req).unwrap();
1667        assert!(json.contains("\"keyword\":\"search\""));
1668    }
1669
1670    // ===== video_account/interact.rs tests =====
1671    #[test]
1672    fn test_finder_opt_request_serialize() {
1673        let req = FinderOptRequest {
1674            app_id: "app123",
1675            my_user_name: "myuser",
1676            my_role_type: 1,
1677            to_user_name: "touser",
1678            op_type: 1,
1679            id: "id123",
1680            remain: 10,
1681        };
1682        let json = serde_json::to_string(&req).unwrap();
1683        assert!(json.contains("\"opType\":1"));
1684        assert!(json.contains("\"id\":\"id123\""));
1685        assert!(json.contains("\"remain\":10"));
1686    }
1687
1688    #[test]
1689    fn test_browse_finder_request_serialize() {
1690        let req = BrowseFinderRequest {
1691            app_id: "app123",
1692            object_id: 456,
1693            session_buffer: Some("buffer"),
1694            object_nonce_id: "nonce123",
1695            my_user_name: "myuser",
1696            my_role_type: 1,
1697        };
1698        let json = serde_json::to_string(&req).unwrap();
1699        assert!(json.contains("\"objectId\":456"));
1700        assert!(json.contains("\"objectNonceId\":\"nonce123\""));
1701    }
1702
1703    #[test]
1704    fn test_id_fav_request_serialize() {
1705        let req = IdFavRequest {
1706            app_id: "app123",
1707            my_user_name: "myuser",
1708            op_type: 1,
1709            object_nonce_id: "nonce123",
1710            session_buffer: "buffer",
1711            object_id: 789,
1712            to_user_name: "touser",
1713            my_role_type: 1,
1714        };
1715        let json = serde_json::to_string(&req).unwrap();
1716        assert!(json.contains("\"objectId\":789"));
1717        assert!(json.contains("\"sessionBuffer\":\"buffer\""));
1718    }
1719
1720    #[test]
1721    fn test_id_like_request_serialize() {
1722        let req = IdLikeRequest {
1723            app_id: "app123",
1724            object_id: 999,
1725            session_buffer: Some("buffer"),
1726            object_nonce_id: "nonce",
1727            op_type: 1,
1728            my_user_name: "myuser",
1729            my_role_type: 1,
1730            to_user_name: "touser",
1731        };
1732        let json = serde_json::to_string(&req).unwrap();
1733        assert!(json.contains("\"objectId\":999"));
1734        assert!(json.contains("\"opType\":1"));
1735    }
1736
1737    #[test]
1738    fn test_like_fav_list_request_serialize() {
1739        let req = LikeFavListRequest {
1740            app_id: "app123",
1741            my_user_name: "myuser",
1742            my_role_type: 1,
1743            last_buffer: None,
1744            flag: 2,
1745        };
1746        let json = serde_json::to_string(&req).unwrap();
1747        assert!(json.contains("\"flag\":2"));
1748        assert!(!json.contains("last_buffer"));
1749    }
1750
1751    #[test]
1752    fn test_comment_finder_request_serialize() {
1753        let req = CommentFinderRequest {
1754            app_id: "app123",
1755            proxy_ip: "127.0.0.1",
1756            my_user_name: "myuser",
1757            op_type: 1,
1758            object_nonce_id: "nonce",
1759            session_buffer: "buffer",
1760            object_id: 123,
1761            my_role_type: 1,
1762            content: "Nice video!",
1763            comment_id: "cmt123",
1764            reply_user_name: "replyuser",
1765            ref_comment_id: 456,
1766            root_comment_id: 789,
1767        };
1768        let json = serde_json::to_string(&req).unwrap();
1769        assert!(json.contains("\"content\":\"Nice video!\""));
1770        assert!(json.contains("\"commentId\":\"cmt123\""));
1771    }
1772
1773    #[test]
1774    fn test_comment_finder_response_deserialize() {
1775        let json = r#"{"commentId":"cmt456"}"#;
1776        let resp: CommentFinderResponse = serde_json::from_str(json).unwrap();
1777        assert_eq!(resp.comment_id, Some("cmt456".to_string()));
1778    }
1779
1780    #[test]
1781    fn test_comment_list_request_serialize() {
1782        let req = CommentListRequest {
1783            app_id: "app123",
1784            object_id: 111,
1785            last_buffer: Some("buff"),
1786            session_buffer: "session",
1787            object_nonce_id: None,
1788            ref_comment_id: Some(222),
1789            root_comment_id: Some(333),
1790        };
1791        let json = serde_json::to_string(&req).unwrap();
1792        assert!(json.contains("\"objectId\":111"));
1793        assert!(json.contains("\"refCommentId\":222"));
1794    }
1795
1796    // ===== video_account/publish.rs tests =====
1797    #[test]
1798    fn test_upload_finder_video_request_serialize() {
1799        let req = UploadFinderVideoRequest {
1800            app_id: "app123",
1801            video_url: "http://video.mp4",
1802            cover_img_url: "http://cover.jpg",
1803        };
1804        let json = serde_json::to_string(&req).unwrap();
1805        assert!(json.contains("\"videoUrl\":\"http://video.mp4\""));
1806        assert!(json.contains("\"coverImgUrl\":\"http://cover.jpg\""));
1807    }
1808
1809    #[test]
1810    fn test_upload_finder_video_response_deserialize() {
1811        let json = r#"{"fileUrl":"http://file.mp4","thumbUrl":"http://thumb.jpg","mp4Identify":"mp4id","fileSize":2048,"thumbMD5":"tmd5","fileKey":"fkey"}"#;
1812        let resp: UploadFinderVideoResponse = serde_json::from_str(json).unwrap();
1813        assert_eq!(resp.file_url, "http://file.mp4");
1814        assert_eq!(resp.file_size, 2048);
1815        assert_eq!(resp.file_key, "fkey");
1816    }
1817
1818    #[test]
1819    fn test_finder_video_cdn_deserialize() {
1820        let json = r#"{"fileUrl":"http://cdn.mp4","thumbUrl":"http://thumb.jpg","mp4Identify":"mp4","fileSize":1024,"thumbMD5":"md5","fileKey":"key"}"#;
1821        let cdn: FinderVideoCdn = serde_json::from_str(json).unwrap();
1822        assert_eq!(cdn.file_url, "http://cdn.mp4");
1823        assert_eq!(cdn.file_size, 1024);
1824    }
1825
1826    #[test]
1827    fn test_publish_finder_cdn_request_serialize() {
1828        let video_cdn = FinderVideoCdn {
1829            file_url: "http://cdn.mp4".to_string(),
1830            thumb_url: "http://thumb.jpg".to_string(),
1831            mp4_identify: "mp4".to_string(),
1832            file_size: 1024,
1833            thumb_md5: "md5".to_string(),
1834            file_key: "key".to_string(),
1835        };
1836        let req = PublishFinderCdnRequest {
1837            app_id: "app123",
1838            topic: vec!["topic1", "topic2"],
1839            my_user_name: "myuser",
1840            my_role_type: 1,
1841            description: "Video desc",
1842            video_cdn,
1843        };
1844        let json = serde_json::to_string(&req).unwrap();
1845        assert!(json.contains("\"topic\":[\"topic1\",\"topic2\"]"));
1846        assert!(json.contains("\"description\":\"Video desc\""));
1847    }
1848
1849    #[test]
1850    fn test_publish_finder_cdn_response_deserialize() {
1851        let json = r#"{"code":"0","msg":"success"}"#;
1852        let resp: PublishFinderCdnResponse = serde_json::from_str(json).unwrap();
1853        assert_eq!(resp.code, "0");
1854        assert_eq!(resp.msg, Some("success".to_string()));
1855    }
1856
1857    #[test]
1858    fn test_publish_finder_web_request_serialize() {
1859        let req = PublishFinderWebRequest {
1860            app_id: "app123",
1861            title: "Video Title",
1862            video_url: "http://video.mp4",
1863            thumb_url: "http://thumb.jpg",
1864            description: "Description",
1865        };
1866        let json = serde_json::to_string(&req).unwrap();
1867        assert!(json.contains("\"title\":\"Video Title\""));
1868        assert!(json.contains("\"description\":\"Description\""));
1869    }
1870
1871    #[test]
1872    fn test_publish_finder_web_response_deserialize() {
1873        let json = r#"{"id":12345}"#;
1874        let resp: PublishFinderWebResponse = serde_json::from_str(json).unwrap();
1875        assert_eq!(resp.id, 12345);
1876    }
1877
1878    #[test]
1879    fn test_send_finder_sns_request_serialize() {
1880        let req = SendFinderSnsRequest {
1881            app_id: "app123",
1882            allow_wx_ids: vec!["wxid1"],
1883            at_wx_ids: vec!["wxid2"],
1884            disable_wx_ids: vec![],
1885            id: 789,
1886            username: "user",
1887            nickname: "Nick",
1888            head_url: "http://head.jpg",
1889            nonce_id: "nonce",
1890            media_type: "video",
1891            width: "1920",
1892            height: "1080",
1893            url: "http://video.mp4",
1894            thumb_url: "http://thumb.jpg",
1895            thumb_url_token: "token",
1896            description: "desc",
1897            video_play_len: "60",
1898        };
1899        let json = serde_json::to_string(&req).unwrap();
1900        assert!(json.contains("\"allowWxIds\":[\"wxid1\"]"));
1901        assert!(json.contains("\"id\":789"));
1902    }
1903
1904    // ===== video_account/search.rs tests =====
1905    #[test]
1906    fn test_search_finder_request_serialize() {
1907        let req = SearchFinderRequest {
1908            app_id: "app123",
1909            content: "search query",
1910            category: Some(1),
1911            filter: Some(2),
1912            page: Some(1),
1913            cookie: Some("cookie123"),
1914            search_id: Some("sid123"),
1915            offset: Some(0),
1916        };
1917        let json = serde_json::to_string(&req).unwrap();
1918        assert!(json.contains("\"content\":\"search query\""));
1919        assert!(json.contains("\"category\":1"));
1920        assert!(json.contains("\"searchId\":\"sid123\""));
1921    }
1922
1923    #[test]
1924    fn test_search_finder_request_minimal() {
1925        let req = SearchFinderRequest {
1926            app_id: "app123",
1927            content: "query",
1928            category: None,
1929            filter: None,
1930            page: None,
1931            cookie: None,
1932            search_id: None,
1933            offset: None,
1934        };
1935        let json = serde_json::to_string(&req).unwrap();
1936        assert!(!json.contains("category"));
1937        assert!(!json.contains("filter"));
1938    }
1939
1940    // ===== video_account/scan.rs tests =====
1941    #[test]
1942    fn test_scan_follow_request_serialize() {
1943        let req = ScanFollowRequest {
1944            app_id: "app123",
1945            proxy_ip: "127.0.0.1",
1946            my_user_name: "myuser",
1947            my_role_type: 1,
1948            qr_content: "qr123",
1949            object_id: "oid123",
1950            object_nonce_id: "nonce123",
1951        };
1952        let json = serde_json::to_string(&req).unwrap();
1953        assert!(json.contains("\"qrContent\":\"qr123\""));
1954        assert!(json.contains("\"objectId\":\"oid123\""));
1955    }
1956
1957    #[test]
1958    fn test_scan_browse_request_serialize() {
1959        let req = ScanBrowseRequest {
1960            app_id: "app123",
1961            my_user_name: "myuser",
1962            my_role_type: 1,
1963            qr_content: "qr123",
1964            object_id: 456,
1965        };
1966        let json = serde_json::to_string(&req).unwrap();
1967        assert!(json.contains("\"objectId\":456"));
1968    }
1969
1970    #[test]
1971    fn test_scan_fav_request_serialize() {
1972        let req = ScanFavRequest {
1973            app_id: "app123",
1974            my_user_name: "myuser",
1975            my_role_type: 1,
1976            qr_content: "qr123",
1977            object_id: 789,
1978        };
1979        let json = serde_json::to_string(&req).unwrap();
1980        assert!(json.contains("\"objectId\":789"));
1981    }
1982
1983    #[test]
1984    fn test_scan_comment_request_serialize() {
1985        let req = ScanCommentRequest {
1986            app_id: "app123",
1987            my_user_name: "myuser",
1988            my_role_type: 1,
1989            qr_content: "qr123",
1990            object_id: 111,
1991            comment_content: "Nice!",
1992            reply_username: Some("replyuser"),
1993            ref_comment_id: Some(222),
1994            root_comment_id: Some(333),
1995        };
1996        let json = serde_json::to_string(&req).unwrap();
1997        assert!(json.contains("\"commentContent\":\"Nice!\""));
1998        assert!(json.contains("\"refCommentId\":222"));
1999    }
2000
2001    #[test]
2002    fn test_scan_qr_code_request_serialize() {
2003        let req = ScanQrCodeRequest {
2004            app_id: "app123",
2005            my_user_name: "myuser",
2006            my_role_type: 1,
2007            qr_content: "qr123",
2008        };
2009        let json = serde_json::to_string(&req).unwrap();
2010        assert!(json.contains("\"qrContent\":\"qr123\""));
2011    }
2012
2013    #[test]
2014    fn test_scan_login_channels_request_serialize() {
2015        let req = ScanLoginChannelsRequest {
2016            app_id: "app123",
2017            qr_content: "qr123",
2018        };
2019        let json = serde_json::to_string(&req).unwrap();
2020        assert!(json.contains("\"qrContent\":\"qr123\""));
2021    }
2022
2023    #[test]
2024    fn test_scan_login_finder_info_deserialize() {
2025        let json = r#"{"finderUsername":"user","nickname":"Nick","headImgUrl":"http://head.jpg","spamFlag":0}"#;
2026        let info: ScanLoginFinderInfo = serde_json::from_str(json).unwrap();
2027        assert_eq!(info.finder_username, Some("user".to_string()));
2028        assert_eq!(info.nickname, Some("Nick".to_string()));
2029    }
2030
2031    #[test]
2032    fn test_scan_login_channels_response_deserialize() {
2033        let json = r#"{"sessionId":"session123","finderList":[],"acctStatus":1}"#;
2034        let resp: ScanLoginChannelsResponse = serde_json::from_str(json).unwrap();
2035        assert_eq!(resp.session_id, "session123");
2036        assert_eq!(resp.acct_status, 1);
2037    }
2038
2039    // ===== video_account/common.rs tests =====
2040    #[test]
2041    fn test_finder_ext_info_deserialize() {
2042        let json = r#"{"country":"CN","province":"BJ","city":"Beijing","sex":1}"#;
2043        let info: FinderExtInfo = serde_json::from_str(json).unwrap();
2044        assert_eq!(info.country, Some("CN".to_string()));
2045        assert_eq!(info.sex, Some(1));
2046    }
2047
2048    #[test]
2049    fn test_finder_contact_profile_deserialize() {
2050        let json = r#"{"username":"user1","nickname":"Nick","headUrl":"http://head.jpg","signature":"Hi","auth_info":null}"#;
2051        let profile: FinderContactProfile = serde_json::from_str(json).unwrap();
2052        assert_eq!(profile.username, "user1");
2053        assert_eq!(profile.nickname, "Nick");
2054        assert_eq!(profile.head_url, "http://head.jpg");
2055        assert_eq!(profile.signature, "Hi");
2056    }
2057
2058    #[test]
2059    fn test_finder_search_info_serialize() {
2060        let info = FinderSearchInfo {
2061            cookies: Some("cookie123"),
2062            search_id: Some("sid123"),
2063            doc_id: None,
2064        };
2065        let json = serde_json::to_string(&info).unwrap();
2066        assert!(json.contains("\"cookies\":\"cookie123\""));
2067        assert!(json.contains("\"searchId\":\"sid123\""));
2068        assert!(!json.contains("docId"));
2069    }
2070
2071    // ===== group/manage.rs tests =====
2072    #[test]
2073    fn test_create_chatroom_request_serialize() {
2074        let req = CreateChatroomRequest {
2075            app_id: "app123",
2076            wxids: vec!["wxid1", "wxid2", "wxid3"],
2077        };
2078        let json = serde_json::to_string(&req).unwrap();
2079        assert!(json.contains("\"appId\":\"app123\""));
2080        assert!(json.contains("\"wxids\":[\"wxid1\",\"wxid2\",\"wxid3\"]"));
2081    }
2082
2083    #[test]
2084    fn test_create_chatroom_response_deserialize() {
2085        let json = r#"{"headImgBase64":"base64data","chatroomId":"room123"}"#;
2086        let resp: CreateChatroomResponse = serde_json::from_str(json).unwrap();
2087        assert_eq!(resp.chatroom_id, "room123");
2088        assert_eq!(resp.head_img_base64, Some("base64data".to_string()));
2089    }
2090
2091    #[test]
2092    fn test_create_chatroom_response_without_head_img() {
2093        let json = r#"{"chatroomId":"room456"}"#;
2094        let resp: CreateChatroomResponse = serde_json::from_str(json).unwrap();
2095        assert_eq!(resp.chatroom_id, "room456");
2096        assert_eq!(resp.head_img_base64, None);
2097    }
2098
2099    #[test]
2100    fn test_disband_chatroom_request_serialize() {
2101        let req = DisbandChatroomRequest {
2102            app_id: "app123",
2103            chatroom_id: "room456",
2104        };
2105        let json = serde_json::to_string(&req).unwrap();
2106        assert!(json.contains("\"chatroomId\":\"room456\""));
2107    }
2108
2109    #[test]
2110    fn test_quit_chatroom_request_serialize() {
2111        let req = QuitChatroomRequest {
2112            app_id: "app123",
2113            chatroom_id: "room789",
2114        };
2115        let json = serde_json::to_string(&req).unwrap();
2116        assert!(json.contains("\"chatroomId\":\"room789\""));
2117    }
2118
2119    #[test]
2120    fn test_modify_chatroom_name_request_serialize() {
2121        let req = ModifyChatroomNameRequest {
2122            app_id: "app123",
2123            chatroom_name: "New Group Name",
2124            chatroom_id: "room123",
2125        };
2126        let json = serde_json::to_string(&req).unwrap();
2127        assert!(json.contains("\"chatroomName\":\"New Group Name\""));
2128        assert!(json.contains("\"chatroomId\":\"room123\""));
2129    }
2130
2131    #[test]
2132    fn test_modify_chatroom_remark_request_serialize() {
2133        let req = ModifyChatroomRemarkRequest {
2134            app_id: "app123",
2135            chatroom_remark: "Important Group",
2136            chatroom_id: "room123",
2137        };
2138        let json = serde_json::to_string(&req).unwrap();
2139        assert!(json.contains("\"chatroomRemark\":\"Important Group\""));
2140    }
2141
2142    #[test]
2143    fn test_modify_chatroom_nickname_for_self_request_serialize() {
2144        let req = ModifyChatroomNickNameForSelfRequest {
2145            app_id: "app123",
2146            chatroom_id: "room123",
2147            nick_name: "MyNickname",
2148        };
2149        let json = serde_json::to_string(&req).unwrap();
2150        assert!(json.contains("\"nickName\":\"MyNickname\""));
2151        assert!(json.contains("\"chatroomId\":\"room123\""));
2152    }
2153
2154    // ===== Default trait tests =====
2155    #[test]
2156    fn test_get_login_qr_code_response_default() {
2157        let resp = GetLoginQrCodeResponse::default();
2158        assert_eq!(resp.qr_data, "");
2159        assert_eq!(resp.uuid, "");
2160    }
2161
2162    #[test]
2163    fn test_check_login_response_default() {
2164        let resp = CheckLoginResponse::default();
2165        assert_eq!(resp.status, 0);
2166        assert!(resp.login_info.is_none());
2167    }
2168
2169    #[test]
2170    fn test_login_info_default() {
2171        let info = LoginInfo::default();
2172        assert!(info.uin.is_none());
2173        assert!(info.wxid.is_none());
2174    }
2175
2176    #[test]
2177    fn test_label_info_default() {
2178        let info = LabelInfo::default();
2179        assert_eq!(info.label_name, "");
2180        assert_eq!(info.label_id, 0);
2181    }
2182
2183    #[test]
2184    fn test_send_text_response_default() {
2185        let resp = SendTextResponse::default();
2186        assert_eq!(resp.to_wxid, "");
2187        assert_eq!(resp.msg_type, 0);
2188    }
2189
2190    #[test]
2191    fn test_chatroom_member_default() {
2192        let member = ChatroomMember::default();
2193        assert_eq!(member.wxid, "");
2194        assert_eq!(member.sex, 0);
2195    }
2196
2197    // ===== Clone tests =====
2198    #[test]
2199    fn test_app_id_clone() {
2200        let app_id = AppId("test".to_string());
2201        let cloned = app_id.clone();
2202        assert_eq!(app_id, cloned);
2203    }
2204
2205    #[test]
2206    fn test_bot_context_clone() {
2207        let ctx = BotContext {
2208            app_id: AppId("app".to_string()),
2209            token: "token".to_string(),
2210            webhook_secret: None,
2211            description: None,
2212        };
2213        let cloned = ctx.clone();
2214        assert_eq!(ctx.app_id, cloned.app_id);
2215        assert_eq!(ctx.token, cloned.token);
2216    }
2217
2218    // ===== Debug tests =====
2219    #[test]
2220    fn test_gewe_error_debug() {
2221        let err = GeweError::MissingData;
2222        let debug_str = format!("{:?}", err);
2223        assert!(debug_str.contains("MissingData"));
2224    }
2225
2226    #[test]
2227    fn test_app_id_debug() {
2228        let app_id = AppId("test123".to_string());
2229        let debug_str = format!("{:?}", app_id);
2230        assert!(debug_str.contains("test123"));
2231    }
2232
2233    // ===== Hash tests =====
2234    #[test]
2235    fn test_app_id_hash() {
2236        use std::collections::HashSet;
2237        let mut set = HashSet::new();
2238        set.insert(AppId("test1".to_string()));
2239        set.insert(AppId("test2".to_string()));
2240        set.insert(AppId("test1".to_string())); // duplicate
2241        assert_eq!(set.len(), 2);
2242    }
2243
2244    #[test]
2245    fn test_bot_id_hash() {
2246        use std::collections::HashSet;
2247        let mut set = HashSet::new();
2248        set.insert(BotId("bot1".to_string()));
2249        set.insert(BotId("bot2".to_string()));
2250        assert_eq!(set.len(), 2);
2251    }
2252}