gewe_core/
common.rs

1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
5#[serde(transparent)]
6pub struct AppId(pub String);
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(transparent)]
10pub struct BotId(pub String);
11
12impl From<String> for BotId {
13    fn from(value: String) -> Self {
14        Self(value)
15    }
16}
17
18impl From<&str> for BotId {
19    fn from(value: &str) -> Self {
20        Self(value.to_string())
21    }
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct BotContext {
27    pub app_id: AppId,
28    pub token: String,
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub webhook_secret: Option<String>,
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub description: Option<String>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct CallbackEnvelope<T> {
38    pub appid: String,
39    pub data: T,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct ApiEnvelope<T> {
45    pub ret: i32,
46    pub msg: String,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub data: Option<T>,
49}
50
51#[derive(Debug, Error)]
52pub enum GeweError {
53    #[error("http error: {0}")]
54    Http(String),
55    #[error("api error code={code}: {message}")]
56    Api { code: i32, message: String },
57    #[error("decode error: {0}")]
58    Decode(String),
59    #[error("missing data")]
60    MissingData,
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_app_id_serialization() {
69        let app_id = AppId("test_app_id".to_string());
70        let json = serde_json::to_string(&app_id).unwrap();
71        assert_eq!(json, r#""test_app_id""#);
72    }
73
74    #[test]
75    fn test_app_id_deserialization() {
76        let json = r#""test_app_id""#;
77        let app_id: AppId = serde_json::from_str(json).unwrap();
78        assert_eq!(app_id.0, "test_app_id");
79    }
80
81    #[test]
82    fn test_bot_id_from_string() {
83        let bot_id: BotId = "test_bot_id".to_string().into();
84        assert_eq!(bot_id.0, "test_bot_id");
85    }
86
87    #[test]
88    fn test_bot_id_from_str() {
89        let bot_id: BotId = "test_bot_id".into();
90        assert_eq!(bot_id.0, "test_bot_id");
91    }
92
93    #[test]
94    fn test_bot_id_serialization() {
95        let bot_id = BotId("test_bot_id".to_string());
96        let json = serde_json::to_string(&bot_id).unwrap();
97        assert_eq!(json, r#""test_bot_id""#);
98    }
99
100    #[test]
101    fn test_bot_id_deserialization() {
102        let json = r#""test_bot_id""#;
103        let bot_id: BotId = serde_json::from_str(json).unwrap();
104        assert_eq!(bot_id.0, "test_bot_id");
105    }
106
107    #[test]
108    fn test_bot_context_serialization() {
109        let ctx = BotContext {
110            app_id: AppId("app123".to_string()),
111            token: "token123".to_string(),
112            webhook_secret: Some("secret123".to_string()),
113            description: Some("Test bot".to_string()),
114        };
115        let json = serde_json::to_string(&ctx).unwrap();
116        assert!(json.contains("app123"));
117        assert!(json.contains("token123"));
118        assert!(json.contains("secret123"));
119        assert!(json.contains("Test bot"));
120    }
121
122    #[test]
123    fn test_bot_context_deserialization() {
124        let json = r#"{
125            "appId": "app123",
126            "token": "token123",
127            "webhookSecret": "secret123",
128            "description": "Test bot"
129        }"#;
130        let ctx: BotContext = serde_json::from_str(json).unwrap();
131        assert_eq!(ctx.app_id.0, "app123");
132        assert_eq!(ctx.token, "token123");
133        assert_eq!(ctx.webhook_secret, Some("secret123".to_string()));
134        assert_eq!(ctx.description, Some("Test bot".to_string()));
135    }
136
137    #[test]
138    fn test_bot_context_optional_fields() {
139        let json = r#"{
140            "appId": "app123",
141            "token": "token123"
142        }"#;
143        let ctx: BotContext = serde_json::from_str(json).unwrap();
144        assert_eq!(ctx.app_id.0, "app123");
145        assert_eq!(ctx.token, "token123");
146        assert_eq!(ctx.webhook_secret, None);
147        assert_eq!(ctx.description, None);
148    }
149
150    #[test]
151    fn test_callback_envelope_serialization() {
152        let envelope = CallbackEnvelope {
153            appid: "app123".to_string(),
154            data: "test_data".to_string(),
155        };
156        let json = serde_json::to_string(&envelope).unwrap();
157        assert!(json.contains("app123"));
158        assert!(json.contains("test_data"));
159    }
160
161    #[test]
162    fn test_callback_envelope_deserialization() {
163        let json = r#"{"appid":"app123","data":"test_data"}"#;
164        let envelope: CallbackEnvelope<String> = serde_json::from_str(json).unwrap();
165        assert_eq!(envelope.appid, "app123");
166        assert_eq!(envelope.data, "test_data");
167    }
168
169    #[test]
170    fn test_api_envelope_with_data() {
171        let envelope = ApiEnvelope {
172            ret: 200,
173            msg: "success".to_string(),
174            data: Some("result".to_string()),
175        };
176        let json = serde_json::to_string(&envelope).unwrap();
177        assert!(json.contains("200"));
178        assert!(json.contains("success"));
179        assert!(json.contains("result"));
180    }
181
182    #[test]
183    fn test_api_envelope_without_data() {
184        let json = r#"{"ret":200,"msg":"success"}"#;
185        let envelope: ApiEnvelope<String> = serde_json::from_str(json).unwrap();
186        assert_eq!(envelope.ret, 200);
187        assert_eq!(envelope.msg, "success");
188        assert_eq!(envelope.data, None);
189    }
190
191    #[test]
192    fn test_gewe_error_http() {
193        let err = GeweError::Http("connection failed".to_string());
194        assert_eq!(err.to_string(), "http error: connection failed");
195    }
196
197    #[test]
198    fn test_gewe_error_api() {
199        let err = GeweError::Api {
200            code: 404,
201            message: "not found".to_string(),
202        };
203        assert_eq!(err.to_string(), "api error code=404: not found");
204    }
205
206    #[test]
207    fn test_gewe_error_decode() {
208        let err = GeweError::Decode("invalid json".to_string());
209        assert_eq!(err.to_string(), "decode error: invalid json");
210    }
211
212    #[test]
213    fn test_gewe_error_missing_data() {
214        let err = GeweError::MissingData;
215        assert_eq!(err.to_string(), "missing data");
216    }
217}