diff --git a/test/README.md b/test/README.md index ff16ac8..0174cab 100644 --- a/test/README.md +++ b/test/README.md @@ -4,11 +4,17 @@ be run with any other Lua 5.1 or 5.2 interpreter. ## Running the test suite ## -To run the default test suite, run `test.lua` using the Lua interpreter you -wish to test, for example: +To run the default test suite, run `build.sh` (\*nix) or `build.bat` (Windows, +run from a Visual Studio command prompt) with the directory containing the +include directories of the Lua interpreter to be tested. Then run `test.lua` +using the Lua interpreter you wish to test, for example: + $ ./build.sh ~/luajit-2.0/src $ ~/luajit-2.0/src/luajit test.lua +You don't need to rerun `build.sh` or `build.bat` unless you change one of the +C or C++ source files in `src/`. + If the test suite passes, the final line printed to stdout will be `NNN passed`, and the exit code of the process will be zero. If any tests fail, the exit code will be non-zero. If the failures caused catastrophic diff --git a/test/common/ffi_util.inc b/test/common/ffi_util.lua similarity index 83% rename from test/common/ffi_util.inc rename to test/common/ffi_util.lua index 1eee8dd..0da24ae 100644 --- a/test/common/ffi_util.inc +++ b/test/common/ffi_util.lua @@ -4,7 +4,8 @@ local ffi = require("ffi") -function checkfail(t, f) +local ffi_util = {} +function ffi_util.checkfail(t, f) f = f or ffi.typeof for i=1,1e9 do local tp = t[i] @@ -13,8 +14,8 @@ function checkfail(t, f) end end -function checktypes(t) - for i=1,1e9,3 do +function ffi_util.checktypes(t) + for i=1,#t,3 do local tp = t[i+2] if not tp then break end local id = ffi.typeof(tp) @@ -23,14 +24,14 @@ function checktypes(t) end end -function fails(f, ...) +function ffi_util.fails(f, ...) if pcall(f, ...) ~= false then error("failure expected", 2) end end local incroot = os.getenv("INCROOT") or "/usr/include" local cdefs = os.getenv("CDEFS") or "" -function include(name) +function ffi_util.include(name) local flags = ffi.abi("32bit") and "-m32" or "-m64" if string.sub(name, 1, 1) ~= "/" then name = incroot.."/"..name end local fp = assert(io.popen("cc -E -P "..flags.." "..cdefs.." "..name)) @@ -39,3 +40,4 @@ function include(name) ffi.cdef(s) end +return ffi_util diff --git a/test/index b/test/index index bd4081e..2c4ae31 100644 --- a/test/index +++ b/test/index @@ -4,3 +4,4 @@ bc +luajit>=2 computations.lua trace +jit opt +jit +misc diff --git a/test/lang/goto.lua b/test/lang/goto.lua index 1563a23..8159566 100644 --- a/test/lang/goto.lua +++ b/test/lang/goto.lua @@ -21,6 +21,7 @@ do --- Basic goto and label semantics. expect("goto a; do ::a:: end", "'a'") expect("break", "break") expect("if x then break end", "break") + expect("repeat goto a break until true", "undefined label 'a'") -- Error: goto into variable scope. expect("goto a; local x; ::a:: local y", "'x'") diff --git a/test/lang/meta/len.lua b/test/lang/meta/len.lua index 2410daa..69b2287 100644 --- a/test/lang/meta/len.lua +++ b/test/lang/meta/len.lua @@ -1,4 +1,3 @@ -local compat52 = table.pack local mt = { __len = function(o, o2) if compat52 then assert(o2 == o) diff --git a/test/lib/contents.lua b/test/lib/contents.lua index a1d8b9b..7bfcbed 100644 --- a/test/lib/contents.lua +++ b/test/lib/contents.lua @@ -19,7 +19,12 @@ local function check(m, expected, exclude) end do --- base - check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:getmetatable:io:ipairs:load:loadfile:math:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setmetatable:string:table:tonumber:tostring:type:xpcall", "rawlen:bit:bit32:jit:gcinfo:setfenv:getfenv:loadstring:unpack:module:newproxy") + check(_G, "_G:_VERSION:arg:assert:collectgarbage:compat52" .. + ":coroutine:cpptest:ctest:" .. + "debug:dofile:error:getmetatable:io:ipairs:load:loadfile:" .. + "math:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:" .. + "require:select:setmetatable:string:table:tonumber:tostring:type:xpcall", + "rawlen:bit:bit32:jit:gcinfo:setfenv:getfenv:loadstring:unpack:module:newproxy") end do --- pre-5.2 base +lua<5.2 @@ -54,8 +59,7 @@ do --- math check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh", "log10:mod") end -do --- pre-5.2 math +lua<5.2 -compat5.2 - assert(math.mod) +do --- pre-5.2 math +lua<5.1 -compat5.2 assert(math.log10) end @@ -66,18 +70,11 @@ end do --- string check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper", "gfind") -end - -do --- pre-5.2 string +lua<5.2 -compat5.2 - assert(string.gfind) -end - -do --- 5.2 string +lua>=5.2 assert(not string.gfind) end do --- pre-5.2 table +lua<5.2 - check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort", "pack:unpack:setn:new") + check(table, "concat:foreach:foreachi:getn:insert:maxn:move:remove:sort", "pack:unpack:setn:new") end do --- 5.2 table +lua>=5.2 @@ -139,7 +136,8 @@ do --- package.loaded loaded[k] = v end end - check(loaded, "_G:coroutine:debug:io:math:os:package:string:table", "bit:bit32:common:ffi:jit:table.new") + check(loaded, "_G:coroutine:cpptest:ctest:debug:io:math:os:package:string:table", + "bit:bit32:common:ffi:jit:table.new") end do --- bit +bit diff --git a/test/lib/ffi/bit64.lua b/test/lib/ffi/bit64.lua index d1b47be..2e903a5 100644 --- a/test/lib/ffi/bit64.lua +++ b/test/lib/ffi/bit64.lua @@ -7,7 +7,7 @@ local shl, shr, sar = bit.lshift, bit.rshift, bit.arshift local rol, ror = bit.rol, bit.ror ffi.cdef[[ -typedef enum { ZZI = -1 } ienum_t; +typedef enum { ZZI = -1 } ienum_t_; typedef enum { ZZU } uenum_t; ]] @@ -32,7 +32,7 @@ do --- smoke tohex end do --- tobit/band assorted C types - for _,tp in ipairs{"int", "ienum_t", "uenum_t", "int64_t", "uint64_t"} do + for _,tp in ipairs{"int", "ienum_t_", "uenum_t", "int64_t", "uint64_t"} do local x = ffi.new(tp, 10) local y = tobit(x) local z = band(x) diff --git a/test/lib/ffi/ffi_arith_ptr.lua b/test/lib/ffi/ffi_arith_ptr.lua index 8cf890c..8c9571e 100644 --- a/test/lib/ffi/ffi_arith_ptr.lua +++ b/test/lib/ffi/ffi_arith_ptr.lua @@ -1,6 +1,7 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local fails = ffi_util.fails ffi.cdef[[ typedef struct { int a,b,c; } foo1_t; @@ -9,7 +10,7 @@ void *malloc(size_t); struct incomplete; ]] -do +do --- FFI basic pointer and array operations local a = ffi.new("int[10]") local p1 = a+0 p1[0] = 1; @@ -61,7 +62,7 @@ do assert(b - a == 5) end -do +do --- Null pointers (and only null pointers) act like nil. local p1 = ffi.cast("void *", 0) local p2 = ffi.cast("int *", 1) assert(p1 == p1) @@ -71,7 +72,7 @@ do assert(p2 ~= nil) end -do +do --- Function pointers are not nil, but do not support arithmetic. local f1 = ffi.C.free local f2 = ffi.C.malloc local p1 = ffi.cast("void *", f1) @@ -84,7 +85,7 @@ do fails(function(f1) return f1 + 1 end, f1) end -do +do --- FFI arrays local s = ffi.new("foo1_t[10]") local p1 = s+3 p1.a = 1; p1.b = 2; p1.c = 3 @@ -96,10 +97,10 @@ do assert(p1 - p2 == -3) end -do +do --- Cannot perform arithmetic on pointer to incomplete type local mem = ffi.new("int[1]") local p = ffi.cast("struct incomplete *", mem) - fails(function(p) return p+1 end, p) + ffi_util.fails(function(p) return p+1 end, p) local ok, err = pcall(function(p) return p[1] end, p) assert(not ok and err:match("size.*unknown")) end diff --git a/test/lib/ffi/ffi_bitfield.lua b/test/lib/ffi/ffi_bitfield.lua index cd0b181..2fce79f 100644 --- a/test/lib/ffi/ffi_bitfield.lua +++ b/test/lib/ffi/ffi_bitfield.lua @@ -1,19 +1,16 @@ local ffi = require("ffi") +local x = ffi.new([[ +union { + uint32_t u; + struct { int a:10,b:10,c:11,d:1; }; + struct { unsigned int e:10,f:10,g:11,h:1; }; + struct { int8_t i:4,j:5,k:5,l:3; }; + struct { _Bool b0:1,b1:1,b2:1,b3:1; }; +} +]]) -dofile("../common/ffi_util.inc") -do - local x = ffi.new([[ - union { - uint32_t u; - struct { int a:10,b:10,c:11,d:1; }; - struct { unsigned int e:10,f:10,g:11,h:1; }; - struct { int8_t i:4,j:5,k:5,l:3; }; - struct { _Bool b0:1,b1:1,b2:1,b3:1; }; - } - ]]) - - -- bitfield access +do --- Bitfield acess x.u = 0xffffffff assert(x.a == -1 and x.b == -1 and x.c == -1 and x.d == -1) assert(x.e == 1023 and x.f == 1023 and x.g == 2047 and x.h == 1) @@ -43,8 +40,9 @@ do assert(x.i == -2 and x.j == -6 and x.k == 1 and x.l == -2) assert(x.b0 == true and x.b1 == true and x.b2 == true and x.b3 == false) end +end - -- bitfield insert +do --- bitfield insert x.u = 0xffffffff x.a = 0 if ffi.abi("le") then @@ -73,8 +71,9 @@ do else assert(x.u == 0x003ff000) end +end - -- cumulative bitfield insert +do --- cumulative bitfield insert x.u = 0xffffffff if ffi.abi("le") then x.a = -392; x.b = 277; x.c = 291; x.d = 0 @@ -106,3 +105,12 @@ do end +do --- bitfield JIT compilation + local bf = ffi.new'struct { int x : 2; int y : 30; }' + bf.x = 1 + bf.y = 20 + for i = 1, 100 do + assert(bf.x == 1) + assert(bf.y == 20) + end +end diff --git a/test/lib/ffi/ffi_call.lua b/test/lib/ffi/ffi_call.lua index 1eb5e90..b9aed20 100644 --- a/test/lib/ffi/ffi_call.lua +++ b/test/lib/ffi/ffi_call.lua @@ -1,7 +1,7 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") local tonumber = tonumber @@ -73,39 +73,42 @@ double __stdcall stdcall_dd(double a, double b); float __stdcall stdcall_ff(float a, float b); ]] -local C = ffi.load("../clib/ctest") +local C = ffi.load("src/libctest.so") -assert(C.call_i(-42) == -41) -assert(C.call_ii(-42, 17) == -42+17) -assert(C.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) == -42+17+12345+9987-100+11+51+0x12345678+338-78901234) +do --- Basic FFI calls + assert(C.call_i(-42) == -41) + assert(C.call_ii(-42, 17) == -42+17) + assert(C.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) == -42+17+12345+9987-100+11+51+0x12345678+338-78901234) -assert(C.call_ie(123) == 124) + assert(C.call_ie(123) == 124) -assert(tonumber(C.call_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) -assert(tonumber(C.call_ij(-17, 0x123456789LL)) == tonumber(0x123456789LL-17)) -assert(tonumber(C.call_jj(-42, 17)) == -42+17) -assert(tonumber(C.call_jj(0x123456789abcdef0LL, -0x789abcde99887766LL)) == tonumber(0x123456789abcdef0LL-0x789abcde99887766LL)) + assert(tonumber(C.call_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) + assert(tonumber(C.call_ij(-17, 0x123456789LL)) == tonumber(0x123456789LL-17)) + assert(tonumber(C.call_jj(-42, 17)) == -42+17) + assert(tonumber(C.call_jj(0x123456789abcdef0LL, -0x789abcde99887766LL)) == tonumber(0x123456789abcdef0LL-0x789abcde99887766LL)) -assert(C.call_dd(12.5, -3.25) == 12.5-3.25) -assert(C.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) + assert(C.call_dd(12.5, -3.25) == 12.5-3.25) + assert(C.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) -assert(C.call_ff(12.5, -3.25) == 12.5-3.25) -assert(C.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75) + assert(C.call_ff(12.5, -3.25) == 12.5-3.25) + assert(C.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75) -assert(C.call_idifjd(-42, 17.125, 0x12345, -100.625, 12345678901234, -789012.75) == -42+17.125+0x12345-100.625+12345678901234-789012.75) + assert(C.call_idifjd(-42, 17.125, 0x12345, -100.625, 12345678901234, -789012.75) == -42+17.125+0x12345-100.625+12345678901234-789012.75) +end -do +do --- FFI calls and casts local a = ffi.new("int[10]", -42) assert(C.call_p_i(a) == -42+1) assert(tonumber(ffi.cast("intptr_t", C.call_p_p(a+3))) == tonumber(ffi.cast("intptr_t", a+4))) assert(C.call_pp_i(a+8, a+5) == 3) end --- vararg -assert(C.call_ividi(-42, ffi.new("int", 17), 12.5, ffi.new("int", 131)) == -42+17+12.5+131) +do --- vararg + assert(C.call_ividi(-42, ffi.new("int", 17), 12.5, ffi.new("int", 131)) == -42+17+12.5+131) +end --- complex -if pcall(function() return C.call_dd_cd end) then +do --- complex + if pcall(function() return C.call_dd_cd end) then do local c = C.call_dd_cd(12.5, -3.25) assert(c.re == 12.5 and c.im == -3.25*2) @@ -138,16 +141,16 @@ if pcall(function() return C.call_dd_cd end) then assert(cz.re == 12.5-17.125 and cz.im == -3.25+100.625) end end +end --- structs -do +do --- structs local s1 = ffi.new("s_ii", -42, 17) local sz = C.call_sii(s1) assert(s1.x == -42 and s1.y == 17) assert(sz.x == -42 and sz.y == 17) end -do +do --- 64-bit ints local s1 = ffi.new("s_jj", 0x123456789abcdef0LL, -0x789abcde99887766LL) local sz = C.call_sjj(s1) assert(s1.x == 0x123456789abcdef0LL) @@ -156,28 +159,28 @@ do assert(sz.y == -0x789abcde99887766LL) end -do +do --- more structs local s1 = ffi.new("s_ff", 12.5, -3.25) local sz = C.call_sff(s1) assert(s1.x == 12.5 and s1.y == -3.25) assert(sz.x == 12.5 and sz.y == -3.25) end -do +do --- even more structs local s1 = ffi.new("s_dd", 12.5, -3.25) local sz = C.call_sdd(s1) assert(s1.x == 12.5 and s1.y == -3.25) assert(sz.x == 12.5 and sz.y == -3.25) end -do +do --- complex structs local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) local sz = C.call_s8i(s1) assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678) assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678) end -do +do --- multiple structs passed and returned local s1 = ffi.new("s_ii", -42, 17) local s2 = ffi.new("s_ii", 0x12345, -98765) local sz = C.call_siisii(s1, s2) @@ -186,7 +189,7 @@ do assert(sz.x == -42+0x12345 and sz.y == 17-98765) end -do +do --- structs with floats local s1 = ffi.new("s_ff", 12.5, -3.25) local s2 = ffi.new("s_ff", -17.125, 100.625) local sz = C.call_sffsff(s1, s2) @@ -195,7 +198,7 @@ do assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) end -do +do --- structs with doubles local s1 = ffi.new("s_dd", 12.5, -3.25) local s2 = ffi.new("s_dd", -17.125, 100.625) local sz = C.call_sddsdd(s1, s2) @@ -204,7 +207,7 @@ do assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) end -do +do --- more large structs local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) local s2 = ffi.new("s_8i", 99, 311, 98765, -51, 312, 97, 17, 0x44332211) local sz = C.call_s8is8i(s1, s2) @@ -215,7 +218,7 @@ do assert(sz.h == 0x12345678+0x44332211) end -do +do --- many integer arguments local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) local sz = C.call_is8ii(19, s1, -51) assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678) @@ -224,43 +227,43 @@ do assert(sz.c == 12345-51) end --- target-specific -if jit.arch == "x86" then - assert(C.fastcall_void() == 1) - assert(C.fastcall_i(-42) == -41) - assert(C.fastcall_ii(-42, 17) == -42+17) - assert(C.fastcall_iii(-42, 17, 139) == -42+17+139) - assert(tonumber(C.fastcall_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) - assert(C.fastcall_dd(12.5, -3.25) == 12.5-3.25) - - do - local a = ffi.new("int[10]", -42) - assert(C.fastcall_pp_i(a+8, a+5) == 3) - end - - do - local s1 = ffi.new("s_ii", -42, 17) - local s2 = ffi.new("s_ii", 0x12345, -98765) - local sz = C.fastcall_siisii(s1, s2) - assert(s1.x == -42 and s1.y == 17) - assert(s2.x == 0x12345 and s2.y == -98765) - assert(sz.x == -42+0x12345 and sz.y == 17-98765) - end - - do - local s1 = ffi.new("s_dd", 12.5, -3.25) - local s2 = ffi.new("s_dd", -17.125, 100.625) - local sz = C.fastcall_sddsdd(s1, s2) - assert(s1.x == 12.5 and s1.y == -3.25) - assert(s2.x == -17.125 and s2.y == 100.625) - assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) - end - - if jit.os == "Windows" then - assert(C.stdcall_i(-42) == -41) - assert(C.stdcall_ii(-42, 17) == -42+17) - assert(C.stdcall_dd(12.5, -3.25) == 12.5-3.25) - assert(C.stdcall_ff(12.5, -3.25) == 12.5-3.25) +do --- target-specific – x86 + if jit.arch == "x86" then + assert(C.fastcall_void() == 1) + assert(C.fastcall_i(-42) == -41) + assert(C.fastcall_ii(-42, 17) == -42+17) + assert(C.fastcall_iii(-42, 17, 139) == -42+17+139) + assert(tonumber(C.fastcall_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) + assert(C.fastcall_dd(12.5, -3.25) == 12.5-3.25) + + do + local a = ffi.new("int[10]", -42) + assert(C.fastcall_pp_i(a+8, a+5) == 3) + end + + do + local s1 = ffi.new("s_ii", -42, 17) + local s2 = ffi.new("s_ii", 0x12345, -98765) + local sz = C.fastcall_siisii(s1, s2) + assert(s1.x == -42 and s1.y == 17) + assert(s2.x == 0x12345 and s2.y == -98765) + assert(sz.x == -42+0x12345 and sz.y == 17-98765) + end + + do + local s1 = ffi.new("s_dd", 12.5, -3.25) + local s2 = ffi.new("s_dd", -17.125, 100.625) + local sz = C.fastcall_sddsdd(s1, s2) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(s2.x == -17.125 and s2.y == 100.625) + assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) + end + + if jit.os == "Windows" then + assert(C.stdcall_i(-42) == -41) + assert(C.stdcall_ii(-42, 17) == -42+17) + assert(C.stdcall_dd(12.5, -3.25) == 12.5-3.25) + assert(C.stdcall_ff(12.5, -3.25) == 12.5-3.25) + end end end - diff --git a/test/lib/ffi/ffi_callback.lua b/test/lib/ffi/ffi_callback.lua index 1fd14bd..c6e531e 100644 --- a/test/lib/ffi/ffi_callback.lua +++ b/test/lib/ffi/ffi_callback.lua @@ -6,7 +6,7 @@ void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const uint8_t *, const uint8_t *)); ]] -do +do --- Functions that invoke FFI callbacks get blacklisted from being compiled local cb = ffi.cast("int (*)(int, int, int)", function(a, b, c) return a+b+c end) @@ -19,7 +19,7 @@ do end end -do +do --- Basic FFI callback assert(ffi.cast("int64_t (*)(int64_t, int64_t, int64_t)", function(a, b, c) return a+b+c end)(12345678901234567LL, 70000000000000001LL, 10000000909090904LL) == @@ -50,25 +50,27 @@ do -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) end --- Target-specific tests. -if jit.arch == "x86" then - assert(ffi.cast("__fastcall int (*)(int, int, int)", function(a, b, c) - return a+b+c - end)(10, 99, 13) == 122) - - assert(ffi.cast("__stdcall int (*)(int, int, int)", function(a, b, c) - return a+b+c - end)(10, 99, 13) == 122) - - -- Test reordering. - assert(ffi.cast("int64_t __fastcall (*)(int64_t, int, int)", function(a, b, c) - return a+b+c - end)(12345678901234567LL, 12345, 989797123) == - 12345678901234567LL+12345+989797123) +do --- X86 calling-convention tests + -- Target-specific tests. + if jit.arch == "x86" then + assert(ffi.cast("__fastcall int (*)(int, int, int)", function(a, b, c) + return a+b+c + end)(10, 99, 13) == 122) + + assert(ffi.cast("__stdcall int (*)(int, int, int)", function(a, b, c) + return a+b+c + end)(10, 99, 13) == 122) + + -- Test reordering. + assert(ffi.cast("int64_t __fastcall (*)(int64_t, int, int)", function(a, b, c) + return a+b+c + end)(12345678901234567LL, 12345, 989797123) == + 12345678901234567LL+12345+989797123) + end end -- Error handling. -do +do --- FFI callbacks can throw Lua errors local function f() return end -- Error for result conversion triggered here. @@ -84,7 +86,7 @@ do assert(pcall(ffi.cast("int (*)(int,int,int,int, int,int,int,int, int)", function() error("test") end), 1,1,1,1, 1,1,1,1, 1) == false) end -do +do --- Implicit conversions and callbacks local function cmp(pa, pb) local a, b = pa[0], pb[0] if a < b then @@ -102,28 +104,30 @@ do for i=0,254 do assert(arr[i] <= arr[i+1]) end end -if ffi.abi"win" then - ffi.cdef[[ - typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l); - int EnumWindows(WNDENUMPROC func, intptr_t l); - int SendMessageA(void *hwnd, uint32_t msg, int w, intptr_t l); - enum { WM_GETTEXT = 13 }; - ]] - - local C = ffi.C - local buf = ffi.new("char[?]", 256) - local lbuf = ffi.cast("intptr_t", buf) - local count = 0 - C.EnumWindows(function(hwnd, l) - if C.SendMessageA(hwnd, C.WM_GETTEXT, 255, lbuf) ~= 0 then - count = count + 1 - end - return true - end, 0) - assert(count > 10) +do --- FFI Windows tests + if ffi.abi"win" then + ffi.cdef[[ + typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l); + int EnumWindows(WNDENUMPROC func, intptr_t l); + int SendMessageA(void *hwnd, uint32_t msg, int w, intptr_t l); + enum { WM_GETTEXT = 13 }; + ]] + + local C = ffi.C + local buf = ffi.new("char[?]", 256) + local lbuf = ffi.cast("intptr_t", buf) + local count = 0 + C.EnumWindows(function(hwnd, l) + if C.SendMessageA(hwnd, C.WM_GETTEXT, 255, lbuf) ~= 0 then + count = count + 1 + end + return true + end, 0) + assert(count > 10) + end end -do +do --- FFI callback freeing local cb = ffi.cast("int(*)(void)", function() return 1 end) assert(cb() == 1) cb:free() @@ -136,7 +140,7 @@ do assert(cb() == 3) end -do +do --- Create and free many callbacks local ft = ffi.typeof("void(*)(void)") local function f() end local t = {} @@ -146,13 +150,15 @@ do end end -do +do --- FFI conversion from char to int assert(ffi.cast("int (*)()", function() return string.byte"A" end)() == 65) end -do +do --- FFI callbacks can be used as debug hooks + if false then local f = ffi.cast("void (*)(void)", function() debug.traceback() end) debug.sethook(function() debug.sethook(nil, "", 0); f() end, "", 1) local x + end end diff --git a/test/lib/ffi/ffi_const.lua b/test/lib/ffi/ffi_const.lua index d42133a..e4448e6 100644 --- a/test/lib/ffi/ffi_const.lua +++ b/test/lib/ffi/ffi_const.lua @@ -1,6 +1,7 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local fails = ffi_util.fails ffi.cdef[[ typedef struct s_t { @@ -9,7 +10,7 @@ typedef struct s_t { typedef const s_t cs_t; -typedef enum en_t { EE } en_t; +typedef enum en_t { EF } en_t; typedef struct pcs_t { int v; @@ -18,7 +19,7 @@ typedef struct pcs_t { typedef struct foo_t { static const int cc = 17; - enum { CC = -37 }; + enum { CD = -37 }; int i; const int ci; int bi:8; @@ -41,64 +42,69 @@ typedef struct foo_t { } foo_t; ]] -do - local foo_t = ffi.typeof("foo_t") - local x = foo_t() +local foo_t = ffi.typeof("foo_t") +local x = foo_t() - -- constval +do --- constval assert(x.cc == 17) fails(function(x) x.cc = 1 end, x) - assert(x.CC == -37) - fails(function(x) x.CC = 1 end, x) + assert(x.CD == -37) + fails(function(x) x.CD = 1 end, x) +end - -- fields +do --- fields x.i = 1 fails(function(x) x.ci = 1 end, x) x.e = 1 fails(function(x) x.ce = 1 end, x) +end - -- bitfields +do --- bitfields x.bi = 1 fails(function(x) x.cbi = 1 end, x) +end - -- arrays - do - local a = ffi.new("int[10]") - a[0] = 1 - local ca = ffi.new("const int[10]") - fails(function(ca) ca[0] = 1 end, ca) - end +do --- arrays + local a = ffi.new("int[10]") + a[0] = 1 + local ca = ffi.new("const int[10]") + fails(function(ca) ca[0] = 1 end, ca) +end + +do --- assignment to consts fails x.a[0] = 1 fails(function(x) x.ca[0] = 1 end, x) fails(function(x) x.a = x.ca end, x) -- incompatible type fails(function(x) x.ca = x.a end, x) fails(function(x) x.ca = {} end, x) fails(function(x) x.cac = "abc" end, x) +end - -- structs - do - local s = ffi.new("s_t") - s.v = 1 - local cs = ffi.new("cs_t") - fails(function(cs) cs.v = 1 end, cs) - end +do --- structs + local s = ffi.new("s_t") + s.v = 1 + local cs = ffi.new("cs_t") + fails(function(cs) cs.v = 1 end, cs) x.s.v = 1 fails(function(x) x.cs.v = 1 end, x) x.s = x.cs fails(function(x) x.cs = x.s end, x) fails(function(x) x.cs = {} end, x) +end - -- pseudo-const structs +do --- pseudo-const structs x.pcs1.v = 1 fails(function(x) x.pcs1.w = 1 end, x) fails(function(x) x.pcs1 = x.pcs2 end, x) fails(function(x) x.pcs1 = {} end, x) +end - -- transparent structs +do --- transparent structs local y = x.ni fails(function(x) x.ni = 1 end, x) +end - -- complex subtype is implicitly const and doesn't inherit const attribute +do --- complex subtype is implicitly const and doesn't inherit const attribute x.cx = 1 fails(function(x) x.ccx = 1 end, x) do diff --git a/test/lib/ffi/ffi_convert.lua b/test/lib/ffi/ffi_convert.lua index bd3fb1f..84ce7df 100644 --- a/test/lib/ffi/ffi_convert.lua +++ b/test/lib/ffi/ffi_convert.lua @@ -2,7 +2,8 @@ local ffi = require("ffi") local ctest = require("ctest") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local fails = ffi_util.fails local tonumber = tonumber @@ -32,15 +33,15 @@ typedef struct arrinc_t { int a[]; } arrinc_t; -typedef enum uenum_t { +typedef enum uenum_t_ { UE0, UE71 = 71, UE72 -} uenum_t; +} uenum_t_; typedef enum ienum_t { IE0, IEM12 = -12, IEM11 } ienum_t; -typedef struct foo_t { +typedef struct baz_t { bool b; int8_t i8; uint8_t u8; @@ -79,9 +80,9 @@ typedef struct foo_t { int si_guard; nest_t sn; uni_t ui; - uenum_t ue; + uenum_t_ ue; ienum_t ie; -} foo_t; +} baz_t; char *strcpy(char *dest, const char *src); typedef struct FILE FILE; @@ -89,21 +90,23 @@ int fileno(FILE *stream); int _fileno(FILE *stream); ]] -do - local foo_t = ffi.typeof("foo_t") - local sz = ffi.sizeof(foo_t) - local x = foo_t() - local y = foo_t() - ffi.fill(x, sz, 0xff) - ffi.fill(y, sz, 0xee) +local baz_t = ffi.typeof("baz_t") +local sz = ffi.sizeof(baz_t) +local x = baz_t() +local y = baz_t() +ffi.fill(x, sz, 0xff) +ffi.fill(y, sz, 0xee) - -- unknown member +do --- unknown member fails(function(x) local a = x.bad end, x) fails(function(x) x.bad = 1 end, x) - -- too many initializers +end + +do --- too many initializers fails(function(x) x.d = ffi.new("double", 1,2) end, x) +end - -- conversions to bool +do --- conversions to bool x.b = false assert(x.b == false) x.b = true @@ -123,8 +126,9 @@ do assert(x.b == true) x.b = ffi.new("int32_t", 0) assert(x.b == false) +end - -- conversions from bool +do --- conversions from bool x.i32 = true assert(x.i32 == 1) x.i32 = false @@ -137,13 +141,16 @@ do assert(x.d == 1) x.d = ffi.new("bool", false) assert(x.d == 0) - -- assignment of bool to other types is not allowed +end + +do --- assignment of bool to other types is not allowed fails(function(x) x.cd = true end, x) fails(function(x) x.v4si = true end, x) fails(function(x) x.ai = true end, x) fails(function(x) x.s = true end, x) +end - -- int to int conversions +do --- int to int conversions x.i8 = 99 assert(x.i8 == 99) x.i8 = -99 @@ -299,8 +306,9 @@ do assert(tonumber(x.u64) == 0xffeeddcc) x.u64 = ffi.new("int64_t", -0x7feeddcc*2^32) assert(tonumber(x.u64) == 2^64-0x7feeddcc*2^32) +end - -- FP to int conversions, test for truncation +do --- FP to int conversions, test for truncation x.i32 = 1.9 assert(x.i32 == 1) x.i32 = 2.9 @@ -321,13 +329,16 @@ do assert(x.u32 == 1) x.u64 = 1.9 assert(tonumber(x.u64) == 1) +end - -- int to FP conversions (most tested above) +do --- int to FP conversions (most tested above) x.f = ffi.new("int32_t", -17) assert(x.f == -17) x.d = ffi.new("int32_t", -17) assert(x.d == -17) - -- test for rounding due to precision loss +end + +do --- test for rounding due to precision loss x.f = -1717986919 assert(x.f == -1717986944) x.f = ffi.new("int32_t", 0x77777777) @@ -335,16 +346,20 @@ do x.d = ffi.new("union { uint32_t u32[2]; uint64_t u64; }", {{ 0x77777777, 0x77777777}}).u64 assert(x.d == 0x77777777*2^32 + 0x77777800) +end - -- complex initialization +do --- complex initialization x.cd = ffi.new("complex", 9.125, -78.5) assert(x.cd.re == 9.125 and x.cd.im == -78.5) x.cd = ffi.new("complex", {9.125, -78.5}) assert(x.cd.re == 9.125 and x.cd.im == -78.5) - -- too many initializers +end + +do --- too many initializers for complex fails(function(x) x.cd = ffi.new("complex", 1,2,3) end, x) +end - -- conversions between FP and complex +do --- conversions between FP and complex x.cf = -17.25 assert(x.cf.re == -17.25 and x.cf.im == 0) x.cf = ffi.new("complex float", -57.5) -- missing initializer @@ -372,25 +387,29 @@ do assert(x.d == 9.125) x.d = ffi.new("complex double", 9.125, -78.5) assert(x.d == 9.125) +end - -- conversions between int and complex +do --- conversions between int and complex x.cd = ffi.new("int32_t", -138) assert(x.cd.re == -138 and x.cd.im == 0) x.i32 = ffi.new("complex", 9.125, -78.5) assert(x.i32 == 9) +end - -- vector initialization +do --- vector initialization x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1, 2, 3, 4) assert(x.v4si[0] == 1 and x.v4si[1] == 2 and x.v4si[2] == 3 and x.v4si[3] == 4) x.v2df = ffi.new("double __attribute__((mode(__V2DF__)))", {3.5, -6.75}) - assert(x.v2df[0] == 3.5 and x.v2df[1] == -6.75) - -- too many initializers +end + +do --- too many initializers for vector fails(function(x) x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1,2,3,4,5) end, x) +end - -- conversions to vectors +do --- conversions to vectors x.v4si = -17 assert(x.v4si[0] == -17 and x.v4si[1] == -17 and x.v4si[2] == -17 and x.v4si[3] == -17) @@ -401,14 +420,16 @@ do assert(x.v2df[0] == 12.5 and x.v2df[1] == 12.5) x.v2df = ffi.new("complex", 9.125, -78.5) assert(x.v2df[0] == 9.125 and x.v2df[1] == 9.125) +end - -- assignment of same-sized but differently-typed vectors +do --- assignment of same-sized but differently-typed vectors x.v16qi = 99 x.v4si = 0x33333333 x.v16qi = x.v4si assert(x.v16qi[0] == 0x33 and x.v16qi[15] == 0x33) +end - -- string converted to enum +do --- string converted to enum -- x.ue = -1 -- this is undefined on some architectures -- assert(x.ue == 0xffffffff) x.ue = "UE0" @@ -417,52 +438,65 @@ do assert(x.ue == 72) x.ie = -1 assert(x.ie == -1) - x.ie = "IE0" - assert(x.ie == 0) x.ie = "IEM11" assert(x.ie == -11) + x.ie = "IE0" + assert(x.ie == 0) x.pi = x.pi - -- assignment to pointer with higher qualifiers is ok +end + +do --- assignment to pointer with higher qualifiers is ok x.pci = x.pi x.pvi = x.pi - -- assignment to pointer with lower qualifiers is not ok +end + +do --- assignment to pointer with lower qualifiers is not ok fails(function(x) x.pi = x.pci end, x) fails(function(x) x.pi = x.pvi end, x) fails(function(x) x.pci = x.pvi end, x) fails(function(x) x.pvi = x.pci end, x) - -- assignment of pointers with incompatible child types is not ok +end + +do --- assignment of pointers with incompatible child types is not ok fails(function(x) x.ppi = x.ai end, x) fails(function(x) x.ppi = x.pi end, x) fails(function(x) x.ppv = x.ppi end, x) - -- qualifiers of child types must match, higher qualifiers not ok +end + +do --- qualifiers of child types must match, higher qualifiers not ok fails(function(x) x.ppci = x.ppi end, x) fails(function(x) x.ppi = x.ppci end, x) +end - -- pointer/int conversions are not allowed by default +do --- pointer/int conversions are not allowed by default fails(function(x) x.pi = 1 end, x) fails(function(x) x.i32 = x.pi end, x) assert(tonumber(x.pi) == nil) assert(tonumber(x.ai) == nil) assert(tonumber(x.si) == nil) +end - -- but pointer/int casts are allowed +do --- but pointer/int casts are allowed x.pi = ffi.cast("int *", ffi.new("int32_t", 0x12345678)) x.i32 = ffi.cast("int32_t", x.pi) assert(x.i32 == 0x12345678) x.pi = ffi.cast("int *", 1234560.3) x.i32 = ffi.cast("int32_t", x.pi) - assert(x.i32 == 1234560) - -- bad cast from non-TValue double to pointer +end + +do --- bad cast from non-TValue double to pointer fails(function(x) ffi.cast("int *", ffi.new("double", 1.5)) end, x) +end - -- nil sets a pointer to NULL +do --- nil sets a pointer to NULL x.pi = nil assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0) +end - -- userdata and lightuserdata are treated as void * +do --- userdata and lightuserdata are treated as void * do local u = newproxy() local uaddr = _G.tonumber(string.match(tostring(u), "(0x.*)")) @@ -471,8 +505,9 @@ do x.pi = ctest.lightud(12345678) assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 12345678) end +end - -- io.* file converts to file handle (as a void *) +do --- io.* file converts to file handle (as a void *) if ffi.abi("win") then assert(ffi.C._fileno(io.stdout) == 1) assert(ffi.C._fileno(io.stderr) == 2) @@ -486,8 +521,9 @@ do for i=1,100 do x = ffi.C.fileno(io.stderr) end assert(x == 2) end +end - -- truncation/extension of __ptr32 +do --- truncation/extension of __ptr32 if ffi.abi("64bit") then x.pi = ffi.cast("int *", 15*2^32+0x12345678) assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 15*2^32+0x12345678) @@ -497,8 +533,9 @@ do x.pi = x.p32i assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0x12345678) end +end - -- reference initialization +do --- reference initialization do x.ai[0] = 712 local ri = ffi.new("int &", x.ai) @@ -506,24 +543,29 @@ do local ra = ffi.new("int (&)[10]", ffi.cast("int (*)[10]", x.ai)) assert(ra[0] == 712) end +end - -- ffi.sizeof follows references +do --- ffi.sizeof follows references assert(ffi.sizeof(x.ai) == 4*10) -- ffi.offsetof follows references assert(ffi.offsetof(x.s, "v") == 0) assert(ffi.offsetof(x.s, "w") == 4) +end - -- ffi.fill writes the right amount +do --- ffi.fill writes the right amount ffi.fill(x.ai2, ffi.sizeof(x.ai2), 0x72) ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13) assert(x.ai[0] == 0x13131313) assert(x.ai[9] == 0x13131313) assert(x.ai2[0] == 0x72727272) assert(x.ai2[9] == 0x72727272) +end - -- array cannot be assigned a pointer +do --- array cannot be assigned a pointer fails(function(x) x.ai = x.pi end, x) - -- but pointer can be assigned the address of an array +end + +do --- but pointer can be assigned the address of an array x.pi = x.ai2 assert(x.pi[0] == 0x72727272) assert(x.pi[9] == 0x72727272) @@ -536,7 +578,9 @@ do -- reflected via pointer, too assert(x.pi[0] == 0x72727272) assert(x.pi[9] == 0x72727272) - -- mismatched type or size in array copy +end + +do --- mismatched type or size in array copy fails(function(x) x.ai = x.ac end, x) fails(function(x) x.ai = ffi.new("int[20]") end, x) fails(function(x) x.ai = ffi.new("arrinc_t").a end, x) @@ -547,10 +591,13 @@ do x.s.w = 0x789abcde assert(x.s.v == 0x12345678) assert(x.s.w == 0x789abcde) +end - -- struct cannot be assigned a pointer +do --- struct cannot be assigned a pointer fails(function(x) x.s = x.ps end, x) - -- but pointer can be assigned the address of a struct +end + +do --- but pointer can be assigned the address of a struct x.ps = x.s assert(x.ps.v == 0x12345678) assert(x.ps.w == 0x789abcde) @@ -563,12 +610,14 @@ do -- reflected via pointer, too assert(x.ps.v == 0x59595959) assert(x.ps.w == 0x59595959) +end - -- structs must be identical, structural equivalence is not enough +do --- structs must be identical, structural equivalence is not enough fails(function(x) x.ps = x.sx end, x) fails(function(x) x.s = x.sx end, x) +end - -- string copy to arrays +do --- string copy to arrays x.ac_guard = 99 ffi.fill(x.ac, 10, 0x37) x.ac = "ABCD" @@ -584,27 +633,30 @@ do assert(x.ac[9] == 65+9) x.ac = "ABCDEFGHIJKLM" assert(x.ac[8] == 65+8) - assert(x.ac[9] == 65+9) - do -- copy to a[?] - local vx = ffi.new("struct { char ac[?]; }", 20) - ffi.fill(vx.ac, 20, 0x37) - vx.ac = "ABCDEFGHI" - assert(vx.ac[8] == 65+8) - assert(vx.ac[9] == 0) - end - do -- copy to a[0] - local vx = ffi.new("union { char ac[0]; char c[20]; }") - ffi.fill(vx.ac, 20, 0x37) - vx.ac = "ABCDEFGHI" - assert(vx.ac[8] == 65+8) - assert(vx.ac[9] == 0) - end - -- mismatched type or size in string copy - fails(function(x) x.i32 = "ABCD" end, x) - fails(function(x) x.ai = "ABCD" end, x) - assert(x.ac_guard == 99) -- Check guard +end + +do --- copy to a[?] + local vx = ffi.new("struct { char ac[?]; }", 20) + ffi.fill(vx.ac, 20, 0x37) + vx.ac = "ABCDEFGHI" + assert(vx.ac[8] == 65+8) + assert(vx.ac[9] == 0) +end +do --- copy to a[0] + local vx = ffi.new("union { char ac[0]; char c[20]; }") + ffi.fill(vx.ac, 20, 0x37) + vx.ac = "ABCDEFGHI" + assert(vx.ac[8] == 65+8) + assert(vx.ac[9] == 0) +end + +do --- mismatched type or size in string copy +fails(function(x) x.i32 = "ABCD" end, x) +fails(function(x) x.ai = "ABCD" end, x) +assert(x.ac_guard == 99) -- Check guard +end - -- array initialization +do --- array initialization x.ai = ffi.new("int[10]") -- zero fill for i=0,9 do assert(x.ai[i] == 0) end x.ai = ffi.new("int[10]", -67) -- replicate first element @@ -617,25 +669,28 @@ do for i=0,9 do assert(x.ai[i] == i+1) end x.ai = ffi.new("int[10]", {1,2,3,4,5,6,7,8,9,10}) for i=0,9 do assert(x.ai[i] == i+1) end - -- VLA initialization - do - local v = ffi.new("int[?]", 4) - for i=0,3 do assert(v[i] == 0) end - local v = ffi.new("int[?]", 4, 833) - for i=0,3 do assert(v[i] == 833) end - local v = ffi.new("int[?]", 4, 12, -9) - assert(v[0] == 12 and v[1] == -9 and v[2] == 0 and v[3] == 0) - local v = ffi.new("int[?]", 4, 1,2,3,4) - assert(v[0] == 1 and v[1] == 2 and v[2] == 3 and v[3] == 4) - end - -- too many initializers +end + +do --- VLA initialization + local v = ffi.new("int[?]", 4) + for i=0,3 do assert(v[i] == 0) end + local v = ffi.new("int[?]", 4, 833) + for i=0,3 do assert(v[i] == 833) end + local v = ffi.new("int[?]", 4, 12, -9) + assert(v[0] == 12 and v[1] == -9 and v[2] == 0 and v[3] == 0) + local v = ffi.new("int[?]", 4, 1,2,3,4) + assert(v[0] == 1 and v[1] == 2 and v[2] == 3 and v[3] == 4) +end + +do --- too many initializers fails(function(x) x.ai = {1,2,3,4,5,6,7,8,9,10,11} end, x) for i=0,9 do assert(x.ai[i] == i+1) end -- but it's partially executed fails(function(x) local v = ffi.new("int[?]", 4, 1,2,3,4,5) end, x) +end - -- struct initialization +do --- struct initialization x.sn = ffi.new("nest_t") -- zero fill assert(x.sn.e.e2 == 0) x.sn = ffi.new("nest_t", 1,2) -- remainder filled with zero @@ -650,27 +705,32 @@ do assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4) assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6) assert(x.sn.f[0] == 7 and x.sn.f[1] == 8) - -- VLS initialization - do - local v = ffi.new("struct { int x; int a[?]; }", 4) - assert(v.x == 0) - for i=0,3 do assert(v.a[i] == 0) end - local v = ffi.new("struct { int x; int a[?]; }", 4, 9, {833}) - assert(v.x == 9) - -- NYI: fill up VLA in VLS. currently seen as indefinite length - -- for i=0,3 do assert(v.a[i] == 833) end - assert(v.a[0] == 833 and v.a[1] == 0 and v.a[2] == 0 and v.a[3] == 0) - end - -- no multi-value init beyond first level +end + +do --- VLS initialization + local v = ffi.new("struct { int x; int a[?]; }", 4) + assert(v.x == 0) + for i=0,3 do assert(v.a[i] == 0) end + local v = ffi.new("struct { int x; int a[?]; }", 4, 9, {833}) + assert(v.x == 9) + -- NYI: fill up VLA in VLS. currently seen as indefinite length + -- for i=0,3 do assert(v.a[i] == 833) end + assert(v.a[0] == 833 and v.a[1] == 0 and v.a[2] == 0 and v.a[3] == 0) +end + +do --- no multi-value init beyond first level fails(function(x) x.sn = ffi.new("nest_t", 1,2,3,4,5,6,7,8) end, x) - -- too many initializers +end + +do --- too many initializers fails(function(x) x.sn = ffi.new("nest_t", 1,2,3,4,{5,6},{7,8}, 9) end, x) +end - -- union initialization +do --- union initialization x.ui = ffi.new("uni_t") -- zero fill assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0) x.ui = ffi.new("uni_t", 255) -- initialize first field, remainder is zero @@ -679,15 +739,18 @@ do else assert(x.ui.a == -1 and x.ui.b == -256 and x.ui.c == -16777216) end - -- too many initializers +end + +do --- too many initializers fails(function(x) x.sn = ffi.new("uni_t", 1,2) end, x) fails(function() ffi.new("union { struct { int x; }; int y; }", 1,2) end) +end - -- table converted to array +do --- table converted to array ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13) x.ai_guard = 99 x.ai = {} -- zero fill @@ -701,8 +764,9 @@ do assert(x.ai[1] == -27) for i=2,9 do assert(x.ai[i] == 0) end assert(x.ai_guard == 99) -- Check guard +end - -- table converted to struct +do --- table converted to struct ffi.fill(x.si, ffi.sizeof(x.si), 0x74) x.si_guard = 97 -- convert from array part @@ -724,8 +788,9 @@ do x.si = {b = 12, 5, 6, 7} -- hash part ignored if array part exists assert(x.si.a == 5 and x.si.b == 6 and x.si.c == 7) assert(x.si_guard == 97) -- Check guard +end - -- table converted to struct with transparent/nested structs and arrays +do --- table converted to struct with transparent/nested structs and arrays ffi.fill(x.sn, ffi.sizeof(x.sn), 0x74) x.sn = {} -- zero fill assert(x.sn.e.e2 == 0) @@ -737,8 +802,9 @@ do assert(x.sn.a == 0 and x.sn.b == 0 and x.sn.c == 10 and x.sn.d == 0) assert(x.sn.e.e1 == 11 and x.sn.e.e2 == 12) assert(x.sn.f[0] == 13 and x.sn.f[1] == 14) +end - -- table converted to union +do --- table converted to union ffi.fill(x.ui, ffi.sizeof(x.ui), 0x58) x.ui = {} -- zero fill assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0) @@ -754,22 +820,22 @@ do else assert(x.ui.a == -1 and x.ui.b == -1 and x.ui.c == -65536) end +end - -- copy constructor - do - x.s.v = 1; x.s.w = 2 - local s = ffi.new("bar_t", x.s) - assert(s.v == 1 and s.w == 2) - for i=0,9 do x.ai[i] = i end - local a = ffi.new("int[10]", x.ai) - for i=0,9 do assert(a[i] == i) end - end +do --- copy constructor + x.s.v = 1; x.s.w = 2 + local s = ffi.new("bar_t", x.s) + assert(s.v == 1 and s.w == 2) + for i=0,9 do x.ai[i] = i end + local a = ffi.new("int[10]", x.ai) + for i=0,9 do assert(a[i] == i) end +end - -- assignment to function pointer +do --- assignment to function pointer x.ppf = ffi.C.strcpy end -do +do --- FFI GC collectgarbage() local oc = collectgarbage("count") local cd = ffi.new"struct { struct { int a; } x;}" @@ -785,3 +851,9 @@ do end end +do --- FFI gcstep recursive + local stream = io.open("lib/ffi/ffi_gcstep_recursive.lua", "r") + local func = assert(load(function(x) stream:read('*all') end)) + func() +end + diff --git a/test/lib/ffi/ffi_enum.lua b/test/lib/ffi/ffi_enum.lua index e8e40ad..cbfc25c 100644 --- a/test/lib/ffi/ffi_enum.lua +++ b/test/lib/ffi/ffi_enum.lua @@ -1,8 +1,8 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") - +local ffi_util = require("common.ffi_util") +local fails = ffi_util.fails ffi.cdef[[ typedef enum enum_i { FOO_I = -1, II = 10 } enum_i; typedef enum enum_u { FOO_U = 1, UU = 10 } enum_u; @@ -13,9 +13,9 @@ int call_i_ei(enum_i a) asm("call_i"); int call_i_eu(enum_u a) asm("call_i"); ]] -local C = ffi.load("../clib/ctest") +local C = ffi.load("src/libctest.so") -do +do --- Enum comparison to strings and integers local t = ffi.new("enum_i[100]") for i=0,99 do t[i] = "II" end @@ -42,16 +42,17 @@ do for i=0,99 do assert(t[i] ~= u[i]) end end -do +do --- Enum comparison to strings for i=0,99 do assert(C.call_ei_i(9) == "II") end for i=0,99 do assert(C.call_eu_i(9) == "UU") end for i=0,99 do assert(C.call_i_ei("II") == 11) end for i=0,99 do assert(C.call_i_eu("UU") == 11) end end -do +do --- FFI callbacks returning enums local f = ffi.cast("bool (*)(enum_i)", function(e) return e == "II" end) assert(f("II")) assert(not f(0)) + f:free() end diff --git a/test/lib/ffi/ffi_jit_arith.lua b/test/lib/ffi/ffi_jit_arith.lua index 0554fe6..6a0ba19 100644 --- a/test/lib/ffi/ffi_jit_arith.lua +++ b/test/lib/ffi/ffi_jit_arith.lua @@ -1,6 +1,6 @@ local ffi = require("ffi") -do +do --- Test FFI compilation local a = ffi.new("int64_t[?]", 101) for i=1,100 do a[i] = -2 end for i=1,100 do a[i] = i end @@ -29,7 +29,7 @@ do assert(w == 5050) end -do +do --- More FFI compilation tests local a = ffi.new("uint64_t[?]", 101) for i=1,100 do a[i] = i end local x, y, m = 0ull, 0ull, 0ull @@ -48,32 +48,32 @@ do assert(z == 0x123456789abcdef0ull % 100) end -do +do --- Test JITing of the bit library local x = 0ll for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ll) end assert(x == 262120) end -do +do --- More bit library tests local x, a = 0ll, -2ll for i=1,100 do x = x + a ^ (bit.band(i, 15)+1ll) end assert(x == 262120) end -do +do --- Still more bit library tests local x = 0ull for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ull) end assert(x == 262120) end -do +do --- Even more bitwise jitting test for i=1,200 do local j = bit.band(i, 7); assert((j == 0ll) == (j == 0)) end for i=1,200 do assert((i < 100ll) == (i < 100)) end for i=1,200 do assert((i <= 100ll) == (i <= 100)) end for i=-100,100 do assert((i > 100ull) == (i < 0)) end end -do +do --- FFI array compilation local a = ffi.new("int64_t[?]", 100) for i=0,99 do a[i] = math.random(0, 2^32)*0x100000000LL + math.random(0, 2^32) @@ -121,13 +121,13 @@ do end end -do +do --- Pointer arithmetic doesn't crash local a, b = ffi.new("char *"), ffi.new("char *") local z for i=1,100 do z = a-b end end -do +do --- comparisons between char pointers and Lua strings local x = true local abc = ffi.cast("const char *", "abc") for i=1,100 do x = abc == "abc" end @@ -142,8 +142,7 @@ do assert(x == false) end --- ra_destpair -do +do --- ra_destpair local x, y = 0, 0 for i=1,100 do x = x + i/3LL diff --git a/test/lib/ffi/ffi_jit_call.lua b/test/lib/ffi/ffi_jit_call.lua index b79d60b..aac2771 100644 --- a/test/lib/ffi/ffi_jit_call.lua +++ b/test/lib/ffi/ffi_jit_call.lua @@ -35,9 +35,9 @@ double __stdcall stdcall_dd(double a, double b); float __stdcall stdcall_ff(float a, float b); ]] -local lib = ffi.load("../clib/ctest") +local lib = ffi.load("./ctest.so") -do +do --- Basic calls local x for i=1,100 do x = lib.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) @@ -45,12 +45,13 @@ do assert(x == -42+17+12345+9987-100+11+51+0x12345678+338-78901234) end -do +do --- More basic calls for i=1,100 do pcall(lib.call_max, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i) end end +do --- 64-bit only if ffi.abi("64bit") then local y = ffi.cast("void *", 0x123456789abcdefLL) local x @@ -60,8 +61,9 @@ if ffi.abi("64bit") then end assert(x == 0) end +end -do +do --- Calls with 64-bit integers local x = 0 for i=1,100 do x = x + lib.call_ij(100+i, i*0x300000002LL) @@ -69,7 +71,7 @@ do assert(x == 0x3b2e0000623eLL) end -do +do --- Calls with floating-point numbers local x for i=1,100 do x = lib.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) @@ -77,7 +79,7 @@ do assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) end -do +do --- More floating-point numbers local x for i=1,100 do x = lib.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) @@ -85,7 +87,7 @@ do assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75) end -do +do --- More FFI calls local x for i=-100,100 do if not lib.call_b(i) then x = i end @@ -100,14 +102,14 @@ do assert(x == 90) end -do +do --- FFI tail calls local function tail(x) return lib.call_b(x) end for i=1,100 do local a,b,c = tail(1), tail(1), tail(1) end end -do +do --- FFI narrowing conversions local x = 0 for i=0x01010080,0x010100ff do x = x + lib.call_i_i8(i) end assert(x == -8128) @@ -134,7 +136,7 @@ do assert(x == 8380480) end --- target-specific +do --- target-specific if jit.arch == "x86" then for i=1,100 do assert(lib.fastcall_i(-42) == -41) end for i=1,100 do assert(lib.fastcall_ii(-42, 17) == -42+17) end @@ -151,4 +153,5 @@ if jit.arch == "x86" then for i=1,100 do assert(lib.stdcall_ff(12.5, -3.25) == 12.5-3.25) end end end +end diff --git a/test/lib/ffi/ffi_jit_conv.lua b/test/lib/ffi/ffi_jit_conv.lua index d4707db..08b8d50 100644 --- a/test/lib/ffi/ffi_jit_conv.lua +++ b/test/lib/ffi/ffi_jit_conv.lua @@ -2,7 +2,7 @@ local ffi = require("ffi") local ctest = require("ctest") -do +do --- FFI narrowing local s = ffi.new("struct { int32_t x; }") s.x = -0x12345678 for i=1,100 do @@ -11,7 +11,7 @@ do assert(s.x == -0x12345678+100) end -do +do --- Conversions between uint32_t and Lua numbers local s = ffi.new("struct { uint32_t x; }") s.x = 0x81234567 for i=1,100 do @@ -20,7 +20,7 @@ do assert(s.x == 0x81234567+100) end -do +do --- Conversions between integers and int8_t local s = ffi.new("struct { int8_t x; }") s.x = 42 for i=1,100 do @@ -30,7 +30,7 @@ do assert(s.x == 142-256) end -do +do --- Conversions between integers and uint8_t local s = ffi.new("struct { uint8_t x; }") s.x = 200 for i=1,100 do @@ -40,7 +40,7 @@ do assert(s.x == 300-256) end -do +do --- Conversions between integers and int16_t local s = ffi.new("struct { int16_t x; }") s.x = 32700 for i=1,100 do @@ -50,7 +50,7 @@ do assert(s.x == 32800-65536) end -do +do --- Conversions between integers and uint16_t local s = ffi.new("struct { uint16_t x; }") s.x = 65450 for i=1,100 do @@ -60,7 +60,7 @@ do assert(s.x == 65550-65536) end -do +do --- Conversions between numbers, integers, and uint32_t local s = ffi.new("union { int32_t x; uint32_t y; }") s.x = 0x7fffffff - 60 local x,y = 0,0 @@ -75,7 +75,7 @@ do assert(x == y - 40*2^32) end -do +do --- Conversions between integers and uint32_t local s = ffi.new("union { int32_t x; uint32_t y; }") local x, z = 0, 2^31 + 42 for i=1,100 do @@ -85,7 +85,7 @@ do assert(x == 100*(-2^31 + 42)) end -do +do --- fwd -> CONV.int.i8, CONV.num.int, CONV.int.u8 local s = ffi.new("union { int8_t x; uint8_t y; }") s.x = 42 local x,y = 0,0 @@ -100,7 +100,7 @@ do assert(x == y - (100-(127-42))*256) end -do +do --- FOLD TOBIT + CONV.num.u32 local a = ffi.new("uint32_t[?]", 101) for i=1,100 do a[i] = 0x80000000+i end local x = 0 @@ -110,7 +110,7 @@ do assert(x == 100) end -do +do --- FOLD TOBIT + CONV.num.u32 local a = ffi.new("uint32_t[?]", 101) for i=1,100 do a[i] = 0x80000000+i end local x = 0 @@ -120,7 +120,7 @@ do assert(x == -0x80000000+100) end -do +do --- CONV.num.flt local v = ffi.new("float", 12.5) local x = 0 for i=1,100 do @@ -129,7 +129,7 @@ do assert(x == 100*12.5) end -do +do --- CONV.num.u32 local v = ffi.new("uint32_t", 0x80000000) local x = 0 for i=1,100 do @@ -138,7 +138,7 @@ do assert(x == 100*0x80000000) end -do +do --- CONV.num.i64 local v = ffi.new("int64_t", 0x1234567800000000ll) local x = 0 for i=1,100 do @@ -147,7 +147,7 @@ do assert(x == 100*0x12345678*2^32) end -do +do --- CONV.num.u64 local v = ffi.new("uint64_t", 0x89abcdef00000000ull) local x = 0 for i=1,100 do @@ -156,7 +156,7 @@ do assert(x == 100*0x89abcdef*2^32) end -do +do --- CONV.num.i64 local a = ffi.new("int64_t[?]", 101) for i=1,100 do a[i] = -i end local x = 0 @@ -166,7 +166,7 @@ do assert(x == -5050) end -do +do --- CONV.num.u64 local a = ffi.new("uint64_t[?]", 101) for i=1,100 do a[i] = 2^63+2^32*i end local x = 0 @@ -176,7 +176,7 @@ do assert(x == 2^63*100+2^32*5050) end -do +do --- Conversions between complex and other types local v = ffi.new("complex", 12.5, -3.25) local x = 0 for i=1,100 do @@ -185,7 +185,7 @@ do assert(x == 100*12.5) end -do +do --- int64_t conversions local s = ffi.new("struct { int64_t x;}") for i=1,100 do s.x = 0x123456789abcdef0LL @@ -193,7 +193,7 @@ do assert(tonumber(s.x) == tonumber(0x123456789abcdef0LL)) end -do +do --- uint64_t conversions local s = ffi.new("struct { uint64_t x;}") for i=1,100 do s.x = 0x823456789abcdef0ULL @@ -201,7 +201,7 @@ do assert(tonumber(s.x) == tonumber(0x823456789abcdef0ULL)) end -do +do --- FFI enum conversions ffi.cdef[[ typedef enum { AA, BB, CC = -42 } foo_i; typedef enum { DD, EE, FF = 0x80000000u } foo_u; @@ -229,7 +229,7 @@ do assert(x == -42) end -do +do --- Conversions between strings and const char * local s = ffi.new("struct { const char *x; const char *y;}") local a, tmp = "abcd", "ab" for i=1,100 do @@ -240,7 +240,7 @@ do assert(ffi.string(s.y) == "ab") end -do +do --- Conversions between int, bool, and double local s = ffi.new("struct { bool b[200]; int i[200]; double d[200];}") for i=0,199 do s.i[i] = i-100; s.d[i] = i-100 end for i=0,99 do s.b[i] = 0 end @@ -253,13 +253,13 @@ do for i=0,199 do assert(s.b[i] == (i ~= 100)) end end -do +do --- Conversions involving int16_t local a = ffi.new("int16_t[100]", 1) for i=1,99 do a[i] = a[i] + a[i-1] end assert(a[99] == 100) end -do +do --- Casting between light userdata, void*, and uintptr_t local ud = ctest.lightud(12345678) local s = ffi.new("struct { void *p; }") for i=1,100 do @@ -269,7 +269,7 @@ do assert(ffi.cast("uintptr_t", s.p) == 12345678) end -do +do --- FFI reference conversions local x = ffi.new("struct { int & x;}", ffi.new("int[1]", 42)) local z for i=1,100 do z = x.x end diff --git a/test/lib/ffi/ffi_lex_number.lua b/test/lib/ffi/ffi_lex_number.lua index e26650e..7281746 100644 --- a/test/lib/ffi/ffi_lex_number.lua +++ b/test/lib/ffi/ffi_lex_number.lua @@ -1,7 +1,6 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") - +local ffi_util = require("common.ffi_util") local function checklex(t) for i=1,1e9,2 do local s = t[i+1] @@ -13,7 +12,7 @@ local function checklex(t) end end end - +do --- FFI C parser lexes numbers correctly checklex{ "0LL", "0ll", "0LL", "0LL", @@ -37,7 +36,7 @@ checklex{ "0-0i", "-0i", } -checkfail({ +ffi_util.checkfail({ "0l", "0lll", "0u", @@ -48,4 +47,5 @@ checkfail({ ".0ll", "0ii", }, function(s) assert(loadstring("return "..s)) end) +end diff --git a/test/lib/ffi/ffi_metatype.lua b/test/lib/ffi/ffi_metatype.lua index 2db717f..04daf99 100644 --- a/test/lib/ffi/ffi_metatype.lua +++ b/test/lib/ffi/ffi_metatype.lua @@ -1,6 +1,8 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") + +local fails = ffi_util.fails ffi.cdef[[ typedef struct { int x; } idx1_t; @@ -14,8 +16,11 @@ local function ptreq(a, b) return ffi.cast("void *", a) == ffi.cast("void *", b) end -do - local nidx = {} +local cs +local s +local nidx = {} + +do --- FFI metatypes can only be set once local tp = ffi.metatype("idx1_t", { __index = { foo = 99, method = function(c, v) return v end }, __newindex = nidx, @@ -23,29 +28,33 @@ do fails(function() ffi.metatype("idx1_t", {}) end) - local s = tp(1234) + s = tp(1234) assert(s.foo == 99) assert(s.x == 1234) - -- bad field in __index metatable +end + +do --- bad field in __index metatable fails(function(s) local x = s.bar end, s) assert(s:method(123) == 123) s.bar = 42 assert(nidx.bar == 42) +end - local cs = ffi.new("const idx1_t", 9876) +do --- write to const struct + cs = ffi.new("const idx1_t", 9876) assert(cs.foo == 99) assert(cs.x == 9876) - -- write to const struct fails(function(cs) cs.bar = 42 end, cs) +end +do --- write to const struct pointer local cp = ffi.new("const idx1_t *", cs) assert(cp.foo == 99) assert(cp.x == 9876) - -- write to const struct pointer fails(function(cp) cp.bar = 42 end, cp) end -do +do --- misc FFI metatables local uc, uk, uv local tp = ffi.metatype("idx2_t", { __index = function(c, k, x, y) @@ -78,7 +87,7 @@ do fails(function(p) p[0] = 11 end, p) end -do +do --- more misc FFI metatype stuff local uc, uk, uv local ti, tn = {}, {} local tp = ffi.metatype("idx3_t", { @@ -103,7 +112,7 @@ do uc, uk, uv = nil, nil, nil end -do +do --- FFI arithmatic metamethods local tp tp = ffi.metatype("arith_t", { __add = function(a, b) return tp(a.x+b.x, a.y+b.y) end, @@ -174,7 +183,7 @@ do assert(x == 3000) end -do +do --- ffi.gc works local count = 0 local tp = ffi.metatype("gc_t", { __gc = function(x) count = count + 1 end, @@ -206,7 +215,7 @@ do assert(count == 103) end -do +do --- FFI metatable index works local tp = ffi.metatype([[ struct { static const int Z42 = 42; @@ -236,10 +245,9 @@ struct { assert(o.x == 5) end -do +do --- FFI structs can be used as __index tables local fb = ffi.new("struct { int x; }", 99) local xt = ffi.metatype("struct { }", { __index = fb }) local o = xt() assert(o.x == 99) end - diff --git a/test/lib/ffi/ffi_new.lua b/test/lib/ffi/ffi_new.lua index 9cdbd53..f9a1127 100644 --- a/test/lib/ffi/ffi_new.lua +++ b/test/lib/ffi/ffi_new.lua @@ -1,7 +1,7 @@ local ffi = require("ffi") local bit = require("bit") - -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local fails = ffi_util.fails ffi.cdef([[ typedef struct { int a,b,c; } foo1_t; @@ -10,7 +10,7 @@ void *malloc(size_t size); void free(void *ptr); ]]) -do +do --- FFI new test 1 assert(ffi.sizeof("foo1_t") == 12) local cd = ffi.new("foo1_t") assert(ffi.sizeof(cd) == 12) @@ -20,7 +20,7 @@ do assert(ffi.sizeof(cd) == 12) end -do +do --- FFI new test 2 assert(ffi.sizeof("foo2_t", 3) == 12) local cd = ffi.new("foo2_t", 3) assert(ffi.sizeof(cd) == 12) @@ -31,7 +31,7 @@ do assert(ffi.sizeof(cd) == 12) end -do +do --- FFI new test 3 local tpi = ffi.typeof("int") local tpb = ffi.typeof("uint8_t") local t = {} @@ -42,7 +42,7 @@ do assert(x == 199*257 + 1) end -do +do --- FFI alignment test local oc = collectgarbage("count") for al=0,15 do local align = 2^al -- 1, 2, 4, ..., 32768 @@ -57,14 +57,14 @@ do assert(nc < oc + 3000, "GC step missing for ffi.new") end -do +do --- FFI new of variable-sized array local t = {} for i=1,100 do t[i] = ffi.new("int[?]", i) end assert(ffi.sizeof(t[100]) == 400) for i=0,99 do assert(t[100][i] == 0) end end -do +do --- FFI new of variable-sized array in struct local t = {} local ct = ffi.typeof("struct { double x; int y[?];}") for i=1,100 do t[i] = ct(i) end @@ -72,7 +72,7 @@ do for i=0,99 do assert(t[100].y[i] == 0) end end -do +do --- FFI alignment test 2 local ct = ffi.typeof("struct __attribute__((aligned(16))) { int x; }") local y for i=1,200 do @@ -82,7 +82,7 @@ do assert(bit.band(ffi.cast("intptr_t", ffi.cast("void *", y)), 15) == 0) end -do +do --- FFI GC test local q local p = ffi.gc(ffi.new("int[1]"), function(x) q = x end) p = nil @@ -93,13 +93,13 @@ do assert(q == nil) end -do +do --- FFI GC test 2 local p = ffi.gc(ffi.C.malloc(2^20), ffi.C.free) p = nil collectgarbage() end -do +do --- lua_close can cleanup cdata correctly local p = ffi.gc(ffi.new("int[1]"), function(x) assert(type(x) == "cdata") end) -- test for lua_close() cleanup. end diff --git a/test/lib/ffi/ffi_parse_array.lua b/test/lib/ffi/ffi_parse_array.lua index 3a9616d..6ae634f 100644 --- a/test/lib/ffi/ffi_parse_array.lua +++ b/test/lib/ffi/ffi_parse_array.lua @@ -1,75 +1,81 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local P = ffi.sizeof("void *") -checkfail{ - "int [", - "int [-1]", - "int [[1]]", - "int [10][]", - "int [10][?]", - "int [][]", - "int [][?]", - "int [?][]", - "int [?][?]", - "int [0x10000][0x2000]", - "int [256][256][256][256]", - "int [10](void)", - "int (void)[10]", - "int &[10]", - "union { double x; int a[?]; }", -} +do --- FFI parse errors + ffi_util.checkfail{ + "int [", + "int [-1]", + "int [[1]]", + "int [10][]", + "int [10][?]", + "int [][]", + "int [][?]", + "int [?][]", + "int [?][?]", + "int [0x10000][0x2000]", + "int [256][256][256][256]", + "int [10](void)", + "int (void)[10]", + "int &[10]", + "union { double x; int a[?]; }", + } +end -ffi.cdef([[ - typedef int foo1_t[10]; - typedef foo1_t foo2_t[5]; -]]) -assert(ffi.sizeof("foo1_t") == 40) -assert(ffi.sizeof("foo2_t") == 200) +do --- FFI array typedef sizeof + ffi.cdef([[ + typedef int foo1_t_[10]; + typedef foo1_t_ foo2_t_[5]; + ]]) + assert(ffi.sizeof("foo1_t_") == 40) + assert(ffi.sizeof("foo2_t_") == 200) +end -local P = ffi.sizeof("void *") -checktypes{ - 10, 1, "char [10]", - 4*10, 4, "int [10]", - 4*10, 4, "int [10]", - 4*10*5, 4, "int [10][5]", - 4*10*5*3*2*7, 4, "int [10][5][3][2][7]", - 4*10*5, 4, "int ([10])[5]", - P*10, P, "int *[10]", - P, P, "int (*)[10]", - P*5, P, "int (*[5])[10]", - 8*10, 4, "struct { int x; char y; } [10]", - P*5*10, P, "volatile int *(* const *[5][10])(void)", - nil, 4, "int []", - 4*10, 8, "int __attribute__((aligned(8))) [10]", - 4*10, 8, "__attribute__((aligned(8))) int [10]", - 4*10, 8, "int [10] __attribute__((aligned(8)))", - 97, 1, "char ['a']", - 83, 1, "char ['\\123']", - 79, 1, "char ['\x4F']", - 5, 1, "char [sizeof(\"aa\" \"bb\")]", - 80, 8, "double [10]", -} +do --- FFI array parsing + ffi_util.checktypes{ + 10, 1, "char [10]", + 4*10, 4, "int [10]", + 4*10, 4, "int [10]", + 4*10*5, 4, "int [10][5]", + 4*10*5*3*2*7, 4, "int [10][5][3][2][7]", + 4*10*5, 4, "int ([10])[5]", + P*10, P, "int *[10]", + P, P, "int (*)[10]", + P*5, P, "int (*[5])[10]", + 8*10, 4, "struct { int x; char y; } [10]", + P*5*10, P, "volatile int *(* const *[5][10])(void)", + nil, 4, "int []", + 4*10, 8, "int __attribute__((aligned(8))) [10]", + 4*10, 8, "__attribute__((aligned(8))) int [10]", + 4*10, 8, "int [10] __attribute__((aligned(8)))", + 97, 1, "char ['a']", + 83, 1, "char ['\\123']", + 79, 1, "char ['\x4F']", + 5, 1, "char [sizeof(\"aa\" \"bb\")]", + 80, 8, "double [10]", + } +end -do +do --- FFI sizeof and typeof for arrays assert(ffi.sizeof("int [?]", 10) == 4*10) local id = ffi.typeof("const short [?]") assert(ffi.sizeof(id, 10) == 2*10) assert(ffi.sizeof(id, 0) == 0*10) - fails(ffi.sizeof, id) + ffi_util.fails(ffi.sizeof, id) assert(ffi.sizeof(id, -1) == nil) assert(ffi.sizeof(id, 0x80000000) == nil) assert(ffi.sizeof(id, 0x40000000) == nil) assert(ffi.sizeof(id, 0x3fffffff) == 2*0x3fffffff) end -do +do --- More ffi sizeof and typeof for arrays assert(ffi.sizeof("struct { double x; int a[?]; }", 10) == 8+4*10) local id = ffi.typeof("struct { int x; short a[?]; }") assert(ffi.sizeof(id, 10) == 4+2*10) assert(ffi.sizeof(id, 0) == 4+0*10) - fails(ffi.sizeof, id) + ffi_util.fails(ffi.sizeof, id) assert(ffi.sizeof(id, -1) == nil) assert(ffi.sizeof(id, 0x80000000) == nil) assert(ffi.sizeof(id, 0x40000000) == nil) diff --git a/test/lib/ffi/ffi_parse_basic.lua b/test/lib/ffi/ffi_parse_basic.lua index c054bcf..1d37449 100644 --- a/test/lib/ffi/ffi_parse_basic.lua +++ b/test/lib/ffi/ffi_parse_basic.lua @@ -1,7 +1,12 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local checkfail, checktypes = ffi_util.checkfail, ffi_util.checktypes +local L = (ffi.abi("32bit") or ffi.abi("win")) and 4 or 8 +local P = ffi.abi("32bit") and 4 or 8 +local W = ffi.abi("win") and 2 or 4 +do --- FFI syntax errors checkfail{ "", " ", @@ -32,8 +37,10 @@ checkfail{ "int double", "int;", } +end -checktypes{ +do --- FFI comments and sizeof(char) +ffi_util.checktypes{ 1, 1, "char", 1, 1, " \n\r\t\vchar \n\r\t\v", 1, 1, "ch\\\nar", @@ -41,7 +48,9 @@ checktypes{ 1, 1, "char /* abc */ const", 1, 1, "char // abc\n const", } +end +do --- properties of primitive types checktypes{ nil, 1, "void", 1, 1, "bool", @@ -68,8 +77,9 @@ checktypes{ 16, 8, "_Complex", 16, 8, "_Complex double", } +end --- mode/vector_size attributes +do --- mode/vector_size attributes checktypes{ 1, 1, "int __attribute__((mode(QI)))", 2, 2, "int __attribute__((mode(HI)))", @@ -87,12 +97,9 @@ checktypes{ 32, 16, "double __attribute__((vector_size(32)))", 64, 16, "double __attribute__((vector_size(64)))", } +end --- ABI-specific types: -local L = (ffi.abi("32bit") or ffi.abi("win")) and 4 or 8 -local P = ffi.abi("32bit") and 4 or 8 -local W = ffi.abi("win") and 2 or 4 - +do --- Properties of integer and pointer types checktypes{ L, L, "long", L, L, "signed long", @@ -101,10 +108,12 @@ checktypes{ P, P, "int **", 4, 4, "int * __ptr32", } +end +do --- Properties of stdint.h types checktypes{ - P, P, "ptrdiff_t", P, P, "size_t", + P, P, "ptrdiff_t" , W, W, "wchar_t", 1, 1, "int8_t", 2, 2, "int16_t", @@ -117,7 +126,9 @@ checktypes{ P, P, "intptr_t", P, P, "uintptr_t", } +end +do --- Attributes dictating alignment checktypes{ 1, 8, "char __attribute__((aligned(8)))", 1, 8, "char __attribute((aligned(8)))", @@ -128,4 +139,5 @@ checktypes{ 1, 2, "char __attribute__((aligned(8))) const __attribute__((aligned(2)))", 1, 16, "char __attribute__((aligned(8))) const __attribute__((aligned(16)))", } +end diff --git a/test/lib/ffi/ffi_parse_cdef.lua b/test/lib/ffi/ffi_parse_cdef.lua index 4bb5d90..67cf8f1 100644 --- a/test/lib/ffi/ffi_parse_cdef.lua +++ b/test/lib/ffi/ffi_parse_cdef.lua @@ -1,7 +1,10 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local checkfail, checktypes, fails = + ffi_util.checkfail, ffi_util.checktypes, ffi_util.fails +do --- Invalid FFI declarations rejected checkfail({ "int", "int aa1; int aa2 ", @@ -12,7 +15,9 @@ checkfail({ "struct { static int x = 1; };", ";;static int y" }, ffi.cdef) +end +do --- FFI const definitions ffi.cdef[[ static const int K_42a = 42; static const char K_42b = 42+256; @@ -22,7 +27,9 @@ static const int K_1b = 0xffffffff >> 31; static const int K_1c = 0xffffffffu >> 31; static const int K_M1b = (int)0xffffffff >> 31; ]] +end +do --- Arrays with size given by consts checktypes{ 42, 1, "char[K_42a]", 42, 1, "char[K_42b]", @@ -32,7 +39,9 @@ checktypes{ 1, 1, "char[K_1c]", 1, 1, "char[-K_M1b]", } +end +do --- Static consts in structs ffi.cdef[[ struct str1 { enum { @@ -41,7 +50,9 @@ struct str1 { static const int K_55 = 55; } extk; ]] +end +do --- Constant expression evaluation works checktypes{ 99, 1, "char[K_99]", 99, 1, "char[extk.K_99]", @@ -49,11 +60,15 @@ checktypes{ 99, 1, "char[((struct str1 *)0)->K_99]", 55, 1, "char[extk.K_55]", } +end +do --- Static consts in structs do not have global scope checkfail{ "char[K_55]", } +end +do --- Inline function definitions ignored ffi.cdef[[ extern int func1(void); extern int func2(); @@ -69,9 +84,11 @@ static inline int func4(int n) } ;;; ]] +end +do --- Extern variables ffi.cdef[[ int ext1; extern int ext2; ]] - +end diff --git a/test/lib/ffi/ffi_parse_struct.lua b/test/lib/ffi/ffi_parse_struct.lua index 16a3d05..b4d036b 100644 --- a/test/lib/ffi/ffi_parse_struct.lua +++ b/test/lib/ffi/ffi_parse_struct.lua @@ -1,7 +1,13 @@ local ffi = require("ffi") -dofile("../common/ffi_util.inc") +local ffi_util = require("common.ffi_util") +local checkfail, checktypes, fails = + ffi_util.checkfail, ffi_util.checktypes, ffi_util.fails +local P = ffi.sizeof("void *") +local A = (ffi.arch == "x86" and not ffi.abi("win")) and 4 or 8 + +do --- Invalid FFI declarations rejected checkfail{ "struct", "struct {", @@ -22,30 +28,31 @@ checkfail{ "union { int x(void); }", "union recursive1 { union recursive1 { } x; }", } +end -- NYI: rollback doesn't recover struct state -- ffi.cdef("struct zzz") -- fails(ffi.cdef, "struct zzz { int") -- ffi.cdef("struct zzz { int x; }") -ffi.cdef("struct foo; typedef struct foo foo_t;") -assert(ffi.sizeof("struct foo") == nil) -assert(ffi.sizeof("foo_t") == nil) -ffi.cdef("struct foo { int x,y; };") -assert(ffi.sizeof("struct foo") == 8) -assert(ffi.sizeof("foo_t") == 8) -assert(ffi.sizeof(ffi.typeof("struct foo")) == 8) -assert(ffi.sizeof(ffi.typeof("foo_t")) == 8) -ffi.cdef("struct foo;") -fails(ffi.cdef, "struct foo {};") -fails(ffi.cdef, "union foo;") -fails(ffi.cdef, "union foo {};") -fails(ffi.cdef, "enum foo;") -fails(ffi.cdef, "enum foo { ZZZ1 };") - -local P = ffi.sizeof("void *") -local A = (ffi.arch == "x86" and not ffi.abi("win")) and 4 or 8 +do --- FFI sizeof on opaque types +ffi.cdef("struct $; typedef struct $ foo_t_;", 'foo_', 'foo_') +assert(ffi.sizeof("struct foo_") == nil) +assert(ffi.sizeof("foo_t_") == nil) +ffi.cdef("struct foo_ { int x,y; };") +assert(ffi.sizeof("struct foo_") == 8) +assert(ffi.sizeof("foo_t_") == 8) +assert(ffi.sizeof(ffi.typeof("struct foo_")) == 8) +assert(ffi.sizeof(ffi.typeof("foo_t_")) == 8) +ffi.cdef("struct foo_;") +fails(ffi.cdef, "struct foo_ {};") +fails(ffi.cdef, "union foo_;") +fails(ffi.cdef, "union foo_ {};") +fails(ffi.cdef, "enum foo_;") +fails(ffi.cdef, "enum foo_ { ZZZ1 };") +end +do --- FFI struct alignof and sizeof checktypes{ 0, 1, "struct {}", 1, 1, "struct { char x; }", @@ -59,9 +66,9 @@ checktypes{ P*4, P, "struct { char x,*y,**z,a,b,c,d; }", 64, 4, "struct { struct { struct { struct { int x,y; } a,b; } a,b; } a,b; }", 4, 4, "struct { struct { struct { struct { int x; }; }; }; }", - 8, 4, "struct { struct foo; }", - 8, 4, "struct { foo_t; }", - 8, 8, "struct __attribute__((aligned(sizeof(foo_t)))) { int a; }", + 8, 4, "struct { struct foo_ q; }", + 8, 4, "struct { foo_t_ q; }", + 8, 8, "struct __attribute__((aligned(sizeof(foo_t_)))) { int a; }", 6, 2, "struct { char a; char x; short y; char z; char c; }", 10, 2, "struct { char a; struct { char x; short y; char z; } b; char c; }", 8, A, "struct { double a; }", @@ -77,7 +84,9 @@ checktypes{ 16, 16, "struct { float __attribute__((vector_size(16))) a; }", 32, 16, "struct { int a; float __attribute__((vector_size(16))) b; }", } +end +do --- FFI union size and alignment checktypes{ 0, 1, "union {}", 1, 1, "union { char x; }", @@ -106,8 +115,9 @@ checktypes{ 16, 16, "union { float __attribute__((vector_size(16))) a; }", 16, 16, "union { int a; float __attribute__((vector_size(16))) b; }", } +end -do +do --- FFI offsetof local ct ct = ffi.typeof("struct { int a; char b; short c; int d; }") assert(ffi.offsetof(ct, "a") == 0) @@ -129,6 +139,7 @@ do assert(ffi.offsetof(ct, "b") == A) end +do --- Invalid FFI declarations rejected checkfail{ "struct { int :; }", "struct { int a:; }", @@ -144,7 +155,9 @@ checkfail{ "struct { int a[2]:2; }", "struct { void a:2; }", } +end +do --- FFI bitfield size and alignment checktypes{ 4, 4, "struct { unsigned a:1; }", 4, 4, "struct { unsigned a:1, b:1, c:1; }", @@ -163,6 +176,7 @@ checktypes{ 1, 1, "struct { char a:1; _Bool b:1; }", 1, 1, "struct { char a:1; signed char b:1; unsigned char c:1; }", } +end -- NYI: bit fields > 32 bit -- local L = ffi.alignof("struct { long long a; }") @@ -170,7 +184,7 @@ checktypes{ -- L, L, "struct { long long a:1; }", -- } --- Bit field packing. +do --- Bit field packing. checktypes{ 1, 1, "struct { _Bool a:1, b:1, c:1; }", 4, 4, "struct { short a:9; int b:9; char c; }", @@ -197,8 +211,9 @@ checktypes{ 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))); }", 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))) __attribute((packed)); }", } +end -do +do --- #pragma pack ffi.cdef[[ struct foo_packorig { char a; int b; short c; }; #pragma pack(1) @@ -236,7 +251,7 @@ do assert(ffi.sizeof("struct foo_packpop2") == 12) end -do +do --- Alignment attributes ffi.cdef[[ #pragma pack(2) struct foo_packalign8 { diff --git a/test/lib/ffi/ffi_tabov.lua b/test/lib/ffi/ffi_tabov.lua index ba62196..fff3cd2 100644 --- a/test/lib/ffi/ffi_tabov.lua +++ b/test/lib/ffi/ffi_tabov.lua @@ -2,6 +2,7 @@ local ffi = require("ffi") local last = 0 +do --- FFI table overflow assert(pcall(function() for i=1,65536 do last = i @@ -10,3 +11,5 @@ assert(pcall(function() end) == false) assert(last > 20000) +collectgarbage() +end diff --git a/test/lib/ffi/index b/test/lib/ffi/index index 59e36dd..6727113 100644 --- a/test/lib/ffi/index +++ b/test/lib/ffi/index @@ -10,3 +10,20 @@ jit_struct.lua meta_tostring.lua redir.lua type_punning.lua +ffi_bitfield.lua +ffi +ffi_arith_ptr.lua +ffi +ffi_callback.lua +ffi +ffi_jit_arith.lua +ffi +ffi_call.lua +ffi +ffi_const.lua +ffi +ffi_convert.lua +ffi +ffi_enum.lua +ffi +ffi_jit_conv.lua +ffi +ffi_lex_number.lua +ffi +ffi_metatype.lua +ffi +ffi_new.lua +ffi +ffi_parse_array.lua +ffi +ffi_parse_basic.lua +ffi +ffi_jit_call.lua +ffi +ffi_parse_struct.lua +ffi +ffi_parse_cdef.lua +ffi diff --git a/test/misc/alias_alloc.lua b/test/misc/alias_alloc.lua index 02fe618..94d46a4 100644 --- a/test/misc/alias_alloc.lua +++ b/test/misc/alias_alloc.lua @@ -1,5 +1,5 @@ -do +do --- Alias analysis 1 local t = {1} local x for i=1,100 do @@ -10,7 +10,7 @@ do assert(x == 100 and t[1] == 100) end -do +do --- Alias analysis 2 local t = {1} local x,y for i=1,100 do @@ -22,7 +22,7 @@ do assert(x == 100 and y == 101) end -do +do --- Alias analysis 3 local mt = {} local t = setmetatable({}, mt) local x @@ -33,16 +33,14 @@ do end end --- See also sink_alloc.lua -do +do --- See also sink_alloc.lua local x,k={1,2},{3,4} for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end assert(x[1] == 301) assert(x[2] == 402) end --- FLOAD for tab.asize/tab.array crossing NEWREF. -do +do --- FLOAD for tab.asize/tab.array crossing NEWREF. local t = {1} for i=1,100 do local v = {} diff --git a/test/misc/api_call.lua b/test/misc/api_call.lua index 7dbd5e4..a5712c7 100644 --- a/test/misc/api_call.lua +++ b/test/misc/api_call.lua @@ -57,19 +57,10 @@ local function test_adjust_results(testfunc) ck(cc(-1, retva, 1, 2), 1, 2) end -test_adjust_results(ctest.call) -test_adjust_results(ctest.pcall_err) - - local function gcshrink() for i=1,10 do collectgarbage() end end -assert(select('#', ctest.call(2000, gcshrink)) == 2000) -gcshrink() -assert(select('#', ctest.call(7000, gcshrink)) == 7000) -gcshrink() - local function test_yield(resume, yield) local function inpcall() ck(pack(yield(6, 7)), 18, 19) @@ -91,8 +82,24 @@ local function test_yield(resume, yield) assert(resume(co) == false) end -test_yield(coroutine.resume, coroutine.yield) -test_yield(ctest.resume, coroutine.yield) -test_yield(coroutine.resume, ctest.yield) -test_yield(ctest.resume, ctest.yield) + +do --- C API call 1 + test_adjust_results(ctest.call) + test_adjust_results(ctest.pcall_err) +end + + +do --- C API functions + assert(select('#', ctest.call(2000, gcshrink)) == 2000) + gcshrink() + assert(select('#', ctest.call(7000, gcshrink)) == 7000) + gcshrink() +end + +do --- C API and coroutines + test_yield(coroutine.resume, coroutine.yield) + test_yield(ctest.resume, coroutine.yield) + test_yield(coroutine.resume, ctest.yield) + test_yield(ctest.resume, ctest.yield) +end diff --git a/test/misc/catch_wrap.lua b/test/misc/catch_wrap.lua index 7f656bc..d03f5a1 100644 --- a/test/misc/catch_wrap.lua +++ b/test/misc/catch_wrap.lua @@ -1,31 +1,31 @@ local cp = require("cpptest") cp.wrapon() +local unwind -do +do --- C API wrap 1 local a, b = pcall(cp.catch, function() return "x" end) assert(a == true and b == "x") end -do +do --- C API wrap 2 local a, b = pcall(function() cp.throw("foo") end) assert(a == false and b == "foo") end -local unwind -do +do --- C API wrap 3 local a, b = pcall(cp.catch, function() cp.throw("foo") end) unwind = a assert((a == false and b == "foo") or (a == true and b == "catch ...")) end -do +do --- C API wrap 4 local st = cp.alloc(function() return cp.isalloc() end) assert(st == true) assert(cp.isalloc() == false) end -do +do --- C API wrap 5 local a, b = pcall(cp.alloc, function() assert(cp.isalloc() == true) return "foo", cp.throw @@ -34,7 +34,7 @@ do assert(cp.isalloc() == false) end -do +do --- C API wrap 6 local a, b = pcall(cp.alloc, function() assert(cp.isalloc() == true) return "foo", error @@ -43,3 +43,6 @@ do if unwind then assert(cp.isalloc() == false) end end +do --- C API unwrap + cp.wrapoff() +end diff --git a/test/misc/coro_traceback.lua b/test/misc/coro_traceback.lua index 2676d2c..8453da5 100644 --- a/test/misc/coro_traceback.lua +++ b/test/misc/coro_traceback.lua @@ -1,8 +1,9 @@ - -local co = coroutine.create(function() - local x = nil - local y = x.x -end) -assert(coroutine.resume(co) == false) -debug.traceback(co) +do --- debug.traceback doesn't crash on a dead coroutine + local co = coroutine.create(function() + local x = nil + local y = x.x + end) + assert(coroutine.resume(co) == false) + debug.traceback(co) +end diff --git a/test/misc/coro_yield.lua b/test/misc/coro_yield.lua index ae3206e..0d066ee 100644 --- a/test/misc/coro_yield.lua +++ b/test/misc/coro_yield.lua @@ -3,8 +3,7 @@ local wrap = coroutine.wrap local resume = coroutine.resume local yield = coroutine.yield --- Test stack overflow handling on return from coroutine. -do +do --- Test stack overflow handling on return from coroutine 1. wrap(function() local co = create(function() yield(string.byte(string.rep(" ", 100), 1, 100)) @@ -13,7 +12,7 @@ do end)() end -do +do --- Coroutine yield test 1 wrap(function() local f = wrap(function() yield(string.byte(string.rep(" ", 100), 1, 100)) @@ -22,7 +21,7 @@ do end)() end -do +do --- Coroutine yield test 2 local function cogen(x) return wrap(function(n) repeat x = x+n; n = yield(x) until false end), wrap(function(n) repeat x = x*n; n = yield(x) until false end) @@ -33,7 +32,7 @@ do assert(d(b(c(a(d(b(c(a(1)))))))) == 168428160) end -do +do --- Coroutine yield test 3 local function verify(what, expect, ...) local got = {...} for i=1,100 do @@ -59,7 +58,7 @@ do verify("resume end", { true, "end" }, resume(co, "again")) end -do +do --- Coroutine yield test 4 local function verify(expect, func, ...) local co = create(func) for i=1,100 do diff --git a/test/test.lua b/test/test.lua index b064eff..d2aea07 100644 --- a/test/test.lua +++ b/test/test.lua @@ -7,6 +7,9 @@ local dirsep = package.config:match"^(.-)\n" local own_file = debug.getinfo(1, "S").source:match"^@(.*)" or arg[0] local own_dir = own_file:match("^.*[/".. dirsep .."]") +local ctest = require("ctest") +local cpptest = require("cpptest") + local function default_tags() local tags = {} @@ -178,6 +181,7 @@ end local function scan_tests(path, opts) if path:sub(-4, -4) == "." then + assert(path:sub(-4, -1) == ".lua") local f = assert(io_open(path, "rb")) local contents = f:read"*a" f:close() @@ -297,8 +301,11 @@ local function append_tree_to_plan(test_tree, opts, plan, prefix) end local function seal_globals() + compat52 = table.pack and true or false local sealed_mt = {__newindex = function() error("Tests should not mutate global state", 3) + end, __index = function(x, y) + --print(("Tests should not use undefined globals %q%q"):format(x, y)) end} local function seal(t) if getmetatable(t) then return end @@ -405,8 +412,8 @@ local opts = parse_args{...} if not opts then return end -seal_globals() check_package_path() +seal_globals() local test_tree = scan_tests(opts.root or own_dir or "", opts) local plan = append_tree_to_plan(test_tree, opts, {}, "") plan = mutate_plan(plan, opts)