Mercurial > vim
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 |