use super::{MAX_REPLY_BYTES, Report, done, parse};
#[test]
fn a_kitty_terminal_answers_the_graphics_query_and_da1() {
let replies = b"\x1b_Gi=31;OK\x1b\\\x1bP>|kitty(0.40.1)\x1b\\\x1b[6;44;22t\x1b[?62;c";
assert!(done(replies));
let report = parse(replies);
assert!(report.kitty);
assert!(!report.sixel);
assert_eq!(report.terminal.as_deref(), Some("kitty(0.40.1)"));
assert_eq!(report.cell_size, Some((22, 44)));
assert!(report.answered);
}
#[test]
fn an_iterm2_terminal_reports_name_sixel_and_cell_size() {
let replies = b"\x1bP>|iTerm2 3.5.9\x1b\\\x1b[?1;0;1024S\x1b[6;32;15t\x1b[?62;4c";
let report = parse(replies);
assert!(!report.kitty);
assert!(report.sixel);
assert_eq!(report.terminal.as_deref(), Some("iTerm2 3.5.9"));
assert_eq!(report.cell_size, Some((15, 32)));
assert!(report.answered);
}
#[test]
fn an_xterm_with_sixel_advertises_it_in_da1_and_xtsmgraphics() {
let replies = b"\x1b[?1;0;334S\x1b[?64;1;2;4;6;9;15;18;21;22c";
assert!(done(replies));
let report = parse(replies);
assert!(report.sixel);
assert!(report.answered);
assert_eq!(report.terminal, None);
assert_eq!(report.cell_size, None);
}
#[test]
fn a_failed_xtsmgraphics_status_is_not_sixel_evidence() {
let report = parse(b"\x1b[?1;2;0S\x1b[?62;22c");
assert!(!report.sixel);
assert!(report.answered);
}
#[test]
fn silence_reports_nothing_and_is_not_done() {
assert!(!done(b""));
assert_eq!(parse(b""), Report::default());
assert!(!done(b"garbage\x1b[?62;"));
assert_eq!(parse(b"garbage\x1b[?62;"), Report::default());
}
#[test]
fn a_hairline_cell_size_is_rejected_as_nonsense() {
let report = parse(b"\x1b[6;1;1t\x1b[?62;c");
assert_eq!(report.cell_size, None);
}
#[test]
fn interleaved_unknown_replies_are_skipped() {
let replies = b"\x1b[24;80R\x1bP1$r0m\x1b\\\x1b_Gi=31;OK\x1b\\\x1b[?62;4c";
let report = parse(replies);
assert!(report.kitty);
assert!(report.sixel);
assert!(report.answered);
}
#[test]
fn every_reply_prefix_is_safe_and_agrees_with_the_barrier_parser() {
let replies = b"noise\x1b_Gi=31;OK\x1b\\\x1bP>|terminal\x1b\\\x1b[6;18;9t\x1b[?62;4c";
for end in 0..=replies.len() {
let prefix = &replies[..end];
assert_eq!(parse(prefix).answered, done(prefix), "prefix length {end}");
}
let bytes: Vec<u8> = (u8::MIN..=u8::MAX).collect();
for end in 0..=bytes.len() {
let _ = parse(&bytes[..end]);
let _ = done(&bytes[..end]);
}
}
#[test]
fn deterministic_arbitrary_streams_are_total_and_barrier_consistent() {
let mut state = 0x4d41_4c45_5649_4348_u64;
let known = b"\x1b_Gi=31;OK\x1b\\\x1bP>|terminal\x1b\\\x1b[6;18;9t\x1b[?62;4c";
for case in 0..10_000usize {
let length = next(&mut state) as usize % (MAX_REPLY_BYTES + 1);
let mut bytes = vec![0; length];
for byte in &mut bytes {
*byte = next(&mut state) as u8;
}
if case % 2 == 0 && !bytes.is_empty() {
let copied = known.len().min(bytes.len());
let start = next(&mut state) as usize % (bytes.len() - copied + 1);
bytes[start..start + copied].copy_from_slice(&known[..copied]);
for _ in 0..case % 5 {
let index = next(&mut state) as usize % bytes.len();
bytes[index] = next(&mut state) as u8;
}
}
let report = parse(&bytes);
assert_eq!(
report.answered,
done(&bytes),
"barrier disagreement in generated case {case}"
);
}
}
fn next(state: &mut u64) -> u64 {
*state ^= *state >> 12;
*state ^= *state << 25;
*state ^= *state >> 27;
state.wrapping_mul(0x2545_f491_4f6c_dd1d)
}