summaryrefslogtreecommitdiff
path: root/test/plugins/ffi
diff options
context:
space:
mode:
Diffstat (limited to 'test/plugins/ffi')
-rw-r--r--test/plugins/ffi/builder.lua233
-rw-r--r--test/plugins/ffi/cdef.lua61
-rw-r--r--test/plugins/ffi/parser.lua176
-rw-r--r--test/plugins/ffi/test.lua43
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)