comparison src/testdir/test_channel.vim @ 17559:0ba896d48a56 v8.1.1777

patch 8.1.1777: useless checks for job feature in channel test commit https://github.com/vim/vim/commit/f386f08ccbd88e28479a4131a1b919bd3c0913ea Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jul 29 23:03:03 2019 +0200 patch 8.1.1777: useless checks for job feature in channel test Problem: Useless checks for job feature in channel test. Solution: Remove the checks. Remove ch_log() calls.
author Bram Moolenaar <Bram@vim.org>
date Mon, 29 Jul 2019 23:15:06 +0200
parents 4a22102fda8f
children 0da9bc55c31a
comparison
equal deleted inserted replaced
17558:2f85a7639b50 17559:0ba896d48a56
1 " Test for channel functions. 1 " Test for channel and job functions.
2 2
3 " When +channel is supported then +job is too, so we don't check for that.
3 source check.vim 4 source check.vim
4 CheckFeature channel 5 CheckFeature channel
5 6
6 source shared.vim 7 source shared.vim
7 source screendump.vim 8 source screendump.vim
12 throw 'Skipped: Python command missing' 13 throw 'Skipped: Python command missing'
13 endif 14 endif
14 15
15 " Uncomment the next line to see what happens. Output is in 16 " Uncomment the next line to see what happens. Output is in
16 " src/testdir/channellog. 17 " src/testdir/channellog.
18 " Add ch_log() calls where you want to see what happens.
17 " call ch_logfile('channellog', 'w') 19 " call ch_logfile('channellog', 'w')
18 20
19 let s:chopt = {} 21 let s:chopt = {}
20 22
21 " Run "testfunc" after sarting the server and stop the server afterwards. 23 " Run "testfunc" after sarting the server and stop the server afterwards.
54 unlet s:chopt.noblock 56 unlet s:chopt.noblock
55 if ch_status(handle) == "fail" 57 if ch_status(handle) == "fail"
56 call assert_report("Can't open channel") 58 call assert_report("Can't open channel")
57 return 59 return
58 endif 60 endif
59 if has('job') 61
60 " check that getjob without a job is handled correctly 62 " check that getjob without a job is handled correctly
61 call assert_equal('no process', string(ch_getjob(handle))) 63 call assert_equal('no process', string(ch_getjob(handle)))
62 endif 64
63 let dict = ch_info(handle) 65 let dict = ch_info(handle)
64 call assert_true(dict.id != 0) 66 call assert_true(dict.id != 0)
65 call assert_equal('open', dict.status) 67 call assert_equal('open', dict.status)
66 call assert_equal(a:port, string(dict.port)) 68 call assert_equal(a:port, string(dict.port))
67 call assert_equal('open', dict.sock_status) 69 call assert_equal('open', dict.sock_status)
443 endfunc 445 endfunc
444 446
445 """"""""" 447 """""""""
446 448
447 func Test_raw_pipe() 449 func Test_raw_pipe()
448 if !has('job')
449 return
450 endif
451 call ch_log('Test_raw_pipe()')
452 " Add a dummy close callback to avoid that messages are dropped when calling 450 " Add a dummy close callback to avoid that messages are dropped when calling
453 " ch_canread(). 451 " ch_canread().
454 " Also test the non-blocking option. 452 " Also test the non-blocking option.
455 let job = job_start(s:python . " test_channel_pipe.py", 453 let job = job_start(s:python . " test_channel_pipe.py",
456 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 454 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1})
512 endfor 510 endfor
513 call assert_equal(1, found) 511 call assert_equal(1, found)
514 endfunc 512 endfunc
515 513
516 func Test_raw_pipe_blob() 514 func Test_raw_pipe_blob()
517 if !has('job')
518 return
519 endif
520 call ch_log('Test_raw_pipe_blob()')
521 " Add a dummy close callback to avoid that messages are dropped when calling 515 " Add a dummy close callback to avoid that messages are dropped when calling
522 " ch_canread(). 516 " ch_canread().
523 " Also test the non-blocking option. 517 " Also test the non-blocking option.
524 let job = job_start(s:python . " test_channel_pipe.py", 518 let job = job_start(s:python . " test_channel_pipe.py",
525 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 519 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1})
557 let info = job_info(job) 551 let info = job_info(job)
558 call assert_equal("dead", info.status) 552 call assert_equal("dead", info.status)
559 endfunc 553 endfunc
560 554
561 func Test_nl_pipe() 555 func Test_nl_pipe()
562 if !has('job')
563 return
564 endif
565 call ch_log('Test_nl_pipe()')
566 let job = job_start([s:python, "test_channel_pipe.py"]) 556 let job = job_start([s:python, "test_channel_pipe.py"])
567 call assert_equal("run", job_status(job)) 557 call assert_equal("run", job_status(job))
568 try 558 try
569 let handle = job_getchannel(job) 559 let handle = job_getchannel(job)
570 call ch_sendraw(handle, "echo something\n") 560 call ch_sendraw(handle, "echo something\n")
585 finally 575 finally
586 call job_stop(job) 576 call job_stop(job)
587 endtry 577 endtry
588 endfunc 578 endfunc
589 579
590 func Test_nl_err_to_out_pipe() 580 func Stop_g_job()
591 if !has('job') 581 call job_stop(g:job)
582 if has('win32')
583 " On MS-Windows the server must close the file handle before we are able
584 " to delete the file.
585 call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
586 sleep 10m
587 endif
588 endfunc
589
590 func Test_nl_read_file()
591 call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput')
592 let g:job = job_start(s:python . " test_channel_pipe.py",
593 \ {'in_io': 'file', 'in_name': 'Xinput'})
594 call assert_equal("run", job_status(g:job))
595 try
596 let handle = job_getchannel(g:job)
597 call assert_equal("something", ch_readraw(handle))
598 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'}))
599 call assert_equal("this", ch_readraw(handle))
600 call assert_equal("AND this", ch_readraw(handle))
601 finally
602 call Stop_g_job()
603 call delete('Xinput')
604 endtry
605 endfunc
606
607 func Test_nl_write_out_file()
608 let g:job = job_start(s:python . " test_channel_pipe.py",
609 \ {'out_io': 'file', 'out_name': 'Xoutput'})
610 call assert_equal("run", job_status(g:job))
611 try
612 let handle = job_getchannel(g:job)
613 call ch_sendraw(handle, "echo line one\n")
614 call ch_sendraw(handle, "echo line two\n")
615 call ch_sendraw(handle, "double this\n")
616 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
617 finally
618 call Stop_g_job()
619 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
620 call delete('Xoutput')
621 endtry
622 endfunc
623
624 func Test_nl_write_err_file()
625 let g:job = job_start(s:python . " test_channel_pipe.py",
626 \ {'err_io': 'file', 'err_name': 'Xoutput'})
627 call assert_equal("run", job_status(g:job))
628 try
629 let handle = job_getchannel(g:job)
630 call ch_sendraw(handle, "echoerr line one\n")
631 call ch_sendraw(handle, "echoerr line two\n")
632 call ch_sendraw(handle, "doubleerr this\n")
633 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
634 finally
635 call Stop_g_job()
636 call delete('Xoutput')
637 endtry
638 endfunc
639
640 func Test_nl_write_both_file()
641 let g:job = job_start(s:python . " test_channel_pipe.py",
642 \ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'})
643 call assert_equal("run", job_status(g:job))
644 try
645 let handle = job_getchannel(g:job)
646 call ch_sendraw(handle, "echoerr line one\n")
647 call ch_sendraw(handle, "echo line two\n")
648 call ch_sendraw(handle, "double this\n")
649 call ch_sendraw(handle, "doubleerr that\n")
650 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput'))})
651 finally
652 call Stop_g_job()
653 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
654 call delete('Xoutput')
655 endtry
656 endfunc
657
658 func BufCloseCb(ch)
659 let g:Ch_bufClosed = 'yes'
660 endfunc
661
662 func Run_test_pipe_to_buffer(use_name, nomod, do_msg)
663 let g:Ch_bufClosed = 'no'
664 let options = {'out_io': 'buffer', 'close_cb': 'BufCloseCb'}
665 let expected = ['', 'line one', 'line two', 'this', 'AND this', 'Goodbye!']
666 if a:use_name
667 let options['out_name'] = 'pipe-output'
668 if a:do_msg
669 let expected[0] = 'Reading from channel output...'
670 else
671 let options['out_msg'] = 0
672 call remove(expected, 0)
673 endif
674 else
675 sp pipe-output
676 let options['out_buf'] = bufnr('%')
677 quit
678 call remove(expected, 0)
679 endif
680 if a:nomod
681 let options['out_modifiable'] = 0
682 endif
683 let job = job_start(s:python . " test_channel_pipe.py", options)
684 call assert_equal("run", job_status(job))
685 try
686 let handle = job_getchannel(job)
687 call ch_sendraw(handle, "echo line one\n")
688 call ch_sendraw(handle, "echo line two\n")
689 call ch_sendraw(handle, "double this\n")
690 call ch_sendraw(handle, "quit\n")
691 sp pipe-output
692 call WaitFor('line("$") == ' . len(expected) . ' && g:Ch_bufClosed == "yes"')
693 call assert_equal(expected, getline(1, '$'))
694 if a:nomod
695 call assert_equal(0, &modifiable)
696 else
697 call assert_equal(1, &modifiable)
698 endif
699 call assert_equal('yes', g:Ch_bufClosed)
700 bwipe!
701 finally
702 call job_stop(job)
703 endtry
704 endfunc
705
706 func Test_pipe_to_buffer_name()
707 call Run_test_pipe_to_buffer(1, 0, 1)
708 endfunc
709
710 func Test_pipe_to_buffer_nr()
711 call Run_test_pipe_to_buffer(0, 0, 1)
712 endfunc
713
714 func Test_pipe_to_buffer_name_nomod()
715 call Run_test_pipe_to_buffer(1, 1, 1)
716 endfunc
717
718 func Test_pipe_to_buffer_name_nomsg()
719 call Run_test_pipe_to_buffer(1, 0, 1)
720 endfunc
721
722 func Test_close_output_buffer()
723 enew!
724 let test_lines = ['one', 'two']
725 call setline(1, test_lines)
726 call ch_log('Test_close_output_buffer()')
727 let options = {'out_io': 'buffer'}
728 let options['out_name'] = 'buffer-output'
729 let options['out_msg'] = 0
730 split buffer-output
731 let job = job_start(s:python . " test_channel_write.py", options)
732 call assert_equal("run", job_status(job))
733 try
734 call WaitForAssert({-> assert_equal(3, line('$'))})
735 quit!
736 sleep 100m
737 " Make sure the write didn't happen to the wrong buffer.
738 call assert_equal(test_lines, getline(1, line('$')))
739 call assert_equal(-1, bufwinnr('buffer-output'))
740 sbuf buffer-output
741 call assert_notequal(-1, bufwinnr('buffer-output'))
742 sleep 100m
743 close " no more writes
744 bwipe!
745 finally
746 call job_stop(job)
747 endtry
748 endfunc
749
750 func Run_test_pipe_err_to_buffer(use_name, nomod, do_msg)
751 let options = {'err_io': 'buffer'}
752 let expected = ['', 'line one', 'line two', 'this', 'AND this']
753 if a:use_name
754 let options['err_name'] = 'pipe-err'
755 if a:do_msg
756 let expected[0] = 'Reading from channel error...'
757 else
758 let options['err_msg'] = 0
759 call remove(expected, 0)
760 endif
761 else
762 sp pipe-err
763 let options['err_buf'] = bufnr('%')
764 quit
765 call remove(expected, 0)
766 endif
767 if a:nomod
768 let options['err_modifiable'] = 0
769 endif
770 let job = job_start(s:python . " test_channel_pipe.py", options)
771 call assert_equal("run", job_status(job))
772 try
773 let handle = job_getchannel(job)
774 call ch_sendraw(handle, "echoerr line one\n")
775 call ch_sendraw(handle, "echoerr line two\n")
776 call ch_sendraw(handle, "doubleerr this\n")
777 call ch_sendraw(handle, "quit\n")
778 sp pipe-err
779 call WaitForAssert({-> assert_equal(expected, getline(1, '$'))})
780 if a:nomod
781 call assert_equal(0, &modifiable)
782 else
783 call assert_equal(1, &modifiable)
784 endif
785 bwipe!
786 finally
787 call job_stop(job)
788 endtry
789 endfunc
790
791 func Test_pipe_err_to_buffer_name()
792 call Run_test_pipe_err_to_buffer(1, 0, 1)
793 endfunc
794
795 func Test_pipe_err_to_buffer_nr()
796 call Run_test_pipe_err_to_buffer(0, 0, 1)
797 endfunc
798
799 func Test_pipe_err_to_buffer_name_nomod()
800 call Run_test_pipe_err_to_buffer(1, 1, 1)
801 endfunc
802
803 func Test_pipe_err_to_buffer_name_nomsg()
804 call Run_test_pipe_err_to_buffer(1, 0, 0)
805 endfunc
806
807 func Test_pipe_both_to_buffer()
808 let job = job_start(s:python . " test_channel_pipe.py",
809 \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'})
810 call assert_equal("run", job_status(job))
811 try
812 let handle = job_getchannel(job)
813 call ch_sendraw(handle, "echo line one\n")
814 call ch_sendraw(handle, "echoerr line two\n")
815 call ch_sendraw(handle, "double this\n")
816 call ch_sendraw(handle, "doubleerr that\n")
817 call ch_sendraw(handle, "quit\n")
818 sp pipe-err
819 call WaitForAssert({-> assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'that', 'AND that', 'Goodbye!'], getline(1, '$'))})
820 bwipe!
821 finally
822 call job_stop(job)
823 endtry
824 endfunc
825
826 func Run_test_pipe_from_buffer(use_name)
827 sp pipe-input
828 call setline(1, ['echo one', 'echo two', 'echo three'])
829 let options = {'in_io': 'buffer', 'block_write': 1}
830 if a:use_name
831 let options['in_name'] = 'pipe-input'
832 else
833 let options['in_buf'] = bufnr('%')
834 endif
835
836 let job = job_start(s:python . " test_channel_pipe.py", options)
837 call assert_equal("run", job_status(job))
838 try
839 let handle = job_getchannel(job)
840 call assert_equal('one', ch_read(handle))
841 call assert_equal('two', ch_read(handle))
842 call assert_equal('three', ch_read(handle))
843 bwipe!
844 finally
845 call job_stop(job)
846 endtry
847 endfunc
848
849 func Test_pipe_from_buffer_name()
850 call Run_test_pipe_from_buffer(1)
851 endfunc
852
853 func Test_pipe_from_buffer_nr()
854 call Run_test_pipe_from_buffer(0)
855 endfunc
856
857 func Run_pipe_through_sort(all, use_buffer)
858 if !executable('sort')
859 throw 'Skipped: sort program not found'
860 endif
861 let options = {'out_io': 'buffer', 'out_name': 'sortout'}
862 if a:use_buffer
863 split sortin
864 call setline(1, ['ccc', 'aaa', 'ddd', 'bbb', 'eee'])
865 let options.in_io = 'buffer'
866 let options.in_name = 'sortin'
867 endif
868 if !a:all
869 let options.in_top = 2
870 let options.in_bot = 4
871 endif
872 let job = job_start('sort', options)
873
874 if !a:use_buffer
875 call assert_equal("run", job_status(job))
876 call ch_sendraw(job, "ccc\naaa\nddd\nbbb\neee\n")
877 call ch_close_in(job)
878 endif
879
880 call WaitForAssert({-> assert_equal("dead", job_status(job))})
881
882 sp sortout
883 call WaitFor('line("$") > 3')
884 call assert_equal('Reading from channel output...', getline(1))
885 if a:all
886 call assert_equal(['aaa', 'bbb', 'ccc', 'ddd', 'eee'], getline(2, 6))
887 else
888 call assert_equal(['aaa', 'bbb', 'ddd'], getline(2, 4))
889 endif
890
891 call job_stop(job)
892 if a:use_buffer
893 bwipe! sortin
894 endif
895 bwipe! sortout
896 endfunc
897
898 func Test_pipe_through_sort_all()
899 call ch_log('Test_pipe_through_sort_all()')
900 call Run_pipe_through_sort(1, 1)
901 endfunc
902
903 func Test_pipe_through_sort_some()
904 call ch_log('Test_pipe_through_sort_some()')
905 call Run_pipe_through_sort(0, 1)
906 endfunc
907
908 func Test_pipe_through_sort_feed()
909 call ch_log('Test_pipe_through_sort_feed()')
910 call Run_pipe_through_sort(1, 0)
911 endfunc
912
913 func Test_pipe_to_nameless_buffer()
914 let job = job_start(s:python . " test_channel_pipe.py",
915 \ {'out_io': 'buffer'})
916 call assert_equal("run", job_status(job))
917 try
918 let handle = job_getchannel(job)
919 call ch_sendraw(handle, "echo line one\n")
920 call ch_sendraw(handle, "echo line two\n")
921 exe ch_getbufnr(handle, "out") . 'sbuf'
922 call WaitFor('line("$") >= 3')
923 call assert_equal(['Reading from channel output...', 'line one', 'line two'], getline(1, '$'))
924 bwipe!
925 finally
926 call job_stop(job)
927 endtry
928 endfunc
929
930 func Test_pipe_to_buffer_json()
931 let job = job_start(s:python . " test_channel_pipe.py",
932 \ {'out_io': 'buffer', 'out_mode': 'json'})
933 call assert_equal("run", job_status(job))
934 try
935 let handle = job_getchannel(job)
936 call ch_sendraw(handle, "echo [0, \"hello\"]\n")
937 call ch_sendraw(handle, "echo [-2, 12.34]\n")
938 exe ch_getbufnr(handle, "out") . 'sbuf'
939 call WaitFor('line("$") >= 3')
940 call assert_equal(['Reading from channel output...', '[0,"hello"]', '[-2,12.34]'], getline(1, '$'))
941 bwipe!
942 finally
943 call job_stop(job)
944 endtry
945 endfunc
946
947 " Wait a little while for the last line, minus "offset", to equal "line".
948 func s:wait_for_last_line(line, offset)
949 for i in range(100)
950 if getline(line('$') - a:offset) == a:line
951 break
952 endif
953 sleep 10m
954 endfor
955 endfunc
956
957 func Test_pipe_io_two_buffers()
958 " Create two buffers, one to read from and one to write to.
959 split pipe-output
960 set buftype=nofile
961 split pipe-input
962 set buftype=nofile
963
964 let job = job_start(s:python . " test_channel_pipe.py",
965 \ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0,
966 \ 'out_io': 'buffer', 'out_name': 'pipe-output',
967 \ 'block_write': 1})
968 call assert_equal("run", job_status(job))
969 try
970 exe "normal Gaecho hello\<CR>"
971 exe bufwinnr('pipe-output') . "wincmd w"
972 call s:wait_for_last_line('hello', 0)
973 call assert_equal('hello', getline('$'))
974
975 exe bufwinnr('pipe-input') . "wincmd w"
976 exe "normal Gadouble this\<CR>"
977 exe bufwinnr('pipe-output') . "wincmd w"
978 call s:wait_for_last_line('AND this', 0)
979 call assert_equal('this', getline(line('$') - 1))
980 call assert_equal('AND this', getline('$'))
981
982 bwipe!
983 exe bufwinnr('pipe-input') . "wincmd w"
984 bwipe!
985 finally
986 call job_stop(job)
987 endtry
988 endfunc
989
990 func Test_pipe_io_one_buffer()
991 " Create one buffer to read from and to write to.
992 split pipe-io
993 set buftype=nofile
994
995 let job = job_start(s:python . " test_channel_pipe.py",
996 \ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0,
997 \ 'out_io': 'buffer', 'out_name': 'pipe-io',
998 \ 'block_write': 1})
999 call assert_equal("run", job_status(job))
1000 try
1001 exe "normal Goecho hello\<CR>"
1002 call s:wait_for_last_line('hello', 1)
1003 call assert_equal('hello', getline(line('$') - 1))
1004
1005 exe "normal Gadouble this\<CR>"
1006 call s:wait_for_last_line('AND this', 1)
1007 call assert_equal('this', getline(line('$') - 2))
1008 call assert_equal('AND this', getline(line('$') - 1))
1009
1010 bwipe!
1011 finally
1012 call job_stop(job)
1013 endtry
1014 endfunc
1015
1016 func Test_write_to_buffer_and_scroll()
1017 if !CanRunVimInTerminal()
1018 throw 'Skipped: cannot make screendumps'
1019 endif
1020 let lines =<< trim END
1021 new Xscrollbuffer
1022 call setline(1, range(1, 200))
1023 $
1024 redraw
1025 wincmd w
1026 call deletebufline('Xscrollbuffer', 1, '$')
1027 if has('win32')
1028 let cmd = ['cmd', '/c', 'echo sometext']
1029 else
1030 let cmd = [&shell, &shellcmdflag, 'echo sometext']
1031 endif
1032 call job_start(cmd, #{out_io: 'buffer', out_name: 'Xscrollbuffer'})
1033 END
1034 call writefile(lines, 'XtestBufferScroll')
1035 let buf = RunVimInTerminal('-S XtestBufferScroll', #{rows: 10})
1036 call term_wait(buf, 100)
1037 call VerifyScreenDump(buf, 'Test_job_buffer_scroll_1', {})
1038
1039 " clean up
1040 call StopVimInTerminal(buf)
1041 call delete('XtestBufferScroll')
1042 endfunc
1043
1044 func Test_pipe_null()
1045 " We cannot check that no I/O works, we only check that the job starts
1046 " properly.
1047 let job = job_start(s:python . " test_channel_pipe.py something",
1048 \ {'in_io': 'null'})
1049 call assert_equal("run", job_status(job))
1050 try
1051 call assert_equal('something', ch_read(job))
1052 finally
1053 call job_stop(job)
1054 endtry
1055
1056 let job = job_start(s:python . " test_channel_pipe.py err-out",
1057 \ {'out_io': 'null'})
1058 call assert_equal("run", job_status(job))
1059 try
1060 call assert_equal('err-out', ch_read(job, {"part": "err"}))
1061 finally
1062 call job_stop(job)
1063 endtry
1064
1065 let job = job_start(s:python . " test_channel_pipe.py something",
1066 \ {'err_io': 'null'})
1067 call assert_equal("run", job_status(job))
1068 try
1069 call assert_equal('something', ch_read(job))
1070 finally
1071 call job_stop(job)
1072 endtry
1073
1074 let job = job_start(s:python . " test_channel_pipe.py something",
1075 \ {'out_io': 'null', 'err_io': 'out'})
1076 call assert_equal("run", job_status(job))
1077 call job_stop(job)
1078
1079 let job = job_start(s:python . " test_channel_pipe.py something",
1080 \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
1081 call assert_equal("run", job_status(job))
1082 call assert_equal('channel fail', string(job_getchannel(job)))
1083 call assert_equal('fail', ch_status(job))
1084 call job_stop(job)
1085 endfunc
1086
1087 func Test_pipe_to_buffer_raw()
1088 let options = {'out_mode': 'raw', 'out_io': 'buffer', 'out_name': 'testout'}
1089 split testout
1090 let job = job_start([s:python, '-c',
1091 \ 'import sys; [sys.stdout.write(".") and sys.stdout.flush() for _ in range(10000)]'], options)
1092 " the job may be done quickly, also accept "dead"
1093 call assert_match('^\%(dead\|run\)$', job_status(job))
1094 call WaitFor('len(join(getline(1, "$"), "")) >= 10000')
1095 try
1096 let totlen = 0
1097 for line in getline(1, '$')
1098 call assert_equal('', substitute(line, '^\.*', '', ''))
1099 let totlen += len(line)
1100 endfor
1101 call assert_equal(10000, totlen)
1102 finally
1103 call job_stop(job)
1104 bwipe!
1105 endtry
1106 endfunc
1107
1108 func Test_reuse_channel()
1109 let job = job_start(s:python . " test_channel_pipe.py")
1110 call assert_equal("run", job_status(job))
1111 let handle = job_getchannel(job)
1112 try
1113 call ch_sendraw(handle, "echo something\n")
1114 call assert_equal("something", ch_readraw(handle))
1115 finally
1116 call job_stop(job)
1117 endtry
1118
1119 let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle})
1120 call assert_equal("run", job_status(job))
1121 let handle = job_getchannel(job)
1122 try
1123 call ch_sendraw(handle, "echo again\n")
1124 call assert_equal("again", ch_readraw(handle))
1125 finally
1126 call job_stop(job)
1127 endtry
1128 endfunc
1129
1130 func Test_out_cb()
1131 let dict = {'thisis': 'dict: '}
1132 func dict.outHandler(chan, msg) dict
1133 if type(a:msg) == v:t_string
1134 let g:Ch_outmsg = self.thisis . a:msg
1135 else
1136 let g:Ch_outobj = a:msg
1137 endif
1138 endfunc
1139 func dict.errHandler(chan, msg) dict
1140 let g:Ch_errmsg = self.thisis . a:msg
1141 endfunc
1142 let job = job_start(s:python . " test_channel_pipe.py",
1143 \ {'out_cb': dict.outHandler,
1144 \ 'out_mode': 'json',
1145 \ 'err_cb': dict.errHandler,
1146 \ 'err_mode': 'json'})
1147 call assert_equal("run", job_status(job))
1148 try
1149 let g:Ch_outmsg = ''
1150 let g:Ch_errmsg = ''
1151 call ch_sendraw(job, "echo [0, \"hello\"]\n")
1152 call ch_sendraw(job, "echoerr [0, \"there\"]\n")
1153 call WaitForAssert({-> assert_equal("dict: hello", g:Ch_outmsg)})
1154 call WaitForAssert({-> assert_equal("dict: there", g:Ch_errmsg)})
1155
1156 " Receive a json object split in pieces
1157 unlet! g:Ch_outobj
1158 call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\": 3|}]\n")
1159 let g:Ch_outobj = ''
1160 call WaitForAssert({-> assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)})
1161 finally
1162 call job_stop(job)
1163 endtry
1164 endfunc
1165
1166 func Test_out_close_cb()
1167 let s:counter = 1
1168 let g:Ch_msg1 = ''
1169 let g:Ch_closemsg = 0
1170 func! OutHandler(chan, msg)
1171 if s:counter == 1
1172 let g:Ch_msg1 = a:msg
1173 endif
1174 let s:counter += 1
1175 endfunc
1176 func! CloseHandler(chan)
1177 let g:Ch_closemsg = s:counter
1178 let s:counter += 1
1179 endfunc
1180 let job = job_start(s:python . " test_channel_pipe.py quit now",
1181 \ {'out_cb': 'OutHandler',
1182 \ 'close_cb': 'CloseHandler'})
1183 " the job may be done quickly, also accept "dead"
1184 call assert_match('^\%(dead\|run\)$', job_status(job))
1185 try
1186 call WaitForAssert({-> assert_equal('quit', g:Ch_msg1)})
1187 call WaitForAssert({-> assert_equal(2, g:Ch_closemsg)})
1188 finally
1189 call job_stop(job)
1190 delfunc OutHandler
1191 delfunc CloseHandler
1192 endtry
1193 endfunc
1194
1195 func Test_read_in_close_cb()
1196 let g:Ch_received = ''
1197 func! CloseHandler(chan)
1198 let g:Ch_received = ch_read(a:chan)
1199 endfunc
1200 let job = job_start(s:python . " test_channel_pipe.py quit now",
1201 \ {'close_cb': 'CloseHandler'})
1202 " the job may be done quickly, also accept "dead"
1203 call assert_match('^\%(dead\|run\)$', job_status(job))
1204 try
1205 call WaitForAssert({-> assert_equal('quit', g:Ch_received)})
1206 finally
1207 call job_stop(job)
1208 delfunc CloseHandler
1209 endtry
1210 endfunc
1211
1212 " Use channel in NL mode but received text does not end in NL.
1213 func Test_read_in_close_cb_incomplete()
1214 let g:Ch_received = ''
1215 func! CloseHandler(chan)
1216 while ch_status(a:chan, {'part': 'out'}) == 'buffered'
1217 let g:Ch_received .= ch_read(a:chan)
1218 endwhile
1219 endfunc
1220 let job = job_start(s:python . " test_channel_pipe.py incomplete",
1221 \ {'close_cb': 'CloseHandler'})
1222 " the job may be done quickly, also accept "dead"
1223 call assert_match('^\%(dead\|run\)$', job_status(job))
1224 try
1225 call WaitForAssert({-> assert_equal('incomplete', g:Ch_received)})
1226 finally
1227 call job_stop(job)
1228 delfunc CloseHandler
1229 endtry
1230 endfunc
1231
1232 func Test_out_cb_lambda()
1233 let job = job_start(s:python . " test_channel_pipe.py",
1234 \ {'out_cb': {ch, msg -> execute("let g:Ch_outmsg = 'lambda: ' . msg")},
1235 \ 'out_mode': 'json',
1236 \ 'err_cb': {ch, msg -> execute(":let g:Ch_errmsg = 'lambda: ' . msg")},
1237 \ 'err_mode': 'json'})
1238 call assert_equal("run", job_status(job))
1239 try
1240 let g:Ch_outmsg = ''
1241 let g:Ch_errmsg = ''
1242 call ch_sendraw(job, "echo [0, \"hello\"]\n")
1243 call ch_sendraw(job, "echoerr [0, \"there\"]\n")
1244 call WaitForAssert({-> assert_equal("lambda: hello", g:Ch_outmsg)})
1245 call WaitForAssert({-> assert_equal("lambda: there", g:Ch_errmsg)})
1246 finally
1247 call job_stop(job)
1248 endtry
1249 endfunc
1250
1251 func Test_close_and_exit_cb()
1252 let g:retdict = {'ret': {}}
1253 func g:retdict.close_cb(ch) dict
1254 let self.ret['close_cb'] = job_status(ch_getjob(a:ch))
1255 endfunc
1256 func g:retdict.exit_cb(job, status) dict
1257 let self.ret['exit_cb'] = job_status(a:job)
1258 endfunc
1259
1260 let job = job_start([&shell, &shellcmdflag, 'echo'],
1261 \ {'close_cb': g:retdict.close_cb,
1262 \ 'exit_cb': g:retdict.exit_cb})
1263 " the job may be done quickly, also accept "dead"
1264 call assert_match('^\%(dead\|run\)$', job_status(job))
1265 call WaitForAssert({-> assert_equal(2, len(g:retdict.ret))})
1266 call assert_match('^\%(dead\|run\)$', g:retdict.ret['close_cb'])
1267 call assert_equal('dead', g:retdict.ret['exit_cb'])
1268 unlet g:retdict
1269 endfunc
1270
1271 """"""""""
1272
1273 function ExitCbWipe(job, status)
1274 exe g:wipe_buf 'bw!'
1275 endfunction
1276
1277 " This caused a crash, because messages were handled while peeking for a
1278 " character.
1279 func Test_exit_cb_wipes_buf()
1280 if !has('timers')
592 return 1281 return
593 endif 1282 endif
1283 set cursorline lazyredraw
1284 call test_override('redraw_flag', 1)
1285 new
1286 let g:wipe_buf = bufnr('')
1287
1288 let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'],
1289 \ {'exit_cb': 'ExitCbWipe'})
1290 let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5})
1291 call feedkeys(repeat('g', 1000) . 'o', 'ntx!')
1292 call WaitForAssert({-> assert_equal("dead", job_status(job))})
1293 call timer_stop(timer)
1294
1295 set nocursorline nolazyredraw
1296 unlet g:wipe_buf
1297 call test_override('ALL', 0)
1298 endfunc
1299
1300 """"""""""
1301
1302 let g:Ch_unletResponse = ''
1303 func s:UnletHandler(handle, msg)
1304 let g:Ch_unletResponse = a:msg
1305 unlet s:channelfd
1306 endfunc
1307
1308 " Test that "unlet handle" in a handler doesn't crash Vim.
1309 func Ch_unlet_handle(port)
1310 let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
1311 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')})
1312 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
1313 endfunc
1314
1315 func Test_unlet_handle()
1316 call ch_log('Test_unlet_handle()')
1317 call s:run_server('Ch_unlet_handle')
1318 endfunc
1319
1320 """"""""""
1321
1322 let g:Ch_unletResponse = ''
1323 func Ch_CloseHandler(handle, msg)
1324 let g:Ch_unletResponse = a:msg
1325 call ch_close(s:channelfd)
1326 endfunc
1327
1328 " Test that "unlet handle" in a handler doesn't crash Vim.
1329 func Ch_close_handle(port)
1330 let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
1331 call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')})
1332 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
1333 endfunc
1334
1335 func Test_close_handle()
1336 call ch_log('Test_close_handle()')
1337 call s:run_server('Ch_close_handle')
1338 endfunc
1339
1340 """"""""""
1341
1342 func Test_open_fail()
1343 call ch_log('Test_open_fail()')
1344 silent! let ch = ch_open("noserver")
1345 echo ch
1346 let d = ch
1347 endfunc
1348
1349 """"""""""
1350
1351 func Ch_open_delay(port)
1352 " Wait up to a second for the port to open.
1353 let s:chopt.waittime = 1000
1354 let channel = ch_open('localhost:' . a:port, s:chopt)
1355 unlet s:chopt.waittime
1356 if ch_status(channel) == "fail"
1357 call assert_report("Can't open channel")
1358 return
1359 endif
1360 call assert_equal('got it', ch_evalexpr(channel, 'hello!'))
1361 call ch_close(channel)
1362 endfunc
1363
1364 func Test_open_delay()
1365 call ch_log('Test_open_delay()')
1366 " The server will wait half a second before creating the port.
1367 call s:run_server('Ch_open_delay', 'delay')
1368 endfunc
1369
1370 """""""""
1371
1372 function MyFunction(a,b,c)
1373 let g:Ch_call_ret = [a:a, a:b, a:c]
1374 endfunc
1375
1376 function Ch_test_call(port)
1377 let handle = ch_open('localhost:' . a:port, s:chopt)
1378 if ch_status(handle) == "fail"
1379 call assert_report("Can't open channel")
1380 return
1381 endif
1382
1383 let g:Ch_call_ret = []
1384 call assert_equal('ok', ch_evalexpr(handle, 'call-func'))
1385 call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)})
1386 endfunc
1387
1388 func Test_call()
1389 call ch_log('Test_call()')
1390 call s:run_server('Ch_test_call')
1391 endfunc
1392
1393 """""""""
1394
1395 let g:Ch_job_exit_ret = 'not yet'
1396 function MyExitCb(job, status)
1397 let g:Ch_job_exit_ret = 'done'
1398 endfunc
1399
1400 function Ch_test_exit_callback(port)
1401 call job_setoptions(g:currentJob, {'exit_cb': 'MyExitCb'})
1402 let g:Ch_exit_job = g:currentJob
1403 call assert_equal('MyExitCb', job_info(g:currentJob)['exit_cb'])
1404 endfunc
1405
1406 func Test_exit_callback()
1407 call s:run_server('Ch_test_exit_callback')
1408
1409 " wait up to a second for the job to exit
1410 for i in range(100)
1411 if g:Ch_job_exit_ret == 'done'
1412 break
1413 endif
1414 sleep 10m
1415 " calling job_status() triggers the callback
1416 call job_status(g:Ch_exit_job)
1417 endfor
1418
1419 call assert_equal('done', g:Ch_job_exit_ret)
1420 call assert_equal('dead', job_info(g:Ch_exit_job).status)
1421 unlet g:Ch_exit_job
1422 endfunc
1423
1424 function MyExitTimeCb(job, status)
1425 if job_info(a:job).process == g:exit_cb_val.process
1426 let g:exit_cb_val.end = reltime(g:exit_cb_val.start)
1427 endif
1428 call Resume()
1429 endfunction
1430
1431 func Test_exit_callback_interval()
1432 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
1433 let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1434 let g:exit_cb_val.process = job_info(job).process
1435 call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
1436 let elapsed = reltimefloat(g:exit_cb_val.end)
1437 call assert_true(elapsed > 0.5)
1438 call assert_true(elapsed < 1.0)
1439
1440 " case: unreferenced job, using timer
1441 if !has('timers')
1442 return
1443 endif
1444
1445 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
1446 let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1447 let g:exit_cb_val.process = job_info(g:job).process
1448 unlet g:job
1449 call Standby(1000)
1450 if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0
1451 let elapsed = reltimefloat(g:exit_cb_val.end)
1452 else
1453 let elapsed = 1.0
1454 endif
1455 call assert_inrange(0.5, 1.0, elapsed)
1456 endfunc
1457
1458 """""""""
1459
1460 let g:Ch_close_ret = 'alive'
1461 function MyCloseCb(ch)
1462 let g:Ch_close_ret = 'closed'
1463 endfunc
1464
1465 function Ch_test_close_callback(port)
1466 let handle = ch_open('localhost:' . a:port, s:chopt)
1467 if ch_status(handle) == "fail"
1468 call assert_report("Can't open channel")
1469 return
1470 endif
1471 call ch_setoptions(handle, {'close_cb': 'MyCloseCb'})
1472
1473 call assert_equal('', ch_evalexpr(handle, 'close me'))
1474 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
1475 endfunc
1476
1477 func Test_close_callback()
1478 call ch_log('Test_close_callback()')
1479 call s:run_server('Ch_test_close_callback')
1480 endfunc
1481
1482 function Ch_test_close_partial(port)
1483 let handle = ch_open('localhost:' . a:port, s:chopt)
1484 if ch_status(handle) == "fail"
1485 call assert_report("Can't open channel")
1486 return
1487 endif
1488 let g:Ch_d = {}
1489 func g:Ch_d.closeCb(ch) dict
1490 let self.close_ret = 'closed'
1491 endfunc
1492 call ch_setoptions(handle, {'close_cb': g:Ch_d.closeCb})
1493
1494 call assert_equal('', ch_evalexpr(handle, 'close me'))
1495 call WaitForAssert({-> assert_equal('closed', g:Ch_d.close_ret)})
1496 unlet g:Ch_d
1497 endfunc
1498
1499 func Test_close_partial()
1500 call ch_log('Test_close_partial()')
1501 call s:run_server('Ch_test_close_partial')
1502 endfunc
1503
1504 func Test_job_start_invalid()
1505 call assert_fails('call job_start($x)', 'E474:')
1506 call assert_fails('call job_start("")', 'E474:')
1507 endfunc
1508
1509 func Test_job_stop_immediately()
1510 let g:job = job_start([s:python, '-c', 'import time;time.sleep(10)'])
1511 try
1512 call job_stop(g:job)
1513 call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
1514 finally
1515 call job_stop(g:job, 'kill')
1516 unlet g:job
1517 endtry
1518 endfunc
1519
1520 " This was leaking memory.
1521 func Test_partial_in_channel_cycle()
1522 let d = {}
1523 let d.a = function('string', [d])
1524 try
1525 let d.b = ch_open('nowhere:123', {'close_cb': d.a})
1526 catch
1527 call assert_exception('E901:')
1528 endtry
1529 unlet d
1530 endfunc
1531
1532 func Test_using_freed_memory()
1533 let g:a = job_start(['ls'])
1534 sleep 10m
1535 call test_garbagecollect_now()
1536 endfunc
1537
1538 func Test_collapse_buffers()
1539 if !executable('cat')
1540 throw 'Skipped: cat program not found'
1541 endif
1542 sp test_channel.vim
1543 let g:linecount = line('$')
1544 close
1545 split testout
1546 1,$delete
1547 call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'})
1548 call WaitForAssert({-> assert_inrange(g:linecount, g:linecount + 1, line('$'))})
1549 bwipe!
1550 endfunc
1551
1552 func Test_write_to_deleted_buffer()
1553 if !executable('echo')
1554 throw 'Skipped: echo program not found'
1555 endif
1556 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
1557 let bufnr = bufnr('test_buffer')
1558 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
1559 call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
1560 call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
1561
1562 bdel test_buffer
1563 call assert_equal([], getbufline(bufnr, 1, '$'))
1564
1565 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
1566 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
1567 call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
1568 call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
1569
1570 bwipe! test_buffer
1571 endfunc
1572
1573 func Test_cmd_parsing()
1574 if !has('unix')
1575 return
1576 endif
1577 call assert_false(filereadable("file with space"))
1578 let job = job_start('touch "file with space"')
1579 call WaitForAssert({-> assert_true(filereadable("file with space"))})
1580 call delete("file with space")
1581
1582 let job = job_start('touch file\ with\ space')
1583 call WaitForAssert({-> assert_true(filereadable("file with space"))})
1584 call delete("file with space")
1585 endfunc
1586
1587 func Test_raw_passes_nul()
1588 if !executable('cat')
1589 throw 'Skipped: cat program not found'
1590 endif
1591
1592 " Test lines from the job containing NUL are stored correctly in a buffer.
1593 new
1594 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
1595 w! Xtestread
1596 bwipe!
1597 split testout
1598 1,$delete
1599 call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'})
1600 call WaitFor('line("$") > 2')
1601 call assert_equal("asdf\nasdf", getline(1))
1602 call assert_equal("xxx\n", getline(2))
1603 call assert_equal("\nyyy", getline(3))
1604
1605 call delete('Xtestread')
1606 bwipe!
1607
1608 " Test lines from a buffer with NUL bytes are written correctly to the job.
1609 new mybuffer
1610 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
1611 let g:Ch_job = job_start('cat', {'in_io': 'buffer', 'in_name': 'mybuffer', 'out_io': 'file', 'out_name': 'Xtestwrite'})
1612 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
1613 bwipe!
1614 split Xtestwrite
1615 call assert_equal("asdf\nasdf", getline(1))
1616 call assert_equal("xxx\n", getline(2))
1617 call assert_equal("\nyyy", getline(3))
1618 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xtestwrite$'))
1619
1620 call delete('Xtestwrite')
1621 bwipe!
1622 endfunc
1623
1624 func Test_read_nonl_line()
1625 let g:linecount = 0
1626 let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1627 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
1628 call WaitForAssert({-> assert_equal(3, g:linecount)})
1629 unlet g:linecount
1630 endfunc
1631
1632 func Test_read_nonl_in_close_cb()
1633 func s:close_cb(ch)
1634 while ch_status(a:ch) == 'buffered'
1635 let g:out .= ch_read(a:ch)
1636 endwhile
1637 endfunc
1638
1639 let g:out = ''
1640 let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1641 call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')})
1642 call WaitForAssert({-> assert_equal('123', g:out)})
1643 unlet g:out
1644 delfunc s:close_cb
1645 endfunc
1646
1647 func Test_read_from_terminated_job()
1648 let g:linecount = 0
1649 let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
1650 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
1651 call WaitForAssert({-> assert_equal(1, g:linecount)})
1652 unlet g:linecount
1653 endfunc
1654
1655 func Test_job_start_windows()
1656 CheckMSWindows
1657
1658 " Check that backslash in $COMSPEC is handled properly.
1659 let g:echostr = ''
1660 let cmd = $COMSPEC . ' /c echo 123'
1661 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:echostr .= msg")}})
1662 let info = job_info(job)
1663 call assert_equal([$COMSPEC, '/c', 'echo', '123'], info.cmd)
1664
1665 call WaitForAssert({-> assert_equal("123", g:echostr)})
1666 unlet g:echostr
1667 endfunc
1668
1669 func Test_env()
1670 let g:envstr = ''
1671 if has('win32')
1672 let cmd = ['cmd', '/c', 'echo %FOO%']
1673 else
1674 let cmd = [&shell, &shellcmdflag, 'echo $FOO']
1675 endif
1676 call assert_fails('call job_start(cmd, {"env": 1})', 'E475:')
1677 call job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'env': {'FOO': 'bar'}})
1678 call WaitForAssert({-> assert_equal("bar", g:envstr)})
1679 unlet g:envstr
1680 endfunc
1681
1682 func Test_cwd()
1683 let g:envstr = ''
1684 if has('win32')
1685 let expect = $TEMP
1686 let cmd = ['cmd', '/c', 'echo %CD%']
1687 else
1688 let expect = $HOME
1689 let cmd = ['pwd']
1690 endif
1691 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'cwd': expect})
1692 try
1693 call WaitForAssert({-> assert_notequal("", g:envstr)})
1694 let expect = substitute(expect, '[/\\]$', '', '')
1695 let g:envstr = substitute(g:envstr, '[/\\]$', '', '')
1696 if $CI != '' && stridx(g:envstr, '/private/') == 0
1697 let g:envstr = g:envstr[8:]
1698 endif
1699 call assert_equal(expect, g:envstr)
1700 finally
1701 call job_stop(job)
1702 unlet g:envstr
1703 endtry
1704 endfunc
1705
1706 function Ch_test_close_lambda(port)
1707 let handle = ch_open('localhost:' . a:port, s:chopt)
1708 if ch_status(handle) == "fail"
1709 call assert_report("Can't open channel")
1710 return
1711 endif
1712 let g:Ch_close_ret = ''
1713 call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}})
1714
1715 call assert_equal('', ch_evalexpr(handle, 'close me'))
1716 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
1717 endfunc
1718
1719 func Test_close_lambda()
1720 call ch_log('Test_close_lambda()')
1721 call s:run_server('Ch_test_close_lambda')
1722 endfunc
1723
1724 func s:test_list_args(cmd, out, remove_lf)
1725 try
1726 let g:out = ''
1727 let job = job_start([s:python, '-c', a:cmd], {'callback': {ch, msg -> execute('let g:out .= msg')}, 'out_mode': 'raw'})
1728 call WaitFor('"" != g:out')
1729 if has('win32')
1730 let g:out = substitute(g:out, '\r', '', 'g')
1731 endif
1732 if a:remove_lf
1733 let g:out = substitute(g:out, '\n$', '', 'g')
1734 endif
1735 call assert_equal(a:out, g:out)
1736 finally
1737 call job_stop(job)
1738 unlet g:out
1739 endtry
1740 endfunc
1741
1742 func Test_list_args()
1743 call s:test_list_args('import sys;sys.stdout.write("hello world")', "hello world", 0)
1744 call s:test_list_args('import sys;sys.stdout.write("hello\nworld")', "hello\nworld", 0)
1745 call s:test_list_args('import sys;sys.stdout.write(''hello\nworld'')', "hello\nworld", 0)
1746 call s:test_list_args('import sys;sys.stdout.write(''hello"world'')', "hello\"world", 0)
1747 call s:test_list_args('import sys;sys.stdout.write(''hello^world'')', "hello^world", 0)
1748 call s:test_list_args('import sys;sys.stdout.write("hello&&world")', "hello&&world", 0)
1749 call s:test_list_args('import sys;sys.stdout.write(''hello\\world'')', "hello\\world", 0)
1750 call s:test_list_args('import sys;sys.stdout.write(''hello\\\\world'')', "hello\\\\world", 0)
1751 call s:test_list_args('import sys;sys.stdout.write("hello\"world\"")', 'hello"world"', 0)
1752 call s:test_list_args('import sys;sys.stdout.write("h\"ello worl\"d")', 'h"ello worl"d', 0)
1753 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo wor\\\"l\"d")', 'h"e\"llo wor\"l"d', 0)
1754 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo world")', 'h"e\"llo world', 0)
1755 call s:test_list_args('import sys;sys.stdout.write("hello\tworld")', "hello\tworld", 0)
1756
1757 " tests which not contain spaces in the argument
1758 call s:test_list_args('print("hello\nworld")', "hello\nworld", 1)
1759 call s:test_list_args('print(''hello\nworld'')', "hello\nworld", 1)
1760 call s:test_list_args('print(''hello"world'')', "hello\"world", 1)
1761 call s:test_list_args('print(''hello^world'')', "hello^world", 1)
1762 call s:test_list_args('print("hello&&world")', "hello&&world", 1)
1763 call s:test_list_args('print(''hello\\world'')', "hello\\world", 1)
1764 call s:test_list_args('print(''hello\\\\world'')', "hello\\\\world", 1)
1765 call s:test_list_args('print("hello\"world\"")', 'hello"world"', 1)
1766 call s:test_list_args('print("hello\tworld")', "hello\tworld", 1)
1767 endfunc
1768
1769 func Test_keep_pty_open()
1770 if !has('unix')
1771 return
1772 endif
1773
1774 let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"',
1775 \ {'out_io': 'null', 'err_io': 'null', 'pty': 1})
1776 let elapsed = WaitFor({-> job_status(job) ==# 'dead'})
1777 call assert_inrange(200, 1000, elapsed)
1778 call job_stop(job)
1779 endfunc
1780
1781 func Test_job_start_in_timer()
1782 CheckFeature timers
1783
1784 func OutCb(chan, msg)
1785 let g:val += 1
1786 endfunc
1787
1788 func ExitCb(job, status)
1789 let g:val += 1
1790 call Resume()
1791 endfunc
1792
1793 func TimerCb(timer)
1794 if has('win32')
1795 let cmd = ['cmd', '/c', 'echo.']
1796 else
1797 let cmd = ['echo']
1798 endif
1799 let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'})
1800 call substitute(repeat('a', 100000), '.', '', 'g')
1801 endfunc
1802
1803 " We should be interrupted before 'updatetime' elapsed.
1804 let g:val = 0
1805 call timer_start(1, 'TimerCb')
1806 let elapsed = Standby(&ut)
1807 call assert_inrange(1, &ut / 2, elapsed)
1808
1809 " Wait for both OutCb() and ExitCb() to have been called before deleting
1810 " them.
1811 call WaitForAssert({-> assert_equal(2, g:val)})
1812 call job_stop(g:job)
1813
1814 delfunc OutCb
1815 delfunc ExitCb
1816 delfunc TimerCb
1817 unlet! g:val
1818 unlet! g:job
1819 endfunc
1820
1821 func Test_raw_large_data()
1822 try
1823 let g:out = ''
1824 let job = job_start(s:python . " test_channel_pipe.py",
1825 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1,
1826 \ 'callback': {ch, msg -> execute('let g:out .= msg')}})
1827
1828 let outlen = 79999
1829 let want = repeat('X', outlen) . "\n"
1830 call ch_sendraw(job, want)
1831 call WaitFor({-> len(g:out) >= outlen}, 10000)
1832 call WaitForAssert({-> assert_equal("dead", job_status(job))})
1833 call assert_equal(want, substitute(g:out, '\r', '', 'g'))
1834 finally
1835 call job_stop(job)
1836 unlet g:out
1837 endtry
1838 endfunc
1839
1840 func Test_no_hang_windows()
1841 CheckMSWindows
1842
1843 try
1844 let job = job_start(s:python . " test_channel_pipe.py busy",
1845 \ {'mode': 'raw', 'drop': 'never', 'noblock': 0})
1846 call assert_fails('call ch_sendraw(job, repeat("X", 80000))', 'E631:')
1847 finally
1848 call job_stop(job)
1849 endtry
1850 endfunc
1851
1852 func Test_job_exitval_and_termsig()
1853 if !has('unix')
1854 return
1855 endif
1856
1857 " Terminate job normally
1858 let cmd = ['echo']
1859 let job = job_start(cmd)
1860 call WaitForAssert({-> assert_equal("dead", job_status(job))})
1861 let info = job_info(job)
1862 call assert_equal(0, info.exitval)
1863 call assert_equal("", info.termsig)
1864
1865 " Terminate job by signal
1866 let cmd = ['sleep', '10']
1867 let job = job_start(cmd)
1868 sleep 10m
1869 call job_stop(job)
1870 call WaitForAssert({-> assert_equal("dead", job_status(job))})
1871 let info = job_info(job)
1872 call assert_equal(-1, info.exitval)
1873 call assert_equal("term", info.termsig)
1874 endfunc
1875
1876 func Test_job_tty_in_out()
1877 CheckUnix
1878
1879 call writefile(['test'], 'Xtestin')
1880 let in_opts = [{},
1881 \ {'in_io': 'null'},
1882 \ {'in_io': 'file', 'in_name': 'Xtestin'}]
1883 let out_opts = [{},
1884 \ {'out_io': 'null'},
1885 \ {'out_io': 'file', 'out_name': 'Xtestout'}]
1886 let err_opts = [{},
1887 \ {'err_io': 'null'},
1888 \ {'err_io': 'file', 'err_name': 'Xtesterr'},
1889 \ {'err_io': 'out'}]
1890 let opts = []
1891
1892 for in_opt in in_opts
1893 let x = copy(in_opt)
1894 for out_opt in out_opts
1895 let x = extend(copy(x), out_opt)
1896 for err_opt in err_opts
1897 let x = extend(copy(x), err_opt)
1898 let opts += [extend({'pty': 1}, x)]
1899 endfor
1900 endfor
1901 endfor
1902
1903 for opt in opts
1904 let job = job_start('echo', opt)
1905 let info = job_info(job)
1906 let msg = printf('option={"in_io": "%s", "out_io": "%s", "err_io": "%s"}',
1907 \ get(opt, 'in_io', 'tty'),
1908 \ get(opt, 'out_io', 'tty'),
1909 \ get(opt, 'err_io', 'tty'))
1910
1911 if !has_key(opt, 'in_io') || !has_key(opt, 'out_io') || !has_key(opt, 'err_io')
1912 call assert_notequal('', info.tty_in, msg)
1913 else
1914 call assert_equal('', info.tty_in, msg)
1915 endif
1916 call assert_equal(info.tty_in, info.tty_out, msg)
1917
1918 call WaitForAssert({-> assert_equal('dead', job_status(job))})
1919 endfor
1920
1921 call delete('Xtestin')
1922 call delete('Xtestout')
1923 call delete('Xtesterr')
1924 endfunc
1925
1926 " Do this last, it stops any channel log.
1927 func Test_zz_nl_err_to_out_pipe()
594 call ch_logfile('Xlog') 1928 call ch_logfile('Xlog')
595 call ch_log('Test_nl_err_to_out_pipe()') 1929 call ch_log('Test_zz_nl_err_to_out_pipe()')
596 let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'}) 1930 let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'})
597 call assert_equal("run", job_status(job)) 1931 call assert_equal("run", job_status(job))
598 try 1932 try
599 let handle = job_getchannel(job) 1933 let handle = job_getchannel(job)
600 call ch_sendraw(handle, "echo something\n") 1934 call ch_sendraw(handle, "echo something\n")
610 let found_test = 0 1944 let found_test = 0
611 let found_send = 0 1945 let found_send = 0
612 let found_recv = 0 1946 let found_recv = 0
613 let found_stop = 0 1947 let found_stop = 0
614 for l in loglines 1948 for l in loglines
615 if l =~ 'Test_nl_err_to_out_pipe' 1949 if l =~ 'Test_zz_nl_err_to_out_pipe'
616 let found_test = 1 1950 let found_test = 1
617 endif 1951 endif
618 if l =~ 'SEND on.*echo something' 1952 if l =~ 'SEND on.*echo something'
619 let found_send = 1 1953 let found_send = 1
620 endif 1954 endif
633 sleep 10m 1967 sleep 10m
634 call delete('Xlog') 1968 call delete('Xlog')
635 endtry 1969 endtry
636 endfunc 1970 endfunc
637 1971
638 func Stop_g_job()
639 call job_stop(g:job)
640 if has('win32')
641 " On MS-Windows the server must close the file handle before we are able
642 " to delete the file.
643 call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
644 sleep 10m
645 endif
646 endfunc
647
648 func Test_nl_read_file()
649 if !has('job')
650 return
651 endif
652 call ch_log('Test_nl_read_file()')
653 call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput')
654 let g:job = job_start(s:python . " test_channel_pipe.py",
655 \ {'in_io': 'file', 'in_name': 'Xinput'})
656 call assert_equal("run", job_status(g:job))
657 try
658 let handle = job_getchannel(g:job)
659 call assert_equal("something", ch_readraw(handle))
660 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'}))
661 call assert_equal("this", ch_readraw(handle))
662 call assert_equal("AND this", ch_readraw(handle))
663 finally
664 call Stop_g_job()
665 call delete('Xinput')
666 endtry
667 endfunc
668
669 func Test_nl_write_out_file()
670 if !has('job')
671 return
672 endif
673 call ch_log('Test_nl_write_out_file()')
674 let g:job = job_start(s:python . " test_channel_pipe.py",
675 \ {'out_io': 'file', 'out_name': 'Xoutput'})
676 call assert_equal("run", job_status(g:job))
677 try
678 let handle = job_getchannel(g:job)
679 call ch_sendraw(handle, "echo line one\n")
680 call ch_sendraw(handle, "echo line two\n")
681 call ch_sendraw(handle, "double this\n")
682 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
683 finally
684 call Stop_g_job()
685 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
686 call delete('Xoutput')
687 endtry
688 endfunc
689
690 func Test_nl_write_err_file()
691 if !has('job')
692 return
693 endif
694 call ch_log('Test_nl_write_err_file()')
695 let g:job = job_start(s:python . " test_channel_pipe.py",
696 \ {'err_io': 'file', 'err_name': 'Xoutput'})
697 call assert_equal("run", job_status(g:job))
698 try
699 let handle = job_getchannel(g:job)
700 call ch_sendraw(handle, "echoerr line one\n")
701 call ch_sendraw(handle, "echoerr line two\n")
702 call ch_sendraw(handle, "doubleerr this\n")
703 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))})
704 finally
705 call Stop_g_job()
706 call delete('Xoutput')
707 endtry
708 endfunc
709
710 func Test_nl_write_both_file()
711 if !has('job')
712 return
713 endif
714 call ch_log('Test_nl_write_both_file()')
715 let g:job = job_start(s:python . " test_channel_pipe.py",
716 \ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'})
717 call assert_equal("run", job_status(g:job))
718 try
719 let handle = job_getchannel(g:job)
720 call ch_sendraw(handle, "echoerr line one\n")
721 call ch_sendraw(handle, "echo line two\n")
722 call ch_sendraw(handle, "double this\n")
723 call ch_sendraw(handle, "doubleerr that\n")
724 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput'))})
725 finally
726 call Stop_g_job()
727 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$'))
728 call delete('Xoutput')
729 endtry
730 endfunc
731
732 func BufCloseCb(ch)
733 let g:Ch_bufClosed = 'yes'
734 endfunc
735
736 func Run_test_pipe_to_buffer(use_name, nomod, do_msg)
737 if !has('job')
738 return
739 endif
740 call ch_log('Test_pipe_to_buffer()')
741 let g:Ch_bufClosed = 'no'
742 let options = {'out_io': 'buffer', 'close_cb': 'BufCloseCb'}
743 let expected = ['', 'line one', 'line two', 'this', 'AND this', 'Goodbye!']
744 if a:use_name
745 let options['out_name'] = 'pipe-output'
746 if a:do_msg
747 let expected[0] = 'Reading from channel output...'
748 else
749 let options['out_msg'] = 0
750 call remove(expected, 0)
751 endif
752 else
753 sp pipe-output
754 let options['out_buf'] = bufnr('%')
755 quit
756 call remove(expected, 0)
757 endif
758 if a:nomod
759 let options['out_modifiable'] = 0
760 endif
761 let job = job_start(s:python . " test_channel_pipe.py", options)
762 call assert_equal("run", job_status(job))
763 try
764 let handle = job_getchannel(job)
765 call ch_sendraw(handle, "echo line one\n")
766 call ch_sendraw(handle, "echo line two\n")
767 call ch_sendraw(handle, "double this\n")
768 call ch_sendraw(handle, "quit\n")
769 sp pipe-output
770 call WaitFor('line("$") == ' . len(expected) . ' && g:Ch_bufClosed == "yes"')
771 call assert_equal(expected, getline(1, '$'))
772 if a:nomod
773 call assert_equal(0, &modifiable)
774 else
775 call assert_equal(1, &modifiable)
776 endif
777 call assert_equal('yes', g:Ch_bufClosed)
778 bwipe!
779 finally
780 call job_stop(job)
781 endtry
782 endfunc
783
784 func Test_pipe_to_buffer_name()
785 call Run_test_pipe_to_buffer(1, 0, 1)
786 endfunc
787
788 func Test_pipe_to_buffer_nr()
789 call Run_test_pipe_to_buffer(0, 0, 1)
790 endfunc
791
792 func Test_pipe_to_buffer_name_nomod()
793 call Run_test_pipe_to_buffer(1, 1, 1)
794 endfunc
795
796 func Test_pipe_to_buffer_name_nomsg()
797 call Run_test_pipe_to_buffer(1, 0, 1)
798 endfunc
799
800 func Test_close_output_buffer()
801 if !has('job')
802 return
803 endif
804 enew!
805 let test_lines = ['one', 'two']
806 call setline(1, test_lines)
807 call ch_log('Test_close_output_buffer()')
808 let options = {'out_io': 'buffer'}
809 let options['out_name'] = 'buffer-output'
810 let options['out_msg'] = 0
811 split buffer-output
812 let job = job_start(s:python . " test_channel_write.py", options)
813 call assert_equal("run", job_status(job))
814 try
815 call WaitForAssert({-> assert_equal(3, line('$'))})
816 quit!
817 sleep 100m
818 " Make sure the write didn't happen to the wrong buffer.
819 call assert_equal(test_lines, getline(1, line('$')))
820 call assert_equal(-1, bufwinnr('buffer-output'))
821 sbuf buffer-output
822 call assert_notequal(-1, bufwinnr('buffer-output'))
823 sleep 100m
824 close " no more writes
825 bwipe!
826 finally
827 call job_stop(job)
828 endtry
829 endfunc
830
831 func Run_test_pipe_err_to_buffer(use_name, nomod, do_msg)
832 if !has('job')
833 return
834 endif
835 call ch_log('Test_pipe_err_to_buffer()')
836 let options = {'err_io': 'buffer'}
837 let expected = ['', 'line one', 'line two', 'this', 'AND this']
838 if a:use_name
839 let options['err_name'] = 'pipe-err'
840 if a:do_msg
841 let expected[0] = 'Reading from channel error...'
842 else
843 let options['err_msg'] = 0
844 call remove(expected, 0)
845 endif
846 else
847 sp pipe-err
848 let options['err_buf'] = bufnr('%')
849 quit
850 call remove(expected, 0)
851 endif
852 if a:nomod
853 let options['err_modifiable'] = 0
854 endif
855 let job = job_start(s:python . " test_channel_pipe.py", options)
856 call assert_equal("run", job_status(job))
857 try
858 let handle = job_getchannel(job)
859 call ch_sendraw(handle, "echoerr line one\n")
860 call ch_sendraw(handle, "echoerr line two\n")
861 call ch_sendraw(handle, "doubleerr this\n")
862 call ch_sendraw(handle, "quit\n")
863 sp pipe-err
864 call WaitForAssert({-> assert_equal(expected, getline(1, '$'))})
865 if a:nomod
866 call assert_equal(0, &modifiable)
867 else
868 call assert_equal(1, &modifiable)
869 endif
870 bwipe!
871 finally
872 call job_stop(job)
873 endtry
874 endfunc
875
876 func Test_pipe_err_to_buffer_name()
877 call Run_test_pipe_err_to_buffer(1, 0, 1)
878 endfunc
879
880 func Test_pipe_err_to_buffer_nr()
881 call Run_test_pipe_err_to_buffer(0, 0, 1)
882 endfunc
883
884 func Test_pipe_err_to_buffer_name_nomod()
885 call Run_test_pipe_err_to_buffer(1, 1, 1)
886 endfunc
887
888 func Test_pipe_err_to_buffer_name_nomsg()
889 call Run_test_pipe_err_to_buffer(1, 0, 0)
890 endfunc
891
892 func Test_pipe_both_to_buffer()
893 if !has('job')
894 return
895 endif
896 call ch_log('Test_pipe_both_to_buffer()')
897 let job = job_start(s:python . " test_channel_pipe.py",
898 \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'})
899 call assert_equal("run", job_status(job))
900 try
901 let handle = job_getchannel(job)
902 call ch_sendraw(handle, "echo line one\n")
903 call ch_sendraw(handle, "echoerr line two\n")
904 call ch_sendraw(handle, "double this\n")
905 call ch_sendraw(handle, "doubleerr that\n")
906 call ch_sendraw(handle, "quit\n")
907 sp pipe-err
908 call WaitForAssert({-> assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'that', 'AND that', 'Goodbye!'], getline(1, '$'))})
909 bwipe!
910 finally
911 call job_stop(job)
912 endtry
913 endfunc
914
915 func Run_test_pipe_from_buffer(use_name)
916 if !has('job')
917 return
918 endif
919 call ch_log('Test_pipe_from_buffer()')
920
921 sp pipe-input
922 call setline(1, ['echo one', 'echo two', 'echo three'])
923 let options = {'in_io': 'buffer', 'block_write': 1}
924 if a:use_name
925 let options['in_name'] = 'pipe-input'
926 else
927 let options['in_buf'] = bufnr('%')
928 endif
929
930 let job = job_start(s:python . " test_channel_pipe.py", options)
931 call assert_equal("run", job_status(job))
932 try
933 let handle = job_getchannel(job)
934 call assert_equal('one', ch_read(handle))
935 call assert_equal('two', ch_read(handle))
936 call assert_equal('three', ch_read(handle))
937 bwipe!
938 finally
939 call job_stop(job)
940 endtry
941 endfunc
942
943 func Test_pipe_from_buffer_name()
944 call Run_test_pipe_from_buffer(1)
945 endfunc
946
947 func Test_pipe_from_buffer_nr()
948 call Run_test_pipe_from_buffer(0)
949 endfunc
950
951 func Run_pipe_through_sort(all, use_buffer)
952 if !executable('sort') || !has('job')
953 return
954 endif
955 let options = {'out_io': 'buffer', 'out_name': 'sortout'}
956 if a:use_buffer
957 split sortin
958 call setline(1, ['ccc', 'aaa', 'ddd', 'bbb', 'eee'])
959 let options.in_io = 'buffer'
960 let options.in_name = 'sortin'
961 endif
962 if !a:all
963 let options.in_top = 2
964 let options.in_bot = 4
965 endif
966 let job = job_start('sort', options)
967
968 if !a:use_buffer
969 call assert_equal("run", job_status(job))
970 call ch_sendraw(job, "ccc\naaa\nddd\nbbb\neee\n")
971 call ch_close_in(job)
972 endif
973
974 call WaitForAssert({-> assert_equal("dead", job_status(job))})
975
976 sp sortout
977 call WaitFor('line("$") > 3')
978 call assert_equal('Reading from channel output...', getline(1))
979 if a:all
980 call assert_equal(['aaa', 'bbb', 'ccc', 'ddd', 'eee'], getline(2, 6))
981 else
982 call assert_equal(['aaa', 'bbb', 'ddd'], getline(2, 4))
983 endif
984
985 call job_stop(job)
986 if a:use_buffer
987 bwipe! sortin
988 endif
989 bwipe! sortout
990 endfunc
991
992 func Test_pipe_through_sort_all()
993 call ch_log('Test_pipe_through_sort_all()')
994 call Run_pipe_through_sort(1, 1)
995 endfunc
996
997 func Test_pipe_through_sort_some()
998 call ch_log('Test_pipe_through_sort_some()')
999 call Run_pipe_through_sort(0, 1)
1000 endfunc
1001
1002 func Test_pipe_through_sort_feed()
1003 call ch_log('Test_pipe_through_sort_feed()')
1004 call Run_pipe_through_sort(1, 0)
1005 endfunc
1006
1007 func Test_pipe_to_nameless_buffer()
1008 if !has('job')
1009 return
1010 endif
1011 call ch_log('Test_pipe_to_nameless_buffer()')
1012 let job = job_start(s:python . " test_channel_pipe.py",
1013 \ {'out_io': 'buffer'})
1014 call assert_equal("run", job_status(job))
1015 try
1016 let handle = job_getchannel(job)
1017 call ch_sendraw(handle, "echo line one\n")
1018 call ch_sendraw(handle, "echo line two\n")
1019 exe ch_getbufnr(handle, "out") . 'sbuf'
1020 call WaitFor('line("$") >= 3')
1021 call assert_equal(['Reading from channel output...', 'line one', 'line two'], getline(1, '$'))
1022 bwipe!
1023 finally
1024 call job_stop(job)
1025 endtry
1026 endfunc
1027
1028 func Test_pipe_to_buffer_json()
1029 if !has('job')
1030 return
1031 endif
1032 call ch_log('Test_pipe_to_buffer_json()')
1033 let job = job_start(s:python . " test_channel_pipe.py",
1034 \ {'out_io': 'buffer', 'out_mode': 'json'})
1035 call assert_equal("run", job_status(job))
1036 try
1037 let handle = job_getchannel(job)
1038 call ch_sendraw(handle, "echo [0, \"hello\"]\n")
1039 call ch_sendraw(handle, "echo [-2, 12.34]\n")
1040 exe ch_getbufnr(handle, "out") . 'sbuf'
1041 call WaitFor('line("$") >= 3')
1042 call assert_equal(['Reading from channel output...', '[0,"hello"]', '[-2,12.34]'], getline(1, '$'))
1043 bwipe!
1044 finally
1045 call job_stop(job)
1046 endtry
1047 endfunc
1048
1049 " Wait a little while for the last line, minus "offset", to equal "line".
1050 func s:wait_for_last_line(line, offset)
1051 for i in range(100)
1052 if getline(line('$') - a:offset) == a:line
1053 break
1054 endif
1055 sleep 10m
1056 endfor
1057 endfunc
1058
1059 func Test_pipe_io_two_buffers()
1060 if !has('job')
1061 return
1062 endif
1063 call ch_log('Test_pipe_io_two_buffers()')
1064
1065 " Create two buffers, one to read from and one to write to.
1066 split pipe-output
1067 set buftype=nofile
1068 split pipe-input
1069 set buftype=nofile
1070
1071 let job = job_start(s:python . " test_channel_pipe.py",
1072 \ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0,
1073 \ 'out_io': 'buffer', 'out_name': 'pipe-output',
1074 \ 'block_write': 1})
1075 call assert_equal("run", job_status(job))
1076 try
1077 exe "normal Gaecho hello\<CR>"
1078 exe bufwinnr('pipe-output') . "wincmd w"
1079 call s:wait_for_last_line('hello', 0)
1080 call assert_equal('hello', getline('$'))
1081
1082 exe bufwinnr('pipe-input') . "wincmd w"
1083 exe "normal Gadouble this\<CR>"
1084 exe bufwinnr('pipe-output') . "wincmd w"
1085 call s:wait_for_last_line('AND this', 0)
1086 call assert_equal('this', getline(line('$') - 1))
1087 call assert_equal('AND this', getline('$'))
1088
1089 bwipe!
1090 exe bufwinnr('pipe-input') . "wincmd w"
1091 bwipe!
1092 finally
1093 call job_stop(job)
1094 endtry
1095 endfunc
1096
1097 func Test_pipe_io_one_buffer()
1098 if !has('job')
1099 return
1100 endif
1101 call ch_log('Test_pipe_io_one_buffer()')
1102
1103 " Create one buffer to read from and to write to.
1104 split pipe-io
1105 set buftype=nofile
1106
1107 let job = job_start(s:python . " test_channel_pipe.py",
1108 \ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0,
1109 \ 'out_io': 'buffer', 'out_name': 'pipe-io',
1110 \ 'block_write': 1})
1111 call assert_equal("run", job_status(job))
1112 try
1113 exe "normal Goecho hello\<CR>"
1114 call s:wait_for_last_line('hello', 1)
1115 call assert_equal('hello', getline(line('$') - 1))
1116
1117 exe "normal Gadouble this\<CR>"
1118 call s:wait_for_last_line('AND this', 1)
1119 call assert_equal('this', getline(line('$') - 2))
1120 call assert_equal('AND this', getline(line('$') - 1))
1121
1122 bwipe!
1123 finally
1124 call job_stop(job)
1125 endtry
1126 endfunc
1127
1128 func Test_write_to_buffer_and_scroll()
1129 CheckFeature job
1130 if !CanRunVimInTerminal()
1131 throw 'Skipped: cannot make screendumps'
1132 endif
1133 let lines =<< trim END
1134 new Xscrollbuffer
1135 call setline(1, range(1, 200))
1136 $
1137 redraw
1138 wincmd w
1139 call deletebufline('Xscrollbuffer', 1, '$')
1140 if has('win32')
1141 let cmd = ['cmd', '/c', 'echo sometext']
1142 else
1143 let cmd = [&shell, &shellcmdflag, 'echo sometext']
1144 endif
1145 call job_start(cmd, #{out_io: 'buffer', out_name: 'Xscrollbuffer'})
1146 END
1147 call writefile(lines, 'XtestBufferScroll')
1148 let buf = RunVimInTerminal('-S XtestBufferScroll', #{rows: 10})
1149 sleep 500m
1150 call VerifyScreenDump(buf, 'Test_job_buffer_scroll_1', {})
1151
1152 " clean up
1153 call StopVimInTerminal(buf)
1154 call delete('XtestBufferScroll')
1155 endfunc
1156
1157 func Test_pipe_null()
1158 if !has('job')
1159 return
1160 endif
1161 call ch_log('Test_pipe_null()')
1162
1163 " We cannot check that no I/O works, we only check that the job starts
1164 " properly.
1165 let job = job_start(s:python . " test_channel_pipe.py something",
1166 \ {'in_io': 'null'})
1167 call assert_equal("run", job_status(job))
1168 try
1169 call assert_equal('something', ch_read(job))
1170 finally
1171 call job_stop(job)
1172 endtry
1173
1174 let job = job_start(s:python . " test_channel_pipe.py err-out",
1175 \ {'out_io': 'null'})
1176 call assert_equal("run", job_status(job))
1177 try
1178 call assert_equal('err-out', ch_read(job, {"part": "err"}))
1179 finally
1180 call job_stop(job)
1181 endtry
1182
1183 let job = job_start(s:python . " test_channel_pipe.py something",
1184 \ {'err_io': 'null'})
1185 call assert_equal("run", job_status(job))
1186 try
1187 call assert_equal('something', ch_read(job))
1188 finally
1189 call job_stop(job)
1190 endtry
1191
1192 let job = job_start(s:python . " test_channel_pipe.py something",
1193 \ {'out_io': 'null', 'err_io': 'out'})
1194 call assert_equal("run", job_status(job))
1195 call job_stop(job)
1196
1197 let job = job_start(s:python . " test_channel_pipe.py something",
1198 \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'})
1199 call assert_equal("run", job_status(job))
1200 call assert_equal('channel fail', string(job_getchannel(job)))
1201 call assert_equal('fail', ch_status(job))
1202 call job_stop(job)
1203 endfunc
1204
1205 func Test_pipe_to_buffer_raw()
1206 if !has('job')
1207 return
1208 endif
1209 call ch_log('Test_raw_pipe_to_buffer()')
1210 let options = {'out_mode': 'raw', 'out_io': 'buffer', 'out_name': 'testout'}
1211 split testout
1212 let job = job_start([s:python, '-c',
1213 \ 'import sys; [sys.stdout.write(".") and sys.stdout.flush() for _ in range(10000)]'], options)
1214 " the job may be done quickly, also accept "dead"
1215 call assert_match('^\%(dead\|run\)$', job_status(job))
1216 call WaitFor('len(join(getline(1, "$"), "")) >= 10000')
1217 try
1218 let totlen = 0
1219 for line in getline(1, '$')
1220 call assert_equal('', substitute(line, '^\.*', '', ''))
1221 let totlen += len(line)
1222 endfor
1223 call assert_equal(10000, totlen)
1224 finally
1225 call job_stop(job)
1226 bwipe!
1227 endtry
1228 endfunc
1229
1230 func Test_reuse_channel()
1231 if !has('job')
1232 return
1233 endif
1234 call ch_log('Test_reuse_channel()')
1235
1236 let job = job_start(s:python . " test_channel_pipe.py")
1237 call assert_equal("run", job_status(job))
1238 let handle = job_getchannel(job)
1239 try
1240 call ch_sendraw(handle, "echo something\n")
1241 call assert_equal("something", ch_readraw(handle))
1242 finally
1243 call job_stop(job)
1244 endtry
1245
1246 let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle})
1247 call assert_equal("run", job_status(job))
1248 let handle = job_getchannel(job)
1249 try
1250 call ch_sendraw(handle, "echo again\n")
1251 call assert_equal("again", ch_readraw(handle))
1252 finally
1253 call job_stop(job)
1254 endtry
1255 endfunc
1256
1257 func Test_out_cb()
1258 if !has('job')
1259 return
1260 endif
1261 call ch_log('Test_out_cb()')
1262
1263 let dict = {'thisis': 'dict: '}
1264 func dict.outHandler(chan, msg) dict
1265 if type(a:msg) == v:t_string
1266 let g:Ch_outmsg = self.thisis . a:msg
1267 else
1268 let g:Ch_outobj = a:msg
1269 endif
1270 endfunc
1271 func dict.errHandler(chan, msg) dict
1272 let g:Ch_errmsg = self.thisis . a:msg
1273 endfunc
1274 let job = job_start(s:python . " test_channel_pipe.py",
1275 \ {'out_cb': dict.outHandler,
1276 \ 'out_mode': 'json',
1277 \ 'err_cb': dict.errHandler,
1278 \ 'err_mode': 'json'})
1279 call assert_equal("run", job_status(job))
1280 try
1281 let g:Ch_outmsg = ''
1282 let g:Ch_errmsg = ''
1283 call ch_sendraw(job, "echo [0, \"hello\"]\n")
1284 call ch_sendraw(job, "echoerr [0, \"there\"]\n")
1285 call WaitForAssert({-> assert_equal("dict: hello", g:Ch_outmsg)})
1286 call WaitForAssert({-> assert_equal("dict: there", g:Ch_errmsg)})
1287
1288 " Receive a json object split in pieces
1289 unlet! g:Ch_outobj
1290 call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\": 3|}]\n")
1291 let g:Ch_outobj = ''
1292 call WaitForAssert({-> assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)})
1293 finally
1294 call job_stop(job)
1295 endtry
1296 endfunc
1297
1298 func Test_out_close_cb()
1299 if !has('job')
1300 return
1301 endif
1302 call ch_log('Test_out_close_cb()')
1303
1304 let s:counter = 1
1305 let g:Ch_msg1 = ''
1306 let g:Ch_closemsg = 0
1307 func! OutHandler(chan, msg)
1308 if s:counter == 1
1309 let g:Ch_msg1 = a:msg
1310 endif
1311 let s:counter += 1
1312 endfunc
1313 func! CloseHandler(chan)
1314 let g:Ch_closemsg = s:counter
1315 let s:counter += 1
1316 endfunc
1317 let job = job_start(s:python . " test_channel_pipe.py quit now",
1318 \ {'out_cb': 'OutHandler',
1319 \ 'close_cb': 'CloseHandler'})
1320 " the job may be done quickly, also accept "dead"
1321 call assert_match('^\%(dead\|run\)$', job_status(job))
1322 try
1323 call WaitForAssert({-> assert_equal('quit', g:Ch_msg1)})
1324 call WaitForAssert({-> assert_equal(2, g:Ch_closemsg)})
1325 finally
1326 call job_stop(job)
1327 delfunc OutHandler
1328 delfunc CloseHandler
1329 endtry
1330 endfunc
1331
1332 func Test_read_in_close_cb()
1333 if !has('job')
1334 return
1335 endif
1336 call ch_log('Test_read_in_close_cb()')
1337
1338 let g:Ch_received = ''
1339 func! CloseHandler(chan)
1340 let g:Ch_received = ch_read(a:chan)
1341 endfunc
1342 let job = job_start(s:python . " test_channel_pipe.py quit now",
1343 \ {'close_cb': 'CloseHandler'})
1344 " the job may be done quickly, also accept "dead"
1345 call assert_match('^\%(dead\|run\)$', job_status(job))
1346 try
1347 call WaitForAssert({-> assert_equal('quit', g:Ch_received)})
1348 finally
1349 call job_stop(job)
1350 delfunc CloseHandler
1351 endtry
1352 endfunc
1353
1354 " Use channel in NL mode but received text does not end in NL.
1355 func Test_read_in_close_cb_incomplete()
1356 if !has('job')
1357 return
1358 endif
1359 call ch_log('Test_read_in_close_cb_incomplete()')
1360
1361 let g:Ch_received = ''
1362 func! CloseHandler(chan)
1363 while ch_status(a:chan, {'part': 'out'}) == 'buffered'
1364 let g:Ch_received .= ch_read(a:chan)
1365 endwhile
1366 endfunc
1367 let job = job_start(s:python . " test_channel_pipe.py incomplete",
1368 \ {'close_cb': 'CloseHandler'})
1369 " the job may be done quickly, also accept "dead"
1370 call assert_match('^\%(dead\|run\)$', job_status(job))
1371 try
1372 call WaitForAssert({-> assert_equal('incomplete', g:Ch_received)})
1373 finally
1374 call job_stop(job)
1375 delfunc CloseHandler
1376 endtry
1377 endfunc
1378
1379 func Test_out_cb_lambda()
1380 if !has('job')
1381 return
1382 endif
1383 call ch_log('Test_out_cb_lambda()')
1384
1385 let job = job_start(s:python . " test_channel_pipe.py",
1386 \ {'out_cb': {ch, msg -> execute("let g:Ch_outmsg = 'lambda: ' . msg")},
1387 \ 'out_mode': 'json',
1388 \ 'err_cb': {ch, msg -> execute(":let g:Ch_errmsg = 'lambda: ' . msg")},
1389 \ 'err_mode': 'json'})
1390 call assert_equal("run", job_status(job))
1391 try
1392 let g:Ch_outmsg = ''
1393 let g:Ch_errmsg = ''
1394 call ch_sendraw(job, "echo [0, \"hello\"]\n")
1395 call ch_sendraw(job, "echoerr [0, \"there\"]\n")
1396 call WaitForAssert({-> assert_equal("lambda: hello", g:Ch_outmsg)})
1397 call WaitForAssert({-> assert_equal("lambda: there", g:Ch_errmsg)})
1398 finally
1399 call job_stop(job)
1400 endtry
1401 endfunc
1402
1403 func Test_close_and_exit_cb()
1404 if !has('job')
1405 return
1406 endif
1407 call ch_log('Test_close_and_exit_cb')
1408
1409 let g:retdict = {'ret': {}}
1410 func g:retdict.close_cb(ch) dict
1411 let self.ret['close_cb'] = job_status(ch_getjob(a:ch))
1412 endfunc
1413 func g:retdict.exit_cb(job, status) dict
1414 let self.ret['exit_cb'] = job_status(a:job)
1415 endfunc
1416
1417 let job = job_start([&shell, &shellcmdflag, 'echo'],
1418 \ {'close_cb': g:retdict.close_cb,
1419 \ 'exit_cb': g:retdict.exit_cb})
1420 " the job may be done quickly, also accept "dead"
1421 call assert_match('^\%(dead\|run\)$', job_status(job))
1422 call WaitForAssert({-> assert_equal(2, len(g:retdict.ret))})
1423 call assert_match('^\%(dead\|run\)$', g:retdict.ret['close_cb'])
1424 call assert_equal('dead', g:retdict.ret['exit_cb'])
1425 unlet g:retdict
1426 endfunc
1427
1428 """"""""""
1429
1430 function ExitCbWipe(job, status)
1431 exe g:wipe_buf 'bw!'
1432 endfunction
1433
1434 " This caused a crash, because messages were handled while peeking for a
1435 " character.
1436 func Test_exit_cb_wipes_buf()
1437 if !has('timers')
1438 return
1439 endif
1440 set cursorline lazyredraw
1441 call test_override('redraw_flag', 1)
1442 new
1443 let g:wipe_buf = bufnr('')
1444
1445 let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'],
1446 \ {'exit_cb': 'ExitCbWipe'})
1447 let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5})
1448 call feedkeys(repeat('g', 1000) . 'o', 'ntx!')
1449 call WaitForAssert({-> assert_equal("dead", job_status(job))})
1450 call timer_stop(timer)
1451
1452 set nocursorline nolazyredraw
1453 unlet g:wipe_buf
1454 call test_override('ALL', 0)
1455 endfunc
1456
1457 """"""""""
1458
1459 let g:Ch_unletResponse = ''
1460 func s:UnletHandler(handle, msg)
1461 let g:Ch_unletResponse = a:msg
1462 unlet s:channelfd
1463 endfunc
1464
1465 " Test that "unlet handle" in a handler doesn't crash Vim.
1466 func Ch_unlet_handle(port)
1467 let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
1468 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')})
1469 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
1470 endfunc
1471
1472 func Test_unlet_handle()
1473 call ch_log('Test_unlet_handle()')
1474 call s:run_server('Ch_unlet_handle')
1475 endfunc
1476
1477 """"""""""
1478
1479 let g:Ch_unletResponse = ''
1480 func Ch_CloseHandler(handle, msg)
1481 let g:Ch_unletResponse = a:msg
1482 call ch_close(s:channelfd)
1483 endfunc
1484
1485 " Test that "unlet handle" in a handler doesn't crash Vim.
1486 func Ch_close_handle(port)
1487 let s:channelfd = ch_open('localhost:' . a:port, s:chopt)
1488 call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')})
1489 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
1490 endfunc
1491
1492 func Test_close_handle()
1493 call ch_log('Test_close_handle()')
1494 call s:run_server('Ch_close_handle')
1495 endfunc
1496
1497 """"""""""
1498
1499 func Test_open_fail()
1500 call ch_log('Test_open_fail()')
1501 silent! let ch = ch_open("noserver")
1502 echo ch
1503 let d = ch
1504 endfunc
1505
1506 """"""""""
1507
1508 func Ch_open_delay(port)
1509 " Wait up to a second for the port to open.
1510 let s:chopt.waittime = 1000
1511 let channel = ch_open('localhost:' . a:port, s:chopt)
1512 unlet s:chopt.waittime
1513 if ch_status(channel) == "fail"
1514 call assert_report("Can't open channel")
1515 return
1516 endif
1517 call assert_equal('got it', ch_evalexpr(channel, 'hello!'))
1518 call ch_close(channel)
1519 endfunc
1520
1521 func Test_open_delay()
1522 call ch_log('Test_open_delay()')
1523 " The server will wait half a second before creating the port.
1524 call s:run_server('Ch_open_delay', 'delay')
1525 endfunc
1526
1527 """""""""
1528
1529 function MyFunction(a,b,c)
1530 let g:Ch_call_ret = [a:a, a:b, a:c]
1531 endfunc
1532
1533 function Ch_test_call(port)
1534 let handle = ch_open('localhost:' . a:port, s:chopt)
1535 if ch_status(handle) == "fail"
1536 call assert_report("Can't open channel")
1537 return
1538 endif
1539
1540 let g:Ch_call_ret = []
1541 call assert_equal('ok', ch_evalexpr(handle, 'call-func'))
1542 call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)})
1543 endfunc
1544
1545 func Test_call()
1546 call ch_log('Test_call()')
1547 call s:run_server('Ch_test_call')
1548 endfunc
1549
1550 """""""""
1551
1552 let g:Ch_job_exit_ret = 'not yet'
1553 function MyExitCb(job, status)
1554 let g:Ch_job_exit_ret = 'done'
1555 endfunc
1556
1557 function Ch_test_exit_callback(port)
1558 call job_setoptions(g:currentJob, {'exit_cb': 'MyExitCb'})
1559 let g:Ch_exit_job = g:currentJob
1560 call assert_equal('MyExitCb', job_info(g:currentJob)['exit_cb'])
1561 endfunc
1562
1563 func Test_exit_callback()
1564 if has('job')
1565 call ch_log('Test_exit_callback()')
1566 call s:run_server('Ch_test_exit_callback')
1567
1568 " wait up to a second for the job to exit
1569 for i in range(100)
1570 if g:Ch_job_exit_ret == 'done'
1571 break
1572 endif
1573 sleep 10m
1574 " calling job_status() triggers the callback
1575 call job_status(g:Ch_exit_job)
1576 endfor
1577
1578 call assert_equal('done', g:Ch_job_exit_ret)
1579 call assert_equal('dead', job_info(g:Ch_exit_job).status)
1580 unlet g:Ch_exit_job
1581 endif
1582 endfunc
1583
1584 function MyExitTimeCb(job, status)
1585 if job_info(a:job).process == g:exit_cb_val.process
1586 let g:exit_cb_val.end = reltime(g:exit_cb_val.start)
1587 endif
1588 call Resume()
1589 endfunction
1590
1591 func Test_exit_callback_interval()
1592 if !has('job')
1593 return
1594 endif
1595
1596 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
1597 let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1598 let g:exit_cb_val.process = job_info(job).process
1599 call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0')
1600 let elapsed = reltimefloat(g:exit_cb_val.end)
1601 call assert_true(elapsed > 0.5)
1602 call assert_true(elapsed < 1.0)
1603
1604 " case: unreferenced job, using timer
1605 if !has('timers')
1606 return
1607 endif
1608
1609 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0}
1610 let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'})
1611 let g:exit_cb_val.process = job_info(g:job).process
1612 unlet g:job
1613 call Standby(1000)
1614 if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0
1615 let elapsed = reltimefloat(g:exit_cb_val.end)
1616 else
1617 let elapsed = 1.0
1618 endif
1619 call assert_inrange(0.5, 1.0, elapsed)
1620 endfunc
1621
1622 """""""""
1623
1624 let g:Ch_close_ret = 'alive'
1625 function MyCloseCb(ch)
1626 let g:Ch_close_ret = 'closed'
1627 endfunc
1628
1629 function Ch_test_close_callback(port)
1630 let handle = ch_open('localhost:' . a:port, s:chopt)
1631 if ch_status(handle) == "fail"
1632 call assert_report("Can't open channel")
1633 return
1634 endif
1635 call ch_setoptions(handle, {'close_cb': 'MyCloseCb'})
1636
1637 call assert_equal('', ch_evalexpr(handle, 'close me'))
1638 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
1639 endfunc
1640
1641 func Test_close_callback()
1642 call ch_log('Test_close_callback()')
1643 call s:run_server('Ch_test_close_callback')
1644 endfunc
1645
1646 function Ch_test_close_partial(port)
1647 let handle = ch_open('localhost:' . a:port, s:chopt)
1648 if ch_status(handle) == "fail"
1649 call assert_report("Can't open channel")
1650 return
1651 endif
1652 let g:Ch_d = {}
1653 func g:Ch_d.closeCb(ch) dict
1654 let self.close_ret = 'closed'
1655 endfunc
1656 call ch_setoptions(handle, {'close_cb': g:Ch_d.closeCb})
1657
1658 call assert_equal('', ch_evalexpr(handle, 'close me'))
1659 call WaitForAssert({-> assert_equal('closed', g:Ch_d.close_ret)})
1660 unlet g:Ch_d
1661 endfunc
1662
1663 func Test_close_partial()
1664 call ch_log('Test_close_partial()')
1665 call s:run_server('Ch_test_close_partial')
1666 endfunc
1667
1668 func Test_job_start_invalid()
1669 call assert_fails('call job_start($x)', 'E474:')
1670 call assert_fails('call job_start("")', 'E474:')
1671 endfunc
1672
1673 func Test_job_stop_immediately()
1674 if !has('job')
1675 return
1676 endif
1677
1678 let g:job = job_start([s:python, '-c', 'import time;time.sleep(10)'])
1679 try
1680 call job_stop(g:job)
1681 call WaitForAssert({-> assert_equal('dead', job_status(g:job))})
1682 finally
1683 call job_stop(g:job, 'kill')
1684 unlet g:job
1685 endtry
1686 endfunc
1687
1688 " This was leaking memory.
1689 func Test_partial_in_channel_cycle()
1690 let d = {}
1691 let d.a = function('string', [d])
1692 try
1693 let d.b = ch_open('nowhere:123', {'close_cb': d.a})
1694 catch
1695 call assert_exception('E901:')
1696 endtry
1697 unlet d
1698 endfunc
1699
1700 func Test_using_freed_memory()
1701 let g:a = job_start(['ls'])
1702 sleep 10m
1703 call test_garbagecollect_now()
1704 endfunc
1705
1706 func Test_collapse_buffers()
1707 if !executable('cat') || !has('job')
1708 return
1709 endif
1710 sp test_channel.vim
1711 let g:linecount = line('$')
1712 close
1713 split testout
1714 1,$delete
1715 call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'})
1716 call WaitForAssert({-> assert_inrange(g:linecount, g:linecount + 1, line('$'))})
1717 bwipe!
1718 endfunc
1719
1720 func Test_write_to_deleted_buffer()
1721 if !executable('echo') || !has('job')
1722 return
1723 endif
1724 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
1725 let bufnr = bufnr('test_buffer')
1726 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
1727 call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
1728 call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
1729
1730 bdel test_buffer
1731 call assert_equal([], getbufline(bufnr, 1, '$'))
1732
1733 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0})
1734 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))})
1735 call assert_equal('nofile', getbufvar(bufnr, '&buftype'))
1736 call assert_equal('hide', getbufvar(bufnr, '&bufhidden'))
1737
1738 bwipe! test_buffer
1739 endfunc
1740
1741 func Test_cmd_parsing()
1742 if !has('unix')
1743 return
1744 endif
1745 call assert_false(filereadable("file with space"))
1746 let job = job_start('touch "file with space"')
1747 call WaitForAssert({-> assert_true(filereadable("file with space"))})
1748 call delete("file with space")
1749
1750 let job = job_start('touch file\ with\ space')
1751 call WaitForAssert({-> assert_true(filereadable("file with space"))})
1752 call delete("file with space")
1753 endfunc
1754
1755 func Test_raw_passes_nul()
1756 if !executable('cat') || !has('job')
1757 return
1758 endif
1759
1760 " Test lines from the job containing NUL are stored correctly in a buffer.
1761 new
1762 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
1763 w! Xtestread
1764 bwipe!
1765 split testout
1766 1,$delete
1767 call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'})
1768 call WaitFor('line("$") > 2')
1769 call assert_equal("asdf\nasdf", getline(1))
1770 call assert_equal("xxx\n", getline(2))
1771 call assert_equal("\nyyy", getline(3))
1772
1773 call delete('Xtestread')
1774 bwipe!
1775
1776 " Test lines from a buffer with NUL bytes are written correctly to the job.
1777 new mybuffer
1778 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"])
1779 let g:Ch_job = job_start('cat', {'in_io': 'buffer', 'in_name': 'mybuffer', 'out_io': 'file', 'out_name': 'Xtestwrite'})
1780 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))})
1781 bwipe!
1782 split Xtestwrite
1783 call assert_equal("asdf\nasdf", getline(1))
1784 call assert_equal("xxx\n", getline(2))
1785 call assert_equal("\nyyy", getline(3))
1786 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xtestwrite$'))
1787
1788 call delete('Xtestwrite')
1789 bwipe!
1790 endfunc
1791
1792 func Test_read_nonl_line()
1793 if !has('job')
1794 return
1795 endif
1796
1797 let g:linecount = 0
1798 let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1799 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
1800 call WaitForAssert({-> assert_equal(3, g:linecount)})
1801 unlet g:linecount
1802 endfunc
1803
1804 func Test_read_nonl_in_close_cb()
1805 if !has('job')
1806 return
1807 endif
1808
1809 func s:close_cb(ch)
1810 while ch_status(a:ch) == 'buffered'
1811 let g:out .= ch_read(a:ch)
1812 endwhile
1813 endfunc
1814
1815 let g:out = ''
1816 let arg = 'import sys;sys.stdout.write("1\n2\n3")'
1817 call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')})
1818 call WaitForAssert({-> assert_equal('123', g:out)})
1819 unlet g:out
1820 delfunc s:close_cb
1821 endfunc
1822
1823 func Test_read_from_terminated_job()
1824 if !has('job')
1825 return
1826 endif
1827
1828 let g:linecount = 0
1829 let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")'
1830 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}})
1831 call WaitForAssert({-> assert_equal(1, g:linecount)})
1832 unlet g:linecount
1833 endfunc
1834
1835 func Test_job_start_windows()
1836 CheckFeature job
1837 CheckMSWindows
1838
1839 " Check that backslash in $COMSPEC is handled properly.
1840 let g:echostr = ''
1841 let cmd = $COMSPEC . ' /c echo 123'
1842 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:echostr .= msg")}})
1843 let info = job_info(job)
1844 call assert_equal([$COMSPEC, '/c', 'echo', '123'], info.cmd)
1845
1846 call WaitForAssert({-> assert_equal("123", g:echostr)})
1847 unlet g:echostr
1848 endfunc
1849
1850 func Test_env()
1851 CheckFeature job
1852
1853 let g:envstr = ''
1854 if has('win32')
1855 let cmd = ['cmd', '/c', 'echo %FOO%']
1856 else
1857 let cmd = [&shell, &shellcmdflag, 'echo $FOO']
1858 endif
1859 call assert_fails('call job_start(cmd, {"env": 1})', 'E475:')
1860 call job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'env': {'FOO': 'bar'}})
1861 call WaitForAssert({-> assert_equal("bar", g:envstr)})
1862 unlet g:envstr
1863 endfunc
1864
1865 func Test_cwd()
1866 CheckFeature job
1867
1868 let g:envstr = ''
1869 if has('win32')
1870 let expect = $TEMP
1871 let cmd = ['cmd', '/c', 'echo %CD%']
1872 else
1873 let expect = $HOME
1874 let cmd = ['pwd']
1875 endif
1876 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'cwd': expect})
1877 try
1878 call WaitForAssert({-> assert_notequal("", g:envstr)})
1879 let expect = substitute(expect, '[/\\]$', '', '')
1880 let g:envstr = substitute(g:envstr, '[/\\]$', '', '')
1881 if $CI != '' && stridx(g:envstr, '/private/') == 0
1882 let g:envstr = g:envstr[8:]
1883 endif
1884 call assert_equal(expect, g:envstr)
1885 finally
1886 call job_stop(job)
1887 unlet g:envstr
1888 endtry
1889 endfunc
1890
1891 function Ch_test_close_lambda(port)
1892 let handle = ch_open('localhost:' . a:port, s:chopt)
1893 if ch_status(handle) == "fail"
1894 call assert_report("Can't open channel")
1895 return
1896 endif
1897 let g:Ch_close_ret = ''
1898 call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}})
1899
1900 call assert_equal('', ch_evalexpr(handle, 'close me'))
1901 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)})
1902 endfunc
1903
1904 func Test_close_lambda()
1905 call ch_log('Test_close_lambda()')
1906 call s:run_server('Ch_test_close_lambda')
1907 endfunc
1908
1909 func s:test_list_args(cmd, out, remove_lf)
1910 try
1911 let g:out = ''
1912 let job = job_start([s:python, '-c', a:cmd], {'callback': {ch, msg -> execute('let g:out .= msg')}, 'out_mode': 'raw'})
1913 call WaitFor('"" != g:out')
1914 if has('win32')
1915 let g:out = substitute(g:out, '\r', '', 'g')
1916 endif
1917 if a:remove_lf
1918 let g:out = substitute(g:out, '\n$', '', 'g')
1919 endif
1920 call assert_equal(a:out, g:out)
1921 finally
1922 call job_stop(job)
1923 unlet g:out
1924 endtry
1925 endfunc
1926
1927 func Test_list_args()
1928 CheckFeature job
1929
1930 call s:test_list_args('import sys;sys.stdout.write("hello world")', "hello world", 0)
1931 call s:test_list_args('import sys;sys.stdout.write("hello\nworld")', "hello\nworld", 0)
1932 call s:test_list_args('import sys;sys.stdout.write(''hello\nworld'')', "hello\nworld", 0)
1933 call s:test_list_args('import sys;sys.stdout.write(''hello"world'')', "hello\"world", 0)
1934 call s:test_list_args('import sys;sys.stdout.write(''hello^world'')', "hello^world", 0)
1935 call s:test_list_args('import sys;sys.stdout.write("hello&&world")', "hello&&world", 0)
1936 call s:test_list_args('import sys;sys.stdout.write(''hello\\world'')', "hello\\world", 0)
1937 call s:test_list_args('import sys;sys.stdout.write(''hello\\\\world'')', "hello\\\\world", 0)
1938 call s:test_list_args('import sys;sys.stdout.write("hello\"world\"")', 'hello"world"', 0)
1939 call s:test_list_args('import sys;sys.stdout.write("h\"ello worl\"d")', 'h"ello worl"d', 0)
1940 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo wor\\\"l\"d")', 'h"e\"llo wor\"l"d', 0)
1941 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo world")', 'h"e\"llo world', 0)
1942 call s:test_list_args('import sys;sys.stdout.write("hello\tworld")', "hello\tworld", 0)
1943
1944 " tests which not contain spaces in the argument
1945 call s:test_list_args('print("hello\nworld")', "hello\nworld", 1)
1946 call s:test_list_args('print(''hello\nworld'')', "hello\nworld", 1)
1947 call s:test_list_args('print(''hello"world'')', "hello\"world", 1)
1948 call s:test_list_args('print(''hello^world'')', "hello^world", 1)
1949 call s:test_list_args('print("hello&&world")', "hello&&world", 1)
1950 call s:test_list_args('print(''hello\\world'')', "hello\\world", 1)
1951 call s:test_list_args('print(''hello\\\\world'')', "hello\\\\world", 1)
1952 call s:test_list_args('print("hello\"world\"")', 'hello"world"', 1)
1953 call s:test_list_args('print("hello\tworld")', "hello\tworld", 1)
1954 endfunc
1955
1956 " Do this last, it stops any channel log. 1972 " Do this last, it stops any channel log.
1957 func Test_zz_ch_log() 1973 func Test_zz_ch_log()
1958 call ch_logfile('Xlog', 'w') 1974 call ch_logfile('Xlog', 'w')
1959 call ch_log('hello there') 1975 call ch_log('hello there')
1960 call ch_log('%s%s') 1976 call ch_log('%s%s')
1962 let text = readfile('Xlog') 1978 let text = readfile('Xlog')
1963 call assert_match("hello there", text[1]) 1979 call assert_match("hello there", text[1])
1964 call assert_match("%s%s", text[2]) 1980 call assert_match("%s%s", text[2])
1965 call delete('Xlog') 1981 call delete('Xlog')
1966 endfunc 1982 endfunc
1967
1968 func Test_keep_pty_open()
1969 if !has('unix')
1970 return
1971 endif
1972
1973 let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"',
1974 \ {'out_io': 'null', 'err_io': 'null', 'pty': 1})
1975 let elapsed = WaitFor({-> job_status(job) ==# 'dead'})
1976 call assert_inrange(200, 1000, elapsed)
1977 call job_stop(job)
1978 endfunc
1979
1980 func Test_job_start_in_timer()
1981 CheckFeature job
1982 CheckFeature timers
1983
1984 func OutCb(chan, msg)
1985 let g:val += 1
1986 endfunc
1987
1988 func ExitCb(job, status)
1989 let g:val += 1
1990 call Resume()
1991 endfunc
1992
1993 func TimerCb(timer)
1994 if has('win32')
1995 let cmd = ['cmd', '/c', 'echo.']
1996 else
1997 let cmd = ['echo']
1998 endif
1999 let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'})
2000 call substitute(repeat('a', 100000), '.', '', 'g')
2001 endfunc
2002
2003 " We should be interrupted before 'updatetime' elapsed.
2004 let g:val = 0
2005 call timer_start(1, 'TimerCb')
2006 let elapsed = Standby(&ut)
2007 call assert_inrange(1, &ut / 2, elapsed)
2008
2009 " Wait for both OutCb() and ExitCb() to have been called before deleting
2010 " them.
2011 call WaitForAssert({-> assert_equal(2, g:val)})
2012 call job_stop(g:job)
2013
2014 delfunc OutCb
2015 delfunc ExitCb
2016 delfunc TimerCb
2017 unlet! g:val
2018 unlet! g:job
2019 endfunc
2020
2021 func Test_raw_large_data()
2022 try
2023 let g:out = ''
2024 let job = job_start(s:python . " test_channel_pipe.py",
2025 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1,
2026 \ 'callback': {ch, msg -> execute('let g:out .= msg')}})
2027
2028 let outlen = 79999
2029 let want = repeat('X', outlen) . "\n"
2030 call ch_sendraw(job, want)
2031 call WaitFor({-> len(g:out) >= outlen}, 10000)
2032 call WaitForAssert({-> assert_equal("dead", job_status(job))})
2033 call assert_equal(want, substitute(g:out, '\r', '', 'g'))
2034 finally
2035 call job_stop(job)
2036 unlet g:out
2037 endtry
2038 endfunc
2039
2040 func Test_no_hang_windows()
2041 CheckFeature job
2042 CheckMSWindows
2043
2044 try
2045 let job = job_start(s:python . " test_channel_pipe.py busy",
2046 \ {'mode': 'raw', 'drop': 'never', 'noblock': 0})
2047 call assert_fails('call ch_sendraw(job, repeat("X", 80000))', 'E631:')
2048 finally
2049 call job_stop(job)
2050 endtry
2051 endfunc
2052
2053 func Test_job_exitval_and_termsig()
2054 if !has('unix')
2055 return
2056 endif
2057
2058 " Terminate job normally
2059 let cmd = ['echo']
2060 let job = job_start(cmd)
2061 call WaitForAssert({-> assert_equal("dead", job_status(job))})
2062 let info = job_info(job)
2063 call assert_equal(0, info.exitval)
2064 call assert_equal("", info.termsig)
2065
2066 " Terminate job by signal
2067 let cmd = ['sleep', '10']
2068 let job = job_start(cmd)
2069 sleep 10m
2070 call job_stop(job)
2071 call WaitForAssert({-> assert_equal("dead", job_status(job))})
2072 let info = job_info(job)
2073 call assert_equal(-1, info.exitval)
2074 call assert_equal("term", info.termsig)
2075 endfunc
2076
2077 func Test_job_tty_in_out()
2078 CheckFeature job
2079 CheckUnix
2080
2081 call writefile(['test'], 'Xtestin')
2082 let in_opts = [{},
2083 \ {'in_io': 'null'},
2084 \ {'in_io': 'file', 'in_name': 'Xtestin'}]
2085 let out_opts = [{},
2086 \ {'out_io': 'null'},
2087 \ {'out_io': 'file', 'out_name': 'Xtestout'}]
2088 let err_opts = [{},
2089 \ {'err_io': 'null'},
2090 \ {'err_io': 'file', 'err_name': 'Xtesterr'},
2091 \ {'err_io': 'out'}]
2092 let opts = []
2093
2094 for in_opt in in_opts
2095 let x = copy(in_opt)
2096 for out_opt in out_opts
2097 let x = extend(copy(x), out_opt)
2098 for err_opt in err_opts
2099 let x = extend(copy(x), err_opt)
2100 let opts += [extend({'pty': 1}, x)]
2101 endfor
2102 endfor
2103 endfor
2104
2105 for opt in opts
2106 let job = job_start('echo', opt)
2107 let info = job_info(job)
2108 let msg = printf('option={"in_io": "%s", "out_io": "%s", "err_io": "%s"}',
2109 \ get(opt, 'in_io', 'tty'),
2110 \ get(opt, 'out_io', 'tty'),
2111 \ get(opt, 'err_io', 'tty'))
2112
2113 if !has_key(opt, 'in_io') || !has_key(opt, 'out_io') || !has_key(opt, 'err_io')
2114 call assert_notequal('', info.tty_in, msg)
2115 else
2116 call assert_equal('', info.tty_in, msg)
2117 endif
2118 call assert_equal(info.tty_in, info.tty_out, msg)
2119
2120 call WaitForAssert({-> assert_equal('dead', job_status(job))})
2121 endfor
2122
2123 call delete('Xtestin')
2124 call delete('Xtestout')
2125 call delete('Xtesterr')
2126 endfunc