Skip to content

Commit ee032e7

Browse files
committed
tests/lapi: add table tests
The patch adds a fuzzing tests for Lua table functions except the the function `table.unpack`, it will be tested by `builtin_unpack_test.lua`.
1 parent ab5eb92 commit ee032e7

12 files changed

+401
-0
lines changed

.luacheckrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,13 @@ files["tests/capi/luaL_loadbuffer_proto/preamble.lua"] = {
55
"211",
66
},
77
}
8+
9+
-- The new function introduced in the Lua 5.5, it is not yet
10+
-- supported by the luacheck, see [1].
11+
--
12+
-- 1. https://github.com/lunarmodules/luacheck/issues/132
13+
globals = {
14+
table = {
15+
fields = { "create" }
16+
}
17+
}

tests/lapi/lib.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,23 @@ local function err_handler(ignored_msgs)
105105
end
106106
end
107107

108+
local function is_nan(v)
109+
return v ~= v
110+
end
111+
112+
local function arrays_equal(t1, t2)
113+
for i = 1, #t1 do
114+
if t1[i] ~= t2[i] and
115+
not (is_nan(t1[i]) and is_nan(t2[i])) then
116+
return false
117+
end
118+
end
119+
return #t1 == #t2
120+
end
121+
108122
return {
109123
approx_equal = approx_equal,
124+
arrays_equal = arrays_equal,
110125
bitwise_op = bitwise_op,
111126
err_handler = err_handler,
112127
lua_current_version_ge_than = lua_current_version_ge_than,

tests/lapi/table_concat_test.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--[=[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
5.5 – Table Manipulation,
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Infinite loop on table lookup,
9+
https://github.com/LuaJIT/LuaJIT/issues/494
10+
11+
Synopsis: table.concat(list [, sep [, i [, j]]])
12+
--]=]
13+
14+
local luzer = require("luzer")
15+
local test_lib = require("lib")
16+
17+
local function TestOneInput(buf, _size)
18+
local fdp = luzer.FuzzedDataProvider(buf)
19+
local str = fdp:consume_string(test_lib.MAX_STR_LEN)
20+
local tbl_size = #str
21+
if tbl_size == 0 then return -1 end
22+
23+
-- Split string to a table.
24+
local tbl = {}
25+
str:gsub(".", function(c)
26+
table.insert(tbl, c)
27+
end)
28+
assert(#tbl == tbl_size)
29+
30+
-- Join table to a string.
31+
local j = fdp:consume_integer(1, tbl_size)
32+
local i = fdp:consume_integer(1, j)
33+
local sep = ""
34+
assert(string.sub(str, i, j) == table.concat(tbl, sep, i, j))
35+
end
36+
37+
local args = {
38+
artifact_prefix = "table_concat_",
39+
}
40+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_create_test.lua

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
Bad lookup generated by lj_record_idx in GC64,
6+
https://github.com/LuaJIT/LuaJIT/issues/840
7+
8+
Synopsis:
9+
LuaJIT: table.new(narray, nhash)
10+
PUC Rio Lua: table.create(narray, nhash)
11+
]]
12+
13+
local luzer = require("luzer")
14+
local test_lib = require("lib")
15+
16+
local table_create
17+
if test_lib.lua_version() == "LuaJIT" then
18+
table_create = require("table.new")
19+
elseif test_lib.lua_current_version_ge_than(5, 5) then
20+
-- New function 'table.create()' in PUC Rio Lua,
21+
-- https://github.com/lua/lua/commit/3e9dbe143d3338f5f13a5e421ea593adff482da0
22+
table_create = table.create
23+
else
24+
print("Unsupported version.")
25+
os.exit(0)
26+
end
27+
28+
local function TestOneInput(buf)
29+
local fdp = luzer.FuzzedDataProvider(buf)
30+
-- Beware, huge number triggers OOM or table overflow.
31+
local MAX_N = 1000
32+
local narray = fdp:consume_integer(0, MAX_N)
33+
local nhash = fdp:consume_integer(0, MAX_N)
34+
local _ = table_create(narray, nhash) -- luacheck: no unused
35+
end
36+
37+
local args = {
38+
artifact_prefix = "table_create_",
39+
}
40+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_foreach_test.lua

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
5.4 – Table Manipulation,
6+
https://www.lua.org/manual/5.0/manual.html#5.4
7+
8+
Bad loop initialization in table.foreach(),
9+
https://github.com/LuaJIT/LuaJIT/issues/844
10+
11+
string.dump(table.foreach) will trigger an assert,
12+
https://github.com/LuaJIT/LuaJIT/issues/1038
13+
14+
Synopsis: table.foreach(table, f)
15+
]]
16+
17+
local luzer = require("luzer")
18+
local test_lib = require("lib")
19+
20+
-- Function `table.foreach` is deprecated in Lua 5.1.
21+
if test_lib.lua_current_version_ge_than(5, 2) then
22+
print("Unsupported version.")
23+
os.exit(0)
24+
end
25+
26+
local function TestOneInput(buf, _size)
27+
local fdp = luzer.FuzzedDataProvider(buf)
28+
local count = fdp:consume_integer(1, test_lib.MAX_INT)
29+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
30+
local i = 0
31+
local fn = function(_idx, _v) i = i + 1 end
32+
table.foreach(tbl, fn)
33+
assert(#tbl == i)
34+
end
35+
36+
local args = {
37+
artifact_prefix = "table_foreach_",
38+
}
39+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_foreachi_test.lua

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
5.4 – Table Manipulation,
6+
https://www.lua.org/manual/5.0/manual.html#5.4
7+
8+
Synopsis: table.foreachi(table, f)
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
-- Function `table.foreach` is deprecated in Lua 5.1.
15+
if test_lib.lua_current_version_ge_than(5, 2) then
16+
print("Unsupported version.")
17+
os.exit(0)
18+
end
19+
20+
local function TestOneInput(buf, _size)
21+
local fdp = luzer.FuzzedDataProvider(buf)
22+
local count = fdp:consume_integer(1, test_lib.MAX_INT)
23+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
24+
local i = 0
25+
local fn = function(_idx, _v) i = i + 1 end
26+
table.foreachi(tbl, fn)
27+
assert(#tbl == i)
28+
end
29+
30+
local args = {
31+
artifact_prefix = "table_foreachi_",
32+
}
33+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_insert_test.lua

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2024, Sergey Bronnikov.
4+
5+
5.5 – Table Manipulation,
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Synopsis: table.insert(list, [pos,] value)
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
local MAX_INT = test_lib.MAX_INT
15+
16+
local function TestOneInput(buf, _size)
17+
local fdp = luzer.FuzzedDataProvider(buf)
18+
local str = fdp:consume_string(test_lib.MAX_STR_LEN)
19+
local tbl = {}
20+
str:gsub(".", function(c)
21+
-- The `pos` value cannot be negative in PUC Rio Lua 5.2+
22+
-- and in LuaJIT `table.insert()` works too slow with huge
23+
-- `pos` values.
24+
local MAX_POS = #tbl + 1
25+
if test_lib.lua_version() == "LuaJIT" then
26+
MAX_POS = MAX_INT
27+
end
28+
local pos = fdp:consume_integer(1, MAX_POS)
29+
table.insert(tbl, pos, c)
30+
end)
31+
end
32+
33+
local args = {
34+
artifact_prefix = "table_insert_",
35+
}
36+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_maxn_test.lua

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
5.5 – Table Manipulation,
6+
https://www.lua.org/manual/5.1/manual.html#5.5
7+
8+
Synopsis: table.maxn(table)
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
if test_lib.lua_current_version_ge_than(5, 3) then
15+
print("Unsupported version.")
16+
os.exit(0)
17+
end
18+
19+
local function TestOneInput(buf)
20+
local fdp = luzer.FuzzedDataProvider(buf)
21+
local count = fdp:consume_integer(0, test_lib.MAX_INT64)
22+
local tbl = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
23+
local maxn = table.maxn(tbl)
24+
assert(maxn == #tbl)
25+
end
26+
27+
local args = {
28+
artifact_prefix = "table_maxn_",
29+
}
30+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_move_test.lua

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.6 – Table Manipulation,
6+
https://www.lua.org/manual/5.3/manual.html#6.6
7+
8+
Synopsis: table.move(a1, f, e, t [,a2])
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
if test_lib.lua_current_version_lt_than(5, 3) and
15+
test_lib.lua_version == "PUC Rio Lua" then
16+
print("Unsupported version.")
17+
os.exit(0)
18+
end
19+
20+
local function TestOneInput(buf, _size)
21+
local fdp = luzer.FuzzedDataProvider(buf)
22+
local count = fdp:consume_integer(0, test_lib.MAX_INT)
23+
local a1 = fdp:consume_strings(test_lib.MAX_STR_LEN, count)
24+
local a2 = {}
25+
-- Move random items from the table `a1` to the table `a2`.
26+
-- Beware, `table.move()` works too slow with huge numbers.
27+
local MAX_N = 1000
28+
local f = fdp:consume_integer(-MAX_N, MAX_N)
29+
local e = fdp:consume_integer(-MAX_N, MAX_N)
30+
local t = fdp:consume_integer(-MAX_N, MAX_N)
31+
local res = table.move(a1, f, e, t, a2)
32+
assert(test_lib.arrays_equal(a2, res))
33+
end
34+
35+
local args = {
36+
artifact_prefix = "table_move_",
37+
}
38+
luzer.Fuzz(TestOneInput, nil, args)

tests/lapi/table_pack_test.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
6.5 – Table Manipulation,
6+
https://www.lua.org/manual/5.2/manual.html#6.5
7+
8+
Synopsis: table.pack(...)
9+
]]
10+
11+
local luzer = require("luzer")
12+
local test_lib = require("lib")
13+
14+
if test_lib.lua_current_version_lt_than(5, 2) then
15+
print("Unsupported version.")
16+
os.exit(0)
17+
end
18+
19+
local unpack = unpack or table.unpack
20+
21+
local function TestOneInput(buf, _size)
22+
local fdp = luzer.FuzzedDataProvider(buf)
23+
-- Beware, huge number triggers 'too many results to unpack'.
24+
local MAX_N = 1000
25+
local count = fdp:consume_integer(1, MAX_N)
26+
local tbl = fdp:consume_integers(test_lib.MIN_INT, test_lib.MAX_INT, count)
27+
local packed = table.pack(unpack(tbl))
28+
assert(#packed == #tbl)
29+
assert(test_lib.arrays_equal(packed, tbl))
30+
end
31+
32+
local args = {
33+
artifact_prefix = "table_pack_",
34+
}
35+
luzer.Fuzz(TestOneInput, nil, args)

0 commit comments

Comments
 (0)