use crate::vt_parser::*; pub struct DummyHandler { pub text: String, pub osc_calls: Vec>, } impl Handler for DummyHandler { fn text(&mut self, codepoints: &[u32]) { for &c in codepoints { if let Some(ch) = char::from_u32(c) { self.text.push(ch); } } } fn control(&mut self, _byte: u8) {} fn csi(&mut self, _csi: &CsiParams) {} fn osc(&mut self, osc: &[u8]) { self.osc_calls.push(osc.to_vec()); } fn save_cursor(&mut self) {} fn restore_cursor(&mut self) {} fn reset(&mut self) {} fn index(&mut self) {} fn newline(&mut self) {} fn reverse_index(&mut self) {} fn screen_alignment(&mut self) {} fn set_tab_stop(&mut self) {} fn set_keypad_mode(&mut self, _mode: bool) {} fn add_vt_parser_ns(&mut self, _ns: u64) {} } #[test] fn test_osc_leak_byte_by_byte() { let parser = SharedParser::new(); let mut handler = DummyHandler { text: String::new(), osc_calls: Vec::new() }; let data = b"\x1b]4;1;#769E00\x1b\\\x1b]4;2;#93DE88\x1b\\"; for &byte in data { let (ptr, _) = parser.create_write_buffer(); unsafe { *ptr = byte; } parser.commit_write(1); while parser.run_parse_pass(&mut handler) {} } println!("TEXT: {:?}", handler.text); println!("OSC calls: {}", handler.osc_calls.len()); for call in &handler.osc_calls { println!(" OSC: {:?}", std::str::from_utf8(call).unwrap()); } assert_eq!(handler.text, "", "Text should be empty, but leaked escape sequence bytes!"); assert_eq!(handler.osc_calls.len(), 2, "Should have parsed exactly two OSC calls"); } #[test] fn test_csi_aborted_by_osc() { let parser = SharedParser::new(); let mut handler = DummyHandler { text: String::new(), osc_calls: Vec::new() }; // An incomplete CSI sequence aborted by an OSC sequence let data = b"\x1b[38;2;255;0;0\x1b]4;1;#769E00\x1b\\"; let (ptr, len) = parser.create_write_buffer(); assert!(len >= data.len()); unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), ptr, data.len()); } parser.commit_write(data.len()); while parser.run_parse_pass(&mut handler) {} assert_eq!(handler.text, "", "Text should be empty, but leaked escape sequence bytes!"); assert_eq!(handler.osc_calls.len(), 1, "Should have parsed the OSC sequence even after aborting CSI"); }