#![cfg(feature = "mutation")]
use hyprlang::{Config, ConfigValue};
fn register_device_category(config: &mut Config) {
use hyprlang::SpecialCategoryDescriptor;
config.register_special_category(SpecialCategoryDescriptor::keyed("device", "name"));
config.register_special_category_value("device", "sensitivity", ConfigValue::Float(0.0));
config.register_special_category_value("device", "repeat_rate", ConfigValue::Int(0));
config.register_special_category_value("device", "tap_to_click", ConfigValue::Int(0));
}
#[test]
fn test_serialize_synthetic() {
let mut config = Config::new();
config
.parse(
r#"
$GAPS = 10
$SCALE = 2
border_size = 3
active_opacity = 0.9
decoration {
rounding = 10
}
"#,
)
.unwrap();
let serialized = config.serialize();
assert!(serialized.contains("$GAPS = 10"));
assert!(serialized.contains("$SCALE = 2"));
assert!(serialized.contains("border_size = 3"));
assert!(serialized.contains("active_opacity = 0.9"));
assert!(serialized.contains("decoration"));
}
#[test]
fn test_save_as() {
let mut config = Config::new();
config
.parse(
r#"
test_key = 123
another_key = hello
"#,
)
.unwrap();
let temp_file = "/tmp/hyprlang_test_save.conf";
config.save_as(temp_file).unwrap();
let contents = std::fs::read_to_string(temp_file).unwrap();
assert!(contents.contains("test_key = 123"));
assert!(contents.contains("another_key = hello"));
std::fs::remove_file(temp_file).ok();
}
#[test]
fn test_serialize_with_handlers() {
let mut config = Config::new();
config.register_handler_fn("bind", |_ctx| Ok(()));
config
.parse(
r#"
bind = SUPER, A, exec, terminal
bind = SUPER, B, exec, browser
"#,
)
.unwrap();
let serialized = config.serialize();
assert!(serialized.contains("bind = SUPER, A, exec, terminal"));
assert!(serialized.contains("bind = SUPER, B, exec, browser"));
}
#[test]
fn test_full_fidelity_serialization() {
let mut config = Config::new();
config
.parse(
r#"
# Configuration file
$GAPS = 10
$SCALE = 2
# Window settings
border_size = 3
active_opacity = 0.9
"#,
)
.unwrap();
let initial = config.serialize();
println!("Initial serialization:\n{}", initial);
config.set_variable("GAPS".to_string(), "15".to_string());
config.set_int("border_size", 5);
let mutated = config.serialize();
println!("\nAfter mutation:\n{}", mutated);
assert!(mutated.contains("$GAPS = 15"));
assert!(mutated.contains("border_size = 5"));
assert!(mutated.contains("$SCALE = 2")); assert!(mutated.contains("active_opacity = 0.9")); }
#[test]
fn test_document_preserves_structure() {
let mut config = Config::new();
config
.parse(
r#"
$PRIMARY = red
$SECONDARY = green
general {
border_size = 2
gaps = 10
}
"#,
)
.unwrap();
config.set_int("general:border_size", 5);
let serialized = config.serialize();
println!("Serialized with structure:\n{}", serialized);
assert!(serialized.contains("$PRIMARY = red"));
assert!(serialized.contains("general"));
assert!(serialized.contains("border_size = 5"));
}
#[test]
fn test_round_trip_with_mutation() {
let mut config1 = Config::new();
config1
.parse(
r#"
$VAR = original
key = value1
"#,
)
.unwrap();
config1.set_variable("VAR".to_string(), "modified".to_string());
config1.set_string("key", "value2");
let serialized = config1.serialize();
let mut config2 = Config::new();
config2.parse(&serialized).unwrap();
assert_eq!(config2.get_variable("VAR"), Some("modified"));
assert_eq!(config2.get_string("key").unwrap(), "value2");
}
#[test]
fn test_round_trip_with_all_types() {
let mut config1 = Config::new();
config1.register_handler_fn("bind", |_ctx| Ok(()));
register_device_category(&mut config1);
config1
.parse(
r#"
$VAR = test
int_val = 42
float_val = 3.14
string_val = hello world
bind = SUPER, A, exec, terminal
device[mouse] {
sensitivity = 1.5
}
"#,
)
.unwrap();
let serialized = config1.serialize();
let mut config2 = Config::new();
config2.register_handler_fn("bind", |_ctx| Ok(()));
register_device_category(&mut config2);
config2.parse(&serialized).unwrap();
assert_eq!(config2.get_variable("VAR"), Some("test"));
assert_eq!(config2.get_int("int_val").unwrap(), 42);
assert!((config2.get_float("float_val").unwrap() - 3.14).abs() < 0.001);
assert_eq!(config2.get_string("string_val").unwrap(), "hello world");
let binds = config2.get_handler_calls("bind").unwrap();
assert_eq!(binds.len(), 1);
assert!(binds[0].contains("SUPER, A"));
let mouse = config2.get_special_category("device", "mouse").unwrap();
assert!((mouse.get("sensitivity").unwrap().as_float().unwrap() - 1.5).abs() < 0.001);
}
#[test]
fn test_round_trip_after_handler_removal() {
let mut config = Config::new();
config.register_handler_fn("bind", |_ctx| Ok(()));
config
.parse(
r#"
bind = SUPER, A, exec, term
bind = SUPER, B, exec, browser
bind = SUPER, C, exec, editor
"#,
)
.unwrap();
let removed = config.remove_handler_call("bind", 1).unwrap();
assert!(removed.contains("SUPER, B"));
let serialized = config.serialize();
let mut config2 = Config::new();
config2.register_handler_fn("bind", |_ctx| Ok(()));
config2.parse(&serialized).unwrap();
let binds = config2.get_handler_calls("bind").unwrap();
assert_eq!(binds.len(), 2);
assert!(binds.iter().any(|b| b.contains("SUPER, A")));
assert!(binds.iter().any(|b| b.contains("SUPER, C")));
assert!(!binds.iter().any(|b| b.contains("SUPER, B")));
}
#[test]
fn test_round_trip_after_special_category_removal() {
let mut config = Config::new();
register_device_category(&mut config);
config
.parse(
r#"
device[mouse] {
sensitivity = 1.0
}
device[keyboard] {
repeat_rate = 50
}
device[touchpad] {
tap_to_click = true
}
"#,
)
.unwrap();
config
.remove_special_category_instance("device", "keyboard")
.unwrap();
let serialized = config.serialize();
let mut config2 = Config::new();
register_device_category(&mut config2);
config2.parse(&serialized).unwrap();
assert!(config2.get_special_category("device", "mouse").is_ok());
assert!(config2.get_special_category("device", "touchpad").is_ok());
assert!(config2.get_special_category("device", "keyboard").is_err());
}
#[test]
fn test_round_trip_nested_categories() {
let mut config1 = Config::new();
config1
.parse(
r#"
general {
border_size = 2
gaps_in = 5
gaps_out = 10
}
decoration {
rounding = 8
blur {
enabled = true
size = 3
}
}
"#,
)
.unwrap();
config1.set_int("decoration:blur:size", 5);
let serialized = config1.serialize();
let mut config2 = Config::new();
config2.parse(&serialized).unwrap();
assert_eq!(config2.get_int("general:border_size").unwrap(), 2);
assert_eq!(config2.get_int("decoration:rounding").unwrap(), 8);
assert_eq!(config2.get_int("decoration:blur:size").unwrap(), 5);
}