1" Test for channel functions. 2 3if !has('channel') 4 finish 5endif 6 7source shared.vim 8 9let s:python = PythonProg() 10if s:python == '' 11 " Can't run this test without Python. 12 finish 13endif 14 15" Uncomment the next line to see what happens. Output is in 16" src/testdir/channellog. 17" call ch_logfile('channellog', 'w') 18 19let s:chopt = {} 20 21" Run "testfunc" after sarting the server and stop the server afterwards. 22func s:run_server(testfunc, ...) 23 call RunServer('test_channel.py', a:testfunc, a:000) 24endfunc 25 26" Return a list of open files. 27" Can be used to make sure no resources leaked. 28" Returns an empty list on systems where this is not supported. 29func s:get_resources() 30 let pid = getpid() 31 32 if executable('lsof') 33 return systemlist('lsof -p ' . pid . ' | awk ''$4~/^[0-9]*[rwu]$/&&$5=="REG"{print$NF}''') 34 elseif isdirectory('/proc/' . pid . '/fd/') 35 return systemlist('readlink /proc/' . pid . '/fd/* | grep -v ''^/dev/''') 36 else 37 return [] 38 endif 39endfunc 40 41let g:Ch_responseMsg = '' 42func Ch_requestHandler(handle, msg) 43 let g:Ch_responseHandle = a:handle 44 let g:Ch_responseMsg = a:msg 45endfunc 46 47func Ch_communicate(port) 48 " Avoid dropping messages, since we don't use a callback here. 49 let s:chopt.drop = 'never' 50 " Also add the noblock flag to try it out. 51 let s:chopt.noblock = 1 52 let handle = ch_open('localhost:' . a:port, s:chopt) 53 unlet s:chopt.drop 54 unlet s:chopt.noblock 55 if ch_status(handle) == "fail" 56 call assert_report("Can't open channel") 57 return 58 endif 59 if has('job') 60 " check that getjob without a job is handled correctly 61 call assert_equal('no process', string(ch_getjob(handle))) 62 endif 63 let dict = ch_info(handle) 64 call assert_true(dict.id != 0) 65 call assert_equal('open', dict.status) 66 call assert_equal(a:port, string(dict.port)) 67 call assert_equal('open', dict.sock_status) 68 call assert_equal('socket', dict.sock_io) 69 70 " Simple string request and reply. 71 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 72 73 " Malformed command should be ignored. 74 call assert_equal('ok', ch_evalexpr(handle, 'malformed1')) 75 call assert_equal('ok', ch_evalexpr(handle, 'malformed2')) 76 call assert_equal('ok', ch_evalexpr(handle, 'malformed3')) 77 78 " split command should work 79 call assert_equal('ok', ch_evalexpr(handle, 'split')) 80 call WaitFor('exists("g:split")') 81 call assert_equal(123, g:split) 82 83 " string with ][ should work 84 call assert_equal('this][that', ch_evalexpr(handle, 'echo this][that')) 85 86 " nothing to read now 87 call assert_equal(0, ch_canread(handle)) 88 89 " sending three messages quickly then reading should work 90 for i in range(3) 91 call ch_sendexpr(handle, 'echo hello ' . i) 92 endfor 93 call assert_equal('hello 0', ch_read(handle)[1]) 94 call assert_equal('hello 1', ch_read(handle)[1]) 95 call assert_equal('hello 2', ch_read(handle)[1]) 96 97 " Request that triggers sending two ex commands. These will usually be 98 " handled before getting the response, but it's not guaranteed, thus wait a 99 " tiny bit for the commands to get executed. 100 call assert_equal('ok', ch_evalexpr(handle, 'make change')) 101 call WaitForAssert({-> assert_equal("added2", getline("$"))}) 102 call assert_equal('added1', getline(line('$') - 1)) 103 104 " Request command "foo bar", which fails silently. 105 call assert_equal('ok', ch_evalexpr(handle, 'bad command')) 106 call WaitForAssert({-> assert_match("E492:.*foo bar", v:errmsg)}) 107 108 call assert_equal('ok', ch_evalexpr(handle, 'do normal', {'timeout': 100})) 109 call WaitForAssert({-> assert_equal('added more', getline('$'))}) 110 111 " Send a request with a specific handler. 112 call ch_sendexpr(handle, 'hello!', {'callback': 'Ch_requestHandler'}) 113 call WaitFor('exists("g:Ch_responseHandle")') 114 if !exists('g:Ch_responseHandle') 115 call assert_report('g:Ch_responseHandle was not set') 116 else 117 call assert_equal(handle, g:Ch_responseHandle) 118 unlet g:Ch_responseHandle 119 endif 120 call assert_equal('got it', g:Ch_responseMsg) 121 122 let g:Ch_responseMsg = '' 123 call ch_sendexpr(handle, 'hello!', {'callback': function('Ch_requestHandler')}) 124 call WaitFor('exists("g:Ch_responseHandle")') 125 if !exists('g:Ch_responseHandle') 126 call assert_report('g:Ch_responseHandle was not set') 127 else 128 call assert_equal(handle, g:Ch_responseHandle) 129 unlet g:Ch_responseHandle 130 endif 131 call assert_equal('got it', g:Ch_responseMsg) 132 133 " Using lambda. 134 let g:Ch_responseMsg = '' 135 call ch_sendexpr(handle, 'hello!', {'callback': {a, b -> Ch_requestHandler(a, b)}}) 136 call WaitFor('exists("g:Ch_responseHandle")') 137 if !exists('g:Ch_responseHandle') 138 call assert_report('g:Ch_responseHandle was not set') 139 else 140 call assert_equal(handle, g:Ch_responseHandle) 141 unlet g:Ch_responseHandle 142 endif 143 call assert_equal('got it', g:Ch_responseMsg) 144 145 " Collect garbage, tests that our handle isn't collected. 146 call test_garbagecollect_now() 147 148 " check setting options (without testing the effect) 149 call ch_setoptions(handle, {'callback': 's:NotUsed'}) 150 call ch_setoptions(handle, {'timeout': 1111}) 151 call ch_setoptions(handle, {'mode': 'json'}) 152 call assert_fails("call ch_setoptions(handle, {'waittime': 111})", "E475") 153 call ch_setoptions(handle, {'callback': ''}) 154 call ch_setoptions(handle, {'drop': 'never'}) 155 call ch_setoptions(handle, {'drop': 'auto'}) 156 call assert_fails("call ch_setoptions(handle, {'drop': 'bad'})", "E475") 157 158 " Send an eval request that works. 159 call assert_equal('ok', ch_evalexpr(handle, 'eval-works')) 160 sleep 10m 161 call assert_equal([-1, 'foo123'], ch_evalexpr(handle, 'eval-result')) 162 163 " Send an eval request with special characters. 164 call assert_equal('ok', ch_evalexpr(handle, 'eval-special')) 165 sleep 10m 166 call assert_equal([-2, "foo\x7f\x10\x01bar"], ch_evalexpr(handle, 'eval-result')) 167 168 " Send an eval request to get a line with special characters. 169 call setline(3, "a\nb\<CR>c\x01d\x7fe") 170 call assert_equal('ok', ch_evalexpr(handle, 'eval-getline')) 171 sleep 10m 172 call assert_equal([-3, "a\nb\<CR>c\x01d\x7fe"], ch_evalexpr(handle, 'eval-result')) 173 174 " Send an eval request that fails. 175 call assert_equal('ok', ch_evalexpr(handle, 'eval-fails')) 176 sleep 10m 177 call assert_equal([-4, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 178 179 " Send an eval request that works but can't be encoded. 180 call assert_equal('ok', ch_evalexpr(handle, 'eval-error')) 181 sleep 10m 182 call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 183 184 " Send a bad eval request. There will be no response. 185 call assert_equal('ok', ch_evalexpr(handle, 'eval-bad')) 186 sleep 10m 187 call assert_equal([-5, 'ERROR'], ch_evalexpr(handle, 'eval-result')) 188 189 " Send an expr request 190 call assert_equal('ok', ch_evalexpr(handle, 'an expr')) 191 call WaitForAssert({-> assert_equal('three', getline('$'))}) 192 call assert_equal('one', getline(line('$') - 2)) 193 call assert_equal('two', getline(line('$') - 1)) 194 195 " Request a redraw, we don't check for the effect. 196 call assert_equal('ok', ch_evalexpr(handle, 'redraw')) 197 call assert_equal('ok', ch_evalexpr(handle, 'redraw!')) 198 199 call assert_equal('ok', ch_evalexpr(handle, 'empty-request')) 200 201 " Reading while there is nothing available. 202 call assert_equal(v:none, ch_read(handle, {'timeout': 0})) 203 let start = reltime() 204 call assert_equal(v:none, ch_read(handle, {'timeout': 333})) 205 let elapsed = reltime(start) 206 call assert_true(reltimefloat(elapsed) > 0.3) 207 call assert_true(reltimefloat(elapsed) < 0.6) 208 209 " Send without waiting for a response, then wait for a response. 210 call ch_sendexpr(handle, 'wait a bit') 211 let resp = ch_read(handle) 212 call assert_equal(type([]), type(resp)) 213 call assert_equal(type(11), type(resp[0])) 214 call assert_equal('waited', resp[1]) 215 216 " make the server quit, can't check if this works, should not hang. 217 call ch_sendexpr(handle, '!quit!') 218endfunc 219 220func Test_communicate() 221 call ch_log('Test_communicate()') 222 call s:run_server('Ch_communicate') 223endfunc 224 225" Test that we can open two channels. 226func Ch_two_channels(port) 227 let handle = ch_open('localhost:' . a:port, s:chopt) 228 call assert_equal(v:t_channel, type(handle)) 229 if ch_status(handle) == "fail" 230 call assert_report("Can't open channel") 231 return 232 endif 233 234 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 235 236 let newhandle = ch_open('localhost:' . a:port, s:chopt) 237 if ch_status(newhandle) == "fail" 238 call assert_report("Can't open second channel") 239 return 240 endif 241 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 242 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 243 244 call ch_close(handle) 245 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 246 247 call ch_close(newhandle) 248endfunc 249 250func Test_two_channels() 251 call ch_log('Test_two_channels()') 252 call s:run_server('Ch_two_channels') 253endfunc 254 255" Test that a server crash is handled gracefully. 256func Ch_server_crash(port) 257 let handle = ch_open('localhost:' . a:port, s:chopt) 258 if ch_status(handle) == "fail" 259 call assert_report("Can't open channel") 260 return 261 endif 262 263 call ch_evalexpr(handle, '!crash!') 264 265 sleep 10m 266endfunc 267 268func Test_server_crash() 269 call ch_log('Test_server_crash()') 270 call s:run_server('Ch_server_crash') 271endfunc 272 273""""""""" 274 275func Ch_handler(chan, msg) 276 call ch_log('Ch_handler()') 277 unlet g:Ch_reply 278 let g:Ch_reply = a:msg 279endfunc 280 281func Ch_channel_handler(port) 282 let handle = ch_open('localhost:' . a:port, s:chopt) 283 if ch_status(handle) == "fail" 284 call assert_report("Can't open channel") 285 return 286 endif 287 288 " Test that it works while waiting on a numbered message. 289 call assert_equal('ok', ch_evalexpr(handle, 'call me')) 290 call WaitForAssert({-> assert_equal('we called you', g:Ch_reply)}) 291 292 " Test that it works while not waiting on a numbered message. 293 call ch_sendexpr(handle, 'call me again') 294 call WaitForAssert({-> assert_equal('we did call you', g:Ch_reply)}) 295endfunc 296 297func Test_channel_handler() 298 call ch_log('Test_channel_handler()') 299 let g:Ch_reply = "" 300 let s:chopt.callback = 'Ch_handler' 301 call s:run_server('Ch_channel_handler') 302 let g:Ch_reply = "" 303 let s:chopt.callback = function('Ch_handler') 304 call s:run_server('Ch_channel_handler') 305 unlet s:chopt.callback 306endfunc 307 308""""""""" 309 310let g:Ch_reply = '' 311func Ch_zeroHandler(chan, msg) 312 unlet g:Ch_reply 313 let g:Ch_reply = a:msg 314endfunc 315 316let g:Ch_zero_reply = '' 317func Ch_oneHandler(chan, msg) 318 unlet g:Ch_zero_reply 319 let g:Ch_zero_reply = a:msg 320endfunc 321 322func Ch_channel_zero(port) 323 let handle = ch_open('localhost:' . a:port, s:chopt) 324 if ch_status(handle) == "fail" 325 call assert_report("Can't open channel") 326 return 327 endif 328 329 " Check that eval works. 330 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 331 332 " Check that eval works if a zero id message is sent back. 333 let g:Ch_reply = '' 334 call assert_equal('sent zero', ch_evalexpr(handle, 'send zero')) 335 if s:has_handler 336 call WaitForAssert({-> assert_equal('zero index', g:Ch_reply)}) 337 else 338 sleep 20m 339 call assert_equal('', g:Ch_reply) 340 endif 341 342 " Check that handler works if a zero id message is sent back. 343 let g:Ch_reply = '' 344 let g:Ch_zero_reply = '' 345 call ch_sendexpr(handle, 'send zero', {'callback': 'Ch_oneHandler'}) 346 call WaitForAssert({-> assert_equal('sent zero', g:Ch_zero_reply)}) 347 if s:has_handler 348 call assert_equal('zero index', g:Ch_reply) 349 else 350 call assert_equal('', g:Ch_reply) 351 endif 352endfunc 353 354func Test_zero_reply() 355 call ch_log('Test_zero_reply()') 356 " Run with channel handler 357 let s:has_handler = 1 358 let s:chopt.callback = 'Ch_zeroHandler' 359 call s:run_server('Ch_channel_zero') 360 unlet s:chopt.callback 361 362 " Run without channel handler 363 let s:has_handler = 0 364 call s:run_server('Ch_channel_zero') 365endfunc 366 367""""""""" 368 369let g:Ch_reply1 = "" 370func Ch_handleRaw1(chan, msg) 371 unlet g:Ch_reply1 372 let g:Ch_reply1 = a:msg 373endfunc 374 375let g:Ch_reply2 = "" 376func Ch_handleRaw2(chan, msg) 377 unlet g:Ch_reply2 378 let g:Ch_reply2 = a:msg 379endfunc 380 381let g:Ch_reply3 = "" 382func Ch_handleRaw3(chan, msg) 383 unlet g:Ch_reply3 384 let g:Ch_reply3 = a:msg 385endfunc 386 387func Ch_raw_one_time_callback(port) 388 let handle = ch_open('localhost:' . a:port, s:chopt) 389 if ch_status(handle) == "fail" 390 call assert_report("Can't open channel") 391 return 392 endif 393 call ch_setoptions(handle, {'mode': 'raw'}) 394 395 " The messages are sent raw, we do our own JSON strings here. 396 call ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'}) 397 call WaitForAssert({-> assert_equal("[1, \"got it\"]", g:Ch_reply1)}) 398 call ch_sendraw(handle, "[2, \"echo something\"]\n", {'callback': 'Ch_handleRaw2'}) 399 call ch_sendraw(handle, "[3, \"wait a bit\"]\n", {'callback': 'Ch_handleRaw3'}) 400 call WaitForAssert({-> assert_equal("[2, \"something\"]", g:Ch_reply2)}) 401 " wait for the 200 msec delayed reply 402 call WaitForAssert({-> assert_equal("[3, \"waited\"]", g:Ch_reply3)}) 403endfunc 404 405func Test_raw_one_time_callback() 406 call ch_log('Test_raw_one_time_callback()') 407 call s:run_server('Ch_raw_one_time_callback') 408endfunc 409 410""""""""" 411 412" Test that trying to connect to a non-existing port fails quickly. 413func Test_connect_waittime() 414 call ch_log('Test_connect_waittime()') 415 let start = reltime() 416 let handle = ch_open('localhost:9876', s:chopt) 417 if ch_status(handle) != "fail" 418 " Oops, port does exists. 419 call ch_close(handle) 420 else 421 let elapsed = reltime(start) 422 call assert_true(reltimefloat(elapsed) < 1.0) 423 endif 424 425 " We intend to use a socket that doesn't exist and wait for half a second 426 " before giving up. If the socket does exist it can fail in various ways. 427 " Check for "Connection reset by peer" to avoid flakyness. 428 let start = reltime() 429 try 430 let handle = ch_open('localhost:9867', {'waittime': 500}) 431 if ch_status(handle) != "fail" 432 " Oops, port does exists. 433 call ch_close(handle) 434 else 435 " Failed connection should wait about 500 msec. Can be longer if the 436 " computer is busy with other things. 437 let elapsed = reltime(start) 438 call assert_true(reltimefloat(elapsed) > 0.3) 439 call assert_true(reltimefloat(elapsed) < 1.5) 440 endif 441 catch 442 if v:exception !~ 'Connection reset by peer' 443 call assert_report("Caught exception: " . v:exception) 444 endif 445 endtry 446endfunc 447 448""""""""" 449 450func Test_raw_pipe() 451 if !has('job') 452 return 453 endif 454 call ch_log('Test_raw_pipe()') 455 " Add a dummy close callback to avoid that messages are dropped when calling 456 " ch_canread(). 457 " Also test the non-blocking option. 458 let job = job_start(s:python . " test_channel_pipe.py", 459 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 460 call assert_equal(v:t_job, type(job)) 461 call assert_equal("run", job_status(job)) 462 463 call assert_equal("open", ch_status(job)) 464 call assert_equal("open", ch_status(job), {"part": "out"}) 465 call assert_equal("open", ch_status(job), {"part": "err"}) 466 call assert_fails('call ch_status(job, {"in_mode": "raw"})', 'E475:') 467 call assert_fails('call ch_status(job, {"part": "in"})', 'E475:') 468 469 let dict = ch_info(job) 470 call assert_true(dict.id != 0) 471 call assert_equal('open', dict.status) 472 call assert_equal('open', dict.out_status) 473 call assert_equal('RAW', dict.out_mode) 474 call assert_equal('pipe', dict.out_io) 475 call assert_equal('open', dict.err_status) 476 call assert_equal('RAW', dict.err_mode) 477 call assert_equal('pipe', dict.err_io) 478 479 try 480 " For a change use the job where a channel is expected. 481 call ch_sendraw(job, "echo something\n") 482 let msg = ch_readraw(job) 483 call assert_equal("something\n", substitute(msg, "\r", "", 'g')) 484 485 call ch_sendraw(job, "double this\n") 486 let g:handle = job_getchannel(job) 487 call WaitFor('ch_canread(g:handle)') 488 unlet g:handle 489 let msg = ch_readraw(job) 490 call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g')) 491 492 let g:Ch_reply = "" 493 call ch_sendraw(job, "double this\n", {'callback': 'Ch_handler'}) 494 call WaitForAssert({-> assert_equal("this\nAND this\n", substitute(g:Ch_reply, "\r", "", 'g'))}) 495 496 let reply = ch_evalraw(job, "quit\n", {'timeout': 100}) 497 call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) 498 finally 499 call job_stop(job) 500 endtry 501 502 let g:Ch_job = job 503 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 504 let info = job_info(job) 505 call assert_equal("dead", info.status) 506 call assert_equal("term", info.stoponexit) 507 call assert_equal(2, len(info.cmd)) 508 call assert_equal("test_channel_pipe.py", info.cmd[1]) 509 510 let found = 0 511 for j in job_info() 512 if j == job 513 let found += 1 514 endif 515 endfor 516 call assert_equal(1, found) 517endfunc 518 519func Test_raw_pipe_blob() 520 if !has('job') 521 return 522 endif 523 call ch_log('Test_raw_pipe_blob()') 524 " Add a dummy close callback to avoid that messages are dropped when calling 525 " ch_canread(). 526 " Also test the non-blocking option. 527 let job = job_start(s:python . " test_channel_pipe.py", 528 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 529 call assert_equal(v:t_job, type(job)) 530 call assert_equal("run", job_status(job)) 531 532 call assert_equal("open", ch_status(job)) 533 call assert_equal("open", ch_status(job), {"part": "out"}) 534 535 try 536 " Create a blob with the echo command and write it. 537 let blob = 0z00 538 let cmd = "echo something\n" 539 for i in range(0, len(cmd) - 1) 540 let blob[i] = char2nr(cmd[i]) 541 endfor 542 call assert_equal(len(cmd), len(blob)) 543 call ch_sendraw(job, blob) 544 545 " Read a blob with the reply. 546 let msg = ch_readblob(job) 547 let expected = 'something' 548 for i in range(0, len(expected) - 1) 549 call assert_equal(char2nr(expected[i]), msg[i]) 550 endfor 551 552 let reply = ch_evalraw(job, "quit\n", {'timeout': 100}) 553 call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) 554 finally 555 call job_stop(job) 556 endtry 557 558 let g:Ch_job = job 559 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 560 let info = job_info(job) 561 call assert_equal("dead", info.status) 562endfunc 563 564func Test_nl_pipe() 565 if !has('job') 566 return 567 endif 568 call ch_log('Test_nl_pipe()') 569 let job = job_start([s:python, "test_channel_pipe.py"]) 570 call assert_equal("run", job_status(job)) 571 try 572 let handle = job_getchannel(job) 573 call ch_sendraw(handle, "echo something\n") 574 call assert_equal("something", ch_readraw(handle)) 575 576 call ch_sendraw(handle, "echoerr wrong\n") 577 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'})) 578 579 call ch_sendraw(handle, "double this\n") 580 call assert_equal("this", ch_readraw(handle)) 581 call assert_equal("AND this", ch_readraw(handle)) 582 583 call ch_sendraw(handle, "split this line\n") 584 call assert_equal("this linethis linethis line", ch_read(handle)) 585 586 let reply = ch_evalraw(handle, "quit\n") 587 call assert_equal("Goodbye!", reply) 588 finally 589 call job_stop(job) 590 endtry 591endfunc 592 593func Test_nl_err_to_out_pipe() 594 if !has('job') 595 return 596 endif 597 call ch_logfile('Xlog') 598 call ch_log('Test_nl_err_to_out_pipe()') 599 let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'}) 600 call assert_equal("run", job_status(job)) 601 try 602 let handle = job_getchannel(job) 603 call ch_sendraw(handle, "echo something\n") 604 call assert_equal("something", ch_readraw(handle)) 605 606 call ch_sendraw(handle, "echoerr wrong\n") 607 call assert_equal("wrong", ch_readraw(handle)) 608 finally 609 call job_stop(job) 610 call ch_logfile('') 611 let loglines = readfile('Xlog') 612 call assert_true(len(loglines) > 10) 613 let found_test = 0 614 let found_send = 0 615 let found_recv = 0 616 let found_stop = 0 617 for l in loglines 618 if l =~ 'Test_nl_err_to_out_pipe' 619 let found_test = 1 620 endif 621 if l =~ 'SEND on.*echo something' 622 let found_send = 1 623 endif 624 if l =~ 'RECV on.*something' 625 let found_recv = 1 626 endif 627 if l =~ 'Stopping job with' 628 let found_stop = 1 629 endif 630 endfor 631 call assert_equal(1, found_test) 632 call assert_equal(1, found_send) 633 call assert_equal(1, found_recv) 634 call assert_equal(1, found_stop) 635 " On MS-Windows need to sleep for a moment to be able to delete the file. 636 sleep 10m 637 call delete('Xlog') 638 endtry 639endfunc 640 641func Stop_g_job() 642 call job_stop(g:job) 643 if has('win32') 644 " On MS-Windows the server must close the file handle before we are able 645 " to delete the file. 646 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 647 sleep 10m 648 endif 649endfunc 650 651func Test_nl_read_file() 652 if !has('job') 653 return 654 endif 655 call ch_log('Test_nl_read_file()') 656 call writefile(['echo something', 'echoerr wrong', 'double this'], 'Xinput') 657 let g:job = job_start(s:python . " test_channel_pipe.py", 658 \ {'in_io': 'file', 'in_name': 'Xinput'}) 659 call assert_equal("run", job_status(g:job)) 660 try 661 let handle = job_getchannel(g:job) 662 call assert_equal("something", ch_readraw(handle)) 663 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'})) 664 call assert_equal("this", ch_readraw(handle)) 665 call assert_equal("AND this", ch_readraw(handle)) 666 finally 667 call Stop_g_job() 668 call delete('Xinput') 669 endtry 670endfunc 671 672func Test_nl_write_out_file() 673 if !has('job') 674 return 675 endif 676 call ch_log('Test_nl_write_out_file()') 677 let g:job = job_start(s:python . " test_channel_pipe.py", 678 \ {'out_io': 'file', 'out_name': 'Xoutput'}) 679 call assert_equal("run", job_status(g:job)) 680 try 681 let handle = job_getchannel(g:job) 682 call ch_sendraw(handle, "echo line one\n") 683 call ch_sendraw(handle, "echo line two\n") 684 call ch_sendraw(handle, "double this\n") 685 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))}) 686 finally 687 call Stop_g_job() 688 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$')) 689 call delete('Xoutput') 690 endtry 691endfunc 692 693func Test_nl_write_err_file() 694 if !has('job') 695 return 696 endif 697 call ch_log('Test_nl_write_err_file()') 698 let g:job = job_start(s:python . " test_channel_pipe.py", 699 \ {'err_io': 'file', 'err_name': 'Xoutput'}) 700 call assert_equal("run", job_status(g:job)) 701 try 702 let handle = job_getchannel(g:job) 703 call ch_sendraw(handle, "echoerr line one\n") 704 call ch_sendraw(handle, "echoerr line two\n") 705 call ch_sendraw(handle, "doubleerr this\n") 706 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this'], readfile('Xoutput'))}) 707 finally 708 call Stop_g_job() 709 call delete('Xoutput') 710 endtry 711endfunc 712 713func Test_nl_write_both_file() 714 if !has('job') 715 return 716 endif 717 call ch_log('Test_nl_write_both_file()') 718 let g:job = job_start(s:python . " test_channel_pipe.py", 719 \ {'out_io': 'file', 'out_name': 'Xoutput', 'err_io': 'out'}) 720 call assert_equal("run", job_status(g:job)) 721 try 722 let handle = job_getchannel(g:job) 723 call ch_sendraw(handle, "echoerr line one\n") 724 call ch_sendraw(handle, "echo line two\n") 725 call ch_sendraw(handle, "double this\n") 726 call ch_sendraw(handle, "doubleerr that\n") 727 call WaitForAssert({-> assert_equal(['line one', 'line two', 'this', 'AND this', 'that', 'AND that'], readfile('Xoutput'))}) 728 finally 729 call Stop_g_job() 730 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xoutput$')) 731 call delete('Xoutput') 732 endtry 733endfunc 734 735func BufCloseCb(ch) 736 let g:Ch_bufClosed = 'yes' 737endfunc 738 739func Run_test_pipe_to_buffer(use_name, nomod, do_msg) 740 if !has('job') 741 return 742 endif 743 call ch_log('Test_pipe_to_buffer()') 744 let g:Ch_bufClosed = 'no' 745 let options = {'out_io': 'buffer', 'close_cb': 'BufCloseCb'} 746 let expected = ['', 'line one', 'line two', 'this', 'AND this', 'Goodbye!'] 747 if a:use_name 748 let options['out_name'] = 'pipe-output' 749 if a:do_msg 750 let expected[0] = 'Reading from channel output...' 751 else 752 let options['out_msg'] = 0 753 call remove(expected, 0) 754 endif 755 else 756 sp pipe-output 757 let options['out_buf'] = bufnr('%') 758 quit 759 call remove(expected, 0) 760 endif 761 if a:nomod 762 let options['out_modifiable'] = 0 763 endif 764 let job = job_start(s:python . " test_channel_pipe.py", options) 765 call assert_equal("run", job_status(job)) 766 try 767 let handle = job_getchannel(job) 768 call ch_sendraw(handle, "echo line one\n") 769 call ch_sendraw(handle, "echo line two\n") 770 call ch_sendraw(handle, "double this\n") 771 call ch_sendraw(handle, "quit\n") 772 sp pipe-output 773 call WaitFor('line("$") == ' . len(expected) . ' && g:Ch_bufClosed == "yes"') 774 call assert_equal(expected, getline(1, '$')) 775 if a:nomod 776 call assert_equal(0, &modifiable) 777 else 778 call assert_equal(1, &modifiable) 779 endif 780 call assert_equal('yes', g:Ch_bufClosed) 781 bwipe! 782 finally 783 call job_stop(job) 784 endtry 785endfunc 786 787func Test_pipe_to_buffer_name() 788 call Run_test_pipe_to_buffer(1, 0, 1) 789endfunc 790 791func Test_pipe_to_buffer_nr() 792 call Run_test_pipe_to_buffer(0, 0, 1) 793endfunc 794 795func Test_pipe_to_buffer_name_nomod() 796 call Run_test_pipe_to_buffer(1, 1, 1) 797endfunc 798 799func Test_pipe_to_buffer_name_nomsg() 800 call Run_test_pipe_to_buffer(1, 0, 1) 801endfunc 802 803func Test_close_output_buffer() 804 if !has('job') 805 return 806 endif 807 enew! 808 let test_lines = ['one', 'two'] 809 call setline(1, test_lines) 810 call ch_log('Test_close_output_buffer()') 811 let options = {'out_io': 'buffer'} 812 let options['out_name'] = 'buffer-output' 813 let options['out_msg'] = 0 814 split buffer-output 815 let job = job_start(s:python . " test_channel_write.py", options) 816 call assert_equal("run", job_status(job)) 817 try 818 call WaitForAssert({-> assert_equal(3, line('$'))}) 819 quit! 820 sleep 100m 821 " Make sure the write didn't happen to the wrong buffer. 822 call assert_equal(test_lines, getline(1, line('$'))) 823 call assert_equal(-1, bufwinnr('buffer-output')) 824 sbuf buffer-output 825 call assert_notequal(-1, bufwinnr('buffer-output')) 826 sleep 100m 827 close " no more writes 828 bwipe! 829 finally 830 call job_stop(job) 831 endtry 832endfunc 833 834func Run_test_pipe_err_to_buffer(use_name, nomod, do_msg) 835 if !has('job') 836 return 837 endif 838 call ch_log('Test_pipe_err_to_buffer()') 839 let options = {'err_io': 'buffer'} 840 let expected = ['', 'line one', 'line two', 'this', 'AND this'] 841 if a:use_name 842 let options['err_name'] = 'pipe-err' 843 if a:do_msg 844 let expected[0] = 'Reading from channel error...' 845 else 846 let options['err_msg'] = 0 847 call remove(expected, 0) 848 endif 849 else 850 sp pipe-err 851 let options['err_buf'] = bufnr('%') 852 quit 853 call remove(expected, 0) 854 endif 855 if a:nomod 856 let options['err_modifiable'] = 0 857 endif 858 let job = job_start(s:python . " test_channel_pipe.py", options) 859 call assert_equal("run", job_status(job)) 860 try 861 let handle = job_getchannel(job) 862 call ch_sendraw(handle, "echoerr line one\n") 863 call ch_sendraw(handle, "echoerr line two\n") 864 call ch_sendraw(handle, "doubleerr this\n") 865 call ch_sendraw(handle, "quit\n") 866 sp pipe-err 867 call WaitForAssert({-> assert_equal(expected, getline(1, '$'))}) 868 if a:nomod 869 call assert_equal(0, &modifiable) 870 else 871 call assert_equal(1, &modifiable) 872 endif 873 bwipe! 874 finally 875 call job_stop(job) 876 endtry 877endfunc 878 879func Test_pipe_err_to_buffer_name() 880 call Run_test_pipe_err_to_buffer(1, 0, 1) 881endfunc 882 883func Test_pipe_err_to_buffer_nr() 884 call Run_test_pipe_err_to_buffer(0, 0, 1) 885endfunc 886 887func Test_pipe_err_to_buffer_name_nomod() 888 call Run_test_pipe_err_to_buffer(1, 1, 1) 889endfunc 890 891func Test_pipe_err_to_buffer_name_nomsg() 892 call Run_test_pipe_err_to_buffer(1, 0, 0) 893endfunc 894 895func Test_pipe_both_to_buffer() 896 if !has('job') 897 return 898 endif 899 call ch_log('Test_pipe_both_to_buffer()') 900 let job = job_start(s:python . " test_channel_pipe.py", 901 \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'}) 902 call assert_equal("run", job_status(job)) 903 try 904 let handle = job_getchannel(job) 905 call ch_sendraw(handle, "echo line one\n") 906 call ch_sendraw(handle, "echoerr line two\n") 907 call ch_sendraw(handle, "double this\n") 908 call ch_sendraw(handle, "doubleerr that\n") 909 call ch_sendraw(handle, "quit\n") 910 sp pipe-err 911 call WaitForAssert({-> assert_equal(['Reading from channel output...', 'line one', 'line two', 'this', 'AND this', 'that', 'AND that', 'Goodbye!'], getline(1, '$'))}) 912 bwipe! 913 finally 914 call job_stop(job) 915 endtry 916endfunc 917 918func Run_test_pipe_from_buffer(use_name) 919 if !has('job') 920 return 921 endif 922 call ch_log('Test_pipe_from_buffer()') 923 924 sp pipe-input 925 call setline(1, ['echo one', 'echo two', 'echo three']) 926 let options = {'in_io': 'buffer', 'block_write': 1} 927 if a:use_name 928 let options['in_name'] = 'pipe-input' 929 else 930 let options['in_buf'] = bufnr('%') 931 endif 932 933 let job = job_start(s:python . " test_channel_pipe.py", options) 934 call assert_equal("run", job_status(job)) 935 try 936 let handle = job_getchannel(job) 937 call assert_equal('one', ch_read(handle)) 938 call assert_equal('two', ch_read(handle)) 939 call assert_equal('three', ch_read(handle)) 940 bwipe! 941 finally 942 call job_stop(job) 943 endtry 944endfunc 945 946func Test_pipe_from_buffer_name() 947 call Run_test_pipe_from_buffer(1) 948endfunc 949 950func Test_pipe_from_buffer_nr() 951 call Run_test_pipe_from_buffer(0) 952endfunc 953 954func Run_pipe_through_sort(all, use_buffer) 955 if !executable('sort') || !has('job') 956 return 957 endif 958 let options = {'out_io': 'buffer', 'out_name': 'sortout'} 959 if a:use_buffer 960 split sortin 961 call setline(1, ['ccc', 'aaa', 'ddd', 'bbb', 'eee']) 962 let options.in_io = 'buffer' 963 let options.in_name = 'sortin' 964 endif 965 if !a:all 966 let options.in_top = 2 967 let options.in_bot = 4 968 endif 969 let job = job_start('sort', options) 970 971 if !a:use_buffer 972 call assert_equal("run", job_status(job)) 973 call ch_sendraw(job, "ccc\naaa\nddd\nbbb\neee\n") 974 call ch_close_in(job) 975 endif 976 977 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 978 979 sp sortout 980 call WaitFor('line("$") > 3') 981 call assert_equal('Reading from channel output...', getline(1)) 982 if a:all 983 call assert_equal(['aaa', 'bbb', 'ccc', 'ddd', 'eee'], getline(2, 6)) 984 else 985 call assert_equal(['aaa', 'bbb', 'ddd'], getline(2, 4)) 986 endif 987 988 call job_stop(job) 989 if a:use_buffer 990 bwipe! sortin 991 endif 992 bwipe! sortout 993endfunc 994 995func Test_pipe_through_sort_all() 996 call ch_log('Test_pipe_through_sort_all()') 997 call Run_pipe_through_sort(1, 1) 998endfunc 999 1000func Test_pipe_through_sort_some() 1001 call ch_log('Test_pipe_through_sort_some()') 1002 call Run_pipe_through_sort(0, 1) 1003endfunc 1004 1005func Test_pipe_through_sort_feed() 1006 call ch_log('Test_pipe_through_sort_feed()') 1007 call Run_pipe_through_sort(1, 0) 1008endfunc 1009 1010func Test_pipe_to_nameless_buffer() 1011 if !has('job') 1012 return 1013 endif 1014 call ch_log('Test_pipe_to_nameless_buffer()') 1015 let job = job_start(s:python . " test_channel_pipe.py", 1016 \ {'out_io': 'buffer'}) 1017 call assert_equal("run", job_status(job)) 1018 try 1019 let handle = job_getchannel(job) 1020 call ch_sendraw(handle, "echo line one\n") 1021 call ch_sendraw(handle, "echo line two\n") 1022 exe ch_getbufnr(handle, "out") . 'sbuf' 1023 call WaitFor('line("$") >= 3') 1024 call assert_equal(['Reading from channel output...', 'line one', 'line two'], getline(1, '$')) 1025 bwipe! 1026 finally 1027 call job_stop(job) 1028 endtry 1029endfunc 1030 1031func Test_pipe_to_buffer_json() 1032 if !has('job') 1033 return 1034 endif 1035 call ch_log('Test_pipe_to_buffer_json()') 1036 let job = job_start(s:python . " test_channel_pipe.py", 1037 \ {'out_io': 'buffer', 'out_mode': 'json'}) 1038 call assert_equal("run", job_status(job)) 1039 try 1040 let handle = job_getchannel(job) 1041 call ch_sendraw(handle, "echo [0, \"hello\"]\n") 1042 call ch_sendraw(handle, "echo [-2, 12.34]\n") 1043 exe ch_getbufnr(handle, "out") . 'sbuf' 1044 call WaitFor('line("$") >= 3') 1045 call assert_equal(['Reading from channel output...', '[0,"hello"]', '[-2,12.34]'], getline(1, '$')) 1046 bwipe! 1047 finally 1048 call job_stop(job) 1049 endtry 1050endfunc 1051 1052" Wait a little while for the last line, minus "offset", to equal "line". 1053func s:wait_for_last_line(line, offset) 1054 for i in range(100) 1055 if getline(line('$') - a:offset) == a:line 1056 break 1057 endif 1058 sleep 10m 1059 endfor 1060endfunc 1061 1062func Test_pipe_io_two_buffers() 1063 if !has('job') 1064 return 1065 endif 1066 call ch_log('Test_pipe_io_two_buffers()') 1067 1068 " Create two buffers, one to read from and one to write to. 1069 split pipe-output 1070 set buftype=nofile 1071 split pipe-input 1072 set buftype=nofile 1073 1074 let job = job_start(s:python . " test_channel_pipe.py", 1075 \ {'in_io': 'buffer', 'in_name': 'pipe-input', 'in_top': 0, 1076 \ 'out_io': 'buffer', 'out_name': 'pipe-output', 1077 \ 'block_write': 1}) 1078 call assert_equal("run", job_status(job)) 1079 try 1080 exe "normal Gaecho hello\<CR>" 1081 exe bufwinnr('pipe-output') . "wincmd w" 1082 call s:wait_for_last_line('hello', 0) 1083 call assert_equal('hello', getline('$')) 1084 1085 exe bufwinnr('pipe-input') . "wincmd w" 1086 exe "normal Gadouble this\<CR>" 1087 exe bufwinnr('pipe-output') . "wincmd w" 1088 call s:wait_for_last_line('AND this', 0) 1089 call assert_equal('this', getline(line('$') - 1)) 1090 call assert_equal('AND this', getline('$')) 1091 1092 bwipe! 1093 exe bufwinnr('pipe-input') . "wincmd w" 1094 bwipe! 1095 finally 1096 call job_stop(job) 1097 endtry 1098endfunc 1099 1100func Test_pipe_io_one_buffer() 1101 if !has('job') 1102 return 1103 endif 1104 call ch_log('Test_pipe_io_one_buffer()') 1105 1106 " Create one buffer to read from and to write to. 1107 split pipe-io 1108 set buftype=nofile 1109 1110 let job = job_start(s:python . " test_channel_pipe.py", 1111 \ {'in_io': 'buffer', 'in_name': 'pipe-io', 'in_top': 0, 1112 \ 'out_io': 'buffer', 'out_name': 'pipe-io', 1113 \ 'block_write': 1}) 1114 call assert_equal("run", job_status(job)) 1115 try 1116 exe "normal Goecho hello\<CR>" 1117 call s:wait_for_last_line('hello', 1) 1118 call assert_equal('hello', getline(line('$') - 1)) 1119 1120 exe "normal Gadouble this\<CR>" 1121 call s:wait_for_last_line('AND this', 1) 1122 call assert_equal('this', getline(line('$') - 2)) 1123 call assert_equal('AND this', getline(line('$') - 1)) 1124 1125 bwipe! 1126 finally 1127 call job_stop(job) 1128 endtry 1129endfunc 1130 1131func Test_pipe_null() 1132 if !has('job') 1133 return 1134 endif 1135 call ch_log('Test_pipe_null()') 1136 1137 " We cannot check that no I/O works, we only check that the job starts 1138 " properly. 1139 let job = job_start(s:python . " test_channel_pipe.py something", 1140 \ {'in_io': 'null'}) 1141 call assert_equal("run", job_status(job)) 1142 try 1143 call assert_equal('something', ch_read(job)) 1144 finally 1145 call job_stop(job) 1146 endtry 1147 1148 let job = job_start(s:python . " test_channel_pipe.py err-out", 1149 \ {'out_io': 'null'}) 1150 call assert_equal("run", job_status(job)) 1151 try 1152 call assert_equal('err-out', ch_read(job, {"part": "err"})) 1153 finally 1154 call job_stop(job) 1155 endtry 1156 1157 let job = job_start(s:python . " test_channel_pipe.py something", 1158 \ {'err_io': 'null'}) 1159 call assert_equal("run", job_status(job)) 1160 try 1161 call assert_equal('something', ch_read(job)) 1162 finally 1163 call job_stop(job) 1164 endtry 1165 1166 let job = job_start(s:python . " test_channel_pipe.py something", 1167 \ {'out_io': 'null', 'err_io': 'out'}) 1168 call assert_equal("run", job_status(job)) 1169 call job_stop(job) 1170 1171 let job = job_start(s:python . " test_channel_pipe.py something", 1172 \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'}) 1173 call assert_equal("run", job_status(job)) 1174 call assert_equal('channel fail', string(job_getchannel(job))) 1175 call assert_equal('fail', ch_status(job)) 1176 call job_stop(job) 1177endfunc 1178 1179func Test_pipe_to_buffer_raw() 1180 if !has('job') 1181 return 1182 endif 1183 call ch_log('Test_raw_pipe_to_buffer()') 1184 let options = {'out_mode': 'raw', 'out_io': 'buffer', 'out_name': 'testout'} 1185 split testout 1186 let job = job_start([s:python, '-c', 1187 \ 'import sys; [sys.stdout.write(".") and sys.stdout.flush() for _ in range(10000)]'], options) 1188 " the job may be done quickly, also accept "dead" 1189 call assert_match('^\%(dead\|run\)$', job_status(job)) 1190 call WaitFor('len(join(getline(1, "$"), "")) >= 10000') 1191 try 1192 let totlen = 0 1193 for line in getline(1, '$') 1194 call assert_equal('', substitute(line, '^\.*', '', '')) 1195 let totlen += len(line) 1196 endfor 1197 call assert_equal(10000, totlen) 1198 finally 1199 call job_stop(job) 1200 bwipe! 1201 endtry 1202endfunc 1203 1204func Test_reuse_channel() 1205 if !has('job') 1206 return 1207 endif 1208 call ch_log('Test_reuse_channel()') 1209 1210 let job = job_start(s:python . " test_channel_pipe.py") 1211 call assert_equal("run", job_status(job)) 1212 let handle = job_getchannel(job) 1213 try 1214 call ch_sendraw(handle, "echo something\n") 1215 call assert_equal("something", ch_readraw(handle)) 1216 finally 1217 call job_stop(job) 1218 endtry 1219 1220 let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle}) 1221 call assert_equal("run", job_status(job)) 1222 let handle = job_getchannel(job) 1223 try 1224 call ch_sendraw(handle, "echo again\n") 1225 call assert_equal("again", ch_readraw(handle)) 1226 finally 1227 call job_stop(job) 1228 endtry 1229endfunc 1230 1231func Test_out_cb() 1232 if !has('job') 1233 return 1234 endif 1235 call ch_log('Test_out_cb()') 1236 1237 let dict = {'thisis': 'dict: '} 1238 func dict.outHandler(chan, msg) dict 1239 if type(a:msg) == v:t_string 1240 let g:Ch_outmsg = self.thisis . a:msg 1241 else 1242 let g:Ch_outobj = a:msg 1243 endif 1244 endfunc 1245 func dict.errHandler(chan, msg) dict 1246 let g:Ch_errmsg = self.thisis . a:msg 1247 endfunc 1248 let job = job_start(s:python . " test_channel_pipe.py", 1249 \ {'out_cb': dict.outHandler, 1250 \ 'out_mode': 'json', 1251 \ 'err_cb': dict.errHandler, 1252 \ 'err_mode': 'json'}) 1253 call assert_equal("run", job_status(job)) 1254 try 1255 let g:Ch_outmsg = '' 1256 let g:Ch_errmsg = '' 1257 call ch_sendraw(job, "echo [0, \"hello\"]\n") 1258 call ch_sendraw(job, "echoerr [0, \"there\"]\n") 1259 call WaitForAssert({-> assert_equal("dict: hello", g:Ch_outmsg)}) 1260 call WaitForAssert({-> assert_equal("dict: there", g:Ch_errmsg)}) 1261 1262 " Receive a json object split in pieces 1263 unlet! g:Ch_outobj 1264 call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\": 3|}]\n") 1265 let g:Ch_outobj = '' 1266 call WaitForAssert({-> assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)}) 1267 finally 1268 call job_stop(job) 1269 endtry 1270endfunc 1271 1272func Test_out_close_cb() 1273 if !has('job') 1274 return 1275 endif 1276 call ch_log('Test_out_close_cb()') 1277 1278 let s:counter = 1 1279 let g:Ch_msg1 = '' 1280 let g:Ch_closemsg = 0 1281 func! OutHandler(chan, msg) 1282 if s:counter == 1 1283 let g:Ch_msg1 = a:msg 1284 endif 1285 let s:counter += 1 1286 endfunc 1287 func! CloseHandler(chan) 1288 let g:Ch_closemsg = s:counter 1289 let s:counter += 1 1290 endfunc 1291 let job = job_start(s:python . " test_channel_pipe.py quit now", 1292 \ {'out_cb': 'OutHandler', 1293 \ 'close_cb': 'CloseHandler'}) 1294 " the job may be done quickly, also accept "dead" 1295 call assert_match('^\%(dead\|run\)$', job_status(job)) 1296 try 1297 call WaitForAssert({-> assert_equal('quit', g:Ch_msg1)}) 1298 call WaitForAssert({-> assert_equal(2, g:Ch_closemsg)}) 1299 finally 1300 call job_stop(job) 1301 delfunc OutHandler 1302 delfunc CloseHandler 1303 endtry 1304endfunc 1305 1306func Test_read_in_close_cb() 1307 if !has('job') 1308 return 1309 endif 1310 call ch_log('Test_read_in_close_cb()') 1311 1312 let g:Ch_received = '' 1313 func! CloseHandler(chan) 1314 let g:Ch_received = ch_read(a:chan) 1315 endfunc 1316 let job = job_start(s:python . " test_channel_pipe.py quit now", 1317 \ {'close_cb': 'CloseHandler'}) 1318 " the job may be done quickly, also accept "dead" 1319 call assert_match('^\%(dead\|run\)$', job_status(job)) 1320 try 1321 call WaitForAssert({-> assert_equal('quit', g:Ch_received)}) 1322 finally 1323 call job_stop(job) 1324 delfunc CloseHandler 1325 endtry 1326endfunc 1327 1328" Use channel in NL mode but received text does not end in NL. 1329func Test_read_in_close_cb_incomplete() 1330 if !has('job') 1331 return 1332 endif 1333 call ch_log('Test_read_in_close_cb_incomplete()') 1334 1335 let g:Ch_received = '' 1336 func! CloseHandler(chan) 1337 while ch_status(a:chan, {'part': 'out'}) == 'buffered' 1338 let g:Ch_received .= ch_read(a:chan) 1339 endwhile 1340 endfunc 1341 let job = job_start(s:python . " test_channel_pipe.py incomplete", 1342 \ {'close_cb': 'CloseHandler'}) 1343 " the job may be done quickly, also accept "dead" 1344 call assert_match('^\%(dead\|run\)$', job_status(job)) 1345 try 1346 call WaitForAssert({-> assert_equal('incomplete', g:Ch_received)}) 1347 finally 1348 call job_stop(job) 1349 delfunc CloseHandler 1350 endtry 1351endfunc 1352 1353func Test_out_cb_lambda() 1354 if !has('job') 1355 return 1356 endif 1357 call ch_log('Test_out_cb_lambda()') 1358 1359 let job = job_start(s:python . " test_channel_pipe.py", 1360 \ {'out_cb': {ch, msg -> execute("let g:Ch_outmsg = 'lambda: ' . msg")}, 1361 \ 'out_mode': 'json', 1362 \ 'err_cb': {ch, msg -> execute(":let g:Ch_errmsg = 'lambda: ' . msg")}, 1363 \ 'err_mode': 'json'}) 1364 call assert_equal("run", job_status(job)) 1365 try 1366 let g:Ch_outmsg = '' 1367 let g:Ch_errmsg = '' 1368 call ch_sendraw(job, "echo [0, \"hello\"]\n") 1369 call ch_sendraw(job, "echoerr [0, \"there\"]\n") 1370 call WaitForAssert({-> assert_equal("lambda: hello", g:Ch_outmsg)}) 1371 call WaitForAssert({-> assert_equal("lambda: there", g:Ch_errmsg)}) 1372 finally 1373 call job_stop(job) 1374 endtry 1375endfunc 1376 1377func Test_close_and_exit_cb() 1378 if !has('job') 1379 return 1380 endif 1381 call ch_log('Test_close_and_exit_cb') 1382 1383 let g:retdict = {'ret': {}} 1384 func g:retdict.close_cb(ch) dict 1385 let self.ret['close_cb'] = job_status(ch_getjob(a:ch)) 1386 endfunc 1387 func g:retdict.exit_cb(job, status) dict 1388 let self.ret['exit_cb'] = job_status(a:job) 1389 endfunc 1390 1391 let job = job_start([&shell, &shellcmdflag, 'echo'], 1392 \ {'close_cb': g:retdict.close_cb, 1393 \ 'exit_cb': g:retdict.exit_cb}) 1394 " the job may be done quickly, also accept "dead" 1395 call assert_match('^\%(dead\|run\)$', job_status(job)) 1396 call WaitForAssert({-> assert_equal(2, len(g:retdict.ret))}) 1397 call assert_match('^\%(dead\|run\)$', g:retdict.ret['close_cb']) 1398 call assert_equal('dead', g:retdict.ret['exit_cb']) 1399 unlet g:retdict 1400endfunc 1401 1402"""""""""" 1403 1404function ExitCbWipe(job, status) 1405 exe g:wipe_buf 'bw!' 1406endfunction 1407 1408" This caused a crash, because messages were handled while peeking for a 1409" character. 1410func Test_exit_cb_wipes_buf() 1411 if !has('timers') 1412 return 1413 endif 1414 set cursorline lazyredraw 1415 call test_override('redraw_flag', 1) 1416 new 1417 let g:wipe_buf = bufnr('') 1418 1419 let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'], 1420 \ {'exit_cb': 'ExitCbWipe'}) 1421 let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5}) 1422 call feedkeys(repeat('g', 1000) . 'o', 'ntx!') 1423 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 1424 call timer_stop(timer) 1425 1426 set nocursorline nolazyredraw 1427 unlet g:wipe_buf 1428 call test_override('ALL', 0) 1429endfunc 1430 1431"""""""""" 1432 1433let g:Ch_unletResponse = '' 1434func s:UnletHandler(handle, msg) 1435 let g:Ch_unletResponse = a:msg 1436 unlet s:channelfd 1437endfunc 1438 1439" Test that "unlet handle" in a handler doesn't crash Vim. 1440func Ch_unlet_handle(port) 1441 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1442 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')}) 1443 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) 1444endfunc 1445 1446func Test_unlet_handle() 1447 call ch_log('Test_unlet_handle()') 1448 call s:run_server('Ch_unlet_handle') 1449endfunc 1450 1451"""""""""" 1452 1453let g:Ch_unletResponse = '' 1454func Ch_CloseHandler(handle, msg) 1455 let g:Ch_unletResponse = a:msg 1456 call ch_close(s:channelfd) 1457endfunc 1458 1459" Test that "unlet handle" in a handler doesn't crash Vim. 1460func Ch_close_handle(port) 1461 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1462 call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')}) 1463 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) 1464endfunc 1465 1466func Test_close_handle() 1467 call ch_log('Test_close_handle()') 1468 call s:run_server('Ch_close_handle') 1469endfunc 1470 1471"""""""""" 1472 1473func Test_open_fail() 1474 call ch_log('Test_open_fail()') 1475 silent! let ch = ch_open("noserver") 1476 echo ch 1477 let d = ch 1478endfunc 1479 1480"""""""""" 1481 1482func Ch_open_delay(port) 1483 " Wait up to a second for the port to open. 1484 let s:chopt.waittime = 1000 1485 let channel = ch_open('localhost:' . a:port, s:chopt) 1486 unlet s:chopt.waittime 1487 if ch_status(channel) == "fail" 1488 call assert_report("Can't open channel") 1489 return 1490 endif 1491 call assert_equal('got it', ch_evalexpr(channel, 'hello!')) 1492 call ch_close(channel) 1493endfunc 1494 1495func Test_open_delay() 1496 call ch_log('Test_open_delay()') 1497 " The server will wait half a second before creating the port. 1498 call s:run_server('Ch_open_delay', 'delay') 1499endfunc 1500 1501""""""""" 1502 1503function MyFunction(a,b,c) 1504 let g:Ch_call_ret = [a:a, a:b, a:c] 1505endfunc 1506 1507function Ch_test_call(port) 1508 let handle = ch_open('localhost:' . a:port, s:chopt) 1509 if ch_status(handle) == "fail" 1510 call assert_report("Can't open channel") 1511 return 1512 endif 1513 1514 let g:Ch_call_ret = [] 1515 call assert_equal('ok', ch_evalexpr(handle, 'call-func')) 1516 call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)}) 1517endfunc 1518 1519func Test_call() 1520 call ch_log('Test_call()') 1521 call s:run_server('Ch_test_call') 1522endfunc 1523 1524""""""""" 1525 1526let g:Ch_job_exit_ret = 'not yet' 1527function MyExitCb(job, status) 1528 let g:Ch_job_exit_ret = 'done' 1529endfunc 1530 1531function Ch_test_exit_callback(port) 1532 call job_setoptions(g:currentJob, {'exit_cb': 'MyExitCb'}) 1533 let g:Ch_exit_job = g:currentJob 1534 call assert_equal('MyExitCb', job_info(g:currentJob)['exit_cb']) 1535endfunc 1536 1537func Test_exit_callback() 1538 if has('job') 1539 call ch_log('Test_exit_callback()') 1540 call s:run_server('Ch_test_exit_callback') 1541 1542 " wait up to a second for the job to exit 1543 for i in range(100) 1544 if g:Ch_job_exit_ret == 'done' 1545 break 1546 endif 1547 sleep 10m 1548 " calling job_status() triggers the callback 1549 call job_status(g:Ch_exit_job) 1550 endfor 1551 1552 call assert_equal('done', g:Ch_job_exit_ret) 1553 call assert_equal('dead', job_info(g:Ch_exit_job).status) 1554 unlet g:Ch_exit_job 1555 endif 1556endfunc 1557 1558function MyExitTimeCb(job, status) 1559 if job_info(a:job).process == g:exit_cb_val.process 1560 let g:exit_cb_val.end = reltime(g:exit_cb_val.start) 1561 endif 1562 call Resume() 1563endfunction 1564 1565func Test_exit_callback_interval() 1566 if !has('job') 1567 return 1568 endif 1569 1570 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0} 1571 let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'}) 1572 let g:exit_cb_val.process = job_info(job).process 1573 call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0') 1574 let elapsed = reltimefloat(g:exit_cb_val.end) 1575 call assert_true(elapsed > 0.5) 1576 call assert_true(elapsed < 1.0) 1577 1578 " case: unreferenced job, using timer 1579 if !has('timers') 1580 return 1581 endif 1582 1583 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0} 1584 let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'}) 1585 let g:exit_cb_val.process = job_info(g:job).process 1586 unlet g:job 1587 call Standby(1000) 1588 if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0 1589 let elapsed = reltimefloat(g:exit_cb_val.end) 1590 else 1591 let elapsed = 1.0 1592 endif 1593 call assert_true(elapsed > 0.5) 1594 call assert_true(elapsed < 1.0) 1595endfunc 1596 1597""""""""" 1598 1599let g:Ch_close_ret = 'alive' 1600function MyCloseCb(ch) 1601 let g:Ch_close_ret = 'closed' 1602endfunc 1603 1604function Ch_test_close_callback(port) 1605 let handle = ch_open('localhost:' . a:port, s:chopt) 1606 if ch_status(handle) == "fail" 1607 call assert_report("Can't open channel") 1608 return 1609 endif 1610 call ch_setoptions(handle, {'close_cb': 'MyCloseCb'}) 1611 1612 call assert_equal('', ch_evalexpr(handle, 'close me')) 1613 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)}) 1614endfunc 1615 1616func Test_close_callback() 1617 call ch_log('Test_close_callback()') 1618 call s:run_server('Ch_test_close_callback') 1619endfunc 1620 1621function Ch_test_close_partial(port) 1622 let handle = ch_open('localhost:' . a:port, s:chopt) 1623 if ch_status(handle) == "fail" 1624 call assert_report("Can't open channel") 1625 return 1626 endif 1627 let g:Ch_d = {} 1628 func g:Ch_d.closeCb(ch) dict 1629 let self.close_ret = 'closed' 1630 endfunc 1631 call ch_setoptions(handle, {'close_cb': g:Ch_d.closeCb}) 1632 1633 call assert_equal('', ch_evalexpr(handle, 'close me')) 1634 call WaitForAssert({-> assert_equal('closed', g:Ch_d.close_ret)}) 1635 unlet g:Ch_d 1636endfunc 1637 1638func Test_close_partial() 1639 call ch_log('Test_close_partial()') 1640 call s:run_server('Ch_test_close_partial') 1641endfunc 1642 1643func Test_job_start_invalid() 1644 call assert_fails('call job_start($x)', 'E474:') 1645 call assert_fails('call job_start("")', 'E474:') 1646endfunc 1647 1648func Test_job_stop_immediately() 1649 if !has('job') 1650 return 1651 endif 1652 1653 let g:job = job_start([s:python, '-c', 'import time;time.sleep(10)']) 1654 try 1655 call job_stop(g:job) 1656 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 1657 finally 1658 call job_stop(g:job, 'kill') 1659 unlet g:job 1660 endtry 1661endfunc 1662 1663" This was leaking memory. 1664func Test_partial_in_channel_cycle() 1665 let d = {} 1666 let d.a = function('string', [d]) 1667 try 1668 let d.b = ch_open('nowhere:123', {'close_cb': d.a}) 1669 catch 1670 call assert_exception('E901:') 1671 endtry 1672 unlet d 1673endfunc 1674 1675func Test_using_freed_memory() 1676 let g:a = job_start(['ls']) 1677 sleep 10m 1678 call test_garbagecollect_now() 1679endfunc 1680 1681func Test_collapse_buffers() 1682 if !executable('cat') || !has('job') 1683 return 1684 endif 1685 sp test_channel.vim 1686 let g:linecount = line('$') 1687 close 1688 split testout 1689 1,$delete 1690 call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'}) 1691 call WaitForAssert({-> assert_inrange(g:linecount, g:linecount + 1, line('$'))}) 1692 bwipe! 1693endfunc 1694 1695func Test_write_to_deleted_buffer() 1696 if !executable('echo') || !has('job') 1697 return 1698 endif 1699 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0}) 1700 let bufnr = bufnr('test_buffer') 1701 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))}) 1702 call assert_equal('nofile', getbufvar(bufnr, '&buftype')) 1703 call assert_equal('hide', getbufvar(bufnr, '&bufhidden')) 1704 1705 bdel test_buffer 1706 call assert_equal([], getbufline(bufnr, 1, '$')) 1707 1708 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0}) 1709 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))}) 1710 call assert_equal('nofile', getbufvar(bufnr, '&buftype')) 1711 call assert_equal('hide', getbufvar(bufnr, '&bufhidden')) 1712 1713 bwipe! test_buffer 1714endfunc 1715 1716func Test_cmd_parsing() 1717 if !has('unix') 1718 return 1719 endif 1720 call assert_false(filereadable("file with space")) 1721 let job = job_start('touch "file with space"') 1722 call WaitForAssert({-> assert_true(filereadable("file with space"))}) 1723 call delete("file with space") 1724 1725 let job = job_start('touch file\ with\ space') 1726 call WaitForAssert({-> assert_true(filereadable("file with space"))}) 1727 call delete("file with space") 1728endfunc 1729 1730func Test_raw_passes_nul() 1731 if !executable('cat') || !has('job') 1732 return 1733 endif 1734 1735 " Test lines from the job containing NUL are stored correctly in a buffer. 1736 new 1737 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"]) 1738 w! Xtestread 1739 bwipe! 1740 split testout 1741 1,$delete 1742 call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'}) 1743 call WaitFor('line("$") > 2') 1744 call assert_equal("asdf\nasdf", getline(1)) 1745 call assert_equal("xxx\n", getline(2)) 1746 call assert_equal("\nyyy", getline(3)) 1747 1748 call delete('Xtestread') 1749 bwipe! 1750 1751 " Test lines from a buffer with NUL bytes are written correctly to the job. 1752 new mybuffer 1753 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"]) 1754 let g:Ch_job = job_start('cat', {'in_io': 'buffer', 'in_name': 'mybuffer', 'out_io': 'file', 'out_name': 'Xtestwrite'}) 1755 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 1756 bwipe! 1757 split Xtestwrite 1758 call assert_equal("asdf\nasdf", getline(1)) 1759 call assert_equal("xxx\n", getline(2)) 1760 call assert_equal("\nyyy", getline(3)) 1761 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xtestwrite$')) 1762 1763 call delete('Xtestwrite') 1764 bwipe! 1765endfunc 1766 1767func MyLineCountCb(ch, msg) 1768 let g:linecount += 1 1769endfunc 1770 1771func Test_read_nonl_line() 1772 if !has('job') 1773 return 1774 endif 1775 1776 let g:linecount = 0 1777 let arg = 'import sys;sys.stdout.write("1\n2\n3")' 1778 call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'}) 1779 call WaitForAssert({-> assert_equal(3, g:linecount)}) 1780endfunc 1781 1782func Test_read_from_terminated_job() 1783 if !has('job') 1784 return 1785 endif 1786 1787 let g:linecount = 0 1788 let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")' 1789 call job_start([s:python, '-c', arg], {'callback': 'MyLineCountCb'}) 1790 call WaitForAssert({-> assert_equal(1, g:linecount)}) 1791endfunc 1792 1793func Test_job_start_windows() 1794 if !has('job') || !has('win32') 1795 return 1796 endif 1797 1798 " Check that backslash in $COMSPEC is handled properly. 1799 let g:echostr = '' 1800 let cmd = $COMSPEC . ' /c echo 123' 1801 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:echostr .= msg")}}) 1802 let info = job_info(job) 1803 call assert_equal([$COMSPEC, '/c', 'echo', '123'], info.cmd) 1804 1805 call WaitForAssert({-> assert_equal("123", g:echostr)}) 1806 unlet g:echostr 1807endfunc 1808 1809func Test_env() 1810 if !has('job') 1811 return 1812 endif 1813 1814 let g:envstr = '' 1815 if has('win32') 1816 let cmd = ['cmd', '/c', 'echo %FOO%'] 1817 else 1818 let cmd = [&shell, &shellcmdflag, 'echo $FOO'] 1819 endif 1820 call assert_fails('call job_start(cmd, {"env": 1})', 'E475:') 1821 call job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'env': {'FOO': 'bar'}}) 1822 call WaitForAssert({-> assert_equal("bar", g:envstr)}) 1823 unlet g:envstr 1824endfunc 1825 1826func Test_cwd() 1827 if !has('job') 1828 return 1829 endif 1830 1831 let g:envstr = '' 1832 if has('win32') 1833 let expect = $TEMP 1834 let cmd = ['cmd', '/c', 'echo %CD%'] 1835 else 1836 let expect = $HOME 1837 let cmd = ['pwd'] 1838 endif 1839 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'cwd': expect}) 1840 try 1841 call WaitForAssert({-> assert_notequal("", g:envstr)}) 1842 let expect = substitute(expect, '[/\\]$', '', '') 1843 let g:envstr = substitute(g:envstr, '[/\\]$', '', '') 1844 if $CI != '' && stridx(g:envstr, '/private/') == 0 1845 let g:envstr = g:envstr[8:] 1846 endif 1847 call assert_equal(expect, g:envstr) 1848 finally 1849 call job_stop(job) 1850 unlet g:envstr 1851 endtry 1852endfunc 1853 1854function Ch_test_close_lambda(port) 1855 let handle = ch_open('localhost:' . a:port, s:chopt) 1856 if ch_status(handle) == "fail" 1857 call assert_report("Can't open channel") 1858 return 1859 endif 1860 let g:Ch_close_ret = '' 1861 call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}}) 1862 1863 call assert_equal('', ch_evalexpr(handle, 'close me')) 1864 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)}) 1865endfunc 1866 1867func Test_close_lambda() 1868 call ch_log('Test_close_lambda()') 1869 call s:run_server('Ch_test_close_lambda') 1870endfunc 1871 1872func s:test_list_args(cmd, out, remove_lf) 1873 try 1874 let g:out = '' 1875 let job = job_start([s:python, '-c', a:cmd], {'callback': {ch, msg -> execute('let g:out .= msg')}, 'out_mode': 'raw'}) 1876 call WaitFor('"" != g:out') 1877 if has('win32') 1878 let g:out = substitute(g:out, '\r', '', 'g') 1879 endif 1880 if a:remove_lf 1881 let g:out = substitute(g:out, '\n$', '', 'g') 1882 endif 1883 call assert_equal(a:out, g:out) 1884 finally 1885 call job_stop(job) 1886 unlet g:out 1887 endtry 1888endfunc 1889 1890func Test_list_args() 1891 if !has('job') 1892 return 1893 endif 1894 1895 call s:test_list_args('import sys;sys.stdout.write("hello world")', "hello world", 0) 1896 call s:test_list_args('import sys;sys.stdout.write("hello\nworld")', "hello\nworld", 0) 1897 call s:test_list_args('import sys;sys.stdout.write(''hello\nworld'')', "hello\nworld", 0) 1898 call s:test_list_args('import sys;sys.stdout.write(''hello"world'')', "hello\"world", 0) 1899 call s:test_list_args('import sys;sys.stdout.write(''hello^world'')', "hello^world", 0) 1900 call s:test_list_args('import sys;sys.stdout.write("hello&&world")', "hello&&world", 0) 1901 call s:test_list_args('import sys;sys.stdout.write(''hello\\world'')', "hello\\world", 0) 1902 call s:test_list_args('import sys;sys.stdout.write(''hello\\\\world'')', "hello\\\\world", 0) 1903 call s:test_list_args('import sys;sys.stdout.write("hello\"world\"")', 'hello"world"', 0) 1904 call s:test_list_args('import sys;sys.stdout.write("h\"ello worl\"d")', 'h"ello worl"d', 0) 1905 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo wor\\\"l\"d")', 'h"e\"llo wor\"l"d', 0) 1906 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo world")', 'h"e\"llo world', 0) 1907 call s:test_list_args('import sys;sys.stdout.write("hello\tworld")', "hello\tworld", 0) 1908 1909 " tests which not contain spaces in the argument 1910 call s:test_list_args('print("hello\nworld")', "hello\nworld", 1) 1911 call s:test_list_args('print(''hello\nworld'')', "hello\nworld", 1) 1912 call s:test_list_args('print(''hello"world'')', "hello\"world", 1) 1913 call s:test_list_args('print(''hello^world'')', "hello^world", 1) 1914 call s:test_list_args('print("hello&&world")', "hello&&world", 1) 1915 call s:test_list_args('print(''hello\\world'')', "hello\\world", 1) 1916 call s:test_list_args('print(''hello\\\\world'')', "hello\\\\world", 1) 1917 call s:test_list_args('print("hello\"world\"")', 'hello"world"', 1) 1918 call s:test_list_args('print("hello\tworld")', "hello\tworld", 1) 1919endfunc 1920 1921" Do this last, it stops any channel log. 1922func Test_zz_ch_log() 1923 call ch_logfile('Xlog', 'w') 1924 call ch_log('hello there') 1925 call ch_log('%s%s') 1926 call ch_logfile('') 1927 let text = readfile('Xlog') 1928 call assert_match("hello there", text[1]) 1929 call assert_match("%s%s", text[2]) 1930 call delete('Xlog') 1931endfunc 1932 1933func Test_keep_pty_open() 1934 if !has('unix') 1935 return 1936 endif 1937 1938 let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"', 1939 \ {'out_io': 'null', 'err_io': 'null', 'pty': 1}) 1940 let elapsed = WaitFor({-> job_status(job) ==# 'dead'}) 1941 call assert_inrange(200, 1000, elapsed) 1942 call job_stop(job) 1943endfunc 1944 1945func Test_job_start_in_timer() 1946 if !has('job') || !has('timers') 1947 return 1948 endif 1949 1950 func OutCb(chan, msg) 1951 let g:val += 1 1952 endfunc 1953 1954 func ExitCb(job, status) 1955 let g:val += 1 1956 call Resume() 1957 endfunc 1958 1959 func TimerCb(timer) 1960 if has('win32') 1961 let cmd = ['cmd', '/c', 'echo.'] 1962 else 1963 let cmd = ['echo'] 1964 endif 1965 let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'}) 1966 call substitute(repeat('a', 100000), '.', '', 'g') 1967 endfunc 1968 1969 " We should be interrupted before 'updatetime' elapsed. 1970 let g:val = 0 1971 call timer_start(1, 'TimerCb') 1972 let elapsed = Standby(&ut) 1973 call assert_inrange(1, &ut / 2, elapsed) 1974 1975 " Wait for both OutCb() and ExitCb() to have been called before deleting 1976 " them. 1977 call WaitForAssert({-> assert_equal(2, g:val)}) 1978 call job_stop(g:job) 1979 1980 delfunc OutCb 1981 delfunc ExitCb 1982 delfunc TimerCb 1983 unlet! g:val 1984 unlet! g:job 1985endfunc 1986 1987func Test_raw_large_data() 1988 try 1989 let g:out = '' 1990 let job = job_start(s:python . " test_channel_pipe.py", 1991 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1, 1992 \ 'callback': {ch, msg -> execute('let g:out .= msg')}}) 1993 1994 let outlen = 79999 1995 let want = repeat('X', outlen) . "\n" 1996 call ch_sendraw(job, want) 1997 call WaitFor({-> len(g:out) >= outlen}, 10000) 1998 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 1999 call assert_equal(want, substitute(g:out, '\r', '', 'g')) 2000 finally 2001 call job_stop(job) 2002 unlet g:out 2003 endtry 2004endfunc 2005 2006func Test_job_exitval_and_termsig() 2007 if !has('unix') 2008 return 2009 endif 2010 2011 " Terminate job normally 2012 let cmd = ['echo'] 2013 let job = job_start(cmd) 2014 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2015 let info = job_info(job) 2016 call assert_equal(0, info.exitval) 2017 call assert_equal("", info.termsig) 2018 2019 " Terminate job by signal 2020 let cmd = ['sleep', '10'] 2021 let job = job_start(cmd) 2022 sleep 10m 2023 call job_stop(job) 2024 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2025 let info = job_info(job) 2026 call assert_equal(-1, info.exitval) 2027 call assert_equal("term", info.termsig) 2028endfunc 2029