use super::*;
#[test]
fn kitty_flag_stack_push_pop() {
let mut stack = KittyFlagStack::default();
assert_eq!(stack.current(), 0, "fresh stack must report flags=0");
stack.push(3);
assert_eq!(stack.current(), 3, "push(3) should make 3 the active level");
stack.push(5);
assert_eq!(
stack.current(),
5,
"push(5) on top of 3 should make 5 the active level (not OR them)",
);
stack.pop(1);
assert_eq!(
stack.current(),
3,
"pop(1) should reveal the 3 underneath, not clear to 0",
);
stack.pop(1);
assert_eq!(
stack.current(),
0,
"pop(1) past the bottom returns to default 0"
);
}
#[test]
fn kitty_flag_stack_pop_empty() {
let mut stack = KittyFlagStack::default();
stack.pop(5);
assert_eq!(stack.current(), 0);
}
#[test]
fn kitty_flag_stack_pop_multiple() {
let mut stack = KittyFlagStack::default();
stack.push(1);
stack.push(3);
stack.push(5);
stack.pop(2);
assert_eq!(stack.current(), 1);
}
#[test]
fn kitty_flag_stack_overflow_clamped() {
let mut stack = KittyFlagStack::default();
for i in 0..8 {
stack.push(i + 1);
}
assert_eq!(stack.current(), 8);
stack.push(99);
assert_eq!(
stack.current(),
8,
"push past stack capacity must be silently dropped, not overwrite the top",
);
stack.pop(1);
assert_eq!(
stack.current(),
7,
"after a dropped overflow push, pop(1) must reveal the previous valid level (7), not 99",
);
}
#[test]
fn kitty_flag_stack_set_assign() {
let mut stack = KittyFlagStack::default();
stack.push(1);
stack.set(3, 1); assert_eq!(stack.current(), 3);
}
#[test]
fn kitty_flag_stack_set_or() {
let mut stack = KittyFlagStack::default();
stack.push(1);
stack.set(2, 2); assert_eq!(stack.current(), 3); }
#[test]
fn kitty_flag_stack_set_and_not() {
let mut stack = KittyFlagStack::default();
stack.push(3);
stack.set(1, 3); assert_eq!(stack.current(), 2); }
#[test]
fn kitty_flag_stack_set_empty_pushes() {
let mut stack = KittyFlagStack::default();
stack.set(5, 1);
assert_eq!(stack.current(), 5);
}
#[test]
fn kitty_csi_push() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 3);
}
#[test]
fn kitty_csi_pop() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>1u\x1b[>5u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 5);
process(&mut parser, b"\x1b[<u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 1);
}
#[test]
fn kitty_csi_pop_count() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>1u\x1b[>5u");
process(&mut parser, b"\x1b[<2u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 0);
}
#[test]
fn kitty_csi_set_assign() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>1u");
process(&mut parser, b"\x1b[=3;1u"); assert_eq!(parser.screen().kitty_keyboard_flags(), 3);
}
#[test]
fn kitty_csi_set_or() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>1u");
process(&mut parser, b"\x1b[=2;2u"); assert_eq!(parser.screen().kitty_keyboard_flags(), 3);
}
#[test]
fn kitty_csi_set_and_not() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
process(&mut parser, b"\x1b[=1;3u"); assert_eq!(parser.screen().kitty_keyboard_flags(), 2);
}
#[test]
fn kitty_csi_set_default_mode() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>0u");
process(&mut parser, b"\x1b[=3u"); assert_eq!(parser.screen().kitty_keyboard_flags(), 3);
}
#[test]
fn kitty_csi_set_empty_stack() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[=5u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 5);
}
#[test]
fn kitty_csi_query() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[?u");
assert_eq!(drain_replies(&mut parser), b"\x1b[?0u");
process(&mut parser, b"\x1b[>3u");
process(&mut parser, b"\x1b[?u");
assert_eq!(drain_replies(&mut parser), b"\x1b[?3u");
}
#[test]
fn kitty_ris_clears_flags() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>5u");
process(&mut parser, b"\x1bc"); assert_eq!(parser.screen().kitty_keyboard_flags(), 0);
}
#[test]
fn kitty_alternate_screen_isolation() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 3);
process(&mut parser, b"\x1b[?1049h");
assert_eq!(
parser.screen().kitty_keyboard_flags(),
0,
"alt screen must start with a fresh Kitty keyboard flag stack, not inherit primary's flags",
);
process(&mut parser, b"\x1b[>7u");
assert_eq!(parser.screen().kitty_keyboard_flags(), 7);
process(&mut parser, b"\x1b[?1049l");
assert_eq!(
parser.screen().kitty_keyboard_flags(),
3,
"leaving alt screen must restore primary's Kitty keyboard flags, not bleed alt's stack back",
);
}
#[test]
fn kitty_event_on_push() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
let events = parser.screen_mut().drain_events();
assert_eq!(events, vec![ScreenEvent::KittyFlagsChanged(3)]);
}
#[test]
fn kitty_event_on_pop() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
parser.screen_mut().drain_events(); process(&mut parser, b"\x1b[<u");
let events = parser.screen_mut().drain_events();
assert_eq!(events, vec![ScreenEvent::KittyFlagsChanged(0)]);
}
#[test]
fn kitty_no_event_on_noop() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[<u");
let events = parser.screen_mut().drain_events();
assert!(events.is_empty());
}
#[test]
fn kitty_event_on_ris() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>5u");
parser.screen_mut().drain_events();
process(&mut parser, b"\x1bc"); let events = parser.screen_mut().drain_events();
assert!(events.contains(&ScreenEvent::KittyFlagsChanged(0)));
}
#[test]
fn kitty_event_on_alt_screen_switch() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[>3u");
parser.screen_mut().drain_events();
process(&mut parser, b"\x1b[?1049h");
let events = parser.screen_mut().drain_events();
assert_eq!(events, vec![ScreenEvent::KittyFlagsChanged(0)]);
}
#[test]
fn kitty_keyboard_query_emits_event() {
let mut parser = crate::Parser::new(TerminalSize { rows: 24, cols: 80 }, 0);
process(&mut parser, b"\x1b[?u");
let events = parser.screen_mut().drain_events();
assert!(
events
.iter()
.any(|e| matches!(e, ScreenEvent::KittyKeyboardQuery { .. }))
);
}