use super::TEMPLATE_PROVIDERS;
use crate::model_pick::grammar::{
GrammarError, PROVIDERS_YAML, ROLES, entry_field, entry_names, set_field,
};
const OTHER: &str = "models";
const OTHER_FILE: &str = "other.yaml";
const OTHER_TEXT: &str = "# header\n\nmodels:\n gpt-5.4:\n model_id: gpt-5.4\n";
#[test]
fn entry_names_lists_the_block_in_file_order_and_absence_is_empty() {
assert_eq!(
entry_names(TEMPLATE_PROVIDERS, ROLES),
["worker", "compactor"]
);
assert_eq!(entry_names(OTHER_TEXT, OTHER), ["gpt-5.4"]);
assert!(entry_names(TEMPLATE_PROVIDERS, OTHER).is_empty());
assert!(entry_names("roles: {}\n", ROLES).is_empty());
assert!(entry_names("", ROLES).is_empty());
}
#[test]
fn entry_field_reads_one_value_and_folds_every_miss_to_none() {
assert_eq!(
entry_field(TEMPLATE_PROVIDERS, ROLES, "worker", "model").as_deref(),
Some("gpt-5.4")
);
assert_eq!(
entry_field(TEMPLATE_PROVIDERS, OTHER, "worker", "model"),
None
);
assert_eq!(
entry_field(TEMPLATE_PROVIDERS, ROLES, "nobody", "model"),
None
);
assert_eq!(
entry_field(TEMPLATE_PROVIDERS, ROLES, "compactor", "tools"),
None
);
}
#[test]
fn set_field_replaces_one_line_and_preserves_every_other_byte() {
let out = set_field(
PROVIDERS_YAML,
TEMPLATE_PROVIDERS,
ROLES,
"compactor",
"model",
"haiku-9",
)
.unwrap();
assert!(out.contains(" model: haiku-9\n"));
assert!(out.contains(" tools: [bash, read_file, load_skill]\n"));
assert!(out.contains(" worker:\n provider: codex\n model: gpt-5.4\n"));
}
fn refusal(text: &str, entry: &str, field: &'static str) -> GrammarError {
set_field(PROVIDERS_YAML, text, ROLES, entry, field, "x").unwrap_err()
}
#[test]
fn set_field_declines_loudly_on_every_shape_it_does_not_edit() {
assert!(
matches!(refusal("roles: {}\n", "worker", "model"), GrammarError::Inline { key, .. } if key == ROLES)
);
assert!(
matches!(refusal("models:\n m:\n", "worker", "model"), GrammarError::NoEntry { entry, .. } if entry == "worker")
);
assert!(
matches!(refusal(TEMPLATE_PROVIDERS, "nobody", "model"), GrammarError::NoEntry { entry, .. } if entry == "nobody")
);
assert!(
matches!(refusal(TEMPLATE_PROVIDERS, "compactor", "tools"), GrammarError::NoField { field, .. } if field == "tools")
);
}
#[test]
fn the_file_name_a_refusal_carries_is_the_callers() {
let err = set_field(OTHER_FILE, "", OTHER, "m", "provider", "codex").unwrap_err();
assert!(err.to_string().starts_with(OTHER_FILE));
}