use super::claims::{self, Chord, Platform};
use par_term_settings_ui::input_tab::actions_table::AVAILABLE_ACTIONS;
#[cfg(target_os = "macos")]
const KNOWN_MISMATCHES: &[(&str, &str)] = &[
("close_tab", "native_menu/close_window"),
];
#[cfg(target_os = "windows")]
const KNOWN_MISMATCHES: &[(&str, &str)] = &[("close_tab", "native_menu/close_window")];
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
const KNOWN_MISMATCHES: &[(&str, &str)] = &[];
#[cfg(target_os = "macos")]
const CLAIMED_BUT_ADVERTISED_AS_NONE: &[&str] = &[
"close_window (native_menu)",
"maximize_vertically (native_menu)",
"new_window (native_menu)",
"quit (macos_app_menu)",
"select_all (native_menu)",
];
#[cfg(target_os = "windows")]
const CLAIMED_BUT_ADVERTISED_AS_NONE: &[&str] = &[
"close_window (native_menu)",
"maximize_vertically (native_menu)",
"new_window (native_menu)",
"quit (native_menu)",
"select_all (native_menu)",
];
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
const CLAIMED_BUT_ADVERTISED_AS_NONE: &[&str] = &[];
fn advertised() -> Vec<(&'static str, Chord)> {
AVAILABLE_ACTIONS
.iter()
.filter_map(|(action, _, default)| default.map(|d| (*action, d)))
.map(|(action, d)| {
let chord = claims::parse_chord(d)
.unwrap_or_else(|e| panic!("AVAILABLE_ACTIONS row {action:?}: {e}"));
(action, chord)
})
.collect()
}
#[test]
fn every_advertised_chord_parses() {
let bad: Vec<String> = AVAILABLE_ACTIONS
.iter()
.filter_map(|(action, _, default)| {
let d = (*default)?;
claims::parse_chord(d)
.err()
.map(|e| format!("{action}: {e}"))
})
.collect();
assert!(
bad.is_empty(),
"advertised default chords that do not parse: {bad:#?}"
);
}
#[test]
fn advertised_chord_is_dispatched_by_its_own_action() {
let mut violations: Vec<(String, String)> = Vec::new();
for (action, chord) in advertised() {
match claims::first_claimer(chord) {
None => violations.push((action.to_string(), NOTHING_CLAIMS_IT.to_string())),
Some((source, claimed)) if claimed != action => {
violations.push((action.to_string(), format!("{source}/{claimed}")));
}
Some(_) => {}
}
}
violations.sort();
let mut expected: Vec<(String, String)> = KNOWN_MISMATCHES
.iter()
.map(|(a, s)| (a.to_string(), s.to_string()))
.collect();
expected.sort();
assert_eq!(
violations, expected,
"advertised chords whose first claimer is not the advertising action \
changed. {NOTHING_CLAIMS_IT:?} means the shortcut does nothing at all; \
a `source/action` value means a higher-precedence layer eats the chord \
first. A new entry is a defect; a disappeared entry means a known one \
was fixed and KNOWN_MISMATCHES should shrink."
);
}
const NOTHING_CLAIMS_IT: &str = "<nothing>";
#[test]
fn advertised_chord_agrees_with_the_shipped_default() {
let defaults = par_term_config::Config::default().keybindings;
assert!(
!defaults.is_empty(),
"Config::default() shipped no keybindings — this test would be vacuous"
);
let mut checked = 0usize;
let mut wrong: Vec<String> = Vec::new();
for kb in &defaults {
let Some((_, _, Some(shown))) = AVAILABLE_ACTIONS.iter().find(|(a, _, _)| *a == kb.action)
else {
continue;
};
let expected = claims::parse_chord(&kb.key)
.unwrap_or_else(|e| panic!("shipped default {:?}: {e}", kb.key));
let actual = claims::parse_chord(shown)
.unwrap_or_else(|e| panic!("AVAILABLE_ACTIONS row {:?}: {e}", kb.action));
checked += 1;
if expected != actual {
wrong.push(format!(
"{}: table says {shown:?}, default is {:?}",
kb.action, kb.key
));
}
}
assert!(checked > 0, "no advertised action has a shipped default");
assert!(
wrong.is_empty(),
"advertised chords that disagree with Config::default().keybindings: {wrong:#?}"
);
}
#[test]
fn every_key_layer_declares_its_claims() {
assert_eq!(
claims::UNIFORM_LAYER_COUNT,
super::KEY_LAYERS.len(),
"UNIFORM_LAYER_COUNT must track KEY_LAYERS::len()"
);
let layers: Vec<&str> = super::KEY_LAYERS.iter().map(|(name, _)| *name).collect();
let declared: Vec<&str> = claims::LAYER_CLAIMS
.iter()
.take(claims::UNIFORM_LAYER_COUNT)
.map(|(name, _)| *name)
.collect();
assert_eq!(
layers, declared,
"LAYER_CLAIMS must mirror KEY_LAYERS one-for-one and in order"
);
let tail: Vec<&str> = claims::LAYER_CLAIMS
.iter()
.skip(claims::UNIFORM_LAYER_COUNT)
.map(|(name, _)| *name)
.collect();
assert_eq!(
tail,
["utility_shortcuts", "tab_shortcuts", "paste_copy"],
"the sources after KEY_LAYERS are the two event-loop layers and the \
inline paste/copy branch, in that order — `handle_key_event` runs them \
in exactly this sequence"
);
}
#[test]
fn claim_action_names_are_advertised_or_explicitly_internal() {
let unknown: Vec<&str> = claims::LAYER_CLAIMS
.iter()
.flat_map(|(_, cs)| cs.iter())
.map(|c| c.action)
.filter(|a| {
!a.starts_with("internal:") && !AVAILABLE_ACTIONS.iter().any(|(name, _, _)| name == a)
})
.collect();
assert!(
unknown.is_empty(),
"layer claims naming an action that is neither advertised nor prefixed \
`internal:`: {unknown:?}"
);
}
#[test]
fn claimed_actions_advertised_as_having_no_default() {
let unadvertised: Vec<&str> = AVAILABLE_ACTIONS
.iter()
.filter(|(_, _, default)| default.is_none())
.map(|(action, _, _)| *action)
.collect();
let mut found: Vec<String> = claims::claim_chain()
.iter()
.filter(|rule| unadvertised.contains(&rule.action.as_str()))
.map(|rule| format!("{} ({})", rule.action, rule.source))
.collect();
found.sort();
found.dedup();
let mut expected: Vec<String> = CLAIMED_BUT_ADVERTISED_AS_NONE
.iter()
.map(|s| (*s).to_string())
.collect();
expected.sort();
assert_eq!(
found, expected,
"the set of actions that are dispatchable but advertised as having no \
default changed. This is under-advertisement, not a dispatch defect — \
update the list deliberately."
);
}
#[test]
fn chord_parser_rejects_what_it_does_not_understand() {
assert!(claims::parse_chord("Cmd+Nonsense").is_err());
assert!(claims::parse_chord("Cmd+").is_err());
assert!(claims::parse_chord("Cmd+A+B").is_err());
assert!(claims::parse_chord("Shift").is_err());
let plus = claims::parse_chord("Cmd+Plus").expect("Plus is part of the vocabulary");
let equal = claims::parse_chord("Cmd+Equal").expect("Equal is part of the vocabulary");
assert_ne!(
plus, equal,
"`Plus` and `Equal` are different logical keys and must not collapse"
);
}
#[test]
fn cmd_or_ctrl_expands_per_platform() {
let c = claims::parse_chord("CmdOrCtrl+Shift+B").expect("parses");
if Platform::HOST.is_mac() {
assert!(c.mods.sup && !c.mods.ctrl, "CmdOrCtrl is Cmd on macOS");
} else {
assert!(c.mods.ctrl && !c.mods.sup, "CmdOrCtrl is Ctrl elsewhere");
}
assert!(c.mods.shift);
}