use gwm::tui::keymap::Action;
use gwm::tui::palette::{palette_entries, PaletteEntry, PaletteState};
#[test]
fn registry_covers_every_action_variant() {
let entries = palette_entries();
let registered: std::collections::HashSet<Action> = entries.iter().map(|e| e.action).collect();
for variant in Action::all() {
assert!(
registered.contains(&variant),
"Action::{:?} has no palette entry — add it to palette_entries()",
variant
);
}
}
#[test]
fn registry_names_are_unique_and_lowercase_words() {
let entries = palette_entries();
let mut seen = std::collections::HashSet::new();
for entry in entries {
assert!(seen.insert(entry.name), "duplicate palette name {:?}", entry.name);
assert!(!entry.name.is_empty(), "empty name for {:?}", entry.action);
assert!(
entry
.name
.chars()
.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '-'),
"palette name {:?} must be lowercase ascii [a-z0-9_-]",
entry.name
);
assert!(
!entry.description.is_empty(),
"missing description for palette entry {:?}",
entry.name
);
}
}
#[test]
fn registry_lookup_by_name_returns_action() {
let entries = palette_entries();
let create = entries
.iter()
.find(|e| e.name == "create")
.expect("expected a `create` entry");
assert_eq!(create.action, Action::Create);
}
#[test]
fn open_docs_entry_is_named_and_reachable() {
let entries = palette_entries();
let docs = entries
.iter()
.find(|e| e.name == "open-docs")
.expect("expected an `open-docs` entry");
assert_eq!(docs.action, Action::OpenDocs);
}
#[test]
fn docs_url_points_at_the_repository_docs() {
assert_eq!(gwm::tui::DOCS_URL, "https://github.com/kbrdn1/gwm-cli/tree/main/docs");
}
#[test]
fn fresh_palette_is_closed_with_empty_buffer() {
let s = PaletteState::new();
assert!(!s.open, "palette starts closed");
assert!(s.buffer().is_empty());
assert_eq!(s.highlight(), 0);
}
#[test]
fn open_arms_palette_and_pre_filters_full_registry() {
let mut s = PaletteState::new();
s.open();
assert!(s.open);
let matches = s.matches();
let total = palette_entries().len();
assert_eq!(matches.len(), total, "an empty buffer must surface the full registry");
}
#[test]
fn typing_filters_and_resets_highlight() {
let mut s = PaletteState::new();
s.open();
s.push_char('c');
s.push_char('r');
s.push_char('e');
let matches: Vec<&PaletteEntry> = s.matches();
assert!(
matches.iter().any(|e| e.name == "create"),
"`cre` must rank `create` somewhere in the visible matches"
);
assert!(
s.highlight() < matches.len(),
"highlight {} must point at a real match (len = {})",
s.highlight(),
matches.len()
);
}
#[test]
fn backspace_pops_one_char_and_re_expands_matches() {
let mut s = PaletteState::new();
s.open();
s.push_char('z'); let narrow = s.matches().len();
s.pop_char();
let wide = s.matches().len();
assert!(
wide >= narrow,
"popping a char must re-broaden the match set ({wide} >= {narrow})"
);
assert!(s.buffer().is_empty());
}
#[test]
fn cycle_highlight_down_wraps_at_end() {
let mut s = PaletteState::new();
s.open();
let n = s.matches().len();
for _ in 0..n {
s.cycle_highlight_down();
}
assert_eq!(s.highlight(), 0);
}
#[test]
fn cycle_highlight_up_wraps_at_start() {
let mut s = PaletteState::new();
s.open();
s.cycle_highlight_up();
let n = s.matches().len();
assert_eq!(s.highlight(), n - 1, "up from 0 must wrap to the last entry");
}
#[test]
fn accept_returns_highlighted_action_and_closes_palette() {
let mut s = PaletteState::new();
s.open();
s.push_char('c');
s.push_char('r');
s.push_char('e');
let action = s.accept().expect("accept must return a highlighted action");
assert!(
palette_entries().iter().any(|e| e.action == action),
"accepted action must be a registry entry"
);
assert!(!s.open, "accept must close the palette");
assert!(s.buffer().is_empty(), "accept must clear the buffer");
}
#[test]
fn accept_with_no_matches_returns_none() {
let mut s = PaletteState::new();
s.open();
for c in "qqqqq_zz_does_not_exist".chars() {
s.push_char(c);
}
assert!(s.matches().is_empty());
assert!(s.accept().is_none());
assert!(s.open);
}
#[test]
fn close_clears_buffer_and_resets_highlight() {
let mut s = PaletteState::new();
s.open();
s.push_char('a');
s.cycle_highlight_down();
s.close();
assert!(!s.open);
assert!(s.buffer().is_empty());
assert_eq!(s.highlight(), 0);
}