mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
unittest: convert garray_spec.moon to lua
This commit is contained in:
parent
3a766d2c50
commit
097ff4b8b2
391
test/unit/garray_spec.lua
Normal file
391
test/unit/garray_spec.lua
Normal file
@ -0,0 +1,391 @@
|
||||
local helpers = require("test.unit.helpers")
|
||||
|
||||
local cimport = helpers.cimport
|
||||
local internalize = helpers.internalize
|
||||
local eq = helpers.eq
|
||||
local neq = helpers.neq
|
||||
local ffi = helpers.ffi
|
||||
local lib = helpers.lib
|
||||
local cstr = helpers.cstr
|
||||
local to_cstr = helpers.to_cstr
|
||||
local NULL = helpers.NULL
|
||||
|
||||
local garray = cimport('./src/nvim/garray.h')
|
||||
|
||||
-- define a basic interface to garray. We could make it a lot nicer by
|
||||
-- constructing a moonscript class wrapper around garray. It could for
|
||||
-- example associate ga_clear_strings to the underlying garray cdata if the
|
||||
-- garray is a string array. But for now I estimate that that kind of magic
|
||||
-- might make testing less "transparant" (i.e.: the interface would become
|
||||
-- quite different as to how one would use it from C.
|
||||
|
||||
-- accessors
|
||||
function ga_len(garr)
|
||||
return garr[0].ga_len
|
||||
end
|
||||
|
||||
function ga_maxlen(garr)
|
||||
return garr[0].ga_maxlen
|
||||
end
|
||||
|
||||
function ga_itemsize(garr)
|
||||
return garr[0].ga_itemsize
|
||||
end
|
||||
|
||||
function ga_growsize(garr)
|
||||
return garr[0].ga_growsize
|
||||
end
|
||||
|
||||
function ga_data(garr)
|
||||
return garr[0].ga_data
|
||||
end
|
||||
|
||||
-- derived accessors
|
||||
function ga_size(garr)
|
||||
return ga_len(garr) * ga_itemsize(garr)
|
||||
end
|
||||
|
||||
function ga_maxsize(garr)
|
||||
return ga_maxlen(garr) * ga_itemsize(garr)
|
||||
end
|
||||
|
||||
function ga_data_as_bytes(garr)
|
||||
return ffi.cast('uint8_t *', ga_data(garr))
|
||||
end
|
||||
|
||||
function ga_data_as_strings(garr)
|
||||
return ffi.cast('char **', ga_data(garr))
|
||||
end
|
||||
|
||||
function ga_data_as_ints(garr)
|
||||
return ffi.cast('int *', ga_data(garr))
|
||||
end
|
||||
|
||||
-- garray manipulation
|
||||
function ga_init(garr, itemsize, growsize)
|
||||
return garray.ga_init(garr, itemsize, growsize)
|
||||
end
|
||||
|
||||
function ga_clear(garr)
|
||||
return garray.ga_clear(garr)
|
||||
end
|
||||
|
||||
function ga_clear_strings(garr)
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('char *'))
|
||||
return garray.ga_clear_strings(garr)
|
||||
end
|
||||
|
||||
function ga_grow(garr, n)
|
||||
return garray.ga_grow(garr, n)
|
||||
end
|
||||
|
||||
function ga_concat(garr, str)
|
||||
return garray.ga_concat(garr, to_cstr(str))
|
||||
end
|
||||
|
||||
function ga_append(garr, b)
|
||||
if type(b) == 'string' then
|
||||
return garray.ga_append(garr, string.byte(b))
|
||||
else
|
||||
return garray.ga_append(garr, b)
|
||||
end
|
||||
end
|
||||
|
||||
function ga_concat_strings(garr)
|
||||
return internalize(garray.ga_concat_strings(garr))
|
||||
end
|
||||
|
||||
function ga_concat_strings_sep(garr, sep)
|
||||
return internalize(garray.ga_concat_strings_sep(garr, to_cstr(sep)))
|
||||
end
|
||||
|
||||
function ga_remove_duplicate_strings(garr)
|
||||
return garray.ga_remove_duplicate_strings(garr)
|
||||
end
|
||||
|
||||
-- derived manipulators
|
||||
function ga_set_len(garr, len)
|
||||
assert.is_true(len <= ga_maxlen(garr))
|
||||
garr[0].ga_len = len
|
||||
end
|
||||
|
||||
function ga_inc_len(garr, by)
|
||||
return ga_set_len(garr, ga_len(garr) + 1)
|
||||
end
|
||||
|
||||
-- custom append functions
|
||||
-- not the C ga_append, which only works for bytes
|
||||
function ga_append_int(garr, it)
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('int'))
|
||||
ga_grow(garr, 1)
|
||||
local data = ga_data_as_ints(garr)
|
||||
data[ga_len(garr)] = it
|
||||
return ga_inc_len(garr, 1)
|
||||
end
|
||||
|
||||
function ga_append_string(garr, it)
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('char *'))
|
||||
-- make a non-garbage collected string and copy the lua string into it,
|
||||
-- TODO(aktau): we should probably call xmalloc here, though as long as
|
||||
-- xmalloc is based on malloc it should work.
|
||||
local mem = ffi.C.malloc(string.len(it) + 1)
|
||||
ffi.copy(mem, it)
|
||||
ga_grow(garr, 1)
|
||||
local data = ga_data_as_strings(garr)
|
||||
data[ga_len(garr)] = mem
|
||||
return ga_inc_len(garr, 1)
|
||||
end
|
||||
|
||||
function ga_append_strings(garr, ...)
|
||||
local prevlen = ga_len(garr)
|
||||
local len = select('#', ...)
|
||||
for i = 1, len do
|
||||
ga_append_string(garr, select(i, ...))
|
||||
end
|
||||
return eq(prevlen + len, ga_len(garr))
|
||||
end
|
||||
|
||||
function ga_append_ints(garr, ...)
|
||||
local prevlen = ga_len(garr)
|
||||
local len = select('#', ...)
|
||||
for i = 1, len do
|
||||
ga_append_int(garr, select(i, ...))
|
||||
end
|
||||
return eq(prevlen + len, ga_len(garr))
|
||||
end
|
||||
|
||||
-- enhanced constructors
|
||||
local garray_ctype = ffi.typeof('garray_T[1]')
|
||||
function new_garray()
|
||||
local garr = garray_ctype()
|
||||
return ffi.gc(garr, ga_clear)
|
||||
end
|
||||
|
||||
function new_string_garray()
|
||||
local garr = garray_ctype()
|
||||
ga_init(garr, ffi.sizeof("char_u *"), 1)
|
||||
return ffi.gc(garr, ga_clear_strings)
|
||||
end
|
||||
|
||||
function randomByte()
|
||||
return ffi.cast('uint8_t', math.random(0, 255))
|
||||
end
|
||||
|
||||
-- scramble the data in a garray
|
||||
function ga_scramble(garr)
|
||||
local size, bytes = ga_size(garr), ga_data_as_bytes(garr)
|
||||
for i = 0, size - 1 do
|
||||
bytes[i] = randomByte()
|
||||
end
|
||||
end
|
||||
|
||||
describe('garray', function()
|
||||
local itemsize = 14
|
||||
local growsize = 95
|
||||
|
||||
describe('ga_init', function()
|
||||
it('initializes the values of the garray', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
eq(0, ga_len(garr))
|
||||
eq(0, ga_maxlen(garr))
|
||||
eq(growsize, ga_growsize(garr))
|
||||
eq(itemsize, ga_itemsize(garr))
|
||||
eq(NULL, ga_data(garr))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_grow', function()
|
||||
local new_and_grow
|
||||
function new_and_grow(itemsize, growsize, req)
|
||||
local garr = new_garray()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
eq(0, ga_size(garr)) -- should be 0 at first
|
||||
eq(NULL, ga_data(garr)) -- should be NULL
|
||||
ga_grow(garr, req) -- add space for `req` items
|
||||
return garr
|
||||
end
|
||||
|
||||
it('grows by growsize items if num < growsize', function()
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
local grow_by = growsize - 1
|
||||
local garr = new_and_grow(itemsize, growsize, grow_by)
|
||||
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
|
||||
eq(growsize, ga_maxlen(garr)) -- we requested LESS than growsize, so...
|
||||
end)
|
||||
|
||||
it('grows by num items if num > growsize', function()
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
local grow_by = growsize + 1
|
||||
local garr = new_and_grow(itemsize, growsize, grow_by)
|
||||
neq(NULL, ga_data(garr)) -- data should be a ptr to memory
|
||||
eq(grow_by, ga_maxlen(garr)) -- we requested MORE than growsize, so...
|
||||
end)
|
||||
|
||||
it('does not grow when nothing is requested', function()
|
||||
local garr = new_and_grow(16, 4, 0)
|
||||
eq(NULL, ga_data(garr))
|
||||
eq(0, ga_maxlen(garr))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_clear', function()
|
||||
it('clears an already allocated array', function()
|
||||
-- allocate and scramble an array
|
||||
local garr = garray_ctype()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
ga_grow(garr, 4)
|
||||
ga_set_len(garr, 4)
|
||||
ga_scramble(garr)
|
||||
|
||||
-- clear it and check
|
||||
ga_clear(garr)
|
||||
eq(NULL, ga_data(garr))
|
||||
eq(0, ga_maxlen(garr))
|
||||
eq(0, ga_len(garr))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_append', function()
|
||||
it('can append bytes', function()
|
||||
-- this is the actual ga_append, the others are just emulated lua
|
||||
-- versions
|
||||
local garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("uint8_t"), 1)
|
||||
ga_append(garr, 'h')
|
||||
ga_append(garr, 'e')
|
||||
ga_append(garr, 'l')
|
||||
ga_append(garr, 'l')
|
||||
ga_append(garr, 'o')
|
||||
ga_append(garr, 0)
|
||||
local bytes = ga_data_as_bytes(garr)
|
||||
eq('hello', ffi.string(bytes))
|
||||
end)
|
||||
|
||||
it('can append integers', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("int"), 1)
|
||||
local input = {
|
||||
-20,
|
||||
94,
|
||||
867615,
|
||||
90927,
|
||||
86
|
||||
}
|
||||
ga_append_ints(garr, unpack(input))
|
||||
local ints = ga_data_as_ints(garr)
|
||||
for i = 0, #input - 1 do
|
||||
eq(input[i + 1], ints[i])
|
||||
end
|
||||
end)
|
||||
|
||||
it('can append strings to a growing array of strings', function()
|
||||
local garr = new_string_garray()
|
||||
local input = {
|
||||
"some",
|
||||
"str",
|
||||
"\r\n\r●●●●●●,,,",
|
||||
"hmm",
|
||||
"got it"
|
||||
}
|
||||
ga_append_strings(garr, unpack(input))
|
||||
-- check that we can get the same strings out of the array
|
||||
local strings = ga_data_as_strings(garr)
|
||||
for i = 0, #input - 1 do
|
||||
eq(input[i + 1], ffi.string(strings[i]))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_concat', function()
|
||||
it('concatenates the parameter to the growing byte array', function()
|
||||
local garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("char"), 1)
|
||||
local str = "ohwell●●"
|
||||
local loop = 5
|
||||
for i = 1, loop do
|
||||
ga_concat(garr, str)
|
||||
end
|
||||
|
||||
-- ga_concat does NOT append the NUL in the src string to the
|
||||
-- destination, you have to do that manually by calling something like
|
||||
-- ga_append(gar, '\0'). I'ts always used like that in the vim
|
||||
-- codebase. I feel that this is a bit of an unnecesesary
|
||||
-- micro-optimization.
|
||||
ga_append(garr, 0)
|
||||
local result = ffi.string(ga_data_as_bytes(garr))
|
||||
eq(string.rep(str, loop), result)
|
||||
end)
|
||||
end)
|
||||
|
||||
function test_concat_fn(input, fn, sep)
|
||||
local garr = new_string_garray()
|
||||
ga_append_strings(garr, unpack(input))
|
||||
if sep == nil then
|
||||
eq(table.concat(input, ','), fn(garr))
|
||||
else
|
||||
eq(table.concat(input, sep), fn(garr, sep))
|
||||
end
|
||||
end
|
||||
|
||||
describe('ga_concat_strings', function()
|
||||
it('returns an empty string when concatenating an empty array', function()
|
||||
test_concat_fn({ }, ga_concat_strings)
|
||||
end)
|
||||
|
||||
it('can concatenate a non-empty array', function()
|
||||
test_concat_fn({
|
||||
'oh',
|
||||
'my',
|
||||
'neovim'
|
||||
}, ga_concat_strings)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_concat_strings_sep', function()
|
||||
it('returns an empty string when concatenating an empty array', function()
|
||||
test_concat_fn({ }, ga_concat_strings_sep, '---')
|
||||
end)
|
||||
|
||||
it('can concatenate a non-empty array', function()
|
||||
local sep = '-●●-'
|
||||
test_concat_fn({
|
||||
'oh',
|
||||
'my',
|
||||
'neovim'
|
||||
}, ga_concat_strings_sep, sep)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('ga_remove_duplicate_strings', function()
|
||||
it('sorts and removes duplicate strings', function()
|
||||
local garr = new_string_garray()
|
||||
local input = {
|
||||
'ccc',
|
||||
'aaa',
|
||||
'bbb',
|
||||
'ddd●●',
|
||||
'aaa',
|
||||
'bbb',
|
||||
'ccc',
|
||||
'ccc',
|
||||
'ddd●●'
|
||||
}
|
||||
local sorted_dedup_input = {
|
||||
'aaa',
|
||||
'bbb',
|
||||
'ccc',
|
||||
'ddd●●'
|
||||
}
|
||||
ga_append_strings(garr, unpack(input))
|
||||
ga_remove_duplicate_strings(garr)
|
||||
eq(#sorted_dedup_input, ga_len(garr))
|
||||
local strings = ga_data_as_strings(garr)
|
||||
for i = 0, #sorted_dedup_input - 1 do
|
||||
eq(sorted_dedup_input[i + 1], ffi.string(strings[i]))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end)
|
@ -1,271 +0,0 @@
|
||||
{:cimport, :internalize, :eq, :neq, :ffi, :lib, :cstr, :to_cstr, :NULL} = require 'test.unit.helpers'
|
||||
|
||||
garray = cimport './src/nvim/garray.h'
|
||||
|
||||
-- define a basic interface to garray. We could make it a lot nicer by
|
||||
-- constructing a moonscript class wrapper around garray. It could for
|
||||
-- example associate ga_clear_strings to the underlying garray cdata if the
|
||||
-- garray is a string array. But for now I estimate that that kind of magic
|
||||
-- might make testing less "transparant" (i.e.: the interface would become
|
||||
-- quite different as to how one would use it from C.
|
||||
|
||||
-- accessors
|
||||
ga_len = (garr) ->
|
||||
garr[0].ga_len
|
||||
ga_maxlen = (garr) ->
|
||||
garr[0].ga_maxlen
|
||||
ga_itemsize = (garr) ->
|
||||
garr[0].ga_itemsize
|
||||
ga_growsize = (garr) ->
|
||||
garr[0].ga_growsize
|
||||
ga_data = (garr) ->
|
||||
garr[0].ga_data
|
||||
|
||||
-- derived accessors
|
||||
ga_size = (garr) ->
|
||||
ga_len(garr) * ga_itemsize(garr)
|
||||
ga_maxsize = (garr) ->
|
||||
ga_maxlen(garr) * ga_itemsize(garr)
|
||||
ga_data_as_bytes = (garr) ->
|
||||
ffi.cast('uint8_t *', ga_data(garr))
|
||||
ga_data_as_strings = (garr) ->
|
||||
ffi.cast('char **', ga_data(garr))
|
||||
ga_data_as_ints = (garr) ->
|
||||
ffi.cast('int *', ga_data(garr))
|
||||
|
||||
-- garray manipulation
|
||||
ga_init = (garr, itemsize, growsize) ->
|
||||
garray.ga_init(garr, itemsize, growsize)
|
||||
ga_clear = (garr) ->
|
||||
garray.ga_clear(garr)
|
||||
ga_clear_strings = (garr) ->
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('char *'))
|
||||
garray.ga_clear_strings(garr)
|
||||
ga_grow = (garr, n) ->
|
||||
garray.ga_grow(garr, n)
|
||||
ga_concat = (garr, str) ->
|
||||
garray.ga_concat(garr, to_cstr(str))
|
||||
ga_append = (garr, b) ->
|
||||
if type(b) == 'string'
|
||||
garray.ga_append(garr, string.byte(b))
|
||||
else
|
||||
garray.ga_append(garr, b)
|
||||
ga_concat_strings = (garr) ->
|
||||
internalize(garray.ga_concat_strings(garr))
|
||||
ga_concat_strings_sep = (garr, sep) ->
|
||||
internalize(garray.ga_concat_strings_sep(garr, to_cstr(sep)))
|
||||
ga_remove_duplicate_strings = (garr) ->
|
||||
garray.ga_remove_duplicate_strings(garr)
|
||||
|
||||
-- derived manipulators
|
||||
ga_set_len = (garr, len) ->
|
||||
assert.is_true(len <= ga_maxlen(garr))
|
||||
garr[0].ga_len = len
|
||||
ga_inc_len = (garr, by) ->
|
||||
ga_set_len(garr, ga_len(garr) + 1)
|
||||
|
||||
-- custom append functions
|
||||
-- not the C ga_append, which only works for bytes
|
||||
ga_append_int = (garr, it) ->
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('int'))
|
||||
|
||||
ga_grow(garr, 1)
|
||||
data = ga_data_as_ints(garr)
|
||||
data[ga_len(garr)] = it
|
||||
ga_inc_len(garr, 1)
|
||||
ga_append_string = (garr, it) ->
|
||||
assert.is_true(ga_itemsize(garr) == ffi.sizeof('char *'))
|
||||
|
||||
-- make a non-garbage collected string and copy the lua string into it,
|
||||
-- TODO(aktau): we should probably call xmalloc here, though as long as
|
||||
-- xmalloc is based on malloc it should work.
|
||||
mem = ffi.C.malloc(string.len(it) + 1)
|
||||
ffi.copy(mem, it)
|
||||
|
||||
ga_grow(garr, 1)
|
||||
data = ga_data_as_strings(garr)
|
||||
data[ga_len(garr)] = mem
|
||||
ga_inc_len(garr, 1)
|
||||
ga_append_strings = (garr, ...) ->
|
||||
prevlen = ga_len(garr)
|
||||
len = select('#', ...)
|
||||
for i = 1, len
|
||||
ga_append_string(garr, select(i, ...))
|
||||
eq prevlen + len, ga_len(garr)
|
||||
ga_append_ints = (garr, ...) ->
|
||||
prevlen = ga_len(garr)
|
||||
len = select('#', ...)
|
||||
for i = 1, len
|
||||
ga_append_int(garr, select(i, ...))
|
||||
eq prevlen + len, ga_len(garr)
|
||||
|
||||
-- enhanced constructors
|
||||
garray_ctype = ffi.typeof('garray_T[1]')
|
||||
new_garray = ->
|
||||
garr = garray_ctype()
|
||||
ffi.gc(garr, ga_clear)
|
||||
new_string_garray = ->
|
||||
garr = garray_ctype()
|
||||
ga_init(garr, ffi.sizeof("char_u *"), 1)
|
||||
ffi.gc(garr, ga_clear_strings)
|
||||
|
||||
randomByte = ->
|
||||
ffi.cast('uint8_t', math.random(0, 255))
|
||||
|
||||
-- scramble the data in a garray
|
||||
ga_scramble = (garr) ->
|
||||
size, bytes = ga_size(garr), ga_data_as_bytes(garr)
|
||||
|
||||
for i = 0, size - 1
|
||||
bytes[i] = randomByte()
|
||||
|
||||
describe 'garray', ->
|
||||
itemsize = 14
|
||||
growsize = 95
|
||||
|
||||
describe 'ga_init', ->
|
||||
it 'initializes the values of the garray', ->
|
||||
garr = new_garray()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
eq 0, ga_len(garr)
|
||||
eq 0, ga_maxlen(garr)
|
||||
eq growsize, ga_growsize(garr)
|
||||
eq itemsize, ga_itemsize(garr)
|
||||
eq NULL, ga_data(garr)
|
||||
|
||||
describe 'ga_grow', ->
|
||||
new_and_grow = (itemsize, growsize, req) ->
|
||||
garr = new_garray()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
|
||||
eq 0, ga_size(garr) -- should be 0 at first
|
||||
eq NULL, ga_data(garr) -- should be NULL
|
||||
ga_grow(garr, req) -- add space for `req` items
|
||||
|
||||
garr
|
||||
|
||||
it 'grows by growsize items if num < growsize', ->
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
grow_by = growsize - 1
|
||||
garr = new_and_grow(itemsize, growsize, grow_by)
|
||||
neq NULL, ga_data(garr) -- data should be a ptr to memory
|
||||
eq growsize, ga_maxlen(garr) -- we requested LESS than growsize, so...
|
||||
|
||||
it 'grows by num items if num > growsize', ->
|
||||
itemsize = 16
|
||||
growsize = 4
|
||||
grow_by = growsize + 1
|
||||
garr = new_and_grow(itemsize, growsize, grow_by)
|
||||
neq NULL, ga_data(garr) -- data should be a ptr to memory
|
||||
eq grow_by, ga_maxlen(garr) -- we requested MORE than growsize, so...
|
||||
|
||||
it 'does not grow when nothing is requested', ->
|
||||
garr = new_and_grow(16, 4, 0)
|
||||
eq NULL, ga_data(garr)
|
||||
eq 0, ga_maxlen(garr)
|
||||
|
||||
describe 'ga_clear', ->
|
||||
it 'clears an already allocated array', ->
|
||||
-- allocate and scramble an array
|
||||
garr = garray_ctype()
|
||||
ga_init(garr, itemsize, growsize)
|
||||
ga_grow(garr, 4)
|
||||
ga_set_len(garr, 4)
|
||||
ga_scramble(garr)
|
||||
|
||||
-- clear it and check
|
||||
ga_clear(garr)
|
||||
eq NULL, ga_data(garr)
|
||||
eq 0, ga_maxlen(garr)
|
||||
eq 0, ga_len(garr)
|
||||
|
||||
describe 'ga_append', ->
|
||||
it 'can append bytes', ->
|
||||
-- this is the actual ga_append, the others are just emulated lua
|
||||
-- versions
|
||||
garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("uint8_t"), 1)
|
||||
ga_append(garr, 'h')
|
||||
ga_append(garr, 'e')
|
||||
ga_append(garr, 'l')
|
||||
ga_append(garr, 'l')
|
||||
ga_append(garr, 'o')
|
||||
ga_append(garr, 0)
|
||||
bytes = ga_data_as_bytes(garr)
|
||||
eq 'hello', ffi.string(bytes)
|
||||
|
||||
it 'can append integers', ->
|
||||
garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("int"), 1)
|
||||
input = {-20, 94, 867615, 90927, 86}
|
||||
ga_append_ints(garr, unpack(input))
|
||||
|
||||
ints = ga_data_as_ints(garr)
|
||||
for i = 0, #input - 1
|
||||
eq input[i+1], ints[i]
|
||||
|
||||
it 'can append strings to a growing array of strings', ->
|
||||
garr = new_string_garray()
|
||||
input = {"some", "str", "\r\n\r●●●●●●,,,", "hmm", "got it"}
|
||||
ga_append_strings(garr, unpack(input))
|
||||
|
||||
-- check that we can get the same strings out of the array
|
||||
strings = ga_data_as_strings(garr)
|
||||
for i = 0, #input - 1
|
||||
eq input[i+1], ffi.string(strings[i])
|
||||
|
||||
describe 'ga_concat', ->
|
||||
it 'concatenates the parameter to the growing byte array', ->
|
||||
garr = new_garray()
|
||||
ga_init(garr, ffi.sizeof("char"), 1)
|
||||
|
||||
str = "ohwell●●"
|
||||
loop = 5
|
||||
for i = 1, loop
|
||||
ga_concat(garr, str)
|
||||
|
||||
-- ga_concat does NOT append the NUL in the src string to the
|
||||
-- destination, you have to do that manually by calling something like
|
||||
-- ga_append(gar, '\0'). I'ts always used like that in the vim
|
||||
-- codebase. I feel that this is a bit of an unnecesesary
|
||||
-- micro-optimization.
|
||||
ga_append(garr, 0)
|
||||
|
||||
result = ffi.string(ga_data_as_bytes(garr))
|
||||
eq string.rep(str, loop), result
|
||||
|
||||
test_concat_fn = (input, fn, sep) ->
|
||||
garr = new_string_garray()
|
||||
ga_append_strings(garr, unpack(input))
|
||||
if sep == nil
|
||||
eq table.concat(input, ','), fn(garr)
|
||||
else
|
||||
eq table.concat(input, sep), fn(garr, sep)
|
||||
|
||||
describe 'ga_concat_strings', ->
|
||||
it 'returns an empty string when concatenating an empty array', ->
|
||||
test_concat_fn({}, ga_concat_strings)
|
||||
it 'can concatenate a non-empty array', ->
|
||||
test_concat_fn({'oh', 'my', 'neovim'}, ga_concat_strings)
|
||||
|
||||
describe 'ga_concat_strings_sep', ->
|
||||
it 'returns an empty string when concatenating an empty array', ->
|
||||
test_concat_fn({}, ga_concat_strings_sep, '---')
|
||||
it 'can concatenate a non-empty array', ->
|
||||
sep = '-●●-'
|
||||
test_concat_fn({'oh', 'my', 'neovim'}, ga_concat_strings_sep, sep)
|
||||
|
||||
describe 'ga_remove_duplicate_strings', ->
|
||||
it 'sorts and removes duplicate strings', ->
|
||||
garr = new_string_garray()
|
||||
input = {'ccc', 'aaa', 'bbb', 'ddd●●', 'aaa', 'bbb', 'ccc', 'ccc', 'ddd●●'}
|
||||
sorted_dedup_input = {'aaa', 'bbb', 'ccc', 'ddd●●'}
|
||||
|
||||
ga_append_strings(garr, unpack(input))
|
||||
ga_remove_duplicate_strings(garr)
|
||||
eq #sorted_dedup_input, ga_len(garr)
|
||||
|
||||
strings = ga_data_as_strings(garr)
|
||||
for i = 0, #sorted_dedup_input - 1
|
||||
eq sorted_dedup_input[i+1], ffi.string(strings[i])
|
Loading…
Reference in New Issue
Block a user