use super::*;
use crate::compat::MiniToString;
use crate::event::Event;
#[test]
fn test_shortcut_parsing() {
let shortcut = Shortcut::from_string("Ctrl+A").unwrap();
assert_eq!(shortcut.key, Key::A);
assert!(shortcut.modifiers.contains(Modifiers::PRIMARY));
assert!(!shortcut.modifiers.contains(Modifiers::ALT));
assert_eq!(Shortcut::from_string("Cmd+A").unwrap(), shortcut);
assert_eq!(Shortcut::from_string("Primary+A").unwrap(), shortcut);
let shortcut = Shortcut::from_string("Alt+F4").unwrap();
assert_eq!(shortcut.key, Key::F4);
assert!(shortcut.modifiers.contains(Modifiers::ALT));
let shortcut = Shortcut::from_string("Ctrl+Shift+S").unwrap();
assert_eq!(shortcut.key, Key::S);
assert!(shortcut.modifiers.contains(Modifiers::PRIMARY));
assert!(shortcut.modifiers.contains(Modifiers::SHIFT));
let shortcut = Shortcut::from_string("Meta+X").unwrap();
assert!(shortcut.modifiers.contains(Modifiers::META));
assert!(!shortcut.modifiers.contains(Modifiers::PRIMARY));
}
#[test]
fn test_shortcut_to_string() {
let shortcut = Shortcut::ctrl(Key::A);
assert_eq!(shortcut.to_string(), "Control+A");
let shortcut = Shortcut::new(Key::F1, Modifiers::CTRL | Modifiers::ALT);
assert_eq!(shortcut.to_string(), "Control+Alt+F1");
let shortcut = Shortcut::primary(Key::Z);
assert_eq!(shortcut.to_string(), "Primary+Z");
}
#[test]
fn every_key_canonical_spelling_round_trips() {
use Key::*;
let keys = [
None,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
Escape,
Tab,
Enter,
Space,
Backspace,
Delete,
Insert,
Home,
End,
PageUp,
PageDown,
Left,
Right,
Up,
Down,
Minus,
Equals,
LeftBracket,
RightBracket,
Semicolon,
Quote,
Comma,
Period,
Slash,
Backslash,
];
for key in keys {
let spelling = key.format_key();
assert_eq!(
Key::from_string(spelling),
Some(key),
"canonical spelling {spelling:?} must round-trip",
);
}
}
#[test]
fn page_keys_round_trip_without_glyphs() {
assert_eq!(Key::PageUp.format_key(), "PageUp");
assert_eq!(Key::from_string("PageUp"), Some(Key::PageUp));
assert_eq!(Key::PageDown.format_key(), "PageDown");
assert_eq!(Key::from_string("PageDown"), Some(Key::PageDown));
let shortcut = Shortcut::primary(Key::PageUp);
assert_eq!(shortcut.to_string(), "Primary+PageUp");
assert_eq!(Shortcut::from_string(&shortcut.to_string()), Some(shortcut));
assert_eq!(Key::from_string("⇞"), None, "the page-up glyph is not canonical input");
assert_eq!(Key::from_string("⇟"), None, "the page-down glyph is not canonical input");
}
#[test]
fn shortcut_canonical_form_round_trips_and_rejects_multiple_keys() {
use crate::compat::format;
use std::collections::HashMap;
for shortcut in [
Shortcut::ctrl(Key::Z),
Shortcut::ctrl_shift(Key::Z),
Shortcut::ctrl_alt(Key::F1),
Shortcut::primary(Key::Z),
Shortcut::new(Key::A, Modifiers::CTRL | Modifiers::META),
] {
let formatted = shortcut.to_string();
let parsed = Shortcut::from_string(&formatted)
.unwrap_or_else(|| panic!("{formatted:?} must parse back"));
assert_eq!(parsed, shortcut, "{formatted:?} did not round-trip to an equal value");
assert_eq!(
format!("{parsed:?}"),
format!("{shortcut:?}"),
"Eq implies Hash, so Debug must match too"
);
}
let mut map: HashMap<Shortcut, u32> = HashMap::new();
map.insert(Shortcut::ctrl(Key::Z), 1);
let reparsed = Shortcut::from_string(&Shortcut::ctrl(Key::Z).to_string()).unwrap();
assert_eq!(
map.get(&reparsed).copied(),
Some(1),
"a reparsed shortcut must hash to the same key"
);
assert_eq!(Shortcut::from_string("Ctrl+A+B"), None);
assert_eq!(Shortcut::from_string("A+B"), None);
assert!(Shortcut::from_string("Ctrl+A").is_some());
assert!(Shortcut::from_string("Control+A").is_some());
assert_ne!(Shortcut::from_string("Ctrl+A"), Shortcut::from_string("Control+A"));
}
#[test]
fn test_shortcut_manager_register() {
let mut manager = ShortcutManager::new();
assert!(manager.register("action1", Shortcut::ctrl(Key::A), "Action 1"));
assert!(manager.has_action("action1"));
assert!(manager.has_shortcut(&Shortcut::ctrl(Key::A)));
assert!(manager.register("action1", Shortcut::ctrl(Key::A), "Action 1"));
assert!(!manager.register("action2", Shortcut::ctrl(Key::A), "Action 2"));
}
#[test]
fn test_shortcut_manager_trigger() {
let mut manager = ShortcutManager::new();
manager.register("action1", Shortcut::ctrl(Key::A), "Action 1");
assert!(manager.handle_key_event(Key::A, Modifiers::CTRL));
assert!(!manager.handle_key_event(Key::B, Modifiers::CTRL));
assert!(!manager.handle_key_event(Key::A, Modifiers::ALT));
}
#[test]
fn test_shortcut_manager_handles_framework_key_press_event() {
let mut manager = ShortcutManager::new();
manager.register("save", Shortcut::ctrl(Key::S), "Save");
assert!(manager.handle_event(&Event::KeyPress { key: 83, modifiers: 2 }));
assert!(manager.handle_event(&Event::KeyPress { key: 115, modifiers: 2 }));
assert!(!manager.handle_event(&Event::KeyPress { key: 83, modifiers: 4 }));
assert!(!manager.handle_event(&Event::KeyRelease { key: 83, modifiers: 2 }));
}
#[test]
fn test_shortcut_key_code_conversion_covers_navigation_keys() {
assert_eq!(Key::from_key_code(37), Some(Key::Left));
assert_eq!(Key::from_key_code(39), Some(Key::Right));
assert_eq!(Key::from_key_code(13), Some(Key::Enter));
assert_eq!(Key::from_key_code(9999), None);
}
#[test]
fn test_shortcut_manager_enable_disable() {
let mut manager = ShortcutManager::new();
manager.register("action1", Shortcut::ctrl(Key::A), "Action 1");
assert!(manager.handle_key_event(Key::A, Modifiers::CTRL));
manager.disable("action1");
assert!(!manager.handle_key_event(Key::A, Modifiers::CTRL));
manager.enable("action1");
assert!(manager.handle_key_event(Key::A, Modifiers::CTRL));
}
#[test]
fn test_shortcut_conflict_detection() {
let shortcut1 = Shortcut::ctrl(Key::A);
let shortcut2 = Shortcut::ctrl(Key::A);
let shortcut3 = Shortcut::alt(Key::A);
assert!(shortcut1.conflicts_with(&shortcut2));
assert!(!shortcut1.conflicts_with(&shortcut3));
}
#[test]
fn primary_shortcut_renders_per_platform() {
use super::PlatformShortcutStyle::{Desktop, Mac};
let undo = Shortcut::primary(Key::Z);
assert_eq!(format_shortcut_for_platform(&undo, Mac), "⌘Z");
assert_eq!(format_shortcut_for_platform(&undo, Desktop), "Ctrl+Z");
let redo = Shortcut::primary_shift(Key::Z);
assert_eq!(format_shortcut_for_platform(&redo, Mac), "⇧⌘Z");
assert_eq!(format_shortcut_for_platform(&redo, Desktop), "Ctrl+Shift+Z");
let save = Shortcut::primary(Key::S);
assert_eq!(format_shortcut_for_platform(&save, Mac), "⌘S");
assert_eq!(format_shortcut_for_platform(&save, Desktop), "Ctrl+S");
}
#[test]
fn physical_control_is_not_primary() {
use super::PlatformShortcutStyle::{Desktop, Mac};
let control_c = Shortcut::ctrl(Key::C);
assert_eq!(format_shortcut_for_platform(&control_c, Desktop), "Ctrl+C");
assert_eq!(format_shortcut_for_platform(&control_c, Mac), "⌃C");
let primary_c = Shortcut::primary(Key::C);
assert_ne!(primary_c, control_c);
}
#[test]
fn mac_style_uses_glyphs_for_named_keys() {
use super::PlatformShortcutStyle::{Desktop, Mac};
let enter = Shortcut::new(Key::Enter, Modifiers::PRIMARY);
assert_eq!(format_shortcut_for_platform(&enter, Mac), "⌘↩");
assert_eq!(format_shortcut_for_platform(&enter, Desktop), "Ctrl+Enter");
let up = Shortcut::new(Key::Up, Modifiers::ALT);
assert_eq!(format_shortcut_for_platform(&up, Mac), "⌥↑");
assert_eq!(format_shortcut_for_platform(&up, Desktop), "Alt+Up");
}
#[test]
fn current_style_matches_host() {
let expected = crate::platform::types::compile_target_shortcut_style();
assert_eq!(PlatformShortcutStyle::current(), expected);
}
#[test]
fn command_modifier_bit_matches_primary_shortcut() {
let mut manager = ShortcutManager::new();
manager.register("undo", Shortcut::primary(Key::Z), "Undo");
assert_eq!(Key::from_key_code(90), Some(Key::Z));
let command = Modifiers::from_event_bits(0b1000);
assert!(command.contains(Modifiers::PRIMARY));
assert!(command.contains(Modifiers::CTRL));
assert_eq!(command, Modifiers::PRIMARY | Modifiers::CTRL);
assert!(!manager.handle_event(&Event::KeyPress { key: 90, modifiers: 0b1001 }));
match PlatformShortcutStyle::current() {
PlatformShortcutStyle::Mac => {
assert!(manager.handle_event(&Event::KeyPress { key: 90, modifiers: 0b1000 }));
}
PlatformShortcutStyle::Desktop => {
assert!(manager.handle_event(&Event::KeyPress { key: 90, modifiers: 0b0010 }));
assert!(!manager.handle_event(&Event::KeyPress { key: 90, modifiers: 0b1000 }));
}
}
let mut control_manager = ShortcutManager::new();
control_manager.register("physical", Shortcut::ctrl(Key::Z), "Control only");
assert!(control_manager.handle_event(&Event::KeyPress { key: 90, modifiers: 0b0010 }));
}