1" Tests for the terminal window.
2
3if !has('terminal')
4  finish
5endif
6
7source shared.vim
8source screendump.vim
9
10let s:python = PythonProg()
11
12" Open a terminal with a shell, assign the job to g:job and return the buffer
13" number.
14func Run_shell_in_terminal(options)
15  if has('win32')
16    let buf = term_start([&shell,'/k'], a:options)
17  else
18    let buf = term_start(&shell, a:options)
19  endif
20
21  let termlist = term_list()
22  call assert_equal(1, len(termlist))
23  call assert_equal(buf, termlist[0])
24
25  let g:job = term_getjob(buf)
26  call assert_equal(v:t_job, type(g:job))
27
28  let string = string({'job': term_getjob(buf)})
29  call assert_match("{'job': 'process \\d\\+ run'}", string)
30
31  return buf
32endfunc
33
34func Test_terminal_basic()
35  au TerminalOpen * let b:done = 'yes'
36  let buf = Run_shell_in_terminal({})
37
38  if has("unix")
39    call assert_match('^/dev/', job_info(g:job).tty_out)
40    call assert_match('^/dev/', term_gettty(''))
41  else
42    call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
43    call assert_match('^\\\\.\\pipe\\', term_gettty(''))
44  endif
45  call assert_equal('t', mode())
46  call assert_equal('yes', b:done)
47  call assert_match('%aR[^\n]*running]', execute('ls'))
48  call assert_match('%aR[^\n]*running]', execute('ls R'))
49  call assert_notmatch('%[^\n]*running]', execute('ls F'))
50  call assert_notmatch('%[^\n]*running]', execute('ls ?'))
51
52  call Stop_shell_in_terminal(buf)
53  call term_wait(buf)
54  call assert_equal('n', mode())
55  call assert_match('%aF[^\n]*finished]', execute('ls'))
56  call assert_match('%aF[^\n]*finished]', execute('ls F'))
57  call assert_notmatch('%[^\n]*finished]', execute('ls R'))
58  call assert_notmatch('%[^\n]*finished]', execute('ls ?'))
59
60  " closing window wipes out the terminal buffer a with finished job
61  close
62  call assert_equal("", bufname(buf))
63
64  au! TerminalOpen
65  unlet g:job
66endfunc
67
68func Test_terminal_make_change()
69  let buf = Run_shell_in_terminal({})
70  call Stop_shell_in_terminal(buf)
71  call term_wait(buf)
72
73  setlocal modifiable
74  exe "normal Axxx\<Esc>"
75  call assert_fails(buf . 'bwipe', 'E517')
76  undo
77
78  exe buf . 'bwipe'
79  unlet g:job
80endfunc
81
82func Test_terminal_wipe_buffer()
83  let buf = Run_shell_in_terminal({})
84  call assert_fails(buf . 'bwipe', 'E517')
85  exe buf . 'bwipe!'
86  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
87  call assert_equal("", bufname(buf))
88
89  unlet g:job
90endfunc
91
92func Test_terminal_split_quit()
93  let buf = Run_shell_in_terminal({})
94  call term_wait(buf)
95  split
96  quit!
97  call term_wait(buf)
98  sleep 50m
99  call assert_equal('run', job_status(g:job))
100
101  quit!
102  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
103
104  exe buf . 'bwipe'
105  unlet g:job
106endfunc
107
108func Test_terminal_hide_buffer()
109  let buf = Run_shell_in_terminal({})
110  setlocal bufhidden=hide
111  quit
112  for nr in range(1, winnr('$'))
113    call assert_notequal(winbufnr(nr), buf)
114  endfor
115  call assert_true(bufloaded(buf))
116  call assert_true(buflisted(buf))
117
118  exe 'split ' . buf . 'buf'
119  call Stop_shell_in_terminal(buf)
120  exe buf . 'bwipe'
121
122  unlet g:job
123endfunc
124
125func s:Nasty_exit_cb(job, st)
126  exe g:buf . 'bwipe!'
127  let g:buf = 0
128endfunc
129
130func Get_cat_123_cmd()
131  if has('win32')
132    return 'cmd /c "cls && color 2 && echo 123"'
133  else
134    call writefile(["\<Esc>[32m123"], 'Xtext')
135    return "cat Xtext"
136  endif
137endfunc
138
139func Test_terminal_nasty_cb()
140  let cmd = Get_cat_123_cmd()
141  let g:buf = term_start(cmd, {'exit_cb': function('s:Nasty_exit_cb')})
142  let g:job = term_getjob(g:buf)
143
144  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
145  call WaitForAssert({-> assert_equal(0, g:buf)})
146  unlet g:buf
147  unlet g:job
148  call delete('Xtext')
149endfunc
150
151func Check_123(buf)
152  let l = term_scrape(a:buf, 0)
153  call assert_true(len(l) == 0)
154  let l = term_scrape(a:buf, 999)
155  call assert_true(len(l) == 0)
156  let l = term_scrape(a:buf, 1)
157  call assert_true(len(l) > 0)
158  call assert_equal('1', l[0].chars)
159  call assert_equal('2', l[1].chars)
160  call assert_equal('3', l[2].chars)
161  call assert_equal('#00e000', l[0].fg)
162  if has('win32')
163    " On Windows 'background' always defaults to dark, even though the terminal
164    " may use a light background.  Therefore accept both white and black.
165    call assert_match('#ffffff\|#000000', l[0].bg)
166  else
167    if &background == 'light'
168      call assert_equal('#ffffff', l[0].bg)
169    else
170      call assert_equal('#000000', l[0].bg)
171    endif
172  endif
173
174  let l = term_getline(a:buf, -1)
175  call assert_equal('', l)
176  let l = term_getline(a:buf, 0)
177  call assert_equal('', l)
178  let l = term_getline(a:buf, 999)
179  call assert_equal('', l)
180  let l = term_getline(a:buf, 1)
181  call assert_equal('123', l)
182endfunc
183
184func Test_terminal_scrape_123()
185  let cmd = Get_cat_123_cmd()
186  let buf = term_start(cmd)
187
188  let termlist = term_list()
189  call assert_equal(1, len(termlist))
190  call assert_equal(buf, termlist[0])
191
192  " Nothing happens with invalid buffer number
193  call term_wait(1234)
194
195  call term_wait(buf)
196  " On MS-Windows we first get a startup message of two lines, wait for the
197  " "cls" to happen, after that we have one line with three characters.
198  call WaitForAssert({-> assert_equal(3, len(term_scrape(buf, 1)))})
199  call Check_123(buf)
200
201  " Must still work after the job ended.
202  let job = term_getjob(buf)
203  call WaitForAssert({-> assert_equal("dead", job_status(job))})
204  call term_wait(buf)
205  call Check_123(buf)
206
207  exe buf . 'bwipe'
208  call delete('Xtext')
209endfunc
210
211func Test_terminal_scrape_multibyte()
212  if !has('multi_byte')
213    return
214  endif
215  call writefile(["léttまrs"], 'Xtext')
216  if has('win32')
217    " Run cmd with UTF-8 codepage to make the type command print the expected
218    " multibyte characters.
219    let buf = term_start("cmd /K chcp 65001")
220    call term_sendkeys(buf, "type Xtext\<CR>")
221    call term_sendkeys(buf, "exit\<CR>")
222    let line = 4
223  else
224    let buf = term_start("cat Xtext")
225    let line = 1
226  endif
227
228  call WaitFor({-> len(term_scrape(buf, line)) >= 7 && term_scrape(buf, line)[0].chars == "l"})
229  let l = term_scrape(buf, line)
230  call assert_true(len(l) >= 7)
231  call assert_equal('l', l[0].chars)
232  call assert_equal('é', l[1].chars)
233  call assert_equal(1, l[1].width)
234  call assert_equal('t', l[2].chars)
235  call assert_equal('t', l[3].chars)
236  call assert_equal('ま', l[4].chars)
237  call assert_equal(2, l[4].width)
238  call assert_equal('r', l[5].chars)
239  call assert_equal('s', l[6].chars)
240
241  let job = term_getjob(buf)
242  call WaitForAssert({-> assert_equal("dead", job_status(job))})
243  call term_wait(buf)
244
245  exe buf . 'bwipe'
246  call delete('Xtext')
247endfunc
248
249func Test_terminal_scroll()
250  call writefile(range(1, 200), 'Xtext')
251  if has('win32')
252    let cmd = 'cmd /c "type Xtext"'
253  else
254    let cmd = "cat Xtext"
255  endif
256  let buf = term_start(cmd)
257
258  let job = term_getjob(buf)
259  call WaitForAssert({-> assert_equal("dead", job_status(job))})
260  call term_wait(buf)
261  if has('win32')
262    " TODO: this should not be needed
263    sleep 100m
264  endif
265
266  let scrolled = term_getscrolled(buf)
267  call assert_equal('1', getline(1))
268  call assert_equal('1', term_getline(buf, 1 - scrolled))
269  call assert_equal('49', getline(49))
270  call assert_equal('49', term_getline(buf, 49 - scrolled))
271  call assert_equal('200', getline(200))
272  call assert_equal('200', term_getline(buf, 200 - scrolled))
273
274  exe buf . 'bwipe'
275  call delete('Xtext')
276endfunc
277
278func Test_terminal_scrollback()
279  let buf = Run_shell_in_terminal({'term_rows': 15})
280  set termwinscroll=100
281  call writefile(range(150), 'Xtext')
282  if has('win32')
283    call term_sendkeys(buf, "type Xtext\<CR>")
284  else
285    call term_sendkeys(buf, "cat Xtext\<CR>")
286  endif
287  let rows = term_getsize(buf)[0]
288  " On MS-Windows there is an empty line, check both last line and above it.
289  call WaitForAssert({-> assert_match( '149', term_getline(buf, rows - 1) . term_getline(buf, rows - 2))})
290  let lines = line('$')
291  call assert_inrange(91, 100, lines)
292
293  call Stop_shell_in_terminal(buf)
294  call term_wait(buf)
295  exe buf . 'bwipe'
296  set termwinscroll&
297endfunc
298
299func Test_terminal_size()
300  let cmd = Get_cat_123_cmd()
301
302  exe 'terminal ++rows=5 ' . cmd
303  let size = term_getsize('')
304  bwipe!
305  call assert_equal(5, size[0])
306
307  call term_start(cmd, {'term_rows': 6})
308  let size = term_getsize('')
309  bwipe!
310  call assert_equal(6, size[0])
311
312  vsplit
313  exe 'terminal ++rows=5 ++cols=33 ' . cmd
314  call assert_equal([5, 33], term_getsize(''))
315
316  call term_setsize('', 6, 0)
317  call assert_equal([6, 33], term_getsize(''))
318
319  call term_setsize('', 0, 35)
320  call assert_equal([6, 35], term_getsize(''))
321
322  call term_setsize('', 7, 30)
323  call assert_equal([7, 30], term_getsize(''))
324
325  bwipe!
326  call assert_fails("call term_setsize('', 7, 30)", "E955:")
327
328  call term_start(cmd, {'term_rows': 6, 'term_cols': 36})
329  let size = term_getsize('')
330  bwipe!
331  call assert_equal([6, 36], size)
332
333  exe 'vertical terminal ++cols=20 ' . cmd
334  let size = term_getsize('')
335  bwipe!
336  call assert_equal(20, size[1])
337
338  call term_start(cmd, {'vertical': 1, 'term_cols': 26})
339  let size = term_getsize('')
340  bwipe!
341  call assert_equal(26, size[1])
342
343  split
344  exe 'vertical terminal ++rows=6 ++cols=20 ' . cmd
345  let size = term_getsize('')
346  bwipe!
347  call assert_equal([6, 20], size)
348
349  call term_start(cmd, {'vertical': 1, 'term_rows': 7, 'term_cols': 27})
350  let size = term_getsize('')
351  bwipe!
352  call assert_equal([7, 27], size)
353
354  call delete('Xtext')
355endfunc
356
357func Test_terminal_curwin()
358  let cmd = Get_cat_123_cmd()
359  call assert_equal(1, winnr('$'))
360
361  split dummy
362  exe 'terminal ++curwin ' . cmd
363  call assert_equal(2, winnr('$'))
364  bwipe!
365
366  split dummy
367  call term_start(cmd, {'curwin': 1})
368  call assert_equal(2, winnr('$'))
369  bwipe!
370
371  split dummy
372  call setline(1, 'change')
373  call assert_fails('terminal ++curwin ' . cmd, 'E37:')
374  call assert_equal(2, winnr('$'))
375  exe 'terminal! ++curwin ' . cmd
376  call assert_equal(2, winnr('$'))
377  bwipe!
378
379  split dummy
380  call setline(1, 'change')
381  call assert_fails("call term_start(cmd, {'curwin': 1})", 'E37:')
382  call assert_equal(2, winnr('$'))
383  bwipe!
384
385  split dummy
386  bwipe!
387  call delete('Xtext')
388endfunc
389
390func s:get_sleep_cmd()
391  if s:python != ''
392    let cmd = s:python . " test_short_sleep.py"
393    " 500 was not enough for Travis
394    let waittime = 900
395  else
396    echo 'This will take five seconds...'
397    let waittime = 2000
398    if has('win32')
399      let cmd = $windir . '\system32\timeout.exe 1'
400    else
401      let cmd = 'sleep 1'
402    endif
403  endif
404  return [cmd, waittime]
405endfunc
406
407func Test_terminal_finish_open_close()
408  call assert_equal(1, winnr('$'))
409
410  let [cmd, waittime] = s:get_sleep_cmd()
411
412  " shell terminal closes automatically
413  terminal
414  let buf = bufnr('%')
415  call assert_equal(2, winnr('$'))
416  " Wait for the shell to display a prompt
417  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
418  call Stop_shell_in_terminal(buf)
419  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
420
421  " shell terminal that does not close automatically
422  terminal ++noclose
423  let buf = bufnr('%')
424  call assert_equal(2, winnr('$'))
425  " Wait for the shell to display a prompt
426  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
427  call Stop_shell_in_terminal(buf)
428  call assert_equal(2, winnr('$'))
429  quit
430  call assert_equal(1, winnr('$'))
431
432  exe 'terminal ++close ' . cmd
433  call assert_equal(2, winnr('$'))
434  wincmd p
435  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
436
437  call term_start(cmd, {'term_finish': 'close'})
438  call assert_equal(2, winnr('$'))
439  wincmd p
440  call WaitForAssert({-> assert_equal(1, winnr('$'))}, waittime)
441  call assert_equal(1, winnr('$'))
442
443  exe 'terminal ++open ' . cmd
444  close!
445  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
446  bwipe
447
448  call term_start(cmd, {'term_finish': 'open'})
449  close!
450  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
451  bwipe
452
453  exe 'terminal ++hidden ++open ' . cmd
454  call assert_equal(1, winnr('$'))
455  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
456  bwipe
457
458  call term_start(cmd, {'term_finish': 'open', 'hidden': 1})
459  call assert_equal(1, winnr('$'))
460  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
461  bwipe
462
463  call assert_fails("call term_start(cmd, {'term_opencmd': 'open'})", 'E475:')
464  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %x'})", 'E475:')
465  call assert_fails("call term_start(cmd, {'term_opencmd': 'split %d and %s'})", 'E475:')
466  call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:')
467
468  call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'})
469  close!
470  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
471  call assert_equal(4, winheight(0))
472  bwipe
473endfunc
474
475func Test_terminal_cwd()
476  if !executable('pwd')
477    return
478  endif
479  call mkdir('Xdir')
480  let buf = term_start('pwd', {'cwd': 'Xdir'})
481  call WaitForAssert({-> assert_equal('Xdir', fnamemodify(getline(1), ":t"))})
482
483  exe buf . 'bwipe'
484  call delete('Xdir', 'rf')
485endfunc
486
487func Test_terminal_cwd_failure()
488  " Case 1: Provided directory is not actually a directory.  Attempt to make
489  " the file executable as well.
490  call writefile([], 'Xfile')
491  call setfperm('Xfile', 'rwx------')
492  call assert_fails("call term_start(&shell, {'cwd': 'Xfile'})", 'E475:')
493  call delete('Xfile')
494
495  " Case 2: Directory does not exist.
496  call assert_fails("call term_start(&shell, {'cwd': 'Xdir'})", 'E475:')
497
498  " Case 3: Directory exists but is not accessible.
499  " Skip this for root, it will be accessible anyway.
500  if $USER != 'root'
501    call mkdir('XdirNoAccess', '', '0600')
502    " return early if the directory permissions could not be set properly
503    if getfperm('XdirNoAccess')[2] == 'x'
504      call delete('XdirNoAccess', 'rf')
505      return
506    endif
507    call assert_fails("call term_start(&shell, {'cwd': 'XdirNoAccess'})", 'E475:')
508    call delete('XdirNoAccess', 'rf')
509  endif
510endfunc
511
512func Test_terminal_servername()
513  if !has('clientserver')
514    return
515  endif
516  call s:test_environment("VIM_SERVERNAME", v:servername)
517endfunc
518
519func Test_terminal_version()
520  call s:test_environment("VIM_TERMINAL", string(v:version))
521endfunc
522
523func s:test_environment(name, value)
524  let buf = Run_shell_in_terminal({})
525  " Wait for the shell to display a prompt
526  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
527  if has('win32')
528    call term_sendkeys(buf, "echo %" . a:name . "%\r")
529  else
530    call term_sendkeys(buf, "echo $" . a:name . "\r")
531  endif
532  call term_wait(buf)
533  call Stop_shell_in_terminal(buf)
534  call WaitForAssert({-> assert_equal(a:value, getline(2))})
535
536  exe buf . 'bwipe'
537  unlet buf
538endfunc
539
540func Test_terminal_env()
541  let buf = Run_shell_in_terminal({'env': {'TESTENV': 'correct'}})
542  " Wait for the shell to display a prompt
543  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
544  if has('win32')
545    call term_sendkeys(buf, "echo %TESTENV%\r")
546  else
547    call term_sendkeys(buf, "echo $TESTENV\r")
548  endif
549  call term_wait(buf)
550  call Stop_shell_in_terminal(buf)
551  call WaitForAssert({-> assert_equal('correct', getline(2))})
552
553  exe buf . 'bwipe'
554endfunc
555
556func Test_terminal_list_args()
557  let buf = term_start([&shell, &shellcmdflag, 'echo "123"'])
558  call assert_fails(buf . 'bwipe', 'E517')
559  exe buf . 'bwipe!'
560  call assert_equal("", bufname(buf))
561endfunction
562
563func Test_terminal_noblock()
564  let buf = term_start(&shell)
565  if has('mac')
566    " The shell or something else has a problem dealing with more than 1000
567    " characters at the same time.
568    let len = 1000
569  else
570    let len = 5000
571  endif
572
573  for c in ['a','b','c','d','e','f','g','h','i','j','k']
574    call term_sendkeys(buf, 'echo ' . repeat(c, len) . "\<cr>")
575  endfor
576  call term_sendkeys(buf, "echo done\<cr>")
577
578  " On MS-Windows there is an extra empty line below "done".  Find "done" in
579  " the last-but-one or the last-but-two line.
580  let lnum = term_getsize(buf)[0] - 1
581  call WaitFor({-> term_getline(buf, lnum) =~ "done" || term_getline(buf, lnum - 1) =~ "done"}, 10000)
582  let line = term_getline(buf, lnum)
583  if line !~ 'done'
584    let line = term_getline(buf, lnum - 1)
585  endif
586  call assert_match('done', line)
587
588  let g:job = term_getjob(buf)
589  call Stop_shell_in_terminal(buf)
590  call term_wait(buf)
591  unlet g:job
592  bwipe
593endfunc
594
595func Test_terminal_write_stdin()
596  if !executable('wc')
597    throw 'skipped: wc command not available'
598  endif
599  if has('win32')
600    " TODO: enable once writing to stdin works on MS-Windows
601    return
602  endif
603  new
604  call setline(1, ['one', 'two', 'three'])
605  %term wc
606  call WaitForAssert({-> assert_match('3', getline("$"))})
607  let nrs = split(getline('$'))
608  call assert_equal(['3', '3', '14'], nrs)
609  bwipe
610
611  new
612  call setline(1, ['one', 'two', 'three', 'four'])
613  2,3term wc
614  call WaitForAssert({-> assert_match('2', getline("$"))})
615  let nrs = split(getline('$'))
616  call assert_equal(['2', '2', '10'], nrs)
617  bwipe
618
619  if executable('python')
620    new
621    call setline(1, ['print("hello")'])
622    1term ++eof=exit() python
623    " MS-Windows echoes the input, Unix doesn't.
624    call WaitFor('getline("$") =~ "exit" || getline(1) =~ "hello"')
625    if getline(1) =~ 'hello'
626      call assert_equal('hello', getline(1))
627    else
628      call assert_equal('hello', getline(line('$') - 1))
629    endif
630    bwipe
631
632    if has('win32')
633      new
634      call setline(1, ['print("hello")'])
635      1term ++eof=<C-Z> python
636      call WaitForAssert({-> assert_match('Z', getline("$"))})
637      call assert_equal('hello', getline(line('$') - 1))
638      bwipe
639    endif
640  endif
641
642  bwipe!
643endfunc
644
645func Test_terminal_no_cmd()
646  " Todo: make this work in the GUI
647  if !has('gui_running')
648    return
649  endif
650  let buf = term_start('NONE', {})
651  call assert_notequal(0, buf)
652
653  let pty = job_info(term_getjob(buf))['tty_out']
654  call assert_notequal('', pty)
655  if has('win32')
656    silent exe '!start cmd /c "echo look here > ' . pty . '"'
657  else
658    call system('echo "look here" > ' . pty)
659  endif
660  call WaitForAssert({-> assert_match('look here', term_getline(buf, 1))})
661
662  bwipe!
663endfunc
664
665func Test_terminal_special_chars()
666  " this file name only works on Unix
667  if !has('unix')
668    return
669  endif
670  call mkdir('Xdir with spaces')
671  call writefile(['x'], 'Xdir with spaces/quoted"file')
672  term ls Xdir\ with\ spaces/quoted\"file
673  call WaitForAssert({-> assert_match('quoted"file', term_getline('', 1))})
674  call term_wait('')
675
676  call delete('Xdir with spaces', 'rf')
677  bwipe
678endfunc
679
680func Test_terminal_wrong_options()
681  call assert_fails('call term_start(&shell, {
682	\ "in_io": "file",
683	\ "in_name": "xxx",
684	\ "out_io": "file",
685	\ "out_name": "xxx",
686	\ "err_io": "file",
687	\ "err_name": "xxx"
688	\ })', 'E474:')
689  call assert_fails('call term_start(&shell, {
690	\ "out_buf": bufnr("%")
691	\ })', 'E474:')
692  call assert_fails('call term_start(&shell, {
693	\ "err_buf": bufnr("%")
694	\ })', 'E474:')
695endfunc
696
697func Test_terminal_redir_file()
698  let cmd = Get_cat_123_cmd()
699  let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'})
700  call term_wait(buf)
701  call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))})
702  call assert_match('123', readfile('Xfile')[0])
703  let g:job = term_getjob(buf)
704  call WaitForAssert({-> assert_equal("dead", job_status(g:job))})
705  call delete('Xfile')
706  bwipe
707
708  if has('unix')
709    call writefile(['one line'], 'Xfile')
710    let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
711    call term_wait(buf)
712    call WaitForAssert({-> assert_equal('one line', term_getline(buf, 1))})
713    let g:job = term_getjob(buf)
714    call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
715    bwipe
716    call delete('Xfile')
717  endif
718endfunc
719
720func TerminalTmap(remap)
721  let buf = Run_shell_in_terminal({})
722  call assert_equal('t', mode())
723
724  if a:remap
725    tmap 123 456
726  else
727    tnoremap 123 456
728  endif
729  " don't use abcde, it's an existing command
730  tmap 456 abxde
731  call assert_equal('456', maparg('123', 't'))
732  call assert_equal('abxde', maparg('456', 't'))
733  call feedkeys("123", 'tx')
734  call WaitForAssert({-> assert_match('abxde\|456', term_getline(buf, term_getcursor(buf)[0]))})
735  let lnum = term_getcursor(buf)[0]
736  if a:remap
737    call assert_match('abxde', term_getline(buf, lnum))
738  else
739    call assert_match('456', term_getline(buf, lnum))
740  endif
741
742  call term_sendkeys(buf, "\r")
743  call Stop_shell_in_terminal(buf)
744  call term_wait(buf)
745
746  tunmap 123
747  tunmap 456
748  call assert_equal('', maparg('123', 't'))
749  close
750  unlet g:job
751endfunc
752
753func Test_terminal_tmap()
754  call TerminalTmap(1)
755  call TerminalTmap(0)
756endfunc
757
758func Test_terminal_wall()
759  let buf = Run_shell_in_terminal({})
760  wall
761  call Stop_shell_in_terminal(buf)
762  call term_wait(buf)
763  exe buf . 'bwipe'
764  unlet g:job
765endfunc
766
767func Test_terminal_wqall()
768  let buf = Run_shell_in_terminal({})
769  call assert_fails('wqall', 'E948')
770  call Stop_shell_in_terminal(buf)
771  call term_wait(buf)
772  exe buf . 'bwipe'
773  unlet g:job
774endfunc
775
776func Test_terminal_composing_unicode()
777  let save_enc = &encoding
778  set encoding=utf-8
779
780  if has('win32')
781    let cmd = "cmd /K chcp 65001"
782    let lnum = [3, 6, 9]
783  else
784    let cmd = &shell
785    let lnum = [1, 3, 5]
786  endif
787
788  enew
789  let buf = term_start(cmd, {'curwin': bufnr('')})
790  let g:job = term_getjob(buf)
791  call term_wait(buf, 50)
792
793  if has('win32')
794    call assert_equal('cmd', job_info(g:job).cmd[0])
795  else
796    call assert_equal(&shell, job_info(g:job).cmd[0])
797  endif
798
799  " ascii + composing
800  let txt = "a\u0308bc"
801  call term_sendkeys(buf, "echo " . txt . "\r")
802  call term_wait(buf, 50)
803  call assert_match("echo " . txt, term_getline(buf, lnum[0]))
804  call assert_equal(txt, term_getline(buf, lnum[0] + 1))
805  let l = term_scrape(buf, lnum[0] + 1)
806  call assert_equal("a\u0308", l[0].chars)
807  call assert_equal("b", l[1].chars)
808  call assert_equal("c", l[2].chars)
809
810  " multibyte + composing
811  let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099"
812  call term_sendkeys(buf, "echo " . txt . "\r")
813  call term_wait(buf, 50)
814  call assert_match("echo " . txt, term_getline(buf, lnum[1]))
815  call assert_equal(txt, term_getline(buf, lnum[1] + 1))
816  let l = term_scrape(buf, lnum[1] + 1)
817  call assert_equal("\u304b\u3099", l[0].chars)
818  call assert_equal("\u304e", l[1].chars)
819  call assert_equal("\u304f\u3099", l[2].chars)
820  call assert_equal("\u3052", l[3].chars)
821  call assert_equal("\u3053\u3099", l[4].chars)
822
823  " \u00a0 + composing
824  let txt = "abc\u00a0\u0308"
825  call term_sendkeys(buf, "echo " . txt . "\r")
826  call term_wait(buf, 50)
827  call assert_match("echo " . txt, term_getline(buf, lnum[2]))
828  call assert_equal(txt, term_getline(buf, lnum[2] + 1))
829  let l = term_scrape(buf, lnum[2] + 1)
830  call assert_equal("\u00a0\u0308", l[3].chars)
831
832  call term_sendkeys(buf, "exit\r")
833  call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
834  bwipe!
835  unlet g:job
836  let &encoding = save_enc
837endfunc
838
839func Test_terminal_aucmd_on_close()
840  fun Nop()
841    let s:called = 1
842  endfun
843
844  aug repro
845      au!
846      au BufWinLeave * call Nop()
847  aug END
848
849  let [cmd, waittime] = s:get_sleep_cmd()
850
851  call assert_equal(1, winnr('$'))
852  new
853  call setline(1, ['one', 'two'])
854  exe 'term ++close ' . cmd
855  wincmd p
856  call WaitForAssert({-> assert_equal(2, winnr('$'))}, waittime)
857  call assert_equal(1, s:called)
858  bwipe!
859
860  unlet s:called
861  au! repro
862  delfunc Nop
863endfunc
864
865func Test_terminal_term_start_empty_command()
866  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
867  call assert_fails(cmd, 'E474')
868  let cmd = "call term_start('', {'curwin' : 1, 'term_finish' : 'close'})"
869  call assert_fails(cmd, 'E474')
870  let cmd = "call term_start({}, {'curwin' : 1, 'term_finish' : 'close'})"
871  call assert_fails(cmd, 'E474')
872  let cmd = "call term_start(0, {'curwin' : 1, 'term_finish' : 'close'})"
873  call assert_fails(cmd, 'E474')
874endfunc
875
876func Test_terminal_response_to_control_sequence()
877  if !has('unix')
878    return
879  endif
880
881  let buf = Run_shell_in_terminal({})
882  call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
883
884  call term_sendkeys(buf, "cat\<CR>")
885  call WaitForAssert({-> assert_match('cat', term_getline(buf, 1))})
886
887  " Request the cursor position.
888  call term_sendkeys(buf, "\x1b[6n\<CR>")
889
890  " Wait for output from tty to display, below an empty line.
891  call WaitForAssert({-> assert_match('3;1R', term_getline(buf, 4))})
892
893  " End "cat" gently.
894  call term_sendkeys(buf, "\<CR>\<C-D>")
895
896  call Stop_shell_in_terminal(buf)
897  exe buf . 'bwipe'
898  unlet g:job
899endfunc
900
901" Run Vim, start a terminal in that Vim with the kill argument,
902" :qall works.
903func Run_terminal_qall_kill(line1, line2)
904  " 1. Open a terminal window and wait for the prompt to appear
905  " 2. set kill using term_setkill()
906  " 3. make Vim exit, it will kill the shell
907  let after = [
908	\ a:line1,
909	\ 'let buf = bufnr("%")',
910	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
911	\ '  sleep 10m',
912	\ 'endwhile',
913	\ a:line2,
914	\ 'au VimLeavePre * call writefile(["done"], "Xdone")',
915	\ 'qall',
916	\ ]
917  if !RunVim([], after, '')
918    return
919  endif
920  call assert_equal("done", readfile("Xdone")[0])
921  call delete("Xdone")
922endfunc
923
924" Run Vim in a terminal, then start a terminal in that Vim with a kill
925" argument, check that :qall works.
926func Test_terminal_qall_kill_arg()
927  call Run_terminal_qall_kill('term ++kill=kill', '')
928endfunc
929
930" Run Vim, start a terminal in that Vim, set the kill argument with
931" term_setkill(), check that :qall works.
932func Test_terminal_qall_kill_func()
933  call Run_terminal_qall_kill('term', 'call term_setkill(buf, "kill")')
934endfunc
935
936" Run Vim, start a terminal in that Vim without the kill argument,
937" check that :qall does not exit, :qall! does.
938func Test_terminal_qall_exit()
939  let after = [
940	\ 'term',
941	\ 'let buf = bufnr("%")',
942	\ 'while term_getline(buf, 1) =~ "^\\s*$"',
943	\ '  sleep 10m',
944	\ 'endwhile',
945	\ 'set nomore',
946	\ 'au VimLeavePre * call writefile(["too early"], "Xdone")',
947	\ 'qall',
948	\ 'au! VimLeavePre * exe buf . "bwipe!" | call writefile(["done"], "Xdone")',
949	\ 'cquit',
950	\ ]
951  if !RunVim([], after, '')
952    return
953  endif
954  call assert_equal("done", readfile("Xdone")[0])
955  call delete("Xdone")
956endfunc
957
958" Run Vim in a terminal, then start a terminal in that Vim without a kill
959" argument, check that :confirm qall works.
960func Test_terminal_qall_prompt()
961  if !CanRunVimInTerminal()
962    return
963  endif
964  let buf = RunVimInTerminal('', {})
965
966  " Open a terminal window and wait for the prompt to appear
967  call term_sendkeys(buf, ":term\<CR>")
968  call WaitForAssert({-> assert_match('\[running]', term_getline(buf, 10))})
969  call WaitForAssert({-> assert_notmatch('^\s*$', term_getline(buf, 1))})
970
971  " make Vim exit, it will prompt to kill the shell
972  call term_sendkeys(buf, "\<C-W>:confirm qall\<CR>")
973  call WaitForAssert({-> assert_match('ancel:', term_getline(buf, 20))})
974  call term_sendkeys(buf, "y")
975  call WaitForAssert({-> assert_equal('finished', term_getstatus(buf))})
976
977  " close the terminal window where Vim was running
978  quit
979endfunc
980
981func Test_terminal_open_autocmd()
982  augroup repro
983    au!
984    au TerminalOpen * let s:called += 1
985  augroup END
986
987  let s:called = 0
988
989  " Open a terminal window with :terminal
990  terminal
991  call assert_equal(1, s:called)
992  bwipe!
993
994  " Open a terminal window with term_start()
995  call term_start(&shell)
996  call assert_equal(2, s:called)
997  bwipe!
998
999  " Open a hidden terminal buffer with :terminal
1000  terminal ++hidden
1001  call assert_equal(3, s:called)
1002  for buf in term_list()
1003    exe buf . "bwipe!"
1004  endfor
1005
1006  " Open a hidden terminal buffer with term_start()
1007  let buf = term_start(&shell, {'hidden': 1})
1008  call assert_equal(4, s:called)
1009  exe buf . "bwipe!"
1010
1011  unlet s:called
1012  au! repro
1013endfunction
1014
1015func Check_dump01(off)
1016  call assert_equal('one two three four five', trim(getline(a:off + 1)))
1017  call assert_equal('~           Select Word', trim(getline(a:off + 7)))
1018  call assert_equal(':popup PopUp', trim(getline(a:off + 20)))
1019endfunc
1020
1021func Test_terminal_dumpwrite_composing()
1022  if !CanRunVimInTerminal()
1023    return
1024  endif
1025  let save_enc = &encoding
1026  set encoding=utf-8
1027  call assert_equal(1, winnr('$'))
1028
1029  let text = " a\u0300 e\u0302 o\u0308"
1030  call writefile([text], 'Xcomposing')
1031  let buf = RunVimInTerminal('--cmd "set encoding=utf-8" Xcomposing', {})
1032  call WaitForAssert({-> assert_match(text, term_getline(buf, 1))})
1033  call term_dumpwrite(buf, 'Xdump')
1034  let dumpline = readfile('Xdump')[0]
1035  call assert_match('|à| |ê| |ö', dumpline)
1036
1037  call StopVimInTerminal(buf)
1038  call delete('Xcomposing')
1039  call delete('Xdump')
1040  let &encoding = save_enc
1041endfunc
1042
1043" just testing basic functionality.
1044func Test_terminal_dumpload()
1045  call assert_equal(1, winnr('$'))
1046  call term_dumpload('dumps/Test_popup_command_01.dump')
1047  call assert_equal(2, winnr('$'))
1048  call assert_equal(20, line('$'))
1049  call Check_dump01(0)
1050  quit
1051endfunc
1052
1053func Test_terminal_dumpdiff()
1054  call assert_equal(1, winnr('$'))
1055  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump')
1056  call assert_equal(2, winnr('$'))
1057  call assert_equal(62, line('$'))
1058  call Check_dump01(0)
1059  call Check_dump01(42)
1060  call assert_equal('           bbbbbbbbbbbbbbbbbb ', getline(26)[0:29])
1061  quit
1062endfunc
1063
1064func Test_terminal_dumpdiff_options()
1065  set laststatus=0
1066  call assert_equal(1, winnr('$'))
1067  let height = winheight(0)
1068  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 1, 'term_cols': 33})
1069  call assert_equal(2, winnr('$'))
1070  call assert_equal(height, winheight(winnr()))
1071  call assert_equal(33, winwidth(winnr()))
1072  call assert_equal('dump diff dumps/Test_popup_command_01.dump', bufname('%'))
1073  quit
1074
1075  call assert_equal(1, winnr('$'))
1076  let width = winwidth(0)
1077  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'vertical': 0, 'term_rows': 13, 'term_name': 'something else'})
1078  call assert_equal(2, winnr('$'))
1079  call assert_equal(width, winwidth(winnr()))
1080  call assert_equal(13, winheight(winnr()))
1081  call assert_equal('something else', bufname('%'))
1082  quit
1083
1084  call assert_equal(1, winnr('$'))
1085  call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_popup_command_02.dump', {'curwin': 1})
1086  call assert_equal(1, winnr('$'))
1087  bwipe
1088
1089  set laststatus&
1090endfunc
1091
1092func Api_drop_common(options)
1093  call assert_equal(1, winnr('$'))
1094
1095  " Use the title termcap entries to output the escape sequence.
1096  call writefile([
1097	\ 'set title',
1098	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1099	\ 'let &titlestring = ''["drop","Xtextfile"' . a:options . ']''',
1100	\ 'redraw',
1101	\ "set t_ts=",
1102	\ ], 'Xscript')
1103  let buf = RunVimInTerminal('-S Xscript', {})
1104  call WaitFor({-> bufnr('Xtextfile') > 0})
1105  call assert_equal('Xtextfile', expand('%:t'))
1106  call assert_true(winnr('$') >= 3)
1107  return buf
1108endfunc
1109
1110func Test_terminal_api_drop_newwin()
1111  if !CanRunVimInTerminal()
1112    return
1113  endif
1114  let buf = Api_drop_common('')
1115  call assert_equal(0, &bin)
1116  call assert_equal('', &fenc)
1117
1118  call StopVimInTerminal(buf)
1119  call delete('Xscript')
1120  bwipe Xtextfile
1121endfunc
1122
1123func Test_terminal_api_drop_newwin_bin()
1124  if !CanRunVimInTerminal()
1125    return
1126  endif
1127  let buf = Api_drop_common(',{"bin":1}')
1128  call assert_equal(1, &bin)
1129
1130  call StopVimInTerminal(buf)
1131  call delete('Xscript')
1132  bwipe Xtextfile
1133endfunc
1134
1135func Test_terminal_api_drop_newwin_binary()
1136  if !CanRunVimInTerminal()
1137    return
1138  endif
1139  let buf = Api_drop_common(',{"binary":1}')
1140  call assert_equal(1, &bin)
1141
1142  call StopVimInTerminal(buf)
1143  call delete('Xscript')
1144  bwipe Xtextfile
1145endfunc
1146
1147func Test_terminal_api_drop_newwin_nobin()
1148  if !CanRunVimInTerminal()
1149    return
1150  endif
1151  set binary
1152  let buf = Api_drop_common(',{"nobin":1}')
1153  call assert_equal(0, &bin)
1154
1155  call StopVimInTerminal(buf)
1156  call delete('Xscript')
1157  bwipe Xtextfile
1158  set nobinary
1159endfunc
1160
1161func Test_terminal_api_drop_newwin_nobinary()
1162  if !CanRunVimInTerminal()
1163    return
1164  endif
1165  set binary
1166  let buf = Api_drop_common(',{"nobinary":1}')
1167  call assert_equal(0, &bin)
1168
1169  call StopVimInTerminal(buf)
1170  call delete('Xscript')
1171  bwipe Xtextfile
1172  set nobinary
1173endfunc
1174
1175func Test_terminal_api_drop_newwin_ff()
1176  if !CanRunVimInTerminal()
1177    return
1178  endif
1179  let buf = Api_drop_common(',{"ff":"dos"}')
1180  call assert_equal("dos", &ff)
1181
1182  call StopVimInTerminal(buf)
1183  call delete('Xscript')
1184  bwipe Xtextfile
1185endfunc
1186
1187func Test_terminal_api_drop_newwin_fileformat()
1188  if !CanRunVimInTerminal()
1189    return
1190  endif
1191  let buf = Api_drop_common(',{"fileformat":"dos"}')
1192  call assert_equal("dos", &ff)
1193
1194  call StopVimInTerminal(buf)
1195  call delete('Xscript')
1196  bwipe Xtextfile
1197endfunc
1198
1199func Test_terminal_api_drop_newwin_enc()
1200  if !CanRunVimInTerminal()
1201    return
1202  endif
1203  let buf = Api_drop_common(',{"enc":"utf-16"}')
1204  call assert_equal("utf-16", &fenc)
1205
1206  call StopVimInTerminal(buf)
1207  call delete('Xscript')
1208  bwipe Xtextfile
1209endfunc
1210
1211func Test_terminal_api_drop_newwin_encoding()
1212  if !CanRunVimInTerminal()
1213    return
1214  endif
1215  let buf = Api_drop_common(',{"encoding":"utf-16"}')
1216  call assert_equal("utf-16", &fenc)
1217
1218  call StopVimInTerminal(buf)
1219  call delete('Xscript')
1220  bwipe Xtextfile
1221endfunc
1222
1223func Test_terminal_api_drop_oldwin()
1224  if !CanRunVimInTerminal()
1225    return
1226  endif
1227  let firstwinid = win_getid()
1228  split Xtextfile
1229  let textfile_winid = win_getid()
1230  call assert_equal(2, winnr('$'))
1231  call win_gotoid(firstwinid)
1232
1233  " Use the title termcap entries to output the escape sequence.
1234  call writefile([
1235	\ 'set title',
1236	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1237	\ 'let &titlestring = ''["drop","Xtextfile"]''',
1238	\ 'redraw',
1239	\ "set t_ts=",
1240	\ ], 'Xscript')
1241  let buf = RunVimInTerminal('-S Xscript', {'rows': 10})
1242  call WaitForAssert({-> assert_equal('Xtextfile', expand('%:t'))})
1243  call assert_equal(textfile_winid, win_getid())
1244
1245  call StopVimInTerminal(buf)
1246  call delete('Xscript')
1247  bwipe Xtextfile
1248endfunc
1249
1250func Tapi_TryThis(bufnum, arg)
1251  let g:called_bufnum = a:bufnum
1252  let g:called_arg = a:arg
1253endfunc
1254
1255func WriteApiCall(funcname)
1256  " Use the title termcap entries to output the escape sequence.
1257  call writefile([
1258	\ 'set title',
1259	\ 'exe "set t_ts=\<Esc>]51; t_fs=\x07"',
1260	\ 'let &titlestring = ''["call","' . a:funcname . '",["hello",123]]''',
1261	\ 'redraw',
1262	\ "set t_ts=",
1263	\ ], 'Xscript')
1264endfunc
1265
1266func Test_terminal_api_call()
1267  if !CanRunVimInTerminal()
1268    return
1269  endif
1270
1271  call WriteApiCall('Tapi_TryThis')
1272  let buf = RunVimInTerminal('-S Xscript', {})
1273  call WaitFor({-> exists('g:called_bufnum')})
1274  call assert_equal(buf, g:called_bufnum)
1275  call assert_equal(['hello', 123], g:called_arg)
1276
1277  call StopVimInTerminal(buf)
1278  call delete('Xscript')
1279  unlet g:called_bufnum
1280  unlet g:called_arg
1281endfunc
1282
1283func Test_terminal_api_call_fails()
1284  if !CanRunVimInTerminal()
1285    return
1286  endif
1287
1288  call WriteApiCall('TryThis')
1289  call ch_logfile('Xlog', 'w')
1290  let buf = RunVimInTerminal('-S Xscript', {})
1291  call WaitForAssert({-> assert_match('Invalid function name: TryThis', string(readfile('Xlog')))})
1292
1293  call StopVimInTerminal(buf)
1294  call delete('Xscript')
1295  call ch_logfile('', '')
1296  call delete('Xlog')
1297endfunc
1298
1299let s:caught_e937 = 0
1300
1301func Tapi_Delete(bufnum, arg)
1302  try
1303    execute 'bdelete!' a:bufnum
1304  catch /E937:/
1305    let s:caught_e937 = 1
1306  endtry
1307endfunc
1308
1309func Test_terminal_api_call_fail_delete()
1310  if !CanRunVimInTerminal()
1311    return
1312  endif
1313
1314  call WriteApiCall('Tapi_Delete')
1315  let buf = RunVimInTerminal('-S Xscript', {})
1316  call WaitForAssert({-> assert_equal(1, s:caught_e937)})
1317
1318  call StopVimInTerminal(buf)
1319  call delete('Xscript')
1320  call ch_logfile('', '')
1321endfunc
1322
1323func Test_terminal_ansicolors_default()
1324  let colors = [
1325	\ '#000000', '#e00000',
1326	\ '#00e000', '#e0e000',
1327	\ '#0000e0', '#e000e0',
1328	\ '#00e0e0', '#e0e0e0',
1329	\ '#808080', '#ff4040',
1330	\ '#40ff40', '#ffff40',
1331	\ '#4040ff', '#ff40ff',
1332	\ '#40ffff', '#ffffff',
1333	\]
1334
1335  let buf = Run_shell_in_terminal({})
1336  call assert_equal(colors, term_getansicolors(buf))
1337  call Stop_shell_in_terminal(buf)
1338  call term_wait(buf)
1339
1340  exe buf . 'bwipe'
1341endfunc
1342
1343let s:test_colors = [
1344	\ '#616e64', '#0d0a79',
1345	\ '#6d610d', '#0a7373',
1346	\ '#690d0a', '#6d696e',
1347	\ '#0d0a6f', '#616e0d',
1348	\ '#0a6479', '#6d0d0a',
1349	\ '#617373', '#0d0a69',
1350	\ '#6d690d', '#0a6e6f',
1351	\ '#610d0a', '#6e6479',
1352	\]
1353
1354func Test_terminal_ansicolors_global()
1355  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1356  let buf = Run_shell_in_terminal({})
1357  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
1358  call Stop_shell_in_terminal(buf)
1359  call term_wait(buf)
1360
1361  exe buf . 'bwipe'
1362  unlet g:terminal_ansi_colors
1363endfunc
1364
1365func Test_terminal_ansicolors_func()
1366  let g:terminal_ansi_colors = reverse(copy(s:test_colors))
1367  let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors})
1368  call assert_equal(s:test_colors, term_getansicolors(buf))
1369
1370  call term_setansicolors(buf, g:terminal_ansi_colors)
1371  call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf))
1372
1373  let colors = [
1374	\ 'ivory', 'AliceBlue',
1375	\ 'grey67', 'dark goldenrod',
1376	\ 'SteelBlue3', 'PaleVioletRed4',
1377	\ 'MediumPurple2', 'yellow2',
1378	\ 'RosyBrown3', 'OrangeRed2',
1379	\ 'white smoke', 'navy blue',
1380	\ 'grey47', 'gray97',
1381	\ 'MistyRose2', 'DodgerBlue4',
1382	\]
1383  call term_setansicolors(buf, colors)
1384
1385  let colors[4] = 'Invalid'
1386  call assert_fails('call term_setansicolors(buf, colors)', 'E474:')
1387
1388  call Stop_shell_in_terminal(buf)
1389  call term_wait(buf)
1390  exe buf . 'bwipe'
1391endfunc
1392
1393func Test_terminal_termwinsize_option_fixed()
1394  if !CanRunVimInTerminal()
1395    return
1396  endif
1397  set termwinsize=6x40
1398  let text = []
1399  for n in range(10)
1400    call add(text, repeat(n, 50))
1401  endfor
1402  call writefile(text, 'Xwinsize')
1403  let buf = RunVimInTerminal('Xwinsize', {})
1404  let win = bufwinid(buf)
1405  call assert_equal([6, 40], term_getsize(buf))
1406  call assert_equal(6, winheight(win))
1407  call assert_equal(40, winwidth(win))
1408
1409  " resizing the window doesn't resize the terminal.
1410  resize 10
1411  vertical resize 60
1412  call assert_equal([6, 40], term_getsize(buf))
1413  call assert_equal(10, winheight(win))
1414  call assert_equal(60, winwidth(win))
1415
1416  call StopVimInTerminal(buf)
1417  call delete('Xwinsize')
1418
1419  call assert_fails('set termwinsize=40', 'E474')
1420  call assert_fails('set termwinsize=10+40', 'E474')
1421  call assert_fails('set termwinsize=abc', 'E474')
1422
1423  set termwinsize=
1424endfunc
1425
1426func Test_terminal_termwinsize_option_zero()
1427  set termwinsize=0x0
1428  let buf = Run_shell_in_terminal({})
1429  let win = bufwinid(buf)
1430  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1431  call Stop_shell_in_terminal(buf)
1432  call term_wait(buf)
1433  exe buf . 'bwipe'
1434
1435  set termwinsize=7x0
1436  let buf = Run_shell_in_terminal({})
1437  let win = bufwinid(buf)
1438  call assert_equal([7, winwidth(win)], term_getsize(buf))
1439  call Stop_shell_in_terminal(buf)
1440  call term_wait(buf)
1441  exe buf . 'bwipe'
1442
1443  set termwinsize=0x33
1444  let buf = Run_shell_in_terminal({})
1445  let win = bufwinid(buf)
1446  call assert_equal([winheight(win), 33], term_getsize(buf))
1447  call Stop_shell_in_terminal(buf)
1448  call term_wait(buf)
1449  exe buf . 'bwipe'
1450
1451  set termwinsize=
1452endfunc
1453
1454func Test_terminal_termwinsize_mininmum()
1455  set termwinsize=10*50
1456  vsplit
1457  let buf = Run_shell_in_terminal({})
1458  let win = bufwinid(buf)
1459  call assert_inrange(10, 1000, winheight(win))
1460  call assert_inrange(50, 1000, winwidth(win))
1461  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1462
1463  resize 15
1464  vertical resize 60
1465  redraw
1466  call assert_equal([15, 60], term_getsize(buf))
1467  call assert_equal(15, winheight(win))
1468  call assert_equal(60, winwidth(win))
1469
1470  resize 7
1471  vertical resize 30
1472  redraw
1473  call assert_equal([10, 50], term_getsize(buf))
1474  call assert_equal(7, winheight(win))
1475  call assert_equal(30, winwidth(win))
1476
1477  call Stop_shell_in_terminal(buf)
1478  call term_wait(buf)
1479  exe buf . 'bwipe'
1480
1481  set termwinsize=0*0
1482  let buf = Run_shell_in_terminal({})
1483  let win = bufwinid(buf)
1484  call assert_equal([winheight(win), winwidth(win)], term_getsize(buf))
1485  call Stop_shell_in_terminal(buf)
1486  call term_wait(buf)
1487  exe buf . 'bwipe'
1488
1489  set termwinsize=
1490endfunc
1491
1492func Test_terminal_termwinkey()
1493  call assert_equal(1, winnr('$'))
1494  let thiswin = win_getid()
1495
1496  let buf = Run_shell_in_terminal({})
1497  let termwin = bufwinid(buf)
1498  set termwinkey=<C-L>
1499  call feedkeys("\<C-L>w", 'tx')
1500  call assert_equal(thiswin, win_getid())
1501  call feedkeys("\<C-W>w", 'tx')
1502
1503  let job = term_getjob(buf)
1504  call feedkeys("\<C-L>\<C-C>", 'tx')
1505  call WaitForAssert({-> assert_equal("dead", job_status(job))})
1506endfunc
1507
1508func Test_terminal_out_err()
1509  if !has('unix')
1510    return
1511  endif
1512  call writefile([
1513	\ '#!/bin/sh',
1514	\ 'echo "this is standard error" >&2',
1515	\ 'echo "this is standard out" >&1',
1516	\ ], 'Xechoerrout.sh')
1517  call setfperm('Xechoerrout.sh', 'rwxrwx---')
1518
1519  let outfile = 'Xtermstdout'
1520  let buf = term_start(['./Xechoerrout.sh'], {'out_io': 'file', 'out_name': outfile})
1521
1522  call WaitFor({-> !empty(readfile(outfile)) && !empty(term_getline(buf, 1))})
1523  call assert_equal(['this is standard out'], readfile(outfile))
1524  call assert_equal('this is standard error', term_getline(buf, 1))
1525
1526  call WaitForAssert({-> assert_equal('dead', job_status(term_getjob(buf)))})
1527  exe buf . 'bwipe'
1528  call delete('Xechoerrout.sh')
1529  call delete(outfile)
1530endfunc
1531
1532func Test_terminwinscroll()
1533  if !has('unix')
1534    return
1535  endif
1536
1537  " Let the terminal output more than 'termwinscroll' lines, some at the start
1538  " will be dropped.
1539  exe 'set termwinscroll=' . &lines
1540  let buf = term_start('/bin/sh')
1541  for i in range(1, &lines)
1542    call feedkeys("echo " . i . "\<CR>", 'xt')
1543    call WaitForAssert({-> assert_match(string(i), term_getline(buf, term_getcursor(buf)[0] - 1))})
1544  endfor
1545  " Go to Terminal-Normal mode to update the buffer.
1546  call feedkeys("\<C-W>N", 'xt')
1547  call assert_inrange(&lines, &lines * 110 / 100 + winheight(0), line('$'))
1548
1549  " Every "echo nr" must only appear once
1550  let lines = getline(1, line('$'))
1551  for i in range(&lines - len(lines) / 2 + 2, &lines)
1552    let filtered = filter(copy(lines), {idx, val -> val =~ 'echo ' . i . '\>'})
1553    call assert_equal(1, len(filtered), 'for "echo ' . i . '"')
1554  endfor
1555
1556  exe buf . 'bwipe!'
1557endfunc
1558
1559" Resizing the terminal window caused an ml_get error.
1560" TODO: This does not reproduce the original problem.
1561func Test_terminal_resize()
1562  set statusline=x
1563  terminal
1564  call assert_equal(2, winnr('$'))
1565
1566  " Fill the terminal with text.
1567  if has('win32')
1568    call feedkeys("dir\<CR>", 'xt')
1569  else
1570    call feedkeys("ls\<CR>", 'xt')
1571  endif
1572  " Go to Terminal-Normal mode for a moment.
1573  call feedkeys("\<C-W>N", 'xt')
1574  " Open a new window
1575  call feedkeys("i\<C-W>n", 'xt')
1576  call assert_equal(3, winnr('$'))
1577  redraw
1578
1579  close
1580  call assert_equal(2, winnr('$'))
1581  call feedkeys("exit\<CR>", 'xt')
1582  set statusline&
1583endfunc
1584
1585" must be nearly the last, we can't go back from GUI to terminal
1586func Test_zz1_terminal_in_gui()
1587  if !CanRunGui()
1588    return
1589  endif
1590
1591  " Ignore the "failed to create input context" error.
1592  call test_ignore_error('E285:')
1593
1594  gui -f
1595
1596  call assert_equal(1, winnr('$'))
1597  let buf = Run_shell_in_terminal({'term_finish': 'close'})
1598  call Stop_shell_in_terminal(buf)
1599  call term_wait(buf)
1600
1601  " closing window wipes out the terminal buffer a with finished job
1602  call WaitForAssert({-> assert_equal(1, winnr('$'))})
1603  call assert_equal("", bufname(buf))
1604
1605  unlet g:job
1606endfunc
1607
1608func Test_zz2_terminal_guioptions_bang()
1609  if !has('gui_running')
1610    return
1611  endif
1612  set guioptions+=!
1613
1614  let filename = 'Xtestscript'
1615  if has('win32')
1616    let filename .= '.bat'
1617    let prefix = ''
1618    let contents = ['@echo off', 'exit %1']
1619  else
1620    let filename .= '.sh'
1621    let prefix = './'
1622    let contents = ['#!/bin/sh', 'exit $1']
1623  endif
1624  call writefile(contents, filename)
1625  call setfperm(filename, 'rwxrwx---')
1626
1627  " Check if v:shell_error is equal to the exit status.
1628  let exitval = 0
1629  execute printf(':!%s%s %d', prefix, filename, exitval)
1630  call assert_equal(exitval, v:shell_error)
1631
1632  let exitval = 9
1633  execute printf(':!%s%s %d', prefix, filename, exitval)
1634  call assert_equal(exitval, v:shell_error)
1635
1636  set guioptions&
1637  call delete(filename)
1638endfunc
1639
1640func Test_terminal_hidden()
1641  if !has('unix')
1642    return
1643  endif
1644  term ++hidden cat
1645  let bnr = bufnr('$')
1646  call assert_equal('terminal', getbufvar(bnr, '&buftype'))
1647  exe 'sbuf ' . bnr
1648  call assert_equal('terminal', &buftype)
1649  call term_sendkeys(bnr, "asdf\<CR>")
1650  call WaitForAssert({-> assert_match('asdf', term_getline(bnr, 2))})
1651  call term_sendkeys(bnr, "\<C-D>")
1652  call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))})
1653  bwipe!
1654endfunc
1655
1656func Test_terminal_hidden_and_close()
1657  if !has('unix')
1658    return
1659  endif
1660  call assert_equal(1, winnr('$'))
1661  term ++hidden ++close ls
1662  let bnr = bufnr('$')
1663  call assert_equal('terminal', getbufvar(bnr, '&buftype'))
1664  call WaitForAssert({-> assert_false(bufexists(bnr))})
1665  call assert_equal(1, winnr('$'))
1666endfunc
1667
1668func Test_terminal_does_not_truncate_last_newlines()
1669  let contents = [
1670  \   [ 'One', '', 'X' ],
1671  \   [ 'Two', '', '' ],
1672  \   [ 'Three' ] + repeat([''], 30)
1673  \ ]
1674
1675  for c in contents
1676    call writefile(c, 'Xfile')
1677    if has('win32')
1678      term cmd /c type Xfile
1679    else
1680      term cat Xfile
1681    endif
1682    let bnr = bufnr('$')
1683    call assert_equal('terminal', getbufvar(bnr, '&buftype'))
1684    call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))})
1685    sleep 100m
1686    call assert_equal(c, getline(1, line('$')))
1687    quit
1688  endfor
1689
1690  call delete('Xfile')
1691endfunc
1692
1693func Test_terminal_no_job()
1694  let term = term_start('false', {'term_finish': 'close'})
1695  call WaitForAssert({-> assert_equal(v:null, term_getjob(term)) })
1696endfunc
1697
1698func Test_term_gettitle()
1699  if !has('title') || empty(&t_ts)
1700    return
1701  endif
1702  " TODO: this fails on Travis
1703  return
1704
1705  " term_gettitle() returns an empty string for a non-terminal buffer
1706  " or for a non-existing buffer.
1707  call assert_equal('', term_gettitle(bufnr('%')))
1708  call assert_equal('', term_gettitle(bufnr('$') + 1))
1709
1710  let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'])
1711  call WaitForAssert({-> assert_equal('[No Name] - VIM', term_gettitle(term)) })
1712
1713  call term_sendkeys(term, ":e Xfoo\r")
1714  call WaitForAssert({-> assert_match('Xfoo (.*[/\\]testdir) - VIM', term_gettitle(term)) })
1715
1716  call term_sendkeys(term, ":set titlestring=foo\r")
1717  call WaitForAssert({-> assert_equal('foo', term_gettitle(term)) })
1718
1719  exe term . 'bwipe!'
1720endfunc
1721