diff options
Diffstat (limited to 'test/unit')
| -rw-r--r-- | test/unit/buffer_spec.lua | 2 | ||||
| -rw-r--r-- | test/unit/fixtures/queue.c | 16 | ||||
| -rw-r--r-- | test/unit/fixtures/queue.h | 4 | ||||
| -rw-r--r-- | test/unit/fixtures/rbuffer.c | 28 | ||||
| -rw-r--r-- | test/unit/fixtures/rbuffer.h | 9 | ||||
| -rw-r--r-- | test/unit/helpers.lua | 7 | ||||
| -rw-r--r-- | test/unit/os/env_spec.lua | 3 | ||||
| -rw-r--r-- | test/unit/os/fs_spec.lua | 69 | ||||
| -rw-r--r-- | test/unit/os/shell_spec.lua | 2 | ||||
| -rw-r--r-- | test/unit/queue_spec.lua | 123 | ||||
| -rw-r--r-- | test/unit/rbuffer_spec.lua | 350 | ||||
| -rw-r--r-- | test/unit/tempfile_spec.lua | 2 |
12 files changed, 598 insertions, 17 deletions
diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua index 5244c2af86..e0e2b827e9 100644 --- a/test/unit/buffer_spec.lua +++ b/test/unit/buffer_spec.lua @@ -3,8 +3,6 @@ local helpers = require("test.unit.helpers") local to_cstr = helpers.to_cstr local eq = helpers.eq -helpers.vim_init() - local buffer = helpers.cimport("./src/nvim/buffer.h") local window = helpers.cimport("./src/nvim/window.h") local option = helpers.cimport("./src/nvim/option.h") diff --git a/test/unit/fixtures/queue.c b/test/unit/fixtures/queue.c new file mode 100644 index 0000000000..bbb6274b21 --- /dev/null +++ b/test/unit/fixtures/queue.c @@ -0,0 +1,16 @@ +#include <string.h> +#include <stdlib.h> +#include "nvim/event/queue.h" +#include "queue.h" + + +void ut_queue_put(Queue *queue, const char *str) +{ + queue_put(queue, NULL, 1, str); +} + +const char *ut_queue_get(Queue *queue) +{ + Event event = queue_get(queue); + return event.argv[0]; +} diff --git a/test/unit/fixtures/queue.h b/test/unit/fixtures/queue.h new file mode 100644 index 0000000000..ae949c9f29 --- /dev/null +++ b/test/unit/fixtures/queue.h @@ -0,0 +1,4 @@ +#include "nvim/event/queue.h" + +void ut_queue_put(Queue *queue, const char *str); +const char *ut_queue_get(Queue *queue); diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c new file mode 100644 index 0000000000..d587d6b054 --- /dev/null +++ b/test/unit/fixtures/rbuffer.c @@ -0,0 +1,28 @@ +#include "nvim/rbuffer.h" +#include "rbuffer.h" + + +void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb) +{ + RBUFFER_UNTIL_EMPTY(buf, rptr, rcnt) { + cb(rptr, rcnt); + rbuffer_consumed(buf, rcnt); + } +} + +void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb) +{ + RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { + cb(wptr, wcnt); + rbuffer_produced(buf, wcnt); + } +} +void ut_rbuffer_each(RBuffer *buf, each_cb cb) +{ + RBUFFER_EACH(buf, c, i) cb(c, i); +} + +void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb) +{ + RBUFFER_EACH_REVERSE(buf, c, i) cb(c, i); +} diff --git a/test/unit/fixtures/rbuffer.h b/test/unit/fixtures/rbuffer.h new file mode 100644 index 0000000000..640092c627 --- /dev/null +++ b/test/unit/fixtures/rbuffer.h @@ -0,0 +1,9 @@ +#include "nvim/rbuffer.h" + +typedef void(*each_ptr_cb)(char *ptr, size_t cnt); +typedef void(*each_cb)(char c, size_t i); + +void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb); +void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb); +void ut_rbuffer_each(RBuffer *buf, each_cb cb); +void ut_rbuffer_each_reverse(RBuffer *buf, each_cb cb); diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index 708e7a94ab..5bcc661226 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -136,15 +136,11 @@ end -- initialize some global variables, this is still necessary to unit test -- functions that rely on global state. -local function vim_init() - if vim_init_called ~= nil then - return - end +do local main = cimport('./src/nvim/main.h') local time = cimport('./src/nvim/os/time.h') time.time_init() main.early_init() - vim_init_called = true end -- C constants. @@ -167,7 +163,6 @@ return { lib = libnvim, cstr = cstr, to_cstr = to_cstr, - vim_init = vim_init, NULL = NULL, OK = OK, FAIL = FAIL diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua index 9d936c2564..8e18c599d9 100644 --- a/test/unit/os/env_spec.lua +++ b/test/unit/os/env_spec.lua @@ -12,9 +12,6 @@ local NULL = helpers.NULL require('lfs') --- Needed because expand_env_esc uses the char table -helpers.vim_init() - local env = cimport('./src/nvim/os/os.h') describe('env function', function() diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 3d5c6bc885..f7f0cba951 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -19,7 +19,7 @@ require('bit') cimport('unistd.h') cimport('./src/nvim/os/shell.h') cimport('./src/nvim/option_defs.h') -cimport('./src/nvim/os/event.h') +cimport('./src/nvim/main.h') cimport('./src/nvim/fileio.h') local fs = cimport('./src/nvim/os/os.h') cppimport('sys/stat.h') @@ -270,7 +270,7 @@ describe('fs function', function() -- Some systems may not have `id` utility. if (os.execute('id -G > /dev/null 2>&1') ~= 0) then - pending('skipped (missing `id` utility)') + pending('skipped (missing `id` utility)', function() end) else it('owner of a file may change the group of the file to any group of which that owner is a member', function() local file_gid = lfs.attributes(filename, 'gid') @@ -296,7 +296,7 @@ describe('fs function', function() -- On Windows `os_fchown` always returns 0 -- because `uv_fs_chown` is no-op on this platform. if (ffi.os == 'Windows' or ffi.C.geteuid() == 0) then - pending('skipped (os_fchown is no-op on Windows)') + pending('skipped (os_fchown is no-op on Windows)', function() end) else it('returns nonzero if process has not enough permissions', function() -- chown to root @@ -486,6 +486,16 @@ describe('fs function', function() return fs.os_rmdir(to_cstr(path)) end + local function os_mkdir_recurse(path, mode) + local failed_str = ffi.new('char *[1]', {nil}) + local ret = fs.os_mkdir_recurse(path, mode, failed_str) + local str = failed_str[0] + if str ~= nil then + str = ffi.string(str) + end + return ret, str + end + describe('os_mkdir', function() it('returns non-zero when given an already existing directory', function() local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR @@ -501,6 +511,59 @@ describe('fs function', function() end) end) + describe('os_mkdir_recurse', function() + it('returns zero when given an already existing directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse('unit-test-directory', mode) + eq(0, ret) + eq(nil, failed_str) + end) + + it('fails to create a directory where there is a file', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('fails to create a directory where there is a file in path', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file/test', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('succeeds to create a directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + + it('succeeds to create a directory tree', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse/1/2/3', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2/3')) + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2/3') + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2') + lfs.rmdir('unit-test-directory/new-dir-recurse/1') + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + end) + describe('os_rmdir', function() it('returns non_zero when given a non-existing directory', function() neq(0, (os_rmdir('non-existing-directory'))) diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua index 91d807da0b..91123bfd58 100644 --- a/test/unit/os/shell_spec.lua +++ b/test/unit/os/shell_spec.lua @@ -14,7 +14,7 @@ local helpers = require('test.unit.helpers') local shell = helpers.cimport( './src/nvim/os/shell.h', './src/nvim/option_defs.h', - './src/nvim/os/event.h', + './src/nvim/main.h', './src/nvim/misc1.h' ) local ffi, eq, neq = helpers.ffi, helpers.eq, helpers.neq diff --git a/test/unit/queue_spec.lua b/test/unit/queue_spec.lua new file mode 100644 index 0000000000..9326c1cad6 --- /dev/null +++ b/test/unit/queue_spec.lua @@ -0,0 +1,123 @@ +local helpers = require("test.unit.helpers") + +local ffi = helpers.ffi +local eq = helpers.eq + +local queue = helpers.cimport("./test/unit/fixtures/queue.h") + +describe('queue', function() + local parent, child1, child2, child3 + + local function put(q, str) + queue.ut_queue_put(q, str) + end + + local function get(q) + return ffi.string(queue.ut_queue_get(q)) + end + + local function free(q) + queue.queue_free(q) + end + + before_each(function() + parent = queue.queue_new_parent(ffi.NULL, ffi.NULL) + child1 = queue.queue_new_child(parent) + child2 = queue.queue_new_child(parent) + child3 = queue.queue_new_child(parent) + put(child1, 'c1i1') + put(child1, 'c1i2') + put(child2, 'c2i1') + put(child1, 'c1i3') + put(child2, 'c2i2') + put(child2, 'c2i3') + put(child2, 'c2i4') + put(child3, 'c3i1') + put(child3, 'c3i2') + end) + + it('removing from parent removes from child', function() + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + end) + + it('removing from child removes from parent', function() + eq('c2i1', get(child2)) + eq('c2i2', get(child2)) + eq('c1i1', get(child1)) + eq('c1i2', get(parent)) + eq('c1i3', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + end) + + it('removing from child at the beginning of parent', function() + eq('c1i1', get(child1)) + eq('c1i2', get(child1)) + eq('c2i1', get(parent)) + end) + + it('removing from parent after get from parent and put to child', function() + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + eq('c3i1', get(parent)) + put(child1, 'c1i11') + put(child1, 'c1i22') + eq('c3i2', get(parent)) + eq('c1i11', get(parent)) + eq('c1i22', get(parent)) + end) + + it('removing from parent after get and put to child', function() + eq('c1i1', get(child1)) + eq('c1i2', get(child1)) + eq('c2i1', get(child2)) + eq('c1i3', get(child1)) + eq('c2i2', get(child2)) + eq('c2i3', get(child2)) + eq('c2i4', get(child2)) + eq('c3i1', get(child3)) + eq('c3i2', get(parent)) + put(child1, 'c1i11') + put(child2, 'c2i11') + put(child1, 'c1i12') + eq('c2i11', get(child2)) + eq('c1i11', get(parent)) + eq('c1i12', get(parent)) + end) + + it('put after removing from child at the end of parent', function() + eq('c3i1', get(child3)) + eq('c3i2', get(child3)) + put(child1, 'c1i11') + put(child2, 'c2i11') + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c2i1', get(parent)) + eq('c1i3', get(parent)) + eq('c2i2', get(parent)) + eq('c2i3', get(parent)) + eq('c2i4', get(parent)) + eq('c1i11', get(parent)) + eq('c2i11', get(parent)) + end) + + it('removes from parent queue when child is freed', function() + free(child2) + eq('c1i1', get(parent)) + eq('c1i2', get(parent)) + eq('c1i3', get(parent)) + eq('c3i1', get(child3)) + eq('c3i2', get(child3)) + end) +end) diff --git a/test/unit/rbuffer_spec.lua b/test/unit/rbuffer_spec.lua new file mode 100644 index 0000000000..89136410d3 --- /dev/null +++ b/test/unit/rbuffer_spec.lua @@ -0,0 +1,350 @@ +local helpers = require("test.unit.helpers") + +local ffi = helpers.ffi +local eq = helpers.eq +local cstr = helpers.cstr +local to_cstr = helpers.to_cstr + +local rbuffer = helpers.cimport("./test/unit/fixtures/rbuffer.h") + +describe('rbuffer functions', function() + local capacity = 16 + local rbuf + + local function inspect() + return ffi.string(rbuf.start_ptr, capacity) + end + + local function write(str) + local buf = to_cstr(str) + return rbuffer.rbuffer_write(rbuf, buf, #str) + end + + local function read(len) + local buf = cstr(len) + len = rbuffer.rbuffer_read(rbuf, buf, len) + return ffi.string(buf, len) + end + + local function get(idx) + return ffi.string(rbuffer.rbuffer_get(rbuf, idx), 1) + end + + before_each(function() + rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free) + -- fill the internal buffer with the character '0' to simplify inspecting + ffi.C.memset(rbuf.start_ptr, string.byte('0'), capacity) + end) + + describe('RBUFFER_UNTIL_FULL', function() + local chunks + + local function collect_write_chunks() + rbuffer.ut_rbuffer_each_write_chunk(rbuf, function(wptr, wcnt) + table.insert(chunks, ffi.string(wptr, wcnt)) + end) + end + + before_each(function() + chunks = {} + end) + + describe('with empty buffer in one contiguous chunk', function() + it('is called once with the empty chunk', function() + collect_write_chunks() + eq({'0000000000000000'}, chunks) + end) + end) + + describe('with partially empty buffer in one contiguous chunk', function() + before_each(function() + write('string') + end) + + it('is called once with the empty chunk', function() + collect_write_chunks() + eq({'0000000000'}, chunks) + end) + end) + + describe('with filled buffer in one contiguous chunk', function() + before_each(function() + write('abcdefghijklmnopq') + end) + + it('is not called', function() + collect_write_chunks() + eq({}, chunks) + end) + end) + + describe('with buffer partially empty in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(8) + end) + + it('is called twice with each filled chunk', function() + collect_write_chunks() + eq({'000000', '12345678'}, chunks) + end) + end) + + describe('with buffer empty in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + end) + + it('is called twice with each filled chunk', function() + collect_write_chunks() + eq({'00000000', '12345678'}, chunks) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + write('abcdefghijklmnopq') + end) + + it('is not called', function() + collect_write_chunks() + eq({}, chunks) + end) + end) + end) + + describe('RBUFFER_UNTIL_EMPTY', function() + local chunks + + local function collect_read_chunks() + rbuffer.ut_rbuffer_each_read_chunk(rbuf, function(rptr, rcnt) + table.insert(chunks, ffi.string(rptr, rcnt)) + end) + end + + before_each(function() + chunks = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_read_chunks() + eq({}, chunks) + end) + end) + + describe('with partially filled buffer in one contiguous chunk', function() + before_each(function() + write('string') + end) + + it('is called once with the filled chunk', function() + collect_read_chunks() + eq({'string'}, chunks) + end) + end) + + describe('with filled buffer in one contiguous chunk', function() + before_each(function() + write('abcdefghijklmnopq') + end) + + it('is called once with the filled chunk', function() + collect_read_chunks() + eq({'abcdefghijklmnop'}, chunks) + end) + end) + + describe('with buffer partially filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('is called twice with each filled chunk', function() + collect_read_chunks() + eq({'long s', 'tring'}, chunks) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('12345678') + read(8) + write('abcdefghijklmnopq') + end) + + it('is called twice with each filled chunk', function() + collect_read_chunks() + eq({'abcdefgh', 'ijklmnop'}, chunks) + end) + end) + end) + + describe('RBUFFER_EACH', function() + local chars + + local function collect_chars() + rbuffer.ut_rbuffer_each(rbuf, function(c, i) + table.insert(chars, {string.char(c), tonumber(i)}) + end) + end + before_each(function() + chars = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_chars() + eq({}, chars) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('collects each character and index', function() + collect_chars() + eq({{'l', 0}, {'o', 1}, {'n', 2}, {'g', 3}, {' ', 4}, {'s', 5}, + {'t', 6}, {'r', 7}, {'i', 8}, {'n', 9}, {'g', 10}}, chars) + end) + end) + end) + + describe('RBUFFER_EACH_REVERSE', function() + local chars + + local function collect_chars() + rbuffer.ut_rbuffer_each_reverse(rbuf, function(c, i) + table.insert(chars, {string.char(c), tonumber(i)}) + end) + end + before_each(function() + chars = {} + end) + + describe('with empty buffer', function() + it('is not called', function() + collect_chars() + eq({}, chars) + end) + end) + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('collects each character and index', function() + collect_chars() + eq({{'g', 10}, {'n', 9}, {'i', 8}, {'r', 7}, {'t', 6}, {'s', 5}, + {' ', 4}, {'g', 3}, {'n', 2}, {'o', 1}, {'l', 0}}, chars) + end) + end) + end) + + describe('rbuffer_cmp', function() + local function cmp(str) + local rv = rbuffer.rbuffer_cmp(rbuf, to_cstr(str), #str) + if rv == 0 then + return 0 + else + return rv / math.abs(rv) + end + end + + describe('with buffer filled in two contiguous chunks', function() + before_each(function() + write('1234567890') + read(10) + write('long string') + end) + + it('compares the common longest sequence', function() + eq(0, cmp('long string')) + eq(0, cmp('long strin')) + eq(-1, cmp('long striM')) + eq(1, cmp('long strio')) + eq(0, cmp('long')) + eq(-1, cmp('lonG')) + eq(1, cmp('lonh')) + end) + end) + + describe('with empty buffer', function() + it('returns 0 since no characters are compared', function() + eq(0, cmp('')) + end) + end) + end) + + describe('rbuffer_write', function() + it('fills the internal buffer and returns the write count', function() + eq(12, write('short string')) + eq('short string0000', inspect()) + end) + + it('wont write beyond capacity', function() + eq(16, write('very very long string')) + eq('very very long s', inspect()) + end) + end) + + describe('rbuffer_read', function() + it('reads what was previously written', function() + write('to read') + eq('to read', read(20)) + end) + + it('reads nothing if the buffer is empty', function() + eq('', read(20)) + write('empty') + eq('empty', read(20)) + eq('', read(20)) + end) + end) + + describe('rbuffer_get', function() + it('fetch the pointer at offset, wrapping if required', function() + write('1234567890') + read(10) + write('long string') + eq('l', get(0)) + eq('o', get(1)) + eq('n', get(2)) + eq('g', get(3)) + eq(' ', get(4)) + eq('s', get(5)) + eq('t', get(6)) + eq('r', get(7)) + eq('i', get(8)) + eq('n', get(9)) + eq('g', get(10)) + end) + end) + + describe('wrapping behavior', function() + it('writing/reading wraps across the end of the internal buffer', function() + write('1234567890') + eq('1234', read(4)) + eq('5678', read(4)) + write('987654321') + eq('3214567890987654', inspect()) + eq('90987654321', read(20)) + eq('', read(4)) + write('abcdefghijklmnopqrs') + eq('nopabcdefghijklm', inspect()) + eq('abcdefghijklmnop', read(20)) + end) + end) +end) diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua index 6484a98b8f..e558ff04c8 100644 --- a/test/unit/tempfile_spec.lua +++ b/test/unit/tempfile_spec.lua @@ -4,8 +4,6 @@ local helpers = require 'test.unit.helpers' local os = helpers.cimport './src/nvim/os/os.h' local tempfile = helpers.cimport './src/nvim/tempfile.h' -helpers.vim_init() - describe('tempfile related functions', function() after_each(function() tempfile.vim_deltempdir() |