use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
use crate::state::app_dir;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Preferences {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_region: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_port: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_instance_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_system_proxy: Option<bool>,
}
impl Preferences {
pub fn config_file_path() -> Result<PathBuf> {
Ok(app_dir()?.join("config.json"))
}
pub fn load() -> Result<Self> {
let path = Self::config_file_path()?;
if !path.exists() {
return Ok(Self::default());
}
let content = fs::read_to_string(&path)?;
let prefs: Self = serde_json::from_str(&content)?;
Ok(prefs)
}
pub fn save(&self) -> Result<()> {
let path = Self::config_file_path()?;
let content = serde_json::to_string_pretty(self)?;
fs::write(&path, content)?;
Ok(())
}
pub fn is_empty(&self) -> bool {
self.default_region.is_none()
&& self.default_port.is_none()
&& self.default_instance_type.is_none()
&& self.no_system_proxy.is_none()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_preferences() {
let prefs = Preferences::default();
assert!(prefs.default_region.is_none());
assert!(prefs.default_port.is_none());
assert!(prefs.default_instance_type.is_none());
assert!(prefs.no_system_proxy.is_none());
assert!(prefs.is_empty());
}
#[test]
fn test_serialize_deserialize() {
let prefs = Preferences {
default_region: Some("ap-northeast-1".to_string()),
default_port: Some(8080),
default_instance_type: Some("t4g.micro".to_string()),
no_system_proxy: Some(true),
};
let json = serde_json::to_string(&prefs).unwrap();
let deserialized: Preferences = serde_json::from_str(&json).unwrap();
assert_eq!(prefs.default_region, deserialized.default_region);
assert_eq!(prefs.default_port, deserialized.default_port);
assert_eq!(
prefs.default_instance_type,
deserialized.default_instance_type
);
assert_eq!(prefs.no_system_proxy, deserialized.no_system_proxy);
}
#[test]
fn test_serialize_empty_preferences() {
let prefs = Preferences::default();
let json = serde_json::to_string(&prefs).unwrap();
assert_eq!(json, "{}");
}
#[test]
fn test_serialize_partial_preferences() {
let prefs = Preferences {
default_region: Some("us-west-2".to_string()),
default_port: None,
default_instance_type: None,
no_system_proxy: None,
};
let json = serde_json::to_string_pretty(&prefs).unwrap();
assert!(json.contains("default_region"));
assert!(json.contains("us-west-2"));
assert!(!json.contains("default_port"));
}
#[test]
fn test_is_empty() {
let mut prefs = Preferences::default();
assert!(prefs.is_empty());
prefs.default_region = Some("ap-northeast-1".to_string());
assert!(!prefs.is_empty());
}
#[test]
fn test_field_assignment() {
let mut prefs = Preferences::default();
prefs.default_region = Some("eu-west-1".to_string());
assert_eq!(prefs.default_region, Some("eu-west-1".to_string()));
prefs.default_port = Some(9999);
assert_eq!(prefs.default_port, Some(9999));
prefs.default_instance_type = Some("t3.micro".to_string());
assert_eq!(prefs.default_instance_type, Some("t3.micro".to_string()));
prefs.no_system_proxy = Some(true);
assert_eq!(prefs.no_system_proxy, Some(true));
}
#[test]
fn test_config_file_path() {
let path = Preferences::config_file_path().unwrap();
assert!(path.to_string_lossy().contains(".region-proxy"));
assert!(path.to_string_lossy().ends_with("config.json"));
}
}