par-term 0.48.0

Cross-platform GPU-accelerated terminal emulator with inline graphics support (Sixel, iTerm2, Kitty)
//! Tests for snippet_actions module.

use super::key_sequence::extract_prefix_action_char;
use super::workflow::glob_match;
use crate::config::snippets::CustomActionConfig;
use std::collections::HashMap;
use winit::keyboard::{Key, KeyCode, PhysicalKey};

#[test]
fn prefix_action_matching_is_case_insensitive_for_letters() {
    use super::prefix_action_for_char;

    let actions = vec![CustomActionConfig::InsertText {
        id: "git-status".to_string(),
        title: "Git Status".to_string(),
        text: "git status".to_string(),
        variables: HashMap::new(),
        keybinding: None,
        prefix_char: Some('G'),
        keybinding_enabled: true,
        description: None,
    }];

    assert_eq!(
        prefix_action_for_char(&actions, 'g'),
        Some("git-status".to_string())
    );
    assert_eq!(
        prefix_action_for_char(&actions, 'G'),
        Some("git-status".to_string())
    );
}

#[test]
fn prefix_action_matching_keeps_symbol_bindings_exact() {
    use super::prefix_action_for_char;

    let actions = vec![CustomActionConfig::KeySequence {
        id: "split".to_string(),
        title: "Split".to_string(),
        keys: "Ctrl+C".to_string(),
        keybinding: None,
        prefix_char: Some('%'),
        keybinding_enabled: true,
        description: None,
    }];

    assert_eq!(
        prefix_action_for_char(&actions, '%'),
        Some("split".to_string())
    );
    assert_eq!(prefix_action_for_char(&actions, '5'), None);
}

#[test]
fn prefix_action_matching_uses_single_char_keybinding_when_prefix_char_absent() {
    use super::prefix_action_for_char;

    let actions = vec![CustomActionConfig::InsertText {
        id: "lenny1".to_string(),
        title: "lenny1".to_string(),
        text: "ssh root@lenny1".to_string(),
        variables: HashMap::new(),
        keybinding: Some("1".to_string()),
        prefix_char: None,
        keybinding_enabled: true,
        description: None,
    }];

    assert_eq!(
        prefix_action_for_char(&actions, '1'),
        Some("lenny1".to_string())
    );
}

#[test]
fn prefix_action_matching_prefers_explicit_prefix_char_over_keybinding() {
    use super::prefix_action_for_char;

    let actions = vec![
        CustomActionConfig::InsertText {
            id: "from-keybinding".to_string(),
            title: "From Keybinding".to_string(),
            text: "a".to_string(),
            variables: HashMap::new(),
            keybinding: Some("g".to_string()),
            prefix_char: None,
            keybinding_enabled: true,
            description: None,
        },
        CustomActionConfig::InsertText {
            id: "from-prefix".to_string(),
            title: "From Prefix".to_string(),
            text: "b".to_string(),
            variables: HashMap::new(),
            keybinding: None,
            prefix_char: Some('g'),
            keybinding_enabled: true,
            description: None,
        },
    ];

    assert_eq!(
        prefix_action_for_char(&actions, 'g'),
        Some("from-prefix".to_string())
    );
}

#[test]
fn prefix_action_matching_ignores_disabled_single_char_keybinding() {
    use super::prefix_action_for_char;

    let actions = vec![CustomActionConfig::InsertText {
        id: "disabled".to_string(),
        title: "Disabled".to_string(),
        text: "nope".to_string(),
        variables: HashMap::new(),
        keybinding: Some("1".to_string()),
        prefix_char: None,
        keybinding_enabled: false,
        description: None,
    }];

    assert_eq!(prefix_action_for_char(&actions, '1'), None);
}

#[test]
fn prefix_action_matching_ignores_chord_keybindings() {
    use super::prefix_action_for_char;

    let actions = vec![CustomActionConfig::InsertText {
        id: "chord".to_string(),
        title: "Chord".to_string(),
        text: "nope".to_string(),
        variables: HashMap::new(),
        keybinding: Some("Ctrl+1".to_string()),
        prefix_char: None,
        keybinding_enabled: true,
        description: None,
    }];

    assert_eq!(prefix_action_for_char(&actions, '1'), None);
}

#[test]
fn prefix_mode_arms_when_only_single_char_keybinding_exists() {
    use super::actions_have_prefix_follow_up;

    let actions = vec![CustomActionConfig::InsertText {
        id: "lenny1".to_string(),
        title: "lenny1".to_string(),
        text: "ssh root@lenny1".to_string(),
        variables: HashMap::new(),
        keybinding: Some("1".to_string()),
        prefix_char: None,
        keybinding_enabled: true,
        description: None,
    }];

    assert!(actions_have_prefix_follow_up(&actions));
}

#[test]
fn prefix_mode_does_not_arm_for_chord_only_keybindings() {
    use super::actions_have_prefix_follow_up;

    let actions = vec![CustomActionConfig::InsertText {
        id: "chord".to_string(),
        title: "Chord".to_string(),
        text: "nope".to_string(),
        variables: HashMap::new(),
        keybinding: Some("Ctrl+1".to_string()),
        prefix_char: None,
        keybinding_enabled: true,
        description: None,
    }];

    assert!(!actions_have_prefix_follow_up(&actions));
}

#[test]
fn extract_prefix_action_char_prefers_event_text() {
    assert_eq!(
        extract_prefix_action_char(
            Some("r"),
            &Key::Named(winit::keyboard::NamedKey::Enter),
            PhysicalKey::Code(KeyCode::KeyR),
        ),
        Some('r')
    );
}

#[test]
fn extract_prefix_action_char_falls_back_to_physical_key() {
    assert_eq!(
        extract_prefix_action_char(
            None,
            &Key::Named(winit::keyboard::NamedKey::Enter),
            PhysicalKey::Code(KeyCode::KeyR),
        ),
        Some('r')
    );
}

#[test]
fn test_glob_match_exact() {
    assert!(glob_match("main", "main"));
    assert!(!glob_match("main", "master"));
}

#[test]
fn test_glob_match_wildcard() {
    assert!(glob_match("feat/*", "feat/login"));
    assert!(glob_match("*", "anything"));
    assert!(!glob_match("feat/*", "fix/bug"));
}

/// UX.md PN15: sequence steps may name built-in actions, not only user
/// actions; prefix forms that run user content are not built-ins.
#[test]
fn builtin_step_ids_resolve_against_the_dispatch_tables() {
    use super::workflow::builtin_step_id;
    assert!(builtin_step_id("split_right"));
    assert!(builtin_step_id("equalize_panes"));
    assert!(builtin_step_id("increase_font_size"), "display table");
    assert!(builtin_step_id("split_vertical"), "renamed ids resolve");
    assert!(builtin_step_id("layout:tiled"));
    assert!(!builtin_step_id("action:mine"));
    assert!(!builtin_step_id("snippet:mine"));
    assert!(!builtin_step_id("not_an_action"));
}