Krolyxon
Commit 6ffb407

Branches

Tags

Refs →

bench51cratesbench51-guisrcvimtests.rs

358 lines · 12.0 KB · Rust

1//! Engine tests. Buffers are written with `|` marking the cursor.
2
3use super::keys::parse_keys;
4use super::{Cx, Effect, History, Mode, View, Vim};
5
6struct T {
7 vim: Vim,
8 text: String,
9 cursor: usize,
10 history: History,
11 readonly: bool,
12 dirty: bool,
13 fx: Vec<Effect>,
14}
15
16impl T {
17 fn new(marked: &str) -> Self {
18 let cursor = marked.chars().position(|c| c == '|').unwrap_or(0);
19 Self {
20 vim: Vim::default(),
21 text: marked.replace('|', ""),
22 cursor,
23 history: History::default(),
24 readonly: false,
25 dirty: false,
26 fx: Vec::new(),
27 }
28 }
29
30 fn keys(&mut self, keys: &str) -> &mut Self {
31 for k in parse_keys(keys) {
32 let mut cx = Cx {
33 text: &mut self.text,
34 cursor: &mut self.cursor,
35 history: &mut self.history,
36 readonly: self.readonly,
37 dirty: self.dirty,
38 view: View { top: 0, rows: 10 },
39 };
40 let fx = self.vim.key(k, &mut cx);
41 self.fx.extend(fx);
42 }
43 self
44 }
45
46 fn show(&self) -> String {
47 let mut s: Vec<char> = self.text.chars().collect();
48 s.insert(self.cursor.min(s.len()), '|');
49 s.into_iter().collect()
50 }
51}
52
53fn after(start: &str, keys: &str) -> String {
54 T::new(start).keys(keys).show()
55}
56
57#[test]
58fn word_and_line_motions() {
59 assert_eq!(after("|MOV A,#1 ; c", "w"), "MOV |A,#1 ; c");
60 assert_eq!(after("|MOV A,#1 ; c", "ww"), "MOV A|,#1 ; c");
61 assert_eq!(after("|MOV A,#1 ; c", "W"), "MOV |A,#1 ; c");
62 assert_eq!(after("|MOV A,#1 ; c", "2W"), "MOV A,#1 |; c");
63 assert_eq!(after("MOV A,#1 ; |c", "b"), "MOV A,#1 |; c");
64 assert_eq!(after("|MOV A,#1", "e"), "MO|V A,#1");
65 assert_eq!(after(" MOV |A", "0"), "| MOV A");
66 assert_eq!(after(" MOV |A", "^"), " |MOV A");
67 assert_eq!(after(" |MOV A", "$"), " MOV |A");
68 assert_eq!(after("foo\n\n|bar", "b"), "foo\n|\nbar");
69 assert_eq!(after("|foo\n\nbar", "w"), "foo\n|\nbar");
70}
71
72#[test]
73fn vertical_motions_keep_the_column() {
74 assert_eq!(after("abcd|ef\nab\nabcdef", "j"), "abcdef\na|b\nabcdef");
75 assert_eq!(after("abcd|ef\nab\nabcdef", "jj"), "abcdef\nab\nabcd|ef");
76 assert_eq!(after("a|bc\nabcdef", "$j"), "abc\nabcde|f");
77 assert_eq!(after("a\nb\nc\n|d", "gg"), "|a\nb\nc\nd");
78 assert_eq!(after("|a\nb\nc\nd", "G"), "a\nb\nc\n|d");
79 assert_eq!(after("|a\nb\nc\nd", "3G"), "a\nb\n|c\nd");
80 assert_eq!(after("|a\nb\nc\nd", "2j"), "a\nb\n|c\nd");
81 assert_eq!(after("|a\n b", "<CR>"), "a\n |b");
82}
83
84#[test]
85fn find_and_match_motions() {
86 assert_eq!(after("|a,b,c,d", "f,"), "a|,b,c,d");
87 assert_eq!(after("|a,b,c,d", "f,;"), "a,b|,c,d");
88 assert_eq!(after("|a,b,c,d", "f,;,"), "a|,b,c,d");
89 assert_eq!(after("|a,b,c,d", "2f,"), "a,b|,c,d");
90 assert_eq!(after("|a,b,c,d", "t,"), "|a,b,c,d");
91 assert_eq!(after("|ab,c", "t,"), "a|b,c");
92 assert_eq!(after("a,b,|c", "F,"), "a,b|,c");
93 assert_eq!(after("MOV A,|#(1+(2))", "%"), "MOV A,#(1+(2)|)");
94 assert_eq!(after("MOV A,#(1+(2)|)", "%"), "MOV A,#|(1+(2))");
95 assert_eq!(after("|a\nb\n\nc\nd", "}"), "a\nb\n|\nc\nd");
96}
97
98#[test]
99fn delete_yank_put_lines() {
100 assert_eq!(after("a\n|b\nc", "dd"), "a\n|c");
101 assert_eq!(after("a\nb\n|c", "dd"), "a\n|b");
102 assert_eq!(after("|a\nb\nc", "2dd"), "|c");
103 assert_eq!(after("|a\nb\nc", "dj"), "|c");
104 assert_eq!(after("a\n|b\nc", "dk"), "|c");
105 assert_eq!(after("|a\nb", "yyp"), "a\n|a\nb");
106 assert_eq!(after("a\n|b", "yyp"), "a\nb\n|b");
107 assert_eq!(after("a\n|b", "yyP"), "a\n|b\nb");
108 assert_eq!(after("| a\nb", "ddp"), "b\n |a");
109 assert_eq!(after("|a\nb\nc", "dG"), "|");
110 assert_eq!(after("|para\none\n\nnext", "d}"), "|\nnext");
111}
112
113#[test]
114fn charwise_operators() {
115 assert_eq!(after("foo |bar\nbaz", "dw"), "foo| \nbaz");
116 assert_eq!(after("|foo bar", "dw"), "|bar");
117 assert_eq!(after("|foo bar", "d2w"), "|");
118 assert_eq!(after("|MOV A", "cwMOVX<Esc>"), "MOV|X A");
119 assert_eq!(after("MO|V A", "cw<Esc>"), "M|O A");
120 assert_eq!(after("MOV A,B|B", "ciwR7<Esc>"), "MOV A,R|7");
121 assert_eq!(after("DB \"hel|lo\", 0", "ci\"bye<Esc>"), "DB \"by|e\", 0");
122 assert_eq!(after("DB \"hel|lo\", 0", "da\""), "DB |, 0");
123 assert_eq!(after("MOV A,#(1+|2)", "di("), "MOV A,#(|)");
124 assert_eq!(after("MOV A,#(1+|2)", "da("), "MOV A,|#");
125 assert_eq!(after("a|bc", "x"), "a|c");
126 assert_eq!(after("ab|c", "x"), "a|b");
127 assert_eq!(after("ab|c", "X"), "a|c");
128 assert_eq!(after("a|bcd", "D"), "|a");
129 assert_eq!(after("a|bcd", "Cx<Esc>"), "a|x");
130 assert_eq!(after("a|bcd", "sX<Esc>"), "a|Xcd");
131 assert_eq!(after("|MOV A,B", "dt,"), "|,B");
132 assert_eq!(after("|MOV A,B", "df,"), "|B");
133 assert_eq!(after("|MOV A,B", "y$P"), "MOV A,|BMOV A,B");
134}
135
136#[test]
137fn indent_join_case_replace() {
138 assert_eq!(after("|MOV A,B", ">>"), " |MOV A,B");
139 assert_eq!(after(" MOV |A,B", "<<"), "|MOV A,B");
140 assert_eq!(after("|a\nb", "2>>"), " |a\n b");
141 assert_eq!(after("|a\n b", "J"), "a| b");
142 assert_eq!(after("|a\nb\nc", "3J"), "a b| c");
143 assert_eq!(after("|abc", "~~"), "AB|c");
144 assert_eq!(after("|abc", "rx"), "|xbc");
145 assert_eq!(after("|abc", "2rx"), "x|xc");
146}
147
148#[test]
149fn undo_redo_and_dot() {
150 assert_eq!(after("|abc", "xxu"), "|bc");
151 assert_eq!(after("|abc", "xxuu"), "|abc");
152 assert_eq!(after("|abc", "xxuu<C-r>"), "|bc");
153 assert_eq!(after("|abc", "ixy<Esc>u"), "|abc");
154 assert_eq!(after("|a b c d", "dw."), "|c d");
155 assert_eq!(after("|a b c d", "dw2."), "|d");
156 assert_eq!(after("|ab\ncd", "Ax<Esc>j."), "abx\ncd|x");
157 assert_eq!(after("|a b", "cwX<Esc>w."), "X |X");
158 // Undoing a `.` undoes the whole repeated change.
159 assert_eq!(after("|ab\ncd", "Axy<Esc>j.u"), "abxy\nc|d");
160}
161
162#[test]
163fn insert_mode_and_counts() {
164 assert_eq!(after("|", "3ix<Esc>"), "xx|x");
165 assert_eq!(after("a|b", "ix<Esc>"), "a|xb");
166 assert_eq!(after("a|b", "ax<Esc>"), "ab|x");
167 assert_eq!(after(" a|b", "Ix<Esc>"), " |xab");
168 assert_eq!(after("a|b", "Ax<Esc>"), "ab|x");
169 assert_eq!(after("a|b", "ix<BS>y<Esc>"), "a|yb");
170 assert_eq!(after("|", "i<Tab>x<Esc>"), " |x");
171 assert_eq!(after("ab|", "a<CR>c<Esc>"), "ab\n|c");
172 assert_eq!(after("|a", "2ox<Esc>"), "a\nx\n|x");
173}
174
175#[test]
176fn new_lines_line_up_after_labels() {
177 assert_eq!(
178 after("|main: MOV A,#1", "oNOP<Esc>"),
179 "main: MOV A,#1\n NO|P"
180 );
181 assert_eq!(after("|loop:", "oNOP<Esc>"), "loop:\n NO|P");
182 assert_eq!(
183 after("| MOV A,B", "oX<Esc>"),
184 " MOV A,B\n |X"
185 );
186 assert_eq!(after("|; comment", "oX<Esc>"), "; comment\n|X");
187 assert_eq!(after(" |NOP", "OX<Esc>"), " |X\n NOP");
188}
189
190#[test]
191fn visual_mode() {
192 let mut t = T::new("|abcdef");
193 t.keys("lvlly");
194 assert_eq!(t.show(), "a|bcdef");
195 assert!(t.fx.contains(&Effect::Clipboard("bcd".into())));
196 t.keys("$p");
197 assert_eq!(t.show(), "abcdefbc|d");
198 assert_eq!(after("a\n|b\nc\nd", "Vjd"), "a\n|d");
199 assert_eq!(after("|abcdef", "vld"), "|cdef");
200 assert_eq!(after("|abcdef", "vlcX<Esc>"), "|Xcdef");
201 assert_eq!(after("|a\nb", "Vj>"), " |a\n b");
202 assert_eq!(after("|abc", "vl~"), "|ABc");
203 assert_eq!(after("|ab cd", "yiwwviwp"), "ab |ab");
204 let mut t = T::new("|abc");
205 t.keys("v");
206 assert_eq!(t.vim.selection(&t.text, t.cursor), Some((0, 1)));
207 t.keys("l");
208 assert_eq!(t.vim.selection(&t.text, t.cursor), Some((0, 2)));
209 t.keys("<Esc>");
210 assert_eq!(t.vim.mode, Mode::Normal);
211}
212
213#[test]
214fn registers_and_clipboard() {
215 let mut t = T::new("|one\ntwo");
216 t.keys("\"ayyj\"byy\"ap");
217 assert_eq!(t.show(), "one\ntwo\n|one");
218 assert!(t.fx.contains(&Effect::Clipboard("one\n".into())));
219 // The black hole register doesn't touch the clipboard or `"`.
220 let mut t = T::new("|ab");
221 t.keys("yl\"_xp");
222 assert_eq!(t.show(), "b|a");
223 assert_eq!(t.fx, vec![Effect::Clipboard("a".into())]);
224 // Ctrl+V pastes the system clipboard before the cursor.
225 let mut t = T::new("a|b");
226 t.vim.key(
227 super::VimKey::Paste("XY".into()),
228 &mut Cx {
229 text: &mut t.text,
230 cursor: &mut t.cursor,
231 history: &mut t.history,
232 readonly: false,
233 dirty: false,
234 view: View::default(),
235 },
236 );
237 assert_eq!(t.show(), "aX|Yb");
238}
239
240#[test]
241fn search() {
242 assert_eq!(after("|foo bar\nbaz bar", "/bar<CR>"), "foo |bar\nbaz bar");
243 assert_eq!(after("|foo bar\nbaz bar", "/bar<CR>n"), "foo bar\nbaz |bar");
244 assert_eq!(
245 after("|foo bar\nbaz bar", "/bar<CR>nn"),
246 "foo |bar\nbaz bar"
247 );
248 assert_eq!(after("|foo bar\nbaz bar", "/bar<CR>N"), "foo bar\nbaz |bar");
249 assert_eq!(after("|foo bar\nbaz bar", "?baz<CR>"), "foo bar\n|baz bar");
250 assert_eq!(after("|foo Bar bar", "/bar<CR>"), "foo |Bar bar");
251 assert_eq!(after("|foo Bar bar", "/Bar<CR>n"), "foo |Bar bar");
252 assert_eq!(after("|loop loops loop", "*"), "loop loops |loop");
253 assert_eq!(after("|foo bar", "d/bar<CR>"), "|bar");
254 assert_eq!(after("|foo bar", "d/zzz<CR>"), "|foo bar");
255 assert_eq!(after("|foo bar", "d/<Esc>x"), "|oo bar");
256 let mut t = T::new("|foo bar bar");
257 t.keys("/bar<CR>");
258 assert_eq!(t.vim.search_ranges(&t.text), vec![(4, 7), (8, 11)]);
259 t.keys(":noh<CR>");
260 assert!(t.vim.search_ranges(&t.text).is_empty());
261 let mut t = T::new("|foo");
262 t.keys("/zzz<CR>");
263 assert_eq!(t.show(), "|foo");
264 assert!(t.vim.message.as_ref().is_some_and(|m| m.1));
265}
266
267#[test]
268fn macros() {
269 assert_eq!(after("|1\n2\n3", "qaA;<Esc>jq@a"), "1;\n2;\n|3");
270 assert_eq!(after("|1\n2\n3\n4", "qaA;<Esc>jq2@a"), "1;\n2;\n3;\n|4");
271 assert_eq!(after("|1\n2\n3", "qaA;<Esc>jq@a@@"), "1;\n2;\n3|;");
272 let mut t = T::new("|x");
273 t.keys("qa");
274 assert_eq!(t.vim.recording(), Some('a'));
275 t.keys("q");
276 assert_eq!(t.vim.recording(), None);
277}
278
279#[test]
280fn ex_commands() {
281 let mut t = T::new("|a\nb\nc");
282 t.keys(":w<CR>:wq<CR>:qa!<CR>:make<CR>:bn<CR>");
283 assert_eq!(
284 t.fx,
285 vec![
286 Effect::Save,
287 Effect::Save,
288 Effect::Close { force: false },
289 Effect::Quit { force: true },
290 Effect::Make,
291 Effect::NextDoc,
292 ]
293 );
294 assert_eq!(after("|a\nb\n c", ":3<CR>"), "a\nb\n |c");
295 assert_eq!(after("|a\nb\n c", ":$<CR>"), "a\nb\n |c");
296 let mut t = T::new("|a");
297 t.dirty = true;
298 t.keys(":q<CR>");
299 assert!(t.fx.is_empty());
300 assert!(
301 t.vim
302 .message
303 .as_ref()
304 .is_some_and(|m| m.0.starts_with("E37"))
305 );
306 t.keys(":q!<CR>");
307 assert_eq!(t.fx, vec![Effect::Close { force: true }]);
308 let mut t = T::new("|a");
309 t.keys(":wat<CR>");
310 assert!(
311 t.vim
312 .message
313 .as_ref()
314 .is_some_and(|m| m.0.starts_with("E492"))
315 );
316 assert_eq!(t.vim.mode, Mode::Normal);
317}
318
319#[test]
320fn read_only_allows_moving_and_yanking() {
321 let mut t = T::new("|abc\ndef");
322 t.readonly = true;
323 t.keys("x");
324 assert_eq!(t.show(), "|abc\ndef");
325 assert!(t.vim.message.as_ref().is_some_and(|m| m.1));
326 t.keys("ix");
327 assert_eq!(t.vim.mode, Mode::Normal);
328 t.keys("jlyl");
329 assert_eq!(t.show(), "abc\nd|ef");
330 assert!(t.fx.contains(&Effect::Clipboard("e".into())));
331}
332
333#[test]
334fn goto_definition_and_tabs() {
335 assert_eq!(
336 after(" SJMP |loop\nloop: NOP", "gd"),
337 " SJMP loop\n|loop: NOP"
338 );
339 assert_eq!(
340 after("MOV A,#|RELOAD\nRELOAD EQU 5", "gd"),
341 "MOV A,#RELOAD\n|RELOAD EQU 5"
342 );
343 let mut t = T::new("|a");
344 t.keys("gtgT");
345 assert_eq!(t.fx, vec![Effect::NextDoc, Effect::PrevDoc]);
346}
347
348#[test]
349fn escape_and_pending() {
350 let mut t = T::new("|abc");
351 t.keys("2d");
352 assert_eq!(t.vim.pending_label(), "2d");
353 t.keys("<Esc>");
354 assert_eq!(t.vim.pending_label(), "");
355 assert_eq!(t.show(), "|abc");
356 assert_eq!(after("ab|c", "i<Esc>"), "a|bc");
357 assert_eq!(after("|abc", "i<Esc>"), "|abc");
358}