use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct UserPreferences {
pub language: Option<String>,
pub timezone: Option<String>,
pub theme: Option<String>,
pub notifications: NotificationSettings,
pub dashboard: DashboardSettings,
pub api: ApiPreferences,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NotificationSettings {
pub email_enabled: bool,
pub slack_enabled: bool,
pub webhook_enabled: bool,
pub types: Vec<NotificationType>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationType {
RateLimitWarning,
QuotaWarning,
ServiceAlert,
SecurityAlert,
UsageReport,
SystemMaintenance,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DashboardSettings {
pub default_time_range: Option<String>,
pub favorite_charts: Vec<String>,
pub layout: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ApiPreferences {
pub default_model: Option<String>,
pub default_temperature: Option<f32>,
pub default_max_tokens: Option<u32>,
pub preferred_providers: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_preferences_default() {
let prefs = UserPreferences::default();
assert!(prefs.language.is_none());
assert!(prefs.timezone.is_none());
assert!(prefs.theme.is_none());
}
#[test]
fn test_user_preferences_with_values() {
let prefs = UserPreferences {
language: Some("en-US".to_string()),
timezone: Some("America/New_York".to_string()),
theme: Some("dark".to_string()),
notifications: NotificationSettings::default(),
dashboard: DashboardSettings::default(),
api: ApiPreferences::default(),
};
assert_eq!(prefs.language, Some("en-US".to_string()));
assert_eq!(prefs.timezone, Some("America/New_York".to_string()));
assert_eq!(prefs.theme, Some("dark".to_string()));
}
#[test]
fn test_user_preferences_serialize() {
let prefs = UserPreferences {
language: Some("zh-CN".to_string()),
timezone: Some("Asia/Shanghai".to_string()),
theme: Some("light".to_string()),
..Default::default()
};
let json = serde_json::to_string(&prefs).unwrap();
assert!(json.contains("zh-CN"));
assert!(json.contains("Asia/Shanghai"));
assert!(json.contains("light"));
}
#[test]
fn test_user_preferences_deserialize() {
let json = r#"{
"language": "ja-JP",
"timezone": "Asia/Tokyo",
"theme": "auto",
"notifications": {"email_enabled": true, "slack_enabled": false, "webhook_enabled": false, "types": []},
"dashboard": {"default_time_range": null, "favorite_charts": [], "layout": null},
"api": {"default_model": null, "default_temperature": null, "default_max_tokens": null, "preferred_providers": []}
}"#;
let prefs: UserPreferences = serde_json::from_str(json).unwrap();
assert_eq!(prefs.language, Some("ja-JP".to_string()));
assert_eq!(prefs.timezone, Some("Asia/Tokyo".to_string()));
}
#[test]
fn test_user_preferences_clone() {
let original = UserPreferences {
language: Some("fr-FR".to_string()),
..Default::default()
};
let cloned = original.clone();
assert_eq!(original.language, cloned.language);
}
#[test]
fn test_user_preferences_debug() {
let prefs = UserPreferences::default();
let debug_str = format!("{:?}", prefs);
assert!(debug_str.contains("UserPreferences"));
}
#[test]
fn test_notification_settings_default() {
let settings = NotificationSettings::default();
assert!(!settings.email_enabled);
assert!(!settings.slack_enabled);
assert!(!settings.webhook_enabled);
assert!(settings.types.is_empty());
}
#[test]
fn test_notification_settings_all_enabled() {
let settings = NotificationSettings {
email_enabled: true,
slack_enabled: true,
webhook_enabled: true,
types: vec![
NotificationType::RateLimitWarning,
NotificationType::SecurityAlert,
],
};
assert!(settings.email_enabled);
assert!(settings.slack_enabled);
assert!(settings.webhook_enabled);
assert_eq!(settings.types.len(), 2);
}
#[test]
fn test_notification_settings_serialize() {
let settings = NotificationSettings {
email_enabled: true,
slack_enabled: false,
webhook_enabled: true,
types: vec![NotificationType::UsageReport],
};
let json = serde_json::to_string(&settings).unwrap();
assert!(json.contains("\"email_enabled\":true"));
assert!(json.contains("\"slack_enabled\":false"));
assert!(json.contains("usage_report"));
}
#[test]
fn test_notification_settings_deserialize() {
let json = r#"{
"email_enabled": true,
"slack_enabled": true,
"webhook_enabled": false,
"types": ["rate_limit_warning", "quota_warning"]
}"#;
let settings: NotificationSettings = serde_json::from_str(json).unwrap();
assert!(settings.email_enabled);
assert!(settings.slack_enabled);
assert!(!settings.webhook_enabled);
assert_eq!(settings.types.len(), 2);
}
#[test]
fn test_notification_settings_clone() {
let original = NotificationSettings {
email_enabled: true,
slack_enabled: false,
webhook_enabled: true,
types: vec![NotificationType::ServiceAlert],
};
let cloned = original.clone();
assert_eq!(original.email_enabled, cloned.email_enabled);
assert_eq!(original.types.len(), cloned.types.len());
}
#[test]
fn test_notification_type_rate_limit_warning() {
let t = NotificationType::RateLimitWarning;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"rate_limit_warning\"");
}
#[test]
fn test_notification_type_quota_warning() {
let t = NotificationType::QuotaWarning;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"quota_warning\"");
}
#[test]
fn test_notification_type_service_alert() {
let t = NotificationType::ServiceAlert;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"service_alert\"");
}
#[test]
fn test_notification_type_security_alert() {
let t = NotificationType::SecurityAlert;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"security_alert\"");
}
#[test]
fn test_notification_type_usage_report() {
let t = NotificationType::UsageReport;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"usage_report\"");
}
#[test]
fn test_notification_type_system_maintenance() {
let t = NotificationType::SystemMaintenance;
let json = serde_json::to_string(&t).unwrap();
assert_eq!(json, "\"system_maintenance\"");
}
#[test]
fn test_notification_type_deserialize() {
let t: NotificationType = serde_json::from_str("\"security_alert\"").unwrap();
assert!(matches!(t, NotificationType::SecurityAlert));
}
#[test]
fn test_notification_type_clone() {
let original = NotificationType::RateLimitWarning;
let cloned = original.clone();
let json1 = serde_json::to_string(&original).unwrap();
let json2 = serde_json::to_string(&cloned).unwrap();
assert_eq!(json1, json2);
}
#[test]
fn test_notification_type_debug() {
let t = NotificationType::QuotaWarning;
let debug_str = format!("{:?}", t);
assert!(debug_str.contains("QuotaWarning"));
}
#[test]
fn test_dashboard_settings_default() {
let settings = DashboardSettings::default();
assert!(settings.default_time_range.is_none());
assert!(settings.favorite_charts.is_empty());
assert!(settings.layout.is_none());
}
#[test]
fn test_dashboard_settings_with_values() {
let settings = DashboardSettings {
default_time_range: Some("24h".to_string()),
favorite_charts: vec!["requests".to_string(), "latency".to_string()],
layout: Some(serde_json::json!({"columns": 2})),
};
assert_eq!(settings.default_time_range, Some("24h".to_string()));
assert_eq!(settings.favorite_charts.len(), 2);
assert!(settings.layout.is_some());
}
#[test]
fn test_dashboard_settings_serialize() {
let settings = DashboardSettings {
default_time_range: Some("7d".to_string()),
favorite_charts: vec!["errors".to_string()],
layout: None,
};
let json = serde_json::to_string(&settings).unwrap();
assert!(json.contains("7d"));
assert!(json.contains("errors"));
}
#[test]
fn test_dashboard_settings_deserialize() {
let json = r#"{
"default_time_range": "30d",
"favorite_charts": ["cpu", "memory"],
"layout": null
}"#;
let settings: DashboardSettings = serde_json::from_str(json).unwrap();
assert_eq!(settings.default_time_range, Some("30d".to_string()));
assert_eq!(settings.favorite_charts.len(), 2);
}
#[test]
fn test_dashboard_settings_clone() {
let original = DashboardSettings {
default_time_range: Some("1h".to_string()),
favorite_charts: vec!["chart1".to_string()],
layout: Some(serde_json::json!({"test": true})),
};
let cloned = original.clone();
assert_eq!(original.default_time_range, cloned.default_time_range);
assert_eq!(original.favorite_charts, cloned.favorite_charts);
}
#[test]
fn test_dashboard_settings_debug() {
let settings = DashboardSettings::default();
let debug_str = format!("{:?}", settings);
assert!(debug_str.contains("DashboardSettings"));
}
#[test]
fn test_api_preferences_default() {
let prefs = ApiPreferences::default();
assert!(prefs.default_model.is_none());
assert!(prefs.default_temperature.is_none());
assert!(prefs.default_max_tokens.is_none());
assert!(prefs.preferred_providers.is_empty());
}
#[test]
fn test_api_preferences_with_values() {
let prefs = ApiPreferences {
default_model: Some("gpt-4".to_string()),
default_temperature: Some(0.7),
default_max_tokens: Some(2048),
preferred_providers: vec!["openai".to_string(), "anthropic".to_string()],
};
assert_eq!(prefs.default_model, Some("gpt-4".to_string()));
assert_eq!(prefs.default_temperature, Some(0.7));
assert_eq!(prefs.default_max_tokens, Some(2048));
assert_eq!(prefs.preferred_providers.len(), 2);
}
#[test]
fn test_api_preferences_serialize() {
let prefs = ApiPreferences {
default_model: Some("claude-3".to_string()),
default_temperature: Some(0.5),
default_max_tokens: Some(1000),
preferred_providers: vec!["anthropic".to_string()],
};
let json = serde_json::to_string(&prefs).unwrap();
assert!(json.contains("claude-3"));
assert!(json.contains("0.5"));
assert!(json.contains("1000"));
assert!(json.contains("anthropic"));
}
#[test]
fn test_api_preferences_deserialize() {
let json = r#"{
"default_model": "gemini-pro",
"default_temperature": 0.8,
"default_max_tokens": 4096,
"preferred_providers": ["google", "openai"]
}"#;
let prefs: ApiPreferences = serde_json::from_str(json).unwrap();
assert_eq!(prefs.default_model, Some("gemini-pro".to_string()));
assert_eq!(prefs.default_temperature, Some(0.8));
assert_eq!(prefs.default_max_tokens, Some(4096));
assert_eq!(prefs.preferred_providers.len(), 2);
}
#[test]
fn test_api_preferences_clone() {
let original = ApiPreferences {
default_model: Some("test".to_string()),
default_temperature: Some(1.0),
default_max_tokens: Some(100),
preferred_providers: vec!["test".to_string()],
};
let cloned = original.clone();
assert_eq!(original.default_model, cloned.default_model);
assert_eq!(original.default_temperature, cloned.default_temperature);
}
#[test]
fn test_api_preferences_debug() {
let prefs = ApiPreferences::default();
let debug_str = format!("{:?}", prefs);
assert!(debug_str.contains("ApiPreferences"));
}
#[test]
fn test_api_preferences_temperature_range() {
let prefs = ApiPreferences {
default_temperature: Some(0.0),
..Default::default()
};
assert_eq!(prefs.default_temperature, Some(0.0));
let prefs = ApiPreferences {
default_temperature: Some(1.0),
..Default::default()
};
assert_eq!(prefs.default_temperature, Some(1.0));
let prefs = ApiPreferences {
default_temperature: Some(2.0),
..Default::default()
};
assert_eq!(prefs.default_temperature, Some(2.0));
}
#[test]
fn test_api_preferences_max_tokens_range() {
let prefs = ApiPreferences {
default_max_tokens: Some(1),
..Default::default()
};
assert_eq!(prefs.default_max_tokens, Some(1));
let prefs = ApiPreferences {
default_max_tokens: Some(100_000),
..Default::default()
};
assert_eq!(prefs.default_max_tokens, Some(100_000));
}
#[test]
fn test_full_user_preferences() {
let prefs = UserPreferences {
language: Some("en-US".to_string()),
timezone: Some("UTC".to_string()),
theme: Some("system".to_string()),
notifications: NotificationSettings {
email_enabled: true,
slack_enabled: true,
webhook_enabled: false,
types: vec![
NotificationType::RateLimitWarning,
NotificationType::SecurityAlert,
NotificationType::UsageReport,
],
},
dashboard: DashboardSettings {
default_time_range: Some("24h".to_string()),
favorite_charts: vec!["requests".to_string(), "latency".to_string()],
layout: Some(serde_json::json!({"columns": 3, "rows": 2})),
},
api: ApiPreferences {
default_model: Some("gpt-4-turbo".to_string()),
default_temperature: Some(0.7),
default_max_tokens: Some(4096),
preferred_providers: vec!["openai".to_string(), "anthropic".to_string()],
},
};
let json = serde_json::to_string(&prefs).unwrap();
let deserialized: UserPreferences = serde_json::from_str(&json).unwrap();
assert_eq!(prefs.language, deserialized.language);
assert_eq!(
prefs.notifications.email_enabled,
deserialized.notifications.email_enabled
);
assert_eq!(prefs.api.default_model, deserialized.api.default_model);
}
}