use serde::Deserialize;
use crate::error::NikaError;
#[derive(Debug, Clone, Deserialize)]
pub struct IncludeSpec {
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub pkg: Option<String>,
#[serde(default)]
pub prefix: Option<String>,
}
impl IncludeSpec {
pub fn validate(&self) -> Result<(), NikaError> {
match (&self.path, &self.pkg) {
(None, None) => Err(NikaError::ValidationError {
reason: "Include spec must have either 'path' or 'pkg'".into(),
}),
(Some(_), Some(_)) => Err(NikaError::ValidationError {
reason: "Include spec cannot have both 'path' and 'pkg'".into(),
}),
_ => Ok(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::serde_yaml;
#[test]
fn test_include_spec_parse_minimal() {
let yaml = r#"
path: ./lib/tasks.nika.yaml
"#;
let spec: IncludeSpec = serde_yaml::from_str(yaml).unwrap();
assert_eq!(spec.path, Some("./lib/tasks.nika.yaml".to_string()));
assert!(spec.pkg.is_none());
assert!(spec.prefix.is_none());
assert!(spec.validate().is_ok());
}
#[test]
fn test_include_spec_parse_with_prefix() {
let yaml = r#"
path: ./lib/seo-tasks.nika.yaml
prefix: seo_
"#;
let spec: IncludeSpec = serde_yaml::from_str(yaml).unwrap();
assert_eq!(spec.path, Some("./lib/seo-tasks.nika.yaml".to_string()));
assert_eq!(spec.prefix, Some("seo_".to_string()));
assert!(spec.validate().is_ok());
}
#[test]
fn test_include_spec_parse_array() {
let yaml = r#"
- path: ./lib/seo.nika.yaml
prefix: seo_
- path: ./lib/common.nika.yaml
"#;
let specs: Vec<IncludeSpec> = serde_yaml::from_str(yaml).unwrap();
assert_eq!(specs.len(), 2);
assert_eq!(specs[0].prefix, Some("seo_".to_string()));
assert!(specs[1].prefix.is_none());
}
#[test]
fn test_include_spec_empty_prefix() {
let yaml = r#"
path: ./lib/tasks.nika.yaml
prefix: ""
"#;
let spec: IncludeSpec = serde_yaml::from_str(yaml).unwrap();
assert_eq!(spec.prefix, Some(String::new()));
}
#[test]
fn test_include_spec_parse_pkg() {
let yaml = r#"
pkg: "@workflows/seo-audit"
prefix: seo_
"#;
let spec: IncludeSpec = serde_yaml::from_str(yaml).unwrap();
assert_eq!(spec.pkg, Some("@workflows/seo-audit".to_string()));
assert!(spec.path.is_none());
assert_eq!(spec.prefix, Some("seo_".to_string()));
assert!(spec.validate().is_ok());
}
#[test]
fn test_include_spec_validate_missing_both() {
let spec = IncludeSpec {
path: None,
pkg: None,
prefix: None,
};
assert!(spec.validate().is_err());
}
#[test]
fn test_include_spec_validate_both_present() {
let spec = IncludeSpec {
path: Some("./lib/tasks.yaml".to_string()),
pkg: Some("@workflows/seo".to_string()),
prefix: None,
};
assert!(spec.validate().is_err());
}
}