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_inrange(0.3, 0.6, reltimefloat(reltime(start))) 207 208 " Send without waiting for a response, then wait for a response. 209 call ch_sendexpr(handle, 'wait a bit') 210 let resp = ch_read(handle) 211 call assert_equal(type([]), type(resp)) 212 call assert_equal(type(11), type(resp[0])) 213 call assert_equal('waited', resp[1]) 214 215 " make the server quit, can't check if this works, should not hang. 216 call ch_sendexpr(handle, '!quit!') 217endfunc 218 219func Test_communicate() 220 call ch_log('Test_communicate()') 221 call s:run_server('Ch_communicate') 222endfunc 223 224" Test that we can open two channels. 225func Ch_two_channels(port) 226 let handle = ch_open('localhost:' . a:port, s:chopt) 227 call assert_equal(v:t_channel, type(handle)) 228 if ch_status(handle) == "fail" 229 call assert_report("Can't open channel") 230 return 231 endif 232 233 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 234 235 let newhandle = ch_open('localhost:' . a:port, s:chopt) 236 if ch_status(newhandle) == "fail" 237 call assert_report("Can't open second channel") 238 return 239 endif 240 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 241 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 242 243 call ch_close(handle) 244 call assert_equal('got it', ch_evalexpr(newhandle, 'hello!')) 245 246 call ch_close(newhandle) 247endfunc 248 249func Test_two_channels() 250 call ch_log('Test_two_channels()') 251 call s:run_server('Ch_two_channels') 252endfunc 253 254" Test that a server crash is handled gracefully. 255func Ch_server_crash(port) 256 let handle = ch_open('localhost:' . a:port, s:chopt) 257 if ch_status(handle) == "fail" 258 call assert_report("Can't open channel") 259 return 260 endif 261 262 call ch_evalexpr(handle, '!crash!') 263 264 sleep 10m 265endfunc 266 267func Test_server_crash() 268 call ch_log('Test_server_crash()') 269 call s:run_server('Ch_server_crash') 270endfunc 271 272""""""""" 273 274func Ch_handler(chan, msg) 275 call ch_log('Ch_handler()') 276 unlet g:Ch_reply 277 let g:Ch_reply = a:msg 278endfunc 279 280func Ch_channel_handler(port) 281 let handle = ch_open('localhost:' . a:port, s:chopt) 282 if ch_status(handle) == "fail" 283 call assert_report("Can't open channel") 284 return 285 endif 286 287 " Test that it works while waiting on a numbered message. 288 call assert_equal('ok', ch_evalexpr(handle, 'call me')) 289 call WaitForAssert({-> assert_equal('we called you', g:Ch_reply)}) 290 291 " Test that it works while not waiting on a numbered message. 292 call ch_sendexpr(handle, 'call me again') 293 call WaitForAssert({-> assert_equal('we did call you', g:Ch_reply)}) 294endfunc 295 296func Test_channel_handler() 297 call ch_log('Test_channel_handler()') 298 let g:Ch_reply = "" 299 let s:chopt.callback = 'Ch_handler' 300 call s:run_server('Ch_channel_handler') 301 let g:Ch_reply = "" 302 let s:chopt.callback = function('Ch_handler') 303 call s:run_server('Ch_channel_handler') 304 unlet s:chopt.callback 305endfunc 306 307""""""""" 308 309let g:Ch_reply = '' 310func Ch_zeroHandler(chan, msg) 311 unlet g:Ch_reply 312 let g:Ch_reply = a:msg 313endfunc 314 315let g:Ch_zero_reply = '' 316func Ch_oneHandler(chan, msg) 317 unlet g:Ch_zero_reply 318 let g:Ch_zero_reply = a:msg 319endfunc 320 321func Ch_channel_zero(port) 322 let handle = ch_open('localhost:' . a:port, s:chopt) 323 if ch_status(handle) == "fail" 324 call assert_report("Can't open channel") 325 return 326 endif 327 328 " Check that eval works. 329 call assert_equal('got it', ch_evalexpr(handle, 'hello!')) 330 331 " Check that eval works if a zero id message is sent back. 332 let g:Ch_reply = '' 333 call assert_equal('sent zero', ch_evalexpr(handle, 'send zero')) 334 if s:has_handler 335 call WaitForAssert({-> assert_equal('zero index', g:Ch_reply)}) 336 else 337 sleep 20m 338 call assert_equal('', g:Ch_reply) 339 endif 340 341 " Check that handler works if a zero id message is sent back. 342 let g:Ch_reply = '' 343 let g:Ch_zero_reply = '' 344 call ch_sendexpr(handle, 'send zero', {'callback': 'Ch_oneHandler'}) 345 call WaitForAssert({-> assert_equal('sent zero', g:Ch_zero_reply)}) 346 if s:has_handler 347 call assert_equal('zero index', g:Ch_reply) 348 else 349 call assert_equal('', g:Ch_reply) 350 endif 351endfunc 352 353func Test_zero_reply() 354 call ch_log('Test_zero_reply()') 355 " Run with channel handler 356 let s:has_handler = 1 357 let s:chopt.callback = 'Ch_zeroHandler' 358 call s:run_server('Ch_channel_zero') 359 unlet s:chopt.callback 360 361 " Run without channel handler 362 let s:has_handler = 0 363 call s:run_server('Ch_channel_zero') 364endfunc 365 366""""""""" 367 368let g:Ch_reply1 = "" 369func Ch_handleRaw1(chan, msg) 370 unlet g:Ch_reply1 371 let g:Ch_reply1 = a:msg 372endfunc 373 374let g:Ch_reply2 = "" 375func Ch_handleRaw2(chan, msg) 376 unlet g:Ch_reply2 377 let g:Ch_reply2 = a:msg 378endfunc 379 380let g:Ch_reply3 = "" 381func Ch_handleRaw3(chan, msg) 382 unlet g:Ch_reply3 383 let g:Ch_reply3 = a:msg 384endfunc 385 386func Ch_raw_one_time_callback(port) 387 let handle = ch_open('localhost:' . a:port, s:chopt) 388 if ch_status(handle) == "fail" 389 call assert_report("Can't open channel") 390 return 391 endif 392 call ch_setoptions(handle, {'mode': 'raw'}) 393 394 " The messages are sent raw, we do our own JSON strings here. 395 call ch_sendraw(handle, "[1, \"hello!\"]\n", {'callback': 'Ch_handleRaw1'}) 396 call WaitForAssert({-> assert_equal("[1, \"got it\"]", g:Ch_reply1)}) 397 call ch_sendraw(handle, "[2, \"echo something\"]\n", {'callback': 'Ch_handleRaw2'}) 398 call ch_sendraw(handle, "[3, \"wait a bit\"]\n", {'callback': 'Ch_handleRaw3'}) 399 call WaitForAssert({-> assert_equal("[2, \"something\"]", g:Ch_reply2)}) 400 " wait for the 200 msec delayed reply 401 call WaitForAssert({-> assert_equal("[3, \"waited\"]", g:Ch_reply3)}) 402endfunc 403 404func Test_raw_one_time_callback() 405 call ch_log('Test_raw_one_time_callback()') 406 call s:run_server('Ch_raw_one_time_callback') 407endfunc 408 409""""""""" 410 411" Test that trying to connect to a non-existing port fails quickly. 412func Test_connect_waittime() 413 call ch_log('Test_connect_waittime()') 414 let start = reltime() 415 let handle = ch_open('localhost:9876', s:chopt) 416 if ch_status(handle) != "fail" 417 " Oops, port does exists. 418 call ch_close(handle) 419 else 420 let elapsed = reltime(start) 421 call assert_true(reltimefloat(elapsed) < 1.0) 422 endif 423 424 " We intend to use a socket that doesn't exist and wait for half a second 425 " before giving up. If the socket does exist it can fail in various ways. 426 " Check for "Connection reset by peer" to avoid flakyness. 427 let start = reltime() 428 try 429 let handle = ch_open('localhost:9867', {'waittime': 500}) 430 if ch_status(handle) != "fail" 431 " Oops, port does exists. 432 call ch_close(handle) 433 else 434 " Failed connection should wait about 500 msec. Can be longer if the 435 " computer is busy with other things. 436 call assert_inrange(0.3, 1.5, reltimefloat(reltime(start))) 437 endif 438 catch 439 if v:exception !~ 'Connection reset by peer' 440 call assert_report("Caught exception: " . v:exception) 441 endif 442 endtry 443endfunc 444 445""""""""" 446 447func 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 453 " ch_canread(). 454 " Also test the non-blocking option. 455 let job = job_start(s:python . " test_channel_pipe.py", 456 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 457 call assert_equal(v:t_job, type(job)) 458 call assert_equal("run", job_status(job)) 459 460 call assert_equal("open", ch_status(job)) 461 call assert_equal("open", ch_status(job), {"part": "out"}) 462 call assert_equal("open", ch_status(job), {"part": "err"}) 463 call assert_fails('call ch_status(job, {"in_mode": "raw"})', 'E475:') 464 call assert_fails('call ch_status(job, {"part": "in"})', 'E475:') 465 466 let dict = ch_info(job) 467 call assert_true(dict.id != 0) 468 call assert_equal('open', dict.status) 469 call assert_equal('open', dict.out_status) 470 call assert_equal('RAW', dict.out_mode) 471 call assert_equal('pipe', dict.out_io) 472 call assert_equal('open', dict.err_status) 473 call assert_equal('RAW', dict.err_mode) 474 call assert_equal('pipe', dict.err_io) 475 476 try 477 " For a change use the job where a channel is expected. 478 call ch_sendraw(job, "echo something\n") 479 let msg = ch_readraw(job) 480 call assert_equal("something\n", substitute(msg, "\r", "", 'g')) 481 482 call ch_sendraw(job, "double this\n") 483 let g:handle = job_getchannel(job) 484 call WaitFor('ch_canread(g:handle)') 485 unlet g:handle 486 let msg = ch_readraw(job) 487 call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g')) 488 489 let g:Ch_reply = "" 490 call ch_sendraw(job, "double this\n", {'callback': 'Ch_handler'}) 491 call WaitForAssert({-> assert_equal("this\nAND this\n", substitute(g:Ch_reply, "\r", "", 'g'))}) 492 493 let reply = ch_evalraw(job, "quit\n", {'timeout': 100}) 494 call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) 495 finally 496 call job_stop(job) 497 endtry 498 499 let g:Ch_job = job 500 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 501 let info = job_info(job) 502 call assert_equal("dead", info.status) 503 call assert_equal("term", info.stoponexit) 504 call assert_equal(2, len(info.cmd)) 505 call assert_equal("test_channel_pipe.py", info.cmd[1]) 506 507 let found = 0 508 for j in job_info() 509 if j == job 510 let found += 1 511 endif 512 endfor 513 call assert_equal(1, found) 514endfunc 515 516func 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 522 " ch_canread(). 523 " Also test the non-blocking option. 524 let job = job_start(s:python . " test_channel_pipe.py", 525 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1}) 526 call assert_equal(v:t_job, type(job)) 527 call assert_equal("run", job_status(job)) 528 529 call assert_equal("open", ch_status(job)) 530 call assert_equal("open", ch_status(job), {"part": "out"}) 531 532 try 533 " Create a blob with the echo command and write it. 534 let blob = 0z00 535 let cmd = "echo something\n" 536 for i in range(0, len(cmd) - 1) 537 let blob[i] = char2nr(cmd[i]) 538 endfor 539 call assert_equal(len(cmd), len(blob)) 540 call ch_sendraw(job, blob) 541 542 " Read a blob with the reply. 543 let msg = ch_readblob(job) 544 let expected = 'something' 545 for i in range(0, len(expected) - 1) 546 call assert_equal(char2nr(expected[i]), msg[i]) 547 endfor 548 549 let reply = ch_evalraw(job, "quit\n", {'timeout': 100}) 550 call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g')) 551 finally 552 call job_stop(job) 553 endtry 554 555 let g:Ch_job = job 556 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 557 let info = job_info(job) 558 call assert_equal("dead", info.status) 559endfunc 560 561func 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"]) 567 call assert_equal("run", job_status(job)) 568 try 569 let handle = job_getchannel(job) 570 call ch_sendraw(handle, "echo something\n") 571 call assert_equal("something", ch_readraw(handle)) 572 573 call ch_sendraw(handle, "echoerr wrong\n") 574 call assert_equal("wrong", ch_readraw(handle, {'part': 'err'})) 575 576 call ch_sendraw(handle, "double this\n") 577 call assert_equal("this", ch_readraw(handle)) 578 call assert_equal("AND this", ch_readraw(handle)) 579 580 call ch_sendraw(handle, "split this line\n") 581 call assert_equal("this linethis linethis line", ch_read(handle)) 582 583 let reply = ch_evalraw(handle, "quit\n") 584 call assert_equal("Goodbye!", reply) 585 finally 586 call job_stop(job) 587 endtry 588endfunc 589 590func Test_nl_err_to_out_pipe() 591 if !has('job') 592 return 593 endif 594 call ch_logfile('Xlog') 595 call ch_log('Test_nl_err_to_out_pipe()') 596 let job = job_start(s:python . " test_channel_pipe.py", {'err_io': 'out'}) 597 call assert_equal("run", job_status(job)) 598 try 599 let handle = job_getchannel(job) 600 call ch_sendraw(handle, "echo something\n") 601 call assert_equal("something", ch_readraw(handle)) 602 603 call ch_sendraw(handle, "echoerr wrong\n") 604 call assert_equal("wrong", ch_readraw(handle)) 605 finally 606 call job_stop(job) 607 call ch_logfile('') 608 let loglines = readfile('Xlog') 609 call assert_true(len(loglines) > 10) 610 let found_test = 0 611 let found_send = 0 612 let found_recv = 0 613 let found_stop = 0 614 for l in loglines 615 if l =~ 'Test_nl_err_to_out_pipe' 616 let found_test = 1 617 endif 618 if l =~ 'SEND on.*echo something' 619 let found_send = 1 620 endif 621 if l =~ 'RECV on.*something' 622 let found_recv = 1 623 endif 624 if l =~ 'Stopping job with' 625 let found_stop = 1 626 endif 627 endfor 628 call assert_equal(1, found_test) 629 call assert_equal(1, found_send) 630 call assert_equal(1, found_recv) 631 call assert_equal(1, found_stop) 632 " On MS-Windows need to sleep for a moment to be able to delete the file. 633 sleep 10m 634 call delete('Xlog') 635 endtry 636endfunc 637 638func 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 646endfunc 647 648func 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 667endfunc 668 669func 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 688endfunc 689 690func 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 708endfunc 709 710func 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 730endfunc 731 732func BufCloseCb(ch) 733 let g:Ch_bufClosed = 'yes' 734endfunc 735 736func 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 782endfunc 783 784func Test_pipe_to_buffer_name() 785 call Run_test_pipe_to_buffer(1, 0, 1) 786endfunc 787 788func Test_pipe_to_buffer_nr() 789 call Run_test_pipe_to_buffer(0, 0, 1) 790endfunc 791 792func Test_pipe_to_buffer_name_nomod() 793 call Run_test_pipe_to_buffer(1, 1, 1) 794endfunc 795 796func Test_pipe_to_buffer_name_nomsg() 797 call Run_test_pipe_to_buffer(1, 0, 1) 798endfunc 799 800func 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 829endfunc 830 831func 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 874endfunc 875 876func Test_pipe_err_to_buffer_name() 877 call Run_test_pipe_err_to_buffer(1, 0, 1) 878endfunc 879 880func Test_pipe_err_to_buffer_nr() 881 call Run_test_pipe_err_to_buffer(0, 0, 1) 882endfunc 883 884func Test_pipe_err_to_buffer_name_nomod() 885 call Run_test_pipe_err_to_buffer(1, 1, 1) 886endfunc 887 888func Test_pipe_err_to_buffer_name_nomsg() 889 call Run_test_pipe_err_to_buffer(1, 0, 0) 890endfunc 891 892func 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 913endfunc 914 915func 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 941endfunc 942 943func Test_pipe_from_buffer_name() 944 call Run_test_pipe_from_buffer(1) 945endfunc 946 947func Test_pipe_from_buffer_nr() 948 call Run_test_pipe_from_buffer(0) 949endfunc 950 951func 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 990endfunc 991 992func Test_pipe_through_sort_all() 993 call ch_log('Test_pipe_through_sort_all()') 994 call Run_pipe_through_sort(1, 1) 995endfunc 996 997func Test_pipe_through_sort_some() 998 call ch_log('Test_pipe_through_sort_some()') 999 call Run_pipe_through_sort(0, 1) 1000endfunc 1001 1002func Test_pipe_through_sort_feed() 1003 call ch_log('Test_pipe_through_sort_feed()') 1004 call Run_pipe_through_sort(1, 0) 1005endfunc 1006 1007func 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 1026endfunc 1027 1028func 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 1047endfunc 1048 1049" Wait a little while for the last line, minus "offset", to equal "line". 1050func 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 1057endfunc 1058 1059func 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 1095endfunc 1096 1097func 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 1126endfunc 1127 1128func Test_pipe_null() 1129 if !has('job') 1130 return 1131 endif 1132 call ch_log('Test_pipe_null()') 1133 1134 " We cannot check that no I/O works, we only check that the job starts 1135 " properly. 1136 let job = job_start(s:python . " test_channel_pipe.py something", 1137 \ {'in_io': 'null'}) 1138 call assert_equal("run", job_status(job)) 1139 try 1140 call assert_equal('something', ch_read(job)) 1141 finally 1142 call job_stop(job) 1143 endtry 1144 1145 let job = job_start(s:python . " test_channel_pipe.py err-out", 1146 \ {'out_io': 'null'}) 1147 call assert_equal("run", job_status(job)) 1148 try 1149 call assert_equal('err-out', ch_read(job, {"part": "err"})) 1150 finally 1151 call job_stop(job) 1152 endtry 1153 1154 let job = job_start(s:python . " test_channel_pipe.py something", 1155 \ {'err_io': 'null'}) 1156 call assert_equal("run", job_status(job)) 1157 try 1158 call assert_equal('something', ch_read(job)) 1159 finally 1160 call job_stop(job) 1161 endtry 1162 1163 let job = job_start(s:python . " test_channel_pipe.py something", 1164 \ {'out_io': 'null', 'err_io': 'out'}) 1165 call assert_equal("run", job_status(job)) 1166 call job_stop(job) 1167 1168 let job = job_start(s:python . " test_channel_pipe.py something", 1169 \ {'in_io': 'null', 'out_io': 'null', 'err_io': 'null'}) 1170 call assert_equal("run", job_status(job)) 1171 call assert_equal('channel fail', string(job_getchannel(job))) 1172 call assert_equal('fail', ch_status(job)) 1173 call job_stop(job) 1174endfunc 1175 1176func Test_pipe_to_buffer_raw() 1177 if !has('job') 1178 return 1179 endif 1180 call ch_log('Test_raw_pipe_to_buffer()') 1181 let options = {'out_mode': 'raw', 'out_io': 'buffer', 'out_name': 'testout'} 1182 split testout 1183 let job = job_start([s:python, '-c', 1184 \ 'import sys; [sys.stdout.write(".") and sys.stdout.flush() for _ in range(10000)]'], options) 1185 " the job may be done quickly, also accept "dead" 1186 call assert_match('^\%(dead\|run\)$', job_status(job)) 1187 call WaitFor('len(join(getline(1, "$"), "")) >= 10000') 1188 try 1189 let totlen = 0 1190 for line in getline(1, '$') 1191 call assert_equal('', substitute(line, '^\.*', '', '')) 1192 let totlen += len(line) 1193 endfor 1194 call assert_equal(10000, totlen) 1195 finally 1196 call job_stop(job) 1197 bwipe! 1198 endtry 1199endfunc 1200 1201func Test_reuse_channel() 1202 if !has('job') 1203 return 1204 endif 1205 call ch_log('Test_reuse_channel()') 1206 1207 let job = job_start(s:python . " test_channel_pipe.py") 1208 call assert_equal("run", job_status(job)) 1209 let handle = job_getchannel(job) 1210 try 1211 call ch_sendraw(handle, "echo something\n") 1212 call assert_equal("something", ch_readraw(handle)) 1213 finally 1214 call job_stop(job) 1215 endtry 1216 1217 let job = job_start(s:python . " test_channel_pipe.py", {'channel': handle}) 1218 call assert_equal("run", job_status(job)) 1219 let handle = job_getchannel(job) 1220 try 1221 call ch_sendraw(handle, "echo again\n") 1222 call assert_equal("again", ch_readraw(handle)) 1223 finally 1224 call job_stop(job) 1225 endtry 1226endfunc 1227 1228func Test_out_cb() 1229 if !has('job') 1230 return 1231 endif 1232 call ch_log('Test_out_cb()') 1233 1234 let dict = {'thisis': 'dict: '} 1235 func dict.outHandler(chan, msg) dict 1236 if type(a:msg) == v:t_string 1237 let g:Ch_outmsg = self.thisis . a:msg 1238 else 1239 let g:Ch_outobj = a:msg 1240 endif 1241 endfunc 1242 func dict.errHandler(chan, msg) dict 1243 let g:Ch_errmsg = self.thisis . a:msg 1244 endfunc 1245 let job = job_start(s:python . " test_channel_pipe.py", 1246 \ {'out_cb': dict.outHandler, 1247 \ 'out_mode': 'json', 1248 \ 'err_cb': dict.errHandler, 1249 \ 'err_mode': 'json'}) 1250 call assert_equal("run", job_status(job)) 1251 try 1252 let g:Ch_outmsg = '' 1253 let g:Ch_errmsg = '' 1254 call ch_sendraw(job, "echo [0, \"hello\"]\n") 1255 call ch_sendraw(job, "echoerr [0, \"there\"]\n") 1256 call WaitForAssert({-> assert_equal("dict: hello", g:Ch_outmsg)}) 1257 call WaitForAssert({-> assert_equal("dict: there", g:Ch_errmsg)}) 1258 1259 " Receive a json object split in pieces 1260 unlet! g:Ch_outobj 1261 call ch_sendraw(job, "echosplit [0, {\"one\": 1,| \"tw|o\": 2, \"three\": 3|}]\n") 1262 let g:Ch_outobj = '' 1263 call WaitForAssert({-> assert_equal({'one': 1, 'two': 2, 'three': 3}, g:Ch_outobj)}) 1264 finally 1265 call job_stop(job) 1266 endtry 1267endfunc 1268 1269func Test_out_close_cb() 1270 if !has('job') 1271 return 1272 endif 1273 call ch_log('Test_out_close_cb()') 1274 1275 let s:counter = 1 1276 let g:Ch_msg1 = '' 1277 let g:Ch_closemsg = 0 1278 func! OutHandler(chan, msg) 1279 if s:counter == 1 1280 let g:Ch_msg1 = a:msg 1281 endif 1282 let s:counter += 1 1283 endfunc 1284 func! CloseHandler(chan) 1285 let g:Ch_closemsg = s:counter 1286 let s:counter += 1 1287 endfunc 1288 let job = job_start(s:python . " test_channel_pipe.py quit now", 1289 \ {'out_cb': 'OutHandler', 1290 \ 'close_cb': 'CloseHandler'}) 1291 " the job may be done quickly, also accept "dead" 1292 call assert_match('^\%(dead\|run\)$', job_status(job)) 1293 try 1294 call WaitForAssert({-> assert_equal('quit', g:Ch_msg1)}) 1295 call WaitForAssert({-> assert_equal(2, g:Ch_closemsg)}) 1296 finally 1297 call job_stop(job) 1298 delfunc OutHandler 1299 delfunc CloseHandler 1300 endtry 1301endfunc 1302 1303func Test_read_in_close_cb() 1304 if !has('job') 1305 return 1306 endif 1307 call ch_log('Test_read_in_close_cb()') 1308 1309 let g:Ch_received = '' 1310 func! CloseHandler(chan) 1311 let g:Ch_received = ch_read(a:chan) 1312 endfunc 1313 let job = job_start(s:python . " test_channel_pipe.py quit now", 1314 \ {'close_cb': 'CloseHandler'}) 1315 " the job may be done quickly, also accept "dead" 1316 call assert_match('^\%(dead\|run\)$', job_status(job)) 1317 try 1318 call WaitForAssert({-> assert_equal('quit', g:Ch_received)}) 1319 finally 1320 call job_stop(job) 1321 delfunc CloseHandler 1322 endtry 1323endfunc 1324 1325" Use channel in NL mode but received text does not end in NL. 1326func Test_read_in_close_cb_incomplete() 1327 if !has('job') 1328 return 1329 endif 1330 call ch_log('Test_read_in_close_cb_incomplete()') 1331 1332 let g:Ch_received = '' 1333 func! CloseHandler(chan) 1334 while ch_status(a:chan, {'part': 'out'}) == 'buffered' 1335 let g:Ch_received .= ch_read(a:chan) 1336 endwhile 1337 endfunc 1338 let job = job_start(s:python . " test_channel_pipe.py incomplete", 1339 \ {'close_cb': 'CloseHandler'}) 1340 " the job may be done quickly, also accept "dead" 1341 call assert_match('^\%(dead\|run\)$', job_status(job)) 1342 try 1343 call WaitForAssert({-> assert_equal('incomplete', g:Ch_received)}) 1344 finally 1345 call job_stop(job) 1346 delfunc CloseHandler 1347 endtry 1348endfunc 1349 1350func Test_out_cb_lambda() 1351 if !has('job') 1352 return 1353 endif 1354 call ch_log('Test_out_cb_lambda()') 1355 1356 let job = job_start(s:python . " test_channel_pipe.py", 1357 \ {'out_cb': {ch, msg -> execute("let g:Ch_outmsg = 'lambda: ' . msg")}, 1358 \ 'out_mode': 'json', 1359 \ 'err_cb': {ch, msg -> execute(":let g:Ch_errmsg = 'lambda: ' . msg")}, 1360 \ 'err_mode': 'json'}) 1361 call assert_equal("run", job_status(job)) 1362 try 1363 let g:Ch_outmsg = '' 1364 let g:Ch_errmsg = '' 1365 call ch_sendraw(job, "echo [0, \"hello\"]\n") 1366 call ch_sendraw(job, "echoerr [0, \"there\"]\n") 1367 call WaitForAssert({-> assert_equal("lambda: hello", g:Ch_outmsg)}) 1368 call WaitForAssert({-> assert_equal("lambda: there", g:Ch_errmsg)}) 1369 finally 1370 call job_stop(job) 1371 endtry 1372endfunc 1373 1374func Test_close_and_exit_cb() 1375 if !has('job') 1376 return 1377 endif 1378 call ch_log('Test_close_and_exit_cb') 1379 1380 let g:retdict = {'ret': {}} 1381 func g:retdict.close_cb(ch) dict 1382 let self.ret['close_cb'] = job_status(ch_getjob(a:ch)) 1383 endfunc 1384 func g:retdict.exit_cb(job, status) dict 1385 let self.ret['exit_cb'] = job_status(a:job) 1386 endfunc 1387 1388 let job = job_start([&shell, &shellcmdflag, 'echo'], 1389 \ {'close_cb': g:retdict.close_cb, 1390 \ 'exit_cb': g:retdict.exit_cb}) 1391 " the job may be done quickly, also accept "dead" 1392 call assert_match('^\%(dead\|run\)$', job_status(job)) 1393 call WaitForAssert({-> assert_equal(2, len(g:retdict.ret))}) 1394 call assert_match('^\%(dead\|run\)$', g:retdict.ret['close_cb']) 1395 call assert_equal('dead', g:retdict.ret['exit_cb']) 1396 unlet g:retdict 1397endfunc 1398 1399"""""""""" 1400 1401function ExitCbWipe(job, status) 1402 exe g:wipe_buf 'bw!' 1403endfunction 1404 1405" This caused a crash, because messages were handled while peeking for a 1406" character. 1407func Test_exit_cb_wipes_buf() 1408 if !has('timers') 1409 return 1410 endif 1411 set cursorline lazyredraw 1412 call test_override('redraw_flag', 1) 1413 new 1414 let g:wipe_buf = bufnr('') 1415 1416 let job = job_start(has('win32') ? 'cmd /c echo:' : ['true'], 1417 \ {'exit_cb': 'ExitCbWipe'}) 1418 let timer = timer_start(300, {-> feedkeys("\<Esc>", 'nt')}, {'repeat': 5}) 1419 call feedkeys(repeat('g', 1000) . 'o', 'ntx!') 1420 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 1421 call timer_stop(timer) 1422 1423 set nocursorline nolazyredraw 1424 unlet g:wipe_buf 1425 call test_override('ALL', 0) 1426endfunc 1427 1428"""""""""" 1429 1430let g:Ch_unletResponse = '' 1431func s:UnletHandler(handle, msg) 1432 let g:Ch_unletResponse = a:msg 1433 unlet s:channelfd 1434endfunc 1435 1436" Test that "unlet handle" in a handler doesn't crash Vim. 1437func Ch_unlet_handle(port) 1438 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1439 call ch_sendexpr(s:channelfd, "test", {'callback': function('s:UnletHandler')}) 1440 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) 1441endfunc 1442 1443func Test_unlet_handle() 1444 call ch_log('Test_unlet_handle()') 1445 call s:run_server('Ch_unlet_handle') 1446endfunc 1447 1448"""""""""" 1449 1450let g:Ch_unletResponse = '' 1451func Ch_CloseHandler(handle, msg) 1452 let g:Ch_unletResponse = a:msg 1453 call ch_close(s:channelfd) 1454endfunc 1455 1456" Test that "unlet handle" in a handler doesn't crash Vim. 1457func Ch_close_handle(port) 1458 let s:channelfd = ch_open('localhost:' . a:port, s:chopt) 1459 call ch_sendexpr(s:channelfd, "test", {'callback': function('Ch_CloseHandler')}) 1460 call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)}) 1461endfunc 1462 1463func Test_close_handle() 1464 call ch_log('Test_close_handle()') 1465 call s:run_server('Ch_close_handle') 1466endfunc 1467 1468"""""""""" 1469 1470func Test_open_fail() 1471 call ch_log('Test_open_fail()') 1472 silent! let ch = ch_open("noserver") 1473 echo ch 1474 let d = ch 1475endfunc 1476 1477"""""""""" 1478 1479func Ch_open_delay(port) 1480 " Wait up to a second for the port to open. 1481 let s:chopt.waittime = 1000 1482 let channel = ch_open('localhost:' . a:port, s:chopt) 1483 unlet s:chopt.waittime 1484 if ch_status(channel) == "fail" 1485 call assert_report("Can't open channel") 1486 return 1487 endif 1488 call assert_equal('got it', ch_evalexpr(channel, 'hello!')) 1489 call ch_close(channel) 1490endfunc 1491 1492func Test_open_delay() 1493 call ch_log('Test_open_delay()') 1494 " The server will wait half a second before creating the port. 1495 call s:run_server('Ch_open_delay', 'delay') 1496endfunc 1497 1498""""""""" 1499 1500function MyFunction(a,b,c) 1501 let g:Ch_call_ret = [a:a, a:b, a:c] 1502endfunc 1503 1504function Ch_test_call(port) 1505 let handle = ch_open('localhost:' . a:port, s:chopt) 1506 if ch_status(handle) == "fail" 1507 call assert_report("Can't open channel") 1508 return 1509 endif 1510 1511 let g:Ch_call_ret = [] 1512 call assert_equal('ok', ch_evalexpr(handle, 'call-func')) 1513 call WaitForAssert({-> assert_equal([1, 2, 3], g:Ch_call_ret)}) 1514endfunc 1515 1516func Test_call() 1517 call ch_log('Test_call()') 1518 call s:run_server('Ch_test_call') 1519endfunc 1520 1521""""""""" 1522 1523let g:Ch_job_exit_ret = 'not yet' 1524function MyExitCb(job, status) 1525 let g:Ch_job_exit_ret = 'done' 1526endfunc 1527 1528function Ch_test_exit_callback(port) 1529 call job_setoptions(g:currentJob, {'exit_cb': 'MyExitCb'}) 1530 let g:Ch_exit_job = g:currentJob 1531 call assert_equal('MyExitCb', job_info(g:currentJob)['exit_cb']) 1532endfunc 1533 1534func Test_exit_callback() 1535 if has('job') 1536 call ch_log('Test_exit_callback()') 1537 call s:run_server('Ch_test_exit_callback') 1538 1539 " wait up to a second for the job to exit 1540 for i in range(100) 1541 if g:Ch_job_exit_ret == 'done' 1542 break 1543 endif 1544 sleep 10m 1545 " calling job_status() triggers the callback 1546 call job_status(g:Ch_exit_job) 1547 endfor 1548 1549 call assert_equal('done', g:Ch_job_exit_ret) 1550 call assert_equal('dead', job_info(g:Ch_exit_job).status) 1551 unlet g:Ch_exit_job 1552 endif 1553endfunc 1554 1555function MyExitTimeCb(job, status) 1556 if job_info(a:job).process == g:exit_cb_val.process 1557 let g:exit_cb_val.end = reltime(g:exit_cb_val.start) 1558 endif 1559 call Resume() 1560endfunction 1561 1562func Test_exit_callback_interval() 1563 if !has('job') 1564 return 1565 endif 1566 1567 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0} 1568 let job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'}) 1569 let g:exit_cb_val.process = job_info(job).process 1570 call WaitFor('type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0') 1571 let elapsed = reltimefloat(g:exit_cb_val.end) 1572 call assert_true(elapsed > 0.5) 1573 call assert_true(elapsed < 1.0) 1574 1575 " case: unreferenced job, using timer 1576 if !has('timers') 1577 return 1578 endif 1579 1580 let g:exit_cb_val = {'start': reltime(), 'end': 0, 'process': 0} 1581 let g:job = job_start([s:python, '-c', 'import time;time.sleep(0.5)'], {'exit_cb': 'MyExitTimeCb'}) 1582 let g:exit_cb_val.process = job_info(g:job).process 1583 unlet g:job 1584 call Standby(1000) 1585 if type(g:exit_cb_val.end) != v:t_number || g:exit_cb_val.end != 0 1586 let elapsed = reltimefloat(g:exit_cb_val.end) 1587 else 1588 let elapsed = 1.0 1589 endif 1590 call assert_inrange(0.5, 1.0, elapsed) 1591endfunc 1592 1593""""""""" 1594 1595let g:Ch_close_ret = 'alive' 1596function MyCloseCb(ch) 1597 let g:Ch_close_ret = 'closed' 1598endfunc 1599 1600function Ch_test_close_callback(port) 1601 let handle = ch_open('localhost:' . a:port, s:chopt) 1602 if ch_status(handle) == "fail" 1603 call assert_report("Can't open channel") 1604 return 1605 endif 1606 call ch_setoptions(handle, {'close_cb': 'MyCloseCb'}) 1607 1608 call assert_equal('', ch_evalexpr(handle, 'close me')) 1609 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)}) 1610endfunc 1611 1612func Test_close_callback() 1613 call ch_log('Test_close_callback()') 1614 call s:run_server('Ch_test_close_callback') 1615endfunc 1616 1617function Ch_test_close_partial(port) 1618 let handle = ch_open('localhost:' . a:port, s:chopt) 1619 if ch_status(handle) == "fail" 1620 call assert_report("Can't open channel") 1621 return 1622 endif 1623 let g:Ch_d = {} 1624 func g:Ch_d.closeCb(ch) dict 1625 let self.close_ret = 'closed' 1626 endfunc 1627 call ch_setoptions(handle, {'close_cb': g:Ch_d.closeCb}) 1628 1629 call assert_equal('', ch_evalexpr(handle, 'close me')) 1630 call WaitForAssert({-> assert_equal('closed', g:Ch_d.close_ret)}) 1631 unlet g:Ch_d 1632endfunc 1633 1634func Test_close_partial() 1635 call ch_log('Test_close_partial()') 1636 call s:run_server('Ch_test_close_partial') 1637endfunc 1638 1639func Test_job_start_invalid() 1640 call assert_fails('call job_start($x)', 'E474:') 1641 call assert_fails('call job_start("")', 'E474:') 1642endfunc 1643 1644func Test_job_stop_immediately() 1645 if !has('job') 1646 return 1647 endif 1648 1649 let g:job = job_start([s:python, '-c', 'import time;time.sleep(10)']) 1650 try 1651 call job_stop(g:job) 1652 call WaitForAssert({-> assert_equal('dead', job_status(g:job))}) 1653 finally 1654 call job_stop(g:job, 'kill') 1655 unlet g:job 1656 endtry 1657endfunc 1658 1659" This was leaking memory. 1660func Test_partial_in_channel_cycle() 1661 let d = {} 1662 let d.a = function('string', [d]) 1663 try 1664 let d.b = ch_open('nowhere:123', {'close_cb': d.a}) 1665 catch 1666 call assert_exception('E901:') 1667 endtry 1668 unlet d 1669endfunc 1670 1671func Test_using_freed_memory() 1672 let g:a = job_start(['ls']) 1673 sleep 10m 1674 call test_garbagecollect_now() 1675endfunc 1676 1677func Test_collapse_buffers() 1678 if !executable('cat') || !has('job') 1679 return 1680 endif 1681 sp test_channel.vim 1682 let g:linecount = line('$') 1683 close 1684 split testout 1685 1,$delete 1686 call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'}) 1687 call WaitForAssert({-> assert_inrange(g:linecount, g:linecount + 1, line('$'))}) 1688 bwipe! 1689endfunc 1690 1691func Test_write_to_deleted_buffer() 1692 if !executable('echo') || !has('job') 1693 return 1694 endif 1695 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0}) 1696 let bufnr = bufnr('test_buffer') 1697 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))}) 1698 call assert_equal('nofile', getbufvar(bufnr, '&buftype')) 1699 call assert_equal('hide', getbufvar(bufnr, '&bufhidden')) 1700 1701 bdel test_buffer 1702 call assert_equal([], getbufline(bufnr, 1, '$')) 1703 1704 let job = job_start('echo hello', {'out_io': 'buffer', 'out_name': 'test_buffer', 'out_msg': 0}) 1705 call WaitForAssert({-> assert_equal(['hello'], getbufline(bufnr, 1, '$'))}) 1706 call assert_equal('nofile', getbufvar(bufnr, '&buftype')) 1707 call assert_equal('hide', getbufvar(bufnr, '&bufhidden')) 1708 1709 bwipe! test_buffer 1710endfunc 1711 1712func Test_cmd_parsing() 1713 if !has('unix') 1714 return 1715 endif 1716 call assert_false(filereadable("file with space")) 1717 let job = job_start('touch "file with space"') 1718 call WaitForAssert({-> assert_true(filereadable("file with space"))}) 1719 call delete("file with space") 1720 1721 let job = job_start('touch file\ with\ space') 1722 call WaitForAssert({-> assert_true(filereadable("file with space"))}) 1723 call delete("file with space") 1724endfunc 1725 1726func Test_raw_passes_nul() 1727 if !executable('cat') || !has('job') 1728 return 1729 endif 1730 1731 " Test lines from the job containing NUL are stored correctly in a buffer. 1732 new 1733 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"]) 1734 w! Xtestread 1735 bwipe! 1736 split testout 1737 1,$delete 1738 call job_start('cat Xtestread', {'out_io': 'buffer', 'out_name': 'testout'}) 1739 call WaitFor('line("$") > 2') 1740 call assert_equal("asdf\nasdf", getline(1)) 1741 call assert_equal("xxx\n", getline(2)) 1742 call assert_equal("\nyyy", getline(3)) 1743 1744 call delete('Xtestread') 1745 bwipe! 1746 1747 " Test lines from a buffer with NUL bytes are written correctly to the job. 1748 new mybuffer 1749 call setline(1, ["asdf\nasdf", "xxx\n", "\nyyy"]) 1750 let g:Ch_job = job_start('cat', {'in_io': 'buffer', 'in_name': 'mybuffer', 'out_io': 'file', 'out_name': 'Xtestwrite'}) 1751 call WaitForAssert({-> assert_equal("dead", job_status(g:Ch_job))}) 1752 bwipe! 1753 split Xtestwrite 1754 call assert_equal("asdf\nasdf", getline(1)) 1755 call assert_equal("xxx\n", getline(2)) 1756 call assert_equal("\nyyy", getline(3)) 1757 call assert_equal(-1, match(s:get_resources(), '\(^\|/\)Xtestwrite$')) 1758 1759 call delete('Xtestwrite') 1760 bwipe! 1761endfunc 1762 1763func Test_read_nonl_line() 1764 if !has('job') 1765 return 1766 endif 1767 1768 let g:linecount = 0 1769 let arg = 'import sys;sys.stdout.write("1\n2\n3")' 1770 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}}) 1771 call WaitForAssert({-> assert_equal(3, g:linecount)}) 1772 unlet g:linecount 1773endfunc 1774 1775func Test_read_nonl_in_close_cb() 1776 if !has('job') 1777 return 1778 endif 1779 1780 func s:close_cb(ch) 1781 while ch_status(a:ch) == 'buffered' 1782 let g:out .= ch_read(a:ch) 1783 endwhile 1784 endfunc 1785 1786 let g:out = '' 1787 let arg = 'import sys;sys.stdout.write("1\n2\n3")' 1788 call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')}) 1789 call WaitForAssert({-> assert_equal('123', g:out)}) 1790 unlet g:out 1791 delfunc s:close_cb 1792endfunc 1793 1794func Test_read_from_terminated_job() 1795 if !has('job') 1796 return 1797 endif 1798 1799 let g:linecount = 0 1800 let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")' 1801 call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}}) 1802 call WaitForAssert({-> assert_equal(1, g:linecount)}) 1803 unlet g:linecount 1804endfunc 1805 1806func Test_job_start_windows() 1807 if !has('job') || !has('win32') 1808 return 1809 endif 1810 1811 " Check that backslash in $COMSPEC is handled properly. 1812 let g:echostr = '' 1813 let cmd = $COMSPEC . ' /c echo 123' 1814 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:echostr .= msg")}}) 1815 let info = job_info(job) 1816 call assert_equal([$COMSPEC, '/c', 'echo', '123'], info.cmd) 1817 1818 call WaitForAssert({-> assert_equal("123", g:echostr)}) 1819 unlet g:echostr 1820endfunc 1821 1822func Test_env() 1823 if !has('job') 1824 return 1825 endif 1826 1827 let g:envstr = '' 1828 if has('win32') 1829 let cmd = ['cmd', '/c', 'echo %FOO%'] 1830 else 1831 let cmd = [&shell, &shellcmdflag, 'echo $FOO'] 1832 endif 1833 call assert_fails('call job_start(cmd, {"env": 1})', 'E475:') 1834 call job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'env': {'FOO': 'bar'}}) 1835 call WaitForAssert({-> assert_equal("bar", g:envstr)}) 1836 unlet g:envstr 1837endfunc 1838 1839func Test_cwd() 1840 if !has('job') 1841 return 1842 endif 1843 1844 let g:envstr = '' 1845 if has('win32') 1846 let expect = $TEMP 1847 let cmd = ['cmd', '/c', 'echo %CD%'] 1848 else 1849 let expect = $HOME 1850 let cmd = ['pwd'] 1851 endif 1852 let job = job_start(cmd, {'callback': {ch,msg -> execute(":let g:envstr .= msg")}, 'cwd': expect}) 1853 try 1854 call WaitForAssert({-> assert_notequal("", g:envstr)}) 1855 let expect = substitute(expect, '[/\\]$', '', '') 1856 let g:envstr = substitute(g:envstr, '[/\\]$', '', '') 1857 if $CI != '' && stridx(g:envstr, '/private/') == 0 1858 let g:envstr = g:envstr[8:] 1859 endif 1860 call assert_equal(expect, g:envstr) 1861 finally 1862 call job_stop(job) 1863 unlet g:envstr 1864 endtry 1865endfunc 1866 1867function Ch_test_close_lambda(port) 1868 let handle = ch_open('localhost:' . a:port, s:chopt) 1869 if ch_status(handle) == "fail" 1870 call assert_report("Can't open channel") 1871 return 1872 endif 1873 let g:Ch_close_ret = '' 1874 call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}}) 1875 1876 call assert_equal('', ch_evalexpr(handle, 'close me')) 1877 call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)}) 1878endfunc 1879 1880func Test_close_lambda() 1881 call ch_log('Test_close_lambda()') 1882 call s:run_server('Ch_test_close_lambda') 1883endfunc 1884 1885func s:test_list_args(cmd, out, remove_lf) 1886 try 1887 let g:out = '' 1888 let job = job_start([s:python, '-c', a:cmd], {'callback': {ch, msg -> execute('let g:out .= msg')}, 'out_mode': 'raw'}) 1889 call WaitFor('"" != g:out') 1890 if has('win32') 1891 let g:out = substitute(g:out, '\r', '', 'g') 1892 endif 1893 if a:remove_lf 1894 let g:out = substitute(g:out, '\n$', '', 'g') 1895 endif 1896 call assert_equal(a:out, g:out) 1897 finally 1898 call job_stop(job) 1899 unlet g:out 1900 endtry 1901endfunc 1902 1903func Test_list_args() 1904 if !has('job') 1905 return 1906 endif 1907 1908 call s:test_list_args('import sys;sys.stdout.write("hello world")', "hello world", 0) 1909 call s:test_list_args('import sys;sys.stdout.write("hello\nworld")', "hello\nworld", 0) 1910 call s:test_list_args('import sys;sys.stdout.write(''hello\nworld'')', "hello\nworld", 0) 1911 call s:test_list_args('import sys;sys.stdout.write(''hello"world'')', "hello\"world", 0) 1912 call s:test_list_args('import sys;sys.stdout.write(''hello^world'')', "hello^world", 0) 1913 call s:test_list_args('import sys;sys.stdout.write("hello&&world")', "hello&&world", 0) 1914 call s:test_list_args('import sys;sys.stdout.write(''hello\\world'')', "hello\\world", 0) 1915 call s:test_list_args('import sys;sys.stdout.write(''hello\\\\world'')', "hello\\\\world", 0) 1916 call s:test_list_args('import sys;sys.stdout.write("hello\"world\"")', 'hello"world"', 0) 1917 call s:test_list_args('import sys;sys.stdout.write("h\"ello worl\"d")', 'h"ello worl"d', 0) 1918 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo wor\\\"l\"d")', 'h"e\"llo wor\"l"d', 0) 1919 call s:test_list_args('import sys;sys.stdout.write("h\"e\\\"llo world")', 'h"e\"llo world', 0) 1920 call s:test_list_args('import sys;sys.stdout.write("hello\tworld")', "hello\tworld", 0) 1921 1922 " tests which not contain spaces in the argument 1923 call s:test_list_args('print("hello\nworld")', "hello\nworld", 1) 1924 call s:test_list_args('print(''hello\nworld'')', "hello\nworld", 1) 1925 call s:test_list_args('print(''hello"world'')', "hello\"world", 1) 1926 call s:test_list_args('print(''hello^world'')', "hello^world", 1) 1927 call s:test_list_args('print("hello&&world")', "hello&&world", 1) 1928 call s:test_list_args('print(''hello\\world'')', "hello\\world", 1) 1929 call s:test_list_args('print(''hello\\\\world'')', "hello\\\\world", 1) 1930 call s:test_list_args('print("hello\"world\"")', 'hello"world"', 1) 1931 call s:test_list_args('print("hello\tworld")', "hello\tworld", 1) 1932endfunc 1933 1934" Do this last, it stops any channel log. 1935func Test_zz_ch_log() 1936 call ch_logfile('Xlog', 'w') 1937 call ch_log('hello there') 1938 call ch_log('%s%s') 1939 call ch_logfile('') 1940 let text = readfile('Xlog') 1941 call assert_match("hello there", text[1]) 1942 call assert_match("%s%s", text[2]) 1943 call delete('Xlog') 1944endfunc 1945 1946func Test_keep_pty_open() 1947 if !has('unix') 1948 return 1949 endif 1950 1951 let job = job_start(s:python . ' -c "import time;time.sleep(0.2)"', 1952 \ {'out_io': 'null', 'err_io': 'null', 'pty': 1}) 1953 let elapsed = WaitFor({-> job_status(job) ==# 'dead'}) 1954 call assert_inrange(200, 1000, elapsed) 1955 call job_stop(job) 1956endfunc 1957 1958func Test_job_start_in_timer() 1959 if !has('job') || !has('timers') 1960 return 1961 endif 1962 1963 func OutCb(chan, msg) 1964 let g:val += 1 1965 endfunc 1966 1967 func ExitCb(job, status) 1968 let g:val += 1 1969 call Resume() 1970 endfunc 1971 1972 func TimerCb(timer) 1973 if has('win32') 1974 let cmd = ['cmd', '/c', 'echo.'] 1975 else 1976 let cmd = ['echo'] 1977 endif 1978 let g:job = job_start(cmd, {'out_cb': 'OutCb', 'exit_cb': 'ExitCb'}) 1979 call substitute(repeat('a', 100000), '.', '', 'g') 1980 endfunc 1981 1982 " We should be interrupted before 'updatetime' elapsed. 1983 let g:val = 0 1984 call timer_start(1, 'TimerCb') 1985 let elapsed = Standby(&ut) 1986 call assert_inrange(1, &ut / 2, elapsed) 1987 1988 " Wait for both OutCb() and ExitCb() to have been called before deleting 1989 " them. 1990 call WaitForAssert({-> assert_equal(2, g:val)}) 1991 call job_stop(g:job) 1992 1993 delfunc OutCb 1994 delfunc ExitCb 1995 delfunc TimerCb 1996 unlet! g:val 1997 unlet! g:job 1998endfunc 1999 2000func Test_raw_large_data() 2001 try 2002 let g:out = '' 2003 let job = job_start(s:python . " test_channel_pipe.py", 2004 \ {'mode': 'raw', 'drop': 'never', 'noblock': 1, 2005 \ 'callback': {ch, msg -> execute('let g:out .= msg')}}) 2006 2007 let outlen = 79999 2008 let want = repeat('X', outlen) . "\n" 2009 call ch_sendraw(job, want) 2010 call WaitFor({-> len(g:out) >= outlen}, 10000) 2011 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2012 call assert_equal(want, substitute(g:out, '\r', '', 'g')) 2013 finally 2014 call job_stop(job) 2015 unlet g:out 2016 endtry 2017endfunc 2018 2019func Test_no_hang_windows() 2020 if !has('job') || !has('win32') 2021 return 2022 endif 2023 2024 try 2025 let job = job_start(s:python . " test_channel_pipe.py busy", 2026 \ {'mode': 'raw', 'drop': 'never', 'noblock': 0}) 2027 call assert_fails('call ch_sendraw(job, repeat("X", 80000))', 'E631:') 2028 finally 2029 call job_stop(job) 2030 endtry 2031endfunc 2032 2033func Test_job_exitval_and_termsig() 2034 if !has('unix') 2035 return 2036 endif 2037 2038 " Terminate job normally 2039 let cmd = ['echo'] 2040 let job = job_start(cmd) 2041 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2042 let info = job_info(job) 2043 call assert_equal(0, info.exitval) 2044 call assert_equal("", info.termsig) 2045 2046 " Terminate job by signal 2047 let cmd = ['sleep', '10'] 2048 let job = job_start(cmd) 2049 sleep 10m 2050 call job_stop(job) 2051 call WaitForAssert({-> assert_equal("dead", job_status(job))}) 2052 let info = job_info(job) 2053 call assert_equal(-1, info.exitval) 2054 call assert_equal("term", info.termsig) 2055endfunc 2056 2057func Test_job_tty_in_out() 2058 if !has('job') || !has('unix') 2059 return 2060 endif 2061 2062 call writefile(['test'], 'Xtestin') 2063 let in_opts = [{}, 2064 \ {'in_io': 'null'}, 2065 \ {'in_io': 'file', 'in_name': 'Xtestin'}] 2066 let out_opts = [{}, 2067 \ {'out_io': 'null'}, 2068 \ {'out_io': 'file', 'out_name': 'Xtestout'}] 2069 let err_opts = [{}, 2070 \ {'err_io': 'null'}, 2071 \ {'err_io': 'file', 'err_name': 'Xtesterr'}, 2072 \ {'err_io': 'out'}] 2073 let opts = [] 2074 2075 for in_opt in in_opts 2076 let x = copy(in_opt) 2077 for out_opt in out_opts 2078 let x = extend(copy(x), out_opt) 2079 for err_opt in err_opts 2080 let x = extend(copy(x), err_opt) 2081 let opts += [extend({'pty': 1}, x)] 2082 endfor 2083 endfor 2084 endfor 2085 2086 for opt in opts 2087 let job = job_start('echo', opt) 2088 let info = job_info(job) 2089 let msg = printf('option={"in_io": "%s", "out_io": "%s", "err_io": "%s"}', 2090 \ get(opt, 'in_io', 'tty'), 2091 \ get(opt, 'out_io', 'tty'), 2092 \ get(opt, 'err_io', 'tty')) 2093 2094 if !has_key(opt, 'in_io') || !has_key(opt, 'out_io') || !has_key(opt, 'err_io') 2095 call assert_notequal('', info.tty_in, msg) 2096 else 2097 call assert_equal('', info.tty_in, msg) 2098 endif 2099 call assert_equal(info.tty_in, info.tty_out, msg) 2100 2101 call WaitForAssert({-> assert_equal('dead', job_status(job))}) 2102 endfor 2103 2104 call delete('Xtestin') 2105 call delete('Xtestout') 2106 call delete('Xtesterr') 2107endfunc 2108