返回 CodeWhale
osc11_tests.rs
根目录 / vendor / codewhale-ratatui / src / osc11_tests.rs
1 use std::io::{Read, Write};
2 use std::os::fd::AsRawFd;
3 use std::time::Duration;
4
5 use super::{
6 read_terminal_reply, settle_terminal_reply, take_carried_type_ahead, take_consumed_unreplayable,
7 };
8
9 #[test]
10 fn terminal_reply_reader_leaves_one_burst_typed_suffix_on_the_descriptor() {
11 struct Case {
12 query: &'static [u8],
13 response: &'static [u8],
14 reply: &'static [u8],
15 csi: bool,
16 }
17 let cases = [
18 Case {
19 query: b"\x1b]11;?\x07",
20 response: b"\x1b]11;rgb:1e1e/1e1e/1e1e\x07",
21 reply: b"\x1b]11;rgb:1e1e/1e1e/1e1e",
22 csi: false,
23 },
24 Case {
25 query: b"\x1b]11;?\x1b\\",
26 response: b"\x1b]11;rgb:1e1e/1e1e/1e1e\x1b\\",
27 reply: b"\x1b]11;rgb:1e1e/1e1e/1e1e",
28 csi: false,
29 },
30 Case {
31 query: b"\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\",
32 response: b"\x1b_Gi=31;OK\x1b\\",
33 reply: b"\x1b_Gi=31;OK",
34 csi: false,
35 },
36 Case {
37 query: b"\x1b[c",
38 response: b"\x1b[?62;4c",
39 reply: b"\x1b[?62;4c",
40 csi: true,
41 },
42 ];
43
44 for case in cases {
45 let (mut reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
46 let prefix = b"/plu";
47 let suffix = b"gin list\r";
48 let burst = [prefix.as_slice(), case.response, suffix.as_slice()].concat();
49 assert_eq!(
50 writer.write(&burst).expect("write one input burst"),
51 burst.len()
52 );
53
54 // Keep the writer open: a buffered read-ahead must not be rescued by
55 // EOF/readable-HUP while the real tty would have no new bytes ready.
56 let (answered, reply, carried) = read_terminal_reply(
57 reader.as_raw_fd(),
58 case.query,
59 Duration::from_secs(1),
60 case.csi,
61 );
62 drop(writer);
63 let mut remaining = Vec::new();
64 reader
65 .read_to_end(&mut remaining)
66 .expect("read remaining typed input");
67
68 assert!(
69 answered,
70 "complete reply was already on the pipe: {:?}",
71 case.response
72 );
73 assert_eq!(reply, case.reply, "query {:?}", case.query);
74 assert_eq!(
75 carried, prefix,
76 "type-ahead before the reply must be replayable"
77 );
78 assert_eq!(
79 remaining, suffix,
80 "the input pump must still receive the exact suffix"
81 );
82 }
83 }
84
85 #[test]
86 fn terminal_reply_reader_retains_incomplete_control_reply_separately_from_typeahead() {
87 let (reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
88 let prefix = b"/plu";
89 let incomplete = b"\x1b]11;rgb:1e/1e\r\r";
90 let burst = [prefix.as_slice(), incomplete.as_slice()].concat();
91 assert_eq!(
92 writer.write(&burst).expect("write incomplete reply"),
93 burst.len()
94 );
95 drop(writer);
96
97 let (answered, reply, carried) = read_terminal_reply(
98 reader.as_raw_fd(),
99 b"\x1b]11;?\x07",
100 Duration::from_secs(1),
101 false,
102 );
103
104 assert!(
105 !answered,
106 "an unterminated control reply is not a valid answer"
107 );
108 assert_eq!(
109 reply, incomplete,
110 "the caller must account for every unreplayable byte"
111 );
112 assert_eq!(
113 carried, prefix,
114 "control payload and its Enters must not become user input"
115 );
116 }
117
118 /// The probe hands type-ahead to the event loop, and never hands it an
119 /// unterminated control reply. One test owns the process-wide buffers so
120 /// parallel tests cannot race on them.
121 #[test]
122 fn the_probe_parks_type_ahead_for_the_event_loop() {
123 let _ = take_carried_type_ahead();
124 let _ = take_consumed_unreplayable();
125
126 let (reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
127 writer
128 .write_all(b"ls -\x1b]11;rgb:fafa/f8f8/f5f5\x07")
129 .expect("write burst");
130 let reply = settle_terminal_reply(
131 reader.as_raw_fd(),
132 b"\x1b]11;?\x07",
133 Duration::from_secs(1),
134 false,
135 );
136 drop(writer);
137 assert_eq!(
138 reply.as_deref(),
139 Some(b"\x1b]11;rgb:fafa/f8f8/f5f5".as_slice())
140 );
141 assert_eq!(take_carried_type_ahead(), b"ls -");
142 assert!(take_consumed_unreplayable().is_empty());
143
144 let (reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
145 writer.write_all(b"q\x1b]11;rgb:1e").expect("write burst");
146 drop(writer);
147 let reply = settle_terminal_reply(
148 reader.as_raw_fd(),
149 b"\x1b]11;?\x07",
150 Duration::from_secs(1),
151 false,
152 );
153 assert_eq!(reply, None);
154 assert_eq!(take_carried_type_ahead(), b"q");
155 assert_eq!(take_consumed_unreplayable(), b"\x1b]11;rgb:1e");
156 }
157
157 lines RUST