use serde::Deserialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ClipboardBackend {
#[default]
Auto,
System,
Osc52,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ClipboardConfig {
#[serde(default)]
pub backend: ClipboardBackend,
}
impl Default for ClipboardConfig {
fn default() -> Self {
ClipboardConfig {
backend: ClipboardBackend::Auto,
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct TooltipConfig {
#[serde(default = "default_auto_show")]
pub auto_show: bool,
}
fn default_auto_show() -> bool {
true
}
impl Default for TooltipConfig {
fn default() -> Self {
TooltipConfig { auto_show: true }
}
}
#[derive(Debug, Clone, Deserialize, Default)]
pub struct Config {
#[serde(default)]
pub clipboard: ClipboardConfig,
#[serde(default)]
pub tooltip: TooltipConfig,
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_valid_backend_parsing(backend in prop::sample::select(vec!["auto", "system", "osc52"])) {
let toml_content = format!(r#"
[clipboard]
backend = "{}"
"#, backend);
let config: Result<Config, _> = toml::from_str(&toml_content);
prop_assert!(config.is_ok(), "Failed to parse valid backend: {}", backend);
let config = config.unwrap();
let expected = match backend {
"auto" => ClipboardBackend::Auto,
"system" => ClipboardBackend::System,
"osc52" => ClipboardBackend::Osc52,
_ => unreachable!(),
};
prop_assert_eq!(config.clipboard.backend, expected);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_missing_fields_use_defaults(
include_clipboard_section in prop::bool::ANY,
include_backend_field in prop::bool::ANY
) {
let toml_content = if !include_clipboard_section {
String::new()
} else if !include_backend_field {
"[clipboard]\n".to_string()
} else {
r#"
[clipboard]
backend = "system"
"#.to_string()
};
let config: Result<Config, _> = toml::from_str(&toml_content);
prop_assert!(config.is_ok(), "Failed to parse config with missing fields");
let config = config.unwrap();
if !include_clipboard_section || !include_backend_field {
prop_assert_eq!(
config.clipboard.backend,
ClipboardBackend::Auto,
"Missing fields should default to Auto"
);
}
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_valid_tooltip_auto_show_parsing(auto_show: bool) {
let toml_content = format!(r#"
[tooltip]
auto_show = {}
"#, auto_show);
let config: Result<Config, _> = toml::from_str(&toml_content);
prop_assert!(config.is_ok(), "Failed to parse valid auto_show: {}", auto_show);
let config = config.unwrap();
prop_assert_eq!(config.tooltip.auto_show, auto_show);
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn prop_missing_tooltip_section_defaults(
include_tooltip_section in prop::bool::ANY,
include_auto_show_field in prop::bool::ANY
) {
let toml_content = if !include_tooltip_section {
String::new()
} else if !include_auto_show_field {
"[tooltip]\n".to_string()
} else {
r#"
[tooltip]
auto_show = false
"#.to_string()
};
let config: Result<Config, _> = toml::from_str(&toml_content);
prop_assert!(config.is_ok(), "Failed to parse config with missing tooltip fields");
let config = config.unwrap();
if !include_tooltip_section || !include_auto_show_field {
prop_assert!(
config.tooltip.auto_show,
"Missing tooltip.auto_show should default to true"
);
}
}
}
#[test]
fn test_tooltip_config_default() {
let config = TooltipConfig::default();
assert!(config.auto_show);
}
#[test]
fn test_parse_tooltip_auto_show_true() {
let toml = r#"
[tooltip]
auto_show = true
"#;
let config: Config = toml::from_str(toml).unwrap();
assert!(config.tooltip.auto_show);
}
#[test]
fn test_parse_tooltip_auto_show_false() {
let toml = r#"
[tooltip]
auto_show = false
"#;
let config: Config = toml::from_str(toml).unwrap();
assert!(!config.tooltip.auto_show);
}
#[test]
fn test_missing_tooltip_section_uses_default() {
let toml = r#"
[clipboard]
backend = "auto"
"#;
let config: Config = toml::from_str(toml).unwrap();
assert!(config.tooltip.auto_show);
}
#[test]
fn test_empty_tooltip_section_uses_default() {
let toml = r#"
[tooltip]
"#;
let config: Config = toml::from_str(toml).unwrap();
assert!(config.tooltip.auto_show);
}
}