use super::*;
#[test]
fn a_delete_that_would_be_refused_is_never_asked_about() {
let mut s = panel();
s.begin_remove();
assert!(
matches!(s.mode, Mode::Choose),
"no question for a refused delete, got {:?}",
s.mode
);
let status = s.status.as_deref().unwrap_or_default();
assert!(
status.contains("active backend") || status.contains("default_backend"),
"the refusal is shown instead: {status}"
);
}
#[test]
fn the_typed_command_enforces_the_same_refusals_the_confirm_checks() {
let mut s = panel();
let active = s.selected().selection.clone();
let BackendSelection::Named(name) = active else {
panic!("the fixture's first row is a named backend");
};
assert!(
s.remove_refusal(&name).is_some(),
"the active backend is refused"
);
let mut removed: Vec<String> = Vec::new();
let mut remove = |n: &str| -> Result<String, String> {
removed.push(n.to_string());
Ok(String::new())
};
s.begin_command(&format!("d {name}"));
s.run_command(&mut remove);
let removed = removed;
assert!(removed.is_empty(), "the typed path refuses it too");
}
#[test]
fn a_kind_fallback_cannot_be_removed() {
let mut state = panel();
let mut remove = ok_remove();
state.begin_command("");
for c in "d ollama".chars() {
state.command_char(c);
}
assert_eq!(state.run_command(&mut remove), None, "stays open");
assert!(
state.options.iter().any(|o| o.name == "ollama"),
"the fallback survives the delete"
);
assert!(
state.status.as_deref().is_some_and(|s| !s.is_empty()),
"and the refusal is explained"
);
}
#[test]
fn remove_refuses_the_active_backend_without_a_new_selection() {
let mut s = panel();
let called = std::cell::Cell::new(false);
let mut remove = |_: &str| {
called.set(true);
Ok(String::new())
};
s.begin_command("d dgx1");
assert_eq!(s.run_command(&mut remove), None, "refused, stays open");
assert!(!called.get(), "the file is never touched");
assert!(s.status.as_deref().unwrap().contains("active backend"));
s.cycle(1);
s.cycle(1);
s.cycle(1); s.begin_command("d dgx1");
assert_eq!(s.run_command(&mut remove), None);
assert!(!called.get());
assert!(s.pending_remove.is_none());
}
#[test]
fn remove_refuses_the_config_default_even_when_it_is_not_active() {
let mut s = PanelState::new(PanelSeed {
options: vec![
named("dgx1", BackendSource::UserDropIn),
named("gpu-runner", BackendSource::UserDropIn),
BackendOption::kind_fallback("ollama"),
],
active: Some(1),
default_backend: Some("dgx1".to_string()),
});
let called = std::cell::Cell::new(false);
let mut remove = |_: &str| {
called.set(true);
Ok(String::new())
};
s.begin_command("d dgx1");
assert_eq!(s.run_command(&mut remove), None, "refused, stays open");
assert!(!called.get(), "the file is never touched");
assert!(
s.status.as_deref().unwrap().contains("default_backend"),
"{:?}",
s.status
);
assert!(s.named_index("dgx1").is_some());
s.cycle(-1); s.cycle(1); s.begin_command("d dgx1");
assert_eq!(s.run_command(&mut remove), Some(true));
assert!(!called.get(), "the delete is deferred to the caller");
let close = close_outcome(true, &s);
assert_eq!(
close.apply,
Some(BackendSelection::Named("gpu-runner".to_string()))
);
assert_eq!(close.remove_after_apply.as_deref(), Some("dgx1"));
}
#[test]
fn a_project_shadowed_backend_is_neither_editable_nor_removable() {
let mut s = PanelState::new(PanelSeed {
options: vec![
named("dgx1", BackendSource::ShadowedByProject),
named("gpu-runner", BackendSource::UserDropIn),
],
active: Some(1),
default_backend: None,
});
s.cycle(-1); assert_eq!(
s.chooser_rows()[0].provenance,
"shadowed by project config",
"the row admits the shadow"
);
s.begin_edit();
assert_eq!(s.mode, Mode::Choose, "no form for a shadowed entry");
assert!(s.status.as_deref().unwrap().contains("shadowed"));
let called = std::cell::Cell::new(false);
let mut remove = |_: &str| {
called.set(true);
Ok(String::new())
};
s.begin_command("d dgx1");
assert_eq!(s.run_command(&mut remove), None);
assert!(!called.get(), "no phantom delete");
assert!(s.status.as_deref().unwrap().contains("shadowed"));
assert!(s.named_index("dgx1").is_some(), "nothing dropped");
}