diff options
Diffstat (limited to 'test/plugins/ffi')
-rw-r--r-- | test/plugins/ffi/builder.lua | 233 | ||||
-rw-r--r-- | test/plugins/ffi/cdef.lua | 61 | ||||
-rw-r--r-- | test/plugins/ffi/parser.lua | 176 | ||||
-rw-r--r-- | test/plugins/ffi/test.lua | 43 |
4 files changed, 513 insertions, 0 deletions
diff --git a/test/plugins/ffi/builder.lua b/test/plugins/ffi/builder.lua new file mode 100644 index 00000000..ebbfab55 --- /dev/null +++ b/test/plugins/ffi/builder.lua @@ -0,0 +1,233 @@ +local ffi = require 'plugins.ffi' +local util = require 'utility' +rawset(_G, 'TEST', true) + +local function removeEmpty(lines) + local removeLines = {} + for i, v in ipairs(lines) do + if v ~= '\n' then + removeLines[#removeLines+1] = v:gsub('^%s+', '') + end + end + return removeLines +end + +local function formatLines(lines) + if not lines or #lines == 0 then + return {} + end + table.remove(lines, 1) + return removeEmpty(lines) +end + +---@param str string +local function splitLines(str) + local lines = {} + local i = 1 + for line in str:gmatch("[^\r\n]+") do + lines[i] = line + i = i + 1 + end + return lines +end + +function TEST(wanted) + wanted = removeEmpty(splitLines(wanted)) + return function (script) + local lines = formatLines(ffi.compileCodes({ script })) + assert(util.equal(wanted, lines), util.dump(lines)) + end +end + +TEST [[ + ---@alias ffi.namespace*.EVP_MD ffi.namespace*.struct@env_md_st + + ---@return ffi.namespace*.EVP_MD + function m.EVP_md5() end +]] [[ + typedef struct env_md_st EVP_MD; + const EVP_MD *EVP_md5(void); +]] + +TEST [[ + ---@class ffi.namespace*.struct@a + ---@field _in integer +]] [[ + struct a { + int in; + }; +]] + +TEST [[ +---@param _in integer +function m.test(_in) end +]] [[ + void test(int in); +]] + +TEST [[ + ---@alias ffi.namespace*.ENGINE ffi.namespace*.struct@engine_st + ---@alias ffi.namespace*.ENGINE1 ffi.namespace*.enum@engine_st1 +]] [[ + typedef struct engine_st ENGINE; + typedef enum engine_st1 ENGINE1; +]] + +TEST [[ + ---@param a integer[][] + function m.test(a) end +]] [[ + void test(int a[][]); +]] + +TEST [[ + ---@class ffi.namespace*.struct@A + ---@field b integer[] + ---@field c integer[] +]] [[ + struct A { + int b[5]; + int c[]; + }; +]] + +TEST [[ + m.B = 5 + m.A = 0 + m.D = 7 + m.C = 6 +]] [[ + enum { + A, + B=5, + C, + D, + }; +]] + +TEST [[ + m.B = 2 + m.A = 1 + m.C = 5 + ---@alias ffi.namespace*.enum@a 1 | 2 | 'B' | 'A' | 5 | 'C' +]] [[ + enum a { + A = 1, + B = 2, + C = A|B+2, + }; +]] + +TEST [[ + ---@param a boolean + ---@param b boolean + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(bool a, _Bool b, size_t c, ssize_t d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(int8_t a, int16_t b, int32_t c, int64_t d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(uint8_t a, uint16_t b, uint32_t c, uint64_t d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(unsigned char a, unsigned short b, unsigned long c, unsigned int d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(unsigned char a, unsigned short b, unsigned long c, unsigned int d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(signed char a, signed short b, signed long c, signed int d); +]] + +TEST [[ + ---@param a integer + ---@param b integer + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(char a, short b, long c, int d); +]] + +TEST [[ + ---@param a number + ---@param b number + ---@param c integer + ---@param d integer + function m.test(a, b, c, d) end +]] [[ + void test(float a, double b, int8_t c, uint8_t d); +]] + +TEST [[ + ---@alias ffi.namespace*.H ffi.namespace*.void + + function m.test() end +]] [[ + typedef void H; + + H test(); +]] + +TEST [[ + ---@class ffi.namespace*.a + + ---@param a ffi.namespace*.a + function m.test(a) end +]] [[ + typedef struct {} a; + + void test(a* a); +]] + +TEST [[ + ---@class ffi.namespace*.struct@a + ---@field a integer + ---@field b ffi.namespace*.char* + + ---@param a ffi.namespace*.struct@a + function m.test(a) end +]] [[ + struct a {int a;char* b;}; + + void test(struct a* a); +]] diff --git a/test/plugins/ffi/cdef.lua b/test/plugins/ffi/cdef.lua new file mode 100644 index 00000000..cf3992d3 --- /dev/null +++ b/test/plugins/ffi/cdef.lua @@ -0,0 +1,61 @@ + +local files = require 'files' +local code = require 'plugins.ffi.searchCode' +local cdefRerence = require 'plugins.ffi.cdefRerence' + +rawset(_G, 'TEST', true) + +function TEST(wanted) + ---@async + return function (script) + files.setText(TESTURI, script) + local codeResults = code(cdefRerence(), TESTURI) + assert(codeResults) + table.sort(codeResults) + assert(table.concat(codeResults, '|') == wanted, table.concat(codeResults, '|') .. ' ~= ' .. wanted) + files.remove(TESTURI) + end +end + +TEST 'aaa|bbb' [[ +local ffi = require 'ffi' +local cdef = ffi.cdef +cdef('aaa') +cdef = function () +end +cdef('bbb') +]] + +TEST 'aaa' [[ +local ffi = require 'ffi' + +ffi.cdef('aaa') +]] + +TEST 'aa.aa' [[ +local ffi = require 'ffi' +local t1 = ffi + +t1.cdef"aa.aa" +]] + +TEST 'aaa' [[ +local ffi = require 'ffi' +local code = 'aaa' +ffi.cdef(code) +]] + +TEST 'aaa|bbb' [[ +local ffi = require 'ffi' +local code = 'aaa' +code = 'bbb' +local t1 = ffi +t1.cdef(code) +]] + +TEST 'aa.aa' [[ +local ffi = require 'ffi' +local cdef = ffi.cdef + +cdef"aa.aa" +]] diff --git a/test/plugins/ffi/parser.lua b/test/plugins/ffi/parser.lua new file mode 100644 index 00000000..6d7f2cea --- /dev/null +++ b/test/plugins/ffi/parser.lua @@ -0,0 +1,176 @@ +local utility = require 'utility' +local cdriver = require 'plugins.ffi.c-parser.cdriver' + +rawset(_G, 'TEST', true) +local ctypes = require 'plugins.ffi.c-parser.ctypes' +ctypes.TESTMODE = true + +--TODO expand all singlenode +function TEST(wanted, full) + return function (script) + local rrr = cdriver.process_context(script .. "$EOF$") + assert(rrr) + if full then + for i, v in ipairs(rrr) do + assert(utility.equal(v, wanted[i]), utility.dump(v)) + end + else + assert(utility.equal(rrr[1], wanted), utility.dump(rrr[1])) + end + end +end + +TEST { + name = "struct@A", + type = { + fields = { + { + isarray = true, + name = "a", + type = { "int", }, + }, + { + isarray = true, + name = "b", + type = { "int", }, + }, + }, + name = "A", + type = "struct", + }, +} + [[ + struct A { + int a[5]; + int b[]; + }; +]] + +TEST { + name = 'union@a', + type = { + name = 'a', + type = 'union', + fields = { + { name = 'b', type = { 'int' } }, + { name = 'c', type = { 'int8_t' } } + } + } +} [[ + union a{ + int b; + int8_t c; + }; +]] + +TEST { + name = 'union@a', + type = { + name = 'a', + type = 'union', + } +} [[ + union a{}; +]] + +TEST { + name = 'enum@anonymous', + type = { + type = 'enum', + values = { + { name = 'a', value = { '1' } }, + { name = 'b', value = { 'a' } }, + } + } +} [[ + enum { + a = 1, + b = a, + }; +]] + +TEST { + name = 'enum@a', + type = { + name = 'a', + type = 'enum', + values = { + { name = 'b', value = { op = '|', { '1' }, { '2' } } }, + } + } +} [[ + enum a{ + b = 1|2, + }; +]] + +TEST { + name = 'enum@a', + type = { + name = 'a', + type = 'enum', + } +} [[ + enum a{}; +]] + +TEST { + name = 'struct@a', + type = { + name = 'a', + type = 'struct', + fields = { + { name = 'f', type = { 'int' } }, + { name = 'b', type = { 'int', '*', '*' } } + } + } +} [[ + struct a {int f,**b;}; +]] + +TEST { + name = 'struct@a', + type = { + name = 'a', + type = 'struct', + fields = { + { name = 'f', type = { 'int' } }, + } + } +} [[ + struct a {int f;}; +]] + +TEST({ + { name = "struct@anonymous", type = { type = 'struct' } }, + { + name = 'a', + type = { + name = 'a', + type = 'typedef', + def = { + { type = 'struct', } + } + } + } +}, true) [[ + typedef struct {} a; +]] + +TEST { + name = 'a', + type = { + name = 'a', + type = 'function', + params = { + { type = { 'int' }, name = 'b' }, + }, + ret = { + type = { 'int' } + }, + vararg = false + }, + +} [[ + int a(int b); +]] diff --git a/test/plugins/ffi/test.lua b/test/plugins/ffi/test.lua new file mode 100644 index 00000000..93be2ff5 --- /dev/null +++ b/test/plugins/ffi/test.lua @@ -0,0 +1,43 @@ +local lclient = require 'lclient' +local ws = require 'workspace' +local furi = require 'file-uri' +local files = require 'files' +local diagnostic = require 'provider.diagnostic' + +--TODO how to changed the runtime version? +local template = require 'config.template' + +template['Lua.runtime.version'].default = 'LuaJIT' + +TESTURI = furi.encode(TESTROOT .. 'unittest.ffi.lua') + +---@async +local function TestBuilder() + local builder = require 'core.command.reloadFFIMeta' + files.setText(TESTURI, [[ + local ffi = require 'ffi' + ffi.cdef 'void test();' + ]]) + local uri = ws.getFirstScope().uri + builder(uri) +end + +---@async +lclient():start(function (languageClient) + languageClient:registerFakers() + local rootUri = TESTURI + languageClient:initialize { + rootUri = rootUri, + } + + diagnostic.pause() + + ws.awaitReady(rootUri) + + require 'plugins.ffi.cdef' + require 'plugins.ffi.parser' + require 'plugins.ffi.builder' + TestBuilder() + + diagnostic.resume() +end) |