use pokeys_lib::models::{DeviceModel, PinModel, get_default_model_dir, load_model};
use std::collections::HashMap;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_device_model_creation() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
assert_eq!(model.name, "TestDevice");
assert_eq!(model.pins.len(), 2);
assert!(model.pins.contains_key(&1));
assert!(model.pins.contains_key(&2));
let pin1 = model.pins.get(&1).unwrap();
assert_eq!(pin1.capabilities.len(), 2);
assert!(pin1.capabilities.contains(&"DigitalInput".to_string()));
assert!(pin1.capabilities.contains(&"DigitalOutput".to_string()));
let pin2 = model.pins.get(&2).unwrap();
assert_eq!(pin2.capabilities.len(), 2);
assert!(pin2.capabilities.contains(&"DigitalInput".to_string()));
assert!(pin2.capabilities.contains(&"AnalogInput".to_string()));
}
#[test]
fn test_device_model_validation() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
assert!(model.validate().is_ok());
let mut invalid_model = model.clone();
invalid_model.name = "".to_string();
assert!(invalid_model.validate().is_err());
let invalid_model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
assert!(invalid_model.validate().is_err());
let mut invalid_model = model.clone();
invalid_model.pins.insert(
3,
PinModel {
capabilities: vec![],
active: true,
},
);
assert!(invalid_model.validate().is_err());
}
#[test]
fn test_yaml_serialization() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
let yaml = serde_yaml::to_string(&model).unwrap();
let deserialized: DeviceModel = serde_yaml::from_str(&yaml).unwrap();
assert_eq!(model.name, deserialized.name);
assert_eq!(model.pins.len(), deserialized.pins.len());
for (pin_num, pin) in &model.pins {
let deserialized_pin = deserialized.pins.get(pin_num).unwrap();
assert_eq!(pin.capabilities, deserialized_pin.capabilities);
assert_eq!(pin.active, deserialized_pin.active);
}
}
#[test]
fn test_model_file_loading() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("TestDevice.yaml");
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
let yaml = serde_yaml::to_string(&model).unwrap();
fs::write(&file_path, yaml).unwrap();
let loaded_model = DeviceModel::from_file(&file_path).unwrap();
assert_eq!(model.name, loaded_model.name);
assert_eq!(model.pins.len(), loaded_model.pins.len());
for (pin_num, pin) in &model.pins {
let loaded_pin = loaded_model.pins.get(pin_num).unwrap();
assert_eq!(pin.capabilities, loaded_pin.capabilities);
assert_eq!(pin.active, loaded_pin.active);
}
}
#[test]
fn test_related_capabilities() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "Encoder_1A".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "Encoder_1B".to_string()],
active: true,
},
);
assert!(model.validate().is_ok());
let related = model.get_related_capabilities(1, "Encoder_1A");
assert_eq!(related.len(), 1);
assert_eq!(related[0].0, "Encoder_1B");
assert_eq!(related[0].1, 2);
let mut invalid_model = model.clone();
invalid_model.pins.get_mut(&2).unwrap().capabilities = vec!["DigitalInput".to_string()];
assert!(invalid_model.validate().is_err());
let related = invalid_model.get_related_capabilities(1, "Encoder_1A");
assert_eq!(related.len(), 0);
}
#[test]
fn test_pin_capability_validation() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
assert!(model.is_pin_capability_supported(1, "DigitalInput"));
assert!(model.is_pin_capability_supported(1, "DigitalOutput"));
assert!(!model.is_pin_capability_supported(1, "AnalogInput"));
assert!(model.is_pin_capability_supported(2, "DigitalInput"));
assert!(model.is_pin_capability_supported(2, "AnalogInput"));
assert!(!model.is_pin_capability_supported(2, "DigitalOutput"));
assert!(!model.is_pin_capability_supported(3, "DigitalInput"));
assert!(model.validate_pin_capability(1, "DigitalInput").is_ok());
assert!(model.validate_pin_capability(1, "DigitalOutput").is_ok());
assert!(model.validate_pin_capability(2, "DigitalInput").is_ok());
assert!(model.validate_pin_capability(2, "AnalogInput").is_ok());
assert!(model.validate_pin_capability(1, "AnalogInput").is_err());
assert!(model.validate_pin_capability(2, "DigitalOutput").is_err());
assert!(model.validate_pin_capability(3, "DigitalInput").is_err());
}
#[test]
fn test_get_pin_capabilities() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "AnalogInput".to_string()],
active: true,
},
);
let pin1_caps = model.get_pin_capabilities(1);
assert_eq!(pin1_caps.len(), 2);
assert!(pin1_caps.contains(&"DigitalInput".to_string()));
assert!(pin1_caps.contains(&"DigitalOutput".to_string()));
let pin2_caps = model.get_pin_capabilities(2);
assert_eq!(pin2_caps.len(), 2);
assert!(pin2_caps.contains(&"DigitalInput".to_string()));
assert!(pin2_caps.contains(&"AnalogInput".to_string()));
let pin3_caps = model.get_pin_capabilities(3);
assert_eq!(pin3_caps.len(), 0);
}
#[test]
fn test_default_model_dir() {
let dir = get_default_model_dir();
assert!(dir.to_string_lossy().contains(".config/pokeys/models"));
}
#[test]
fn test_load_model_with_custom_dir() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("TestDevice.yaml");
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "DigitalOutput".to_string()],
active: true,
},
);
let yaml = serde_yaml::to_string(&model).unwrap();
fs::write(&file_path, yaml).unwrap();
let loaded_model = load_model("TestDevice", Some(dir.path())).unwrap();
assert_eq!(model.name, loaded_model.name);
assert_eq!(model.pins.len(), loaded_model.pins.len());
}
#[test]
fn test_enhanced_validation() {
let mut model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "Encoder_1A".to_string()],
active: true,
},
);
model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "Encoder_1B".to_string()],
active: true,
},
);
assert!(model.validate().is_ok());
assert!(model.validate_pin_capability(1, "Encoder_1A").is_ok());
assert!(model.validate_pin_capability(2, "Encoder_1B").is_ok());
let mut invalid_model = model.clone();
invalid_model.pins.get_mut(&2).unwrap().capabilities = vec!["DigitalInput".to_string()];
assert!(invalid_model.validate().is_err());
let mut test_model = DeviceModel {
name: "TestDevice".to_string(),
pins: HashMap::new(),
};
test_model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "Encoder_1A".to_string()],
active: true,
},
);
assert!(test_model.validate_pin_capability(1, "Encoder_1A").is_err());
let mut inactive_model = model.clone();
inactive_model.pins.get_mut(&2).unwrap().active = false;
assert!(inactive_model.validate().is_ok());
assert!(
inactive_model
.validate_pin_capability(1, "Encoder_1A")
.is_err()
);
let mut matrix_model = DeviceModel {
name: "MatrixKeyboard".to_string(),
pins: HashMap::new(),
};
matrix_model.pins.insert(
1,
PinModel {
capabilities: vec![
"DigitalInput".to_string(),
"MatrixKeyboard_Row1".to_string(),
],
active: true,
},
);
matrix_model.pins.insert(
2,
PinModel {
capabilities: vec![
"DigitalInput".to_string(),
"MatrixKeyboard_Col1".to_string(),
],
active: true,
},
);
assert!(matrix_model.validate().is_ok());
assert!(
matrix_model
.validate_pin_capability(1, "MatrixKeyboard_Row1")
.is_ok()
);
assert!(
matrix_model
.validate_pin_capability(2, "MatrixKeyboard_Col1")
.is_ok()
);
let mut invalid_matrix = matrix_model.clone();
invalid_matrix.pins.remove(&2);
assert!(invalid_matrix.validate().is_err());
assert!(
invalid_matrix
.validate_pin_capability(1, "MatrixKeyboard_Row1")
.is_err()
);
let mut pwm_model = DeviceModel {
name: "PWMDevice".to_string(),
pins: HashMap::new(),
};
pwm_model.pins.insert(
1,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "PWM_1".to_string()],
active: true,
},
);
pwm_model.pins.insert(
2,
PinModel {
capabilities: vec!["DigitalInput".to_string(), "PWM_2".to_string()],
active: true,
},
);
assert!(pwm_model.validate().is_ok());
let mut invalid_pwm = pwm_model.clone();
invalid_pwm.pins.get_mut(&2).unwrap().capabilities =
vec!["DigitalInput".to_string(), "PWM_3".to_string()];
assert!(invalid_pwm.validate().is_err());
}