Skip to content

Commit 512bdea

Browse files
committed
tests/lapi: add tests for io functions
The patch adds tests for `io.flush()`, `io.read()`, `io.seek()`, `io.setvbuf()`, `io.write()`. Other functions are not covered.
1 parent b8233dc commit 512bdea

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

tests/lapi/io_torture_test.lua

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2023-2025, Sergey Bronnikov.
4+
5+
5.7 – Input and Output Facilities
6+
https://www.lua.org/manual/5.1/manual.html#5.7
7+
https://www.lua.org/pil/21.3.html
8+
9+
Synopsis:
10+
11+
io.close([file])
12+
io.flush()
13+
io.open(filename [, mode])
14+
io.read(...)
15+
io.tmpfile()
16+
io.write(...)
17+
file:seek([whence] [, offset])
18+
file:setvbuf(mode [, size])
19+
]]
20+
21+
local luzer = require("luzer")
22+
local test_lib = require("lib")
23+
24+
-- The maximum file size is 1Mb (1000 * 1000).
25+
local MAX_N = 1e3
26+
27+
local function io_seek(self)
28+
local SEEK_MODE = {
29+
"set", -- Base is position 0 (beginning of the file).
30+
"cur", -- Base is current position.
31+
"end", -- Base is end of file.
32+
}
33+
local mode = self.fdp:oneof(SEEK_MODE)
34+
local offset = self.fdp:consume_integer(0, self.MAX_N)
35+
self.fh:seek(mode, offset)
36+
end
37+
38+
local function io_flush(self)
39+
self.fh:flush()
40+
end
41+
42+
local function io_setvbuf(self)
43+
local VBUF_MODE = {
44+
"no", -- no buffering.
45+
"full", -- full buffering.
46+
"line", -- line buffering.
47+
}
48+
local mode = self.fdp:oneof(VBUF_MODE)
49+
local size = self.fdp:consume_integer(0, self.MAX_N)
50+
self.fh:setvbuf(mode, size)
51+
end
52+
53+
local function io_write(self)
54+
local str = self.fdp:consume_string(self.MAX_N)
55+
self.fh:write(str)
56+
end
57+
58+
local function io_read(self)
59+
local n_formats = self.fdp:consume_integer(1, self.MAX_N)
60+
local READ_FORMAT = {
61+
"*n", -- Reads a number.
62+
"*a", -- Reads the whole file, starting at the current
63+
-- position.
64+
"*l", -- Reads the next line (skipping the end of line),
65+
-- returning nil on end of file.
66+
}
67+
if test_lib.lua_current_version_ge_than(5, 2) then
68+
-- "*L" reads the next line keeping the end of line
69+
-- (if present), returning nil on end of file.
70+
table.insert(READ_FORMAT, "*L")
71+
end
72+
-- Build a table with formats, which specify what to read. For
73+
-- each format, the function returns a string (or a number)
74+
-- with the characters read, or `nil` if it cannot read data
75+
-- with the specified format. When called without formats, it
76+
-- uses a default format that reads the entire next line.
77+
local read_formats = {}
78+
for _ = 1, n_formats do
79+
local format_is_size = self.fdp:consume_boolean()
80+
if format_is_size then
81+
-- As a special case, `io.read(0)` works as a test for
82+
-- end of file: It returns an empty string if there is
83+
-- more to be read or `nil` otherwise.
84+
local size = self.fdp:consume_integer(0, test_lib.MAX_INT64)
85+
table.insert(read_formats, size)
86+
else
87+
local format = self.fdp:oneof(READ_FORMAT)
88+
table.insert(read_formats, format)
89+
end
90+
end
91+
local _ = self.fh:read(unpack(read_formats))
92+
end
93+
94+
local function io_close(self)
95+
self.fh:close()
96+
end
97+
98+
local io_methods = {
99+
io_flush,
100+
io_read,
101+
io_seek,
102+
io_setvbuf,
103+
io_write,
104+
}
105+
106+
local function io_random_op(self)
107+
local io_method = self.fdp:oneof(io_methods)
108+
io_method(self)
109+
end
110+
111+
local function io_new(fdp)
112+
local fh = io.tmpfile()
113+
return {
114+
close = io_close,
115+
fdp = fdp,
116+
fh = fh,
117+
random_operation = io_random_op,
118+
MAX_N = MAX_N,
119+
}
120+
end
121+
122+
local function TestOneInput(buf)
123+
local fdp = luzer.FuzzedDataProvider(buf)
124+
local nops = fdp:consume_integer(1, MAX_N)
125+
local fh = io_new(fdp)
126+
for _ = 1, nops do
127+
fh:random_operation()
128+
end
129+
fh:close()
130+
end
131+
132+
local args = {
133+
artifact_prefix = "io_torture_",
134+
}
135+
luzer.Fuzz(TestOneInput, nil, args)

0 commit comments

Comments
 (0)