1use serde::{Deserialize, Serialize};
2
3#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
9pub struct CodexConfiguration {
10 pub alias_name: String,
12 pub auth_mode: String,
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub openai_api_key: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub id_token: Option<String>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub access_token: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub refresh_token: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub account_id: Option<String>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub last_refresh: Option<String>,
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn test_serialize_apikey_mode() {
40 let config = CodexConfiguration {
41 alias_name: "my-apikey".to_string(),
42 auth_mode: "apikey".to_string(),
43 openai_api_key: Some("sk-abc123".to_string()),
44 id_token: None,
45 access_token: None,
46 refresh_token: None,
47 account_id: None,
48 last_refresh: None,
49 };
50
51 let json = serde_json::to_string(&config).unwrap();
52 assert!(json.contains("\"auth_mode\":\"apikey\""));
53 assert!(json.contains("\"openai_api_key\":\"sk-abc123\""));
54 assert!(!json.contains("id_token"));
56 assert!(!json.contains("access_token"));
57 }
58
59 #[test]
60 fn test_deserialize_apikey_mode() {
61 let json = r#"{
62 "alias_name": "my-apikey",
63 "auth_mode": "apikey",
64 "openai_api_key": "sk-abc123"
65 }"#;
66
67 let config: CodexConfiguration = serde_json::from_str(json).unwrap();
68 assert_eq!(config.alias_name, "my-apikey");
69 assert_eq!(config.auth_mode, "apikey");
70 assert_eq!(config.openai_api_key, Some("sk-abc123".to_string()));
71 assert_eq!(config.id_token, None);
72 assert_eq!(config.access_token, None);
73 }
74
75 #[test]
76 fn test_serialize_chatgpt_mode() {
77 let config = CodexConfiguration {
78 alias_name: "my-chatgpt".to_string(),
79 auth_mode: "chatgpt".to_string(),
80 openai_api_key: None,
81 id_token: Some("id-xyz".to_string()),
82 access_token: Some("at-xyz".to_string()),
83 refresh_token: Some("rt-xyz".to_string()),
84 account_id: Some("acc-123".to_string()),
85 last_refresh: Some("2026-05-16T00:00:00Z".to_string()),
86 };
87
88 let json = serde_json::to_string(&config).unwrap();
89 assert!(json.contains("\"auth_mode\":\"chatgpt\""));
90 assert!(json.contains("\"id_token\":\"id-xyz\""));
91 assert!(json.contains("\"access_token\":\"at-xyz\""));
92 assert!(json.contains("\"refresh_token\":\"rt-xyz\""));
93 assert!(json.contains("\"account_id\":\"acc-123\""));
94 assert!(json.contains("\"last_refresh\""));
95 assert!(!json.contains("openai_api_key"));
96 }
97
98 #[test]
99 fn test_deserialize_chatgpt_mode() {
100 let json = r#"{
101 "alias_name": "my-chatgpt",
102 "auth_mode": "chatgpt",
103 "id_token": "id-xyz",
104 "access_token": "at-xyz",
105 "refresh_token": "rt-xyz",
106 "account_id": "acc-123",
107 "last_refresh": "2026-05-16T00:00:00Z"
108 }"#;
109
110 let config: CodexConfiguration = serde_json::from_str(json).unwrap();
111 assert_eq!(config.alias_name, "my-chatgpt");
112 assert_eq!(config.auth_mode, "chatgpt");
113 assert_eq!(config.id_token, Some("id-xyz".to_string()));
114 assert_eq!(config.access_token, Some("at-xyz".to_string()));
115 assert_eq!(config.refresh_token, Some("rt-xyz".to_string()));
116 assert_eq!(config.account_id, Some("acc-123".to_string()));
117 assert_eq!(
118 config.last_refresh,
119 Some("2026-05-16T00:00:00Z".to_string())
120 );
121 assert_eq!(config.openai_api_key, None);
122 }
123
124 #[test]
125 fn test_roundtrip_serialization() {
126 let config = CodexConfiguration {
127 alias_name: "roundtrip".to_string(),
128 auth_mode: "apikey".to_string(),
129 openai_api_key: Some("sk-roundtrip".to_string()),
130 id_token: None,
131 access_token: None,
132 refresh_token: None,
133 account_id: None,
134 last_refresh: None,
135 };
136
137 let json = serde_json::to_string(&config).unwrap();
138 let deserialized: CodexConfiguration = serde_json::from_str(&json).unwrap();
139 assert_eq!(config, deserialized);
140 }
141}