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