diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-02-23 12:34:20 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-02-23 21:43:33 -0300 |
commit | d7e560e5b309578f142c23467d566877cb54ee9a (patch) | |
tree | 9de6cc3996a01d133cd883d61a7c24a564a772ba /test | |
parent | 1ec7db70ecac75736b5042203e57aae57b65abe6 (diff) | |
download | rneovim-d7e560e5b309578f142c23467d566877cb54ee9a.tar.gz rneovim-d7e560e5b309578f142c23467d566877cb54ee9a.tar.bz2 rneovim-d7e560e5b309578f142c23467d566877cb54ee9a.zip |
job: Allow spawning jobs connected to pseudo terminals
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/job/CMakeLists.txt | 2 | ||||
-rw-r--r-- | test/functional/job/job_spec.lua | 54 | ||||
-rw-r--r-- | test/functional/job/tty-test.c | 114 |
3 files changed, 170 insertions, 0 deletions
diff --git a/test/functional/job/CMakeLists.txt b/test/functional/job/CMakeLists.txt new file mode 100644 index 0000000000..14ec287816 --- /dev/null +++ b/test/functional/job/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(tty-test tty-test.c) +target_link_libraries(tty-test ${LIBUV_LIBRARIES}) diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua index b87c3a827b..0051de09e1 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/job/job_spec.lua @@ -4,6 +4,7 @@ local clear, nvim, eq, neq, ok, expect, eval, next_message, run, stop, session = helpers.clear, helpers.nvim, helpers.eq, helpers.neq, helpers.ok, helpers.expect, helpers.eval, helpers.next_message, helpers.run, helpers.stop, helpers.session +local insert = helpers.insert local channel = nvim('get_api_info')[1] @@ -124,4 +125,57 @@ describe('jobs', function() eq({'notification', 'j', {{jobid, 'stdout', {'abcdef'}}}}, next_message()) eq({'notification', 'j', {{jobid, 'exit'}}}, next_message()) end) + + describe('running tty-test program', function() + local function next_chunk() + local rv = '' + while true do + local msg = next_message() + local data = msg[3][1] + for i = 1, #data do + data[i] = data[i]:gsub('\n', '\000') + end + rv = table.concat(data, '\n') + rv = rv:gsub('\r\n$', '') + if rv ~= '' then + break + end + end + return rv + end + + local function send(str) + nvim('command', 'call jobsend(j, "'..str..'")') + end + + before_each(function() + -- the full path to tty-test seems to be required when running on travis. + insert('build/bin/tty-test') + nvim('command', 'let exec = expand("<cfile>:p")') + nvim('command', notify_str('v:job_data[1]', 'get(v:job_data, 2)')) + nvim('command', "let j = jobstart('xxx', exec, [], {})") + eq('tty ready', next_chunk()) + end) + + it('echoing input', function() + send('test') + -- the tty driver will echo input by default + eq('test', next_chunk()) + end) + + it('resizing window', function() + nvim('command', 'call jobresize(j, 40, 10)') + eq('screen resized. rows: 10, columns: 40', next_chunk()) + nvim('command', 'call jobresize(j, 10, 40)') + eq('screen resized. rows: 40, columns: 10', next_chunk()) + end) + + it('preprocessing ctrl+c with terminal driver', function() + send('\\<c-c>') + eq('^Cinterrupt received, press again to exit', next_chunk()) + send('\\<c-c>') + eq('^Ctty done', next_chunk()) + eq({'notification', 'exit', {0}}, next_message()) + end) + end) end) diff --git a/test/functional/job/tty-test.c b/test/functional/job/tty-test.c new file mode 100644 index 0000000000..25e76840aa --- /dev/null +++ b/test/functional/job/tty-test.c @@ -0,0 +1,114 @@ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <uv.h> + +#ifdef _WIN32 +#include <windows.h> +bool owns_tty(void) +{ + HWND consoleWnd = GetConsoleWindow(); + DWORD dwProcessId; + GetWindowThreadProcessId(consoleWnd, &dwProcessId); + return GetCurrentProcessId() == dwProcessId; +} +#else +bool owns_tty(void) +{ + // TODO: Check if the process is the session leader + return true; +} +#endif + +#define is_terminal(stream) (uv_guess_handle(fileno(stream)) == UV_TTY) +#define BUF_SIZE 0xfff + +static void walk_cb(uv_handle_t *handle, void *arg) { + if (!uv_is_closing(handle)) { + uv_close(handle, NULL); + } +} + +static void sigwinch_cb(uv_signal_t *handle, int signum) +{ + int width, height; + uv_tty_t *tty = handle->data; + uv_tty_get_winsize(tty, &width, &height); + fprintf(stderr, "screen resized. rows: %d, columns: %d\n", height, width); +} + +static void sigint_cb(uv_signal_t *handle, int signum) +{ + bool *interrupted = handle->data; + + if (*interrupted) { + uv_walk(uv_default_loop(), walk_cb, NULL); + return; + } + + *interrupted = true; + fprintf(stderr, "interrupt received, press again to exit\n"); +} + +static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) +{ + buf->len = BUF_SIZE; + buf->base = malloc(BUF_SIZE); +} + +static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf) +{ + if (cnt <= 0) { + uv_read_stop(stream); + return; + } + + fprintf(stderr, "received data: "); + uv_loop_t write_loop; + uv_loop_init(&write_loop); + uv_tty_t out; + uv_tty_init(&write_loop, &out, 1, 0); + uv_write_t req; + uv_buf_t b = {.base = buf->base, .len = buf->len}; + uv_write(&req, (uv_stream_t *)&out, &b, 1, NULL); + uv_run(&write_loop, UV_RUN_DEFAULT); + uv_close((uv_handle_t *)&out, NULL); + uv_run(&write_loop, UV_RUN_DEFAULT); + if (uv_loop_close(&write_loop)) { + abort(); + } + free(buf->base); +} + +int main(int argc, char **argv) +{ + if (!is_terminal(stdin)) { + fprintf(stderr, "stdin is not a terminal\n"); + exit(2); + } + + if (!is_terminal(stdout)) { + fprintf(stderr, "stdout is not a terminal\n"); + exit(2); + } + + if (!is_terminal(stderr)) { + fprintf(stderr, "stderr is not a terminal\n"); + exit(2); + } + + bool interrupted = false; + fprintf(stderr, "tty ready\n"); + uv_tty_t tty; + uv_tty_init(uv_default_loop(), &tty, fileno(stderr), 1); + uv_read_start((uv_stream_t *)&tty, alloc_cb, read_cb); + uv_signal_t sigwinch_watcher, sigint_watcher; + uv_signal_init(uv_default_loop(), &sigwinch_watcher); + sigwinch_watcher.data = &tty; + uv_signal_start(&sigwinch_watcher, sigwinch_cb, SIGWINCH); + uv_signal_init(uv_default_loop(), &sigint_watcher); + sigint_watcher.data = &interrupted; + uv_signal_start(&sigint_watcher, sigint_cb, SIGINT); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + fprintf(stderr, "tty done\n"); +} |