返回 CodeWhale
osc11_tests.rs
根目录 / crates / palette / 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::read_terminal_reply;
6
7 #[test]
8 fn terminal_reply_reader_leaves_one_burst_typed_suffix_on_the_descriptor() {
9 struct Case {
10 query: &'static [u8],
11 response: &'static [u8],
12 reply: &'static [u8],
13 csi: bool,
14 }
15 let cases = [
16 Case {
17 query: b"\x1b]11;?\x07",
18 response: b"\x1b]11;rgb:1e1e/1e1e/1e1e\x07",
19 reply: b"\x1b]11;rgb:1e1e/1e1e/1e1e",
20 csi: false,
21 },
22 Case {
23 query: b"\x1b]11;?\x1b\\",
24 response: b"\x1b]11;rgb:1e1e/1e1e/1e1e\x1b\\",
25 reply: b"\x1b]11;rgb:1e1e/1e1e/1e1e",
26 csi: false,
27 },
28 Case {
29 query: b"\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\",
30 response: b"\x1b_Gi=31;OK\x1b\\",
31 reply: b"\x1b_Gi=31;OK",
32 csi: false,
33 },
34 Case {
35 query: b"\x1b[c",
36 response: b"\x1b[?62;4c",
37 reply: b"\x1b[?62;4c",
38 csi: true,
39 },
40 ];
41
42 for case in cases {
43 let (mut reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
44 let prefix = b"/plu";
45 let suffix = b"gin list\r";
46 let burst = [prefix.as_slice(), case.response, suffix.as_slice()].concat();
47 assert_eq!(
48 writer.write(&burst).expect("write one input burst"),
49 burst.len()
50 );
51
52 // Keep the writer open: a buffered read-ahead must not be rescued by
53 // EOF/readable-HUP while the real tty would have no new bytes ready.
54 let (answered, reply, carried) = read_terminal_reply(
55 reader.as_raw_fd(),
56 case.query,
57 Duration::from_secs(1),
58 case.csi,
59 );
60 drop(writer);
61 let mut remaining = Vec::new();
62 reader
63 .read_to_end(&mut remaining)
64 .expect("read remaining typed input");
65
66 assert!(
67 answered,
68 "complete reply was already on the pipe: {:?}",
69 case.response
70 );
71 assert_eq!(reply, case.reply, "query {:?}", case.query);
72 assert_eq!(
73 carried, prefix,
74 "type-ahead before the reply must be replayable"
75 );
76 assert_eq!(
77 remaining, suffix,
78 "the input pump must still receive the exact suffix"
79 );
80 }
81 }
82
83 #[test]
84 fn terminal_reply_reader_retains_incomplete_control_reply_separately_from_typeahead() {
85 let (reader, mut writer) = std::io::pipe().expect("create isolated input pipe");
86 let prefix = b"/plu";
87 let incomplete = b"\x1b]11;rgb:1e/1e\r\r";
88 let burst = [prefix.as_slice(), incomplete.as_slice()].concat();
89 assert_eq!(
90 writer.write(&burst).expect("write incomplete reply"),
91 burst.len()
92 );
93 drop(writer);
94
95 let (answered, reply, carried) = read_terminal_reply(
96 reader.as_raw_fd(),
97 b"\x1b]11;?\x07",
98 Duration::from_secs(1),
99 false,
100 );
101
102 assert!(
103 !answered,
104 "an unterminated control reply is not a valid answer"
105 );
106 assert_eq!(
107 reply, incomplete,
108 "the caller must account for every unreplayable byte"
109 );
110 assert_eq!(
111 carried, prefix,
112 "control payload and its Enters must not become user input"
113 );
114 }
115
115 lines RUST