blob: ef4d8fba486a54ccb615f77ffcde31c982aa872d [file] [log] [blame]
Foxe Chenb90c2392025-06-27 21:10:35 +02001source check.vim
2source shared.vim
3source window_manager.vim
4
5CheckFeature wayland
6CheckFeature wayland_clipboard
7CheckUnix
8CheckFeature job
9CheckWaylandCompositor
10CheckNotGui
11
12if !executable('wl-paste') || !executable('wl-copy')
13 throw "Skipped: wl-clipboard is not available"
14endif
15
16" Process will be killed when the test ends
17let s:global_wayland_display = StartWaylandCompositor()
18let s:old_wayland_display = $WAYLAND_DISPLAY
19
20" For some reason if $WAYLAND_DISPLAY is set in the global namespace (not in a
21" function), it won't actually be set if $WAYLAND_DISPLAY was not set before
22" (such as in a CI environment) ? Solution is to just set it before the code of
23" every test function
24func s:PreTest()
25 let $WAYLAND_DISPLAY=s:global_wayland_display
26 exe 'wlrestore ' .. $WAYLAND_DISPLAY
27
28 set cpm=wayland
29endfunc
30
31func s:SetupFocusStealing()
32 if !executable('wayland-info')
33 throw "Skipped: wayland-info program not available"
34 endif
35
36 " Starting a headless compositor won't expose a keyboard capability for its
37 " seat, so we must use the user's existing Wayland session if they are in one.
38 let $WAYLAND_DISPLAY = s:old_wayland_display
39
40 exe 'wlrestore ' .. $WAYLAND_DISPLAY
41
42 " Check if we have keyboard capability for seat
43 if system("wayland-info -i wl_seat | grep capabilities") !~? "keyboard"
44 throw "Skipped: seat does not have keyboard"
45 endif
46
47 let $VIM_WAYLAND_FORCE_FS=1
48 wlrestore!
49endfunc
50
51func s:UnsetupFocusStealing()
52 unlet $VIM_WAYLAND_FORCE_FS
53endfunc
54
55" Need X connection for tests that use client server communication
56func s:CheckXConnection()
57 if has('x11')
58 try
59 call remote_send('xxx', '')
60 catch
61 if v:exception =~ 'E240:'
62 throw 'Skipped: no connection to the X server'
63 endif
64 " ignore other errors
65 endtry
66 endif
67endfunc
68
69func s:EndRemoteVim(name, job)
70 eval remote_send(a:name, "\<Esc>:qa!\<CR>")
71 try
72 call WaitForAssert({-> assert_equal("dead", job_status(a:job))})
73 finally
74 if job_status(a:job) != 'dead'
75 call assert_report('Vim instance did not exit')
76 call job_stop(a:job, 'kill')
77 endif
78 endtry
79endfunc
80
81func Test_wayland_startup()
82 call s:PreTest()
83 call s:CheckXConnection()
84
85 let l:name = 'WLVIMTEST'
86 let l:cmd = GetVimCommand() .. ' --servername ' .. l:name
87 let l:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
88
89 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
90 call WaitForAssert({-> assert_match(name, serverlist())})
91
92 call WaitForAssert({-> assert_equal($WAYLAND_DISPLAY,
93 \ remote_expr(l:name, 'v:wayland_display'))})
94
95 call s:EndRemoteVim(l:name, l:job)
96
97 " When $WAYLAND_DISPLAY is invalid
98 let l:job = job_start(cmd, { 'stoponexit': 'kill', 'out_io': 'null',
99 \ 'env': {'WAYLAND_DISPLAY': 'UNKNOWN'}})
100
101 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
102 call WaitForAssert({-> assert_match(name, serverlist())})
103
104 call assert_equal('', remote_expr(l:name, 'v:wayland_display'))
105 call s:EndRemoteVim(l:name, l:job)
106endfunc
107
108func Test_wayland_wlrestore()
109 call s:PreTest()
110
111 let l:wayland_display = StartWaylandCompositor()
112 let l:env_cmd = 'WAYLAND_DISPLAY=' .. l:wayland_display .. ' '
113
114 exe "wlrestore " .. l:wayland_display
115
116 call assert_equal(l:wayland_display, v:wayland_display)
117
118 " Check if calling wlrestore without arguments uses the existing wayland
119 " display.
120 wlrestore!
121 call assert_equal(l:wayland_display, v:wayland_display)
122
123 " If called with invalid display
124 wlrestore IDONTEXIST
125 call assert_equal("", v:wayland_display)
126
127 wlrestore!
128 call assert_equal("", v:wayland_display)
129
130 exe "wlrestore " .. l:wayland_display
131 call assert_equal(l:wayland_display, v:wayland_display)
132
133 " Actually check if connected display is different in case of regression with
134 " v:wayland_display
135 call system('wl-copy "1"')
136 call system(l:env_cmd .. 'wl-copy "2"')
137
138 call assert_equal('2', getreg('+'))
139
140 " Check if wlrestore doesn't disconnect the display if not nessecary by seeing
141 " if Vim doesn't lose the selection
142 call setreg('+', 'testing', 'c')
143
144 wlrestore
145 call assert_match('_VIM_TEXT', system(l:env_cmd .. 'wl-paste -l'))
146
147 " Forcibly disconnect and reconnect the display
148 wlrestore!
149 call assert_notmatch('_VIM_TEXT', system(l:env_cmd .. 'wl-paste -l'))
150
151 call EndWaylandCompositor(l:wayland_display)
152endfunc
153
154" Test behaviour when wayland display connection is lost
155func Test_wayland_connection_lost()
156 call s:PreTest()
157
158 let l:wayland_display = StartWaylandCompositor()
159 let l:env_cmd = 'WAYLAND_DISPLAY=' .. l:wayland_display .. ' '
160
161 exe "wlrestore " .. l:wayland_display
162
163 call system(l:env_cmd .. 'wl-copy test')
164
165 call assert_equal(l:wayland_display, v:wayland_display)
166 call assert_equal('test', getreg('+'))
167
168 call EndWaylandCompositor(l:wayland_display)
169
170 call assert_equal('', getreg('+'))
171 call assert_fails('put +', 'E353:')
172 call assert_fails('yank +', 'E1548:')
173endfunc
174
175" Basic paste tests
176func Test_wayland_paste()
177 call s:PreTest()
178
179 " Prevent 'Register changed while using it' error, guessing this works because
180 " it makes Vim lose the selection?
181 wlrestore!
182
183 " Regular selection
184 new
185
186 call system('wl-copy "TESTING"')
187 put +
188
189 call assert_equal("TESTING", getline(2))
190
191 call system('printf "LINE1\nLINE2\nLINE3" | wl-copy -n')
192 put +
193
194 call assert_equal(["LINE1", "LINE2", "LINE3"], getline(3, 5))
195 bw!
196
197 " Primary selection
198 new
199
200 call system('wl-copy -p "TESTING"')
201 put *
202
203 call assert_equal("TESTING", getline(2))
204
205 call system('printf "LINE1\nLINE2\nLINE3" | wl-copy -p')
206 put *
207
208 call assert_equal(["LINE1", "LINE2", "LINE3"], getline(3, 5))
209
210 bw!
211
212 " Check behaviour when selecton is cleared (empty)
213 call system('wl-copy --clear')
214 call assert_fails('put +', 'E353:')
215endfunc
216
217" Basic yank/copy tests
218func Test_wayland_yank()
219 call s:PreTest()
220
221 wlrestore!
222
223 new
224
225 call setline(1, 'testing')
226 yank +
227
228 call assert_equal("testing\n", system('wl-paste -n'))
229
230 call setline(2, 'testing2')
231 call setline(3, 'testing3')
232 exe '1,3yank +'
233
234 call assert_equal("testing\ntesting2\ntesting3\n", system('wl-paste -n'))
235
236 bw!
237
238 " Primary selection
239 new
240
241 call setline(1, 'testing')
242 yank *
243
244 call assert_equal("testing\n", system('wl-paste -p -n'))
245
246 call setline(2, 'testing2')
247 call setline(3, 'testing3')
248 exe '1,3yank *'
249
250 call assert_equal("testing\ntesting2\ntesting3\n", system('wl-paste -p -n'))
251
252 bw!
253endfunc
254
255
256" Check if correct mime types are advertised when we own the selection
257func Test_wayland_mime_types_correct()
258 call s:PreTest()
259
260 let l:mimes = [
261 \ '_VIMENC_TEXT',
262 \ '_VIM_TEXT',
263 \ 'text/plain;charset=utf-8',
264 \ 'text/plain',
265 \ 'UTF8_STRING',
266 \ 'STRING',
267 \ 'TEXT'
268 \ ]
269
270 call setreg('+', 'text', 'c')
271
272 for mime in split(system('wl-paste -l'), "\n")
273 if index(l:mimes, mime) == -1
274 call assert_report("'" .. mime .. "' is not a supported mime type")
275 endif
276 endfor
277
278 call setreg('*', 'text', 'c')
279
280 for mime in split(system('wl-paste -p -l'), "\n")
281 if index(l:mimes, mime) == -1
282 call assert_report("'" .. mime .. "' is not a supported mime type")
283 endif
284 endfor
285endfunc
286
287" Test if the _VIM_TEXT and _VIMENC_TEXT formats are correct:
288" _VIM_TEXT: preserves motion type (line/char/block wise)
289" _VIMENC_TEXT: same but also indicates the encoding type
290func Test_wayland_paste_vim_format_correct()
291 call s:PreTest()
292
293 " Vim doesn't support null characters in strings, so we use the -v flag of the
294 " cat program to show them in a printable way, if it is available.
295 call system("cat -v")
296 if v:shell_error != 0
297 throw 'Skipped: cat program does not have -v command-line flag'
298 endif
299
300 set encoding=utf-8
301
302 let l:GetSel = {type -> system('wl-paste -t ' .. type .. ' | cat -v')}
303 let l:GetSelP = {type -> system('wl-paste -p -t ' .. type .. ' | cat -v')}
304
305 " Regular selection
306 call setreg('+', 'text', 'c')
307 call assert_equal("^@text", l:GetSel('_VIM_TEXT'))
308 call setreg('+', 'text', 'c')
309 call assert_equal("^@utf-8^@text", l:GetSel('_VIMENC_TEXT'))
310
311 call setreg('+', 'text', 'l')
312 call assert_equal("^Atext\n", l:GetSel('_VIM_TEXT'))
313 call setreg('+', 'text', 'l')
314 call assert_equal("^Autf-8^@text\n",l:GetSel('_VIMENC_TEXT'))
315
316 call setreg('+', 'text', 'b')
317 call assert_equal("^Btext\n", l:GetSel('_VIM_TEXT'))
318 call setreg('+', 'text', 'b')
319 call assert_equal("^Butf-8^@text\n", l:GetSel('_VIMENC_TEXT'))
320
321 " Primary selection
322 call setreg('*', 'text', 'c')
323 call assert_equal("^@text", l:GetSelP('_VIM_TEXT'))
324 call setreg('*', 'text', 'c')
325 call assert_equal("^@utf-8^@text", l:GetSelP('_VIMENC_TEXT'))
326
327 call setreg('*', 'text', 'l')
328 call assert_equal("^Atext\n", l:GetSelP('_VIM_TEXT'))
329 call setreg('*', 'text', 'l')
330 call assert_equal("^Autf-8^@text\n",l:GetSelP('_VIMENC_TEXT'))
331
332 call setreg('*', 'text', 'b')
333 call assert_equal("^Btext\n", l:GetSelP('_VIM_TEXT'))
334 call setreg('*', 'text', 'b')
335 call assert_equal("^Butf-8^@text\n", l:GetSelP('_VIMENC_TEXT'))
336
337 set encoding&
338endfunc
339
340" Test checking if * and + registers are not the same
341func Test_wayland_plus_star_not_same()
342 call s:PreTest()
343 new
344
345 call system('wl-copy "regular"')
346 call system('wl-copy -p "primary"')
347
348 call assert_notequal(getreg('+'), getreg('*'))
349
350 " Check if when we are the source client
351 call setreg('+', 'REGULAR')
352 call setreg('*', 'PRIMARY')
353
354 call assert_notequal(system('wl-paste -p'), system('wl-paste'))
355
356 bw!
357endfunc
358
359" Test if autoselect option in 'clipboard' works properly for wayland
360func Test_wayland_autoselect_works()
361 call s:PreTest()
362 call s:CheckXConnection()
363
364 let l:lines =<< trim END
365 set cpm=wayland
366 set clipboard=autoselect
367
368 new
369 call setline(1, 'LINE 1')
370 call setline(2, 'LINE 2')
371 call setline(3, 'LINE 3')
372
373 call cursor(1, 1)
374 END
375
376 call writefile(l:lines, 'Wltester', 'D')
377
378 let l:name = 'WLVIMTEST'
379 let l:cmd = GetVimCommand() .. ' -S Wltester --servername ' .. l:name
380 let l:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
381
382 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
383 call WaitForAssert({-> assert_match(name, serverlist())})
384 1
385 call remote_send(l:name, "ve")
386 call WaitForAssert({-> assert_equal('LINE', system('wl-paste -p -n'))})
387
388 call remote_send(l:name, "w")
389 call WaitForAssert({-> assert_equal('LINE 1', system('wl-paste -p -n'))})
390
391 call remote_send(l:name, "V")
392 call WaitForAssert({-> assert_equal("LINE 1\n", system('wl-paste -p -n'))})
393
394 " Reset cursor
395 call remote_send(l:name, "\<Esc>:call cursor(1, 1)\<CR>")
396 call WaitForAssert({-> assert_equal("LINE 1\n", system('wl-paste -p -n'))})
397
398 " Test visual block mode
399 call remote_send(l:name, "\<C-q>jjj") " \<C-v> doesn't seem to work but \<C-q>
400 " does...
401
402 call WaitForAssert({-> assert_equal("L\nL\nL\n", system('wl-paste -p -n'))})
403
404 eval remote_send(l:name, "\<Esc>:qa!\<CR>")
405
406 try
407 call WaitForAssert({-> assert_equal("dead", job_status(l:job))})
408 finally
409 if job_status(l:job) != 'dead'
410 call assert_report('Vim instance did not exit')
411 call job_stop(l:job, 'kill')
412 endif
413 endtry
414endfunc
415
416" Check if the -Y flag works properly
417func Test_no_wayland_connect_cmd_flag()
418 call s:PreTest()
419 call s:CheckXConnection()
420
421 let l:name = 'WLFLAGVIMTEST'
422 let l:cmd = GetVimCommand() .. ' -Y --servername ' .. l:name
423 let l:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
424
425 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
426 call WaitForAssert({-> assert_match(name, serverlist())})
427
428 call WaitForAssert({->assert_equal('',
429 \ remote_expr(l:name, 'v:wayland_display'))})
430
431 call remote_send(l:name, ":wlrestore\<CR>")
432 call WaitForAssert({-> assert_equal('',
433 \ remote_expr(l:name, 'v:wayland_display'))})
434
435 call remote_send(l:name, ":wlrestore " .. $WAYLAND_DISPLAY .. "\<CR>")
436 call WaitForAssert({-> assert_equal('',
437 \ remote_expr(l:name, 'v:wayland_display'))})
438
439 call remote_send(l:name, ":wlrestore IDONTEXIST\<CR>")
440 call WaitForAssert({-> assert_equal('',
441 \ remote_expr(l:name, 'v:wayland_display'))})
442
443 eval remote_send(l:name, "\<Esc>:qa!\<CR>")
444 try
445 call WaitForAssert({-> assert_equal("dead", job_status(l:job))})
446 finally
447 if job_status(l:job) != 'dead'
448 call assert_report('Vim instance did not exit')
449 call job_stop(l:job, 'kill')
450 endif
451 endtry
452endfunc
453
454" Test behaviour when we do something like suspend Vim
455func Test_wayland_become_inactive()
456 call s:PreTest()
457 call s:CheckXConnection()
458
459 let l:name = 'WLLOSEVIMTEST'
460 let l:cmd = GetVimCommand() .. ' --servername ' .. l:name
461 let l:job = job_start(cmd, {
462 \ 'stoponexit': 'kill',
463 \ 'out_io': 'null',
464 \ })
465
466 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
467 call WaitForAssert({-> assert_match(name, serverlist())})
468
469 call remote_send(l:name, "iSOME TEXT\<Esc>\"+yy")
470
471 call WaitForAssert({-> assert_equal("SOME TEXT\n",
472 \ system('wl-paste -n'))})
473
474 call remote_send(l:name, "\<C-z>")
475
476 call WaitForAssert({-> assert_equal("Nothing is copied\n",
477 \ system('wl-paste -n'))})
478
479 eval remote_send(l:name, "\<Esc>:qa!\<CR>")
480 try
481 call WaitForAssert({-> assert_equal("dead", job_status(l:job))})
482 finally
483 if job_status(l:job) != 'dead'
484 call assert_report('Vim instance did not exit')
485 call job_stop(l:job, 'kill')
486 endif
487 endtry
488endfunc
489
490" Test wlseat option
491func Test_wayland_seat()
492 call s:PreTest()
493
494 " Don't know a way to create a virtual seat so just test using the existing
495 " one only
496 set wlseat=
497
498 call system('wl-copy "TESTING"')
499 call assert_equal('TESTING', getreg('+'))
500
501 set wlseat=UNKNOWN
502
503 call assert_equal('', getreg('+'))
504
505 set wlseat=idontexist
506
507 call assert_equal('', getreg('+'))
508
509 set wlseat=
510
511 call assert_equal('TESTING', getreg('+'))
512
513 set wlseat&
514endfunc
515
516" Test focus stealing
517func Test_wayland_focus_steal()
518 call s:PreTest()
519 call s:SetupFocusStealing()
520
521 call system('wl-copy regular')
522
523 call assert_equal('regular', getreg('+'))
524
525 call system('wl-copy -p primary')
526
527 call assert_equal('primary', getreg('*'))
528
529 call setreg('+', 'REGULAR')
530
531 call assert_equal('REGULAR', system('wl-paste -n'))
532
533 call setreg('*', 'PRIMARY')
534
535 call assert_equal('PRIMARY', system('wl-paste -p -n'))
536
537 call s:UnsetupFocusStealing()
538endfunc
539
540" Test when environment is not suitable for Wayland
541func Test_wayland_bad_environment()
542 call s:PreTest()
543 call s:CheckXConnection()
544
545 unlet $WAYLAND_DISPLAY
546
547 let l:old = $XDG_RUNTIME_DIR
548 unlet $XDG_RUNTIME_DIR
549
550 let l:name = 'WLVIMTEST'
551 let l:cmd = GetVimCommand() .. ' --servername ' .. l:name
552 let l:job = job_start(cmd, {
553 \ 'stoponexit': 'kill',
554 \ 'out_io': 'null',
555 \ })
556
557 call WaitForAssert({-> assert_equal("run", job_status(l:job))})
558 call WaitForAssert({-> assert_match(name, serverlist())})
559
560 call WaitForAssert({-> assert_equal('',
561 \ remote_expr(l:name, 'v:wayland_display'))})
562
563 eval remote_send(l:name, "\<Esc>:qa!\<CR>")
564 try
565 call WaitForAssert({-> assert_equal("dead", job_status(l:job))})
566 finally
567 if job_status(l:job) != 'dead'
568 call assert_report('Vim instance did not exit')
569 call job_stop(l:job, 'kill')
570 endif
571 endtry
572
573 let $XDG_RUNTIME_DIR = l:old
574endfunc
575
576" Test if Vim still works properly after losing the selection
577func Test_wayland_lost_selection()
578 call s:PreTest()
579
580 call setreg('+', 'regular')
581 call setreg('*', 'primary')
582
583 call assert_equal('regular', getreg('+'))
584 call assert_equal('primary', getreg('*'))
585
586 call system('wl-copy overwrite')
587 call system('wl-copy -p overwrite')
588
589 call assert_equal('overwrite', getreg('+'))
590 call assert_equal('overwrite', getreg('*'))
591
592 call setreg('+', 'regular')
593 call setreg('*', 'primary')
594
595 call assert_equal('regular', getreg('+'))
596 call assert_equal('primary', getreg('*'))
597
598 " Test focus stealing
599 call s:SetupFocusStealing()
600
601 call setreg('+', 'regular')
602 call setreg('*', 'primary')
603
604 call assert_equal('regular', getreg('+'))
605 call assert_equal('primary', getreg('*'))
606
607 call system('wl-copy overwrite')
608 call system('wl-copy -p overwrite')
609
610 call assert_equal('overwrite', getreg('+'))
611 call assert_equal('overwrite', getreg('*'))
612
613 call setreg('+', 'regular')
614 call setreg('*', 'primary')
615
616 call assert_equal('regular', getreg('+'))
617 call assert_equal('primary', getreg('*'))
618
619 call s:UnsetupFocusStealing()
620endfunc
621
622" Test when there are no supported mime types for the selecftion
623func Test_wayland_no_mime_types_supported()
624 call s:PreTest()
625
626 wlrestore!
627
628 call system('wl-copy -t image/png testing')
629
630 call assert_equal('', getreg('+'))
631 call assert_fails('put +', 'E353:')
632endfunc
633
634" Test behaviour with large selections in terms of data size
635func Test_wayland_handle_large_data()
636 call s:PreTest()
637
638 call writefile([''], 'data_file', 'D')
639 call writefile([''], 'data_file_cmp', 'D')
640 call system('yes c | head -5000000 > data_file') " ~ 10 MB
641 call system('wl-copy -t TEXT < data_file')
642
643 edit data_file_cmp
644
645 put! +
646
647 write
648
649 call system('truncate -s -1 data_file_cmp') " Remove newline at the end
650 call system('cmp --silent data_file data_file_cmp')
651 call assert_equal(0, v:shell_error)
652
653 " copy the text
654 call feedkeys('gg0v$G"+yy', 'x')
655 call system('wl-paste -n -t TEXT > data_file')
656
657 call system('cmp --silent data_file data_file_cmp')
658 call assert_equal(0, v:shell_error)
659
660 bw!
661endfunc
662
663" vim: shiftwidth=2 sts=2 expandtab