t_options.lua revision 1.1 1 1.1 rillig -- $NetBSD: t_options.lua,v 1.1 2023/05/20 21:32:05 rillig Exp $
2 1.1 rillig --
3 1.1 rillig -- Copyright (c) 2023 The NetBSD Foundation, Inc.
4 1.1 rillig -- All rights reserved.
5 1.1 rillig --
6 1.1 rillig -- Redistribution and use in source and binary forms, with or without
7 1.1 rillig -- modification, are permitted provided that the following conditions
8 1.1 rillig -- are met:
9 1.1 rillig -- 1. Redistributions of source code must retain the above copyright
10 1.1 rillig -- notice, this list of conditions and the following disclaimer.
11 1.1 rillig -- 2. Redistributions in binary form must reproduce the above copyright
12 1.1 rillig -- notice, this list of conditions and the following disclaimer in the
13 1.1 rillig -- documentation and/or other materials provided with the distribution.
14 1.1 rillig --
15 1.1 rillig -- THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 1.1 rillig -- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 1.1 rillig -- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 1.1 rillig -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 1.1 rillig -- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 1.1 rillig -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 1.1 rillig -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 1.1 rillig -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 1.1 rillig -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 1.1 rillig -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 1.1 rillig -- POSSIBILITY OF SUCH DAMAGE.
26 1.1 rillig
27 1.1 rillig -- Test driver for indent that runs indent on several inputs, checks the
28 1.1 rillig -- output and can run indent with different command line options on the same
29 1.1 rillig -- input.
30 1.1 rillig --
31 1.1 rillig -- The test files contain the input to be formatted, the formatting options
32 1.1 rillig -- and the output, all as close together as possible. The test files use the
33 1.1 rillig -- following directives:
34 1.1 rillig --
35 1.1 rillig -- //indent input [description]
36 1.1 rillig -- Specifies the input to be formatted.
37 1.1 rillig -- //indent run [options]
38 1.1 rillig -- Runs indent on the input, using the given options.
39 1.1 rillig -- //indent end [description]
40 1.1 rillig -- Finishes an '//indent input' or '//indent run' section.
41 1.1 rillig -- //indent run-equals-input [options]
42 1.1 rillig -- Runs indent on the input, expecting unmodified output.
43 1.1 rillig -- //indent run-equals-prev-output [options]
44 1.1 rillig -- Runs indent on the input, expecting the same output as from
45 1.1 rillig -- the previous run.
46 1.1 rillig --
47 1.1 rillig -- All text outside input..end or run..end directives is not passed to indent.
48 1.1 rillig --
49 1.1 rillig -- Inside the input..end or run..end sections, comments that start with '$'
50 1.1 rillig -- are filtered out, they can be used for remarks near the affected code.
51 1.1 rillig --
52 1.1 rillig -- The actual output from running indent is written to stdout, the expected
53 1.1 rillig -- test output is written to 'expected.out'.
54 1.1 rillig
55 1.1 rillig local warned = false
56 1.1 rillig
57 1.1 rillig local filename = ""
58 1.1 rillig local lineno = 0
59 1.1 rillig
60 1.1 rillig local prev_empty_lines = 0 -- the finished "block" of empty lines
61 1.1 rillig local curr_empty_lines = 0 -- the ongoing "block" of empty lines
62 1.1 rillig local max_empty_lines = 0 -- between sections
63 1.1 rillig local seen_input_section = false-- the first input section is not checked
64 1.1 rillig
65 1.1 rillig local section = "" -- "", "input" or "run"
66 1.1 rillig local section_excl_comm = "" -- without dollar comments
67 1.1 rillig local section_incl_comm = "" -- with dollar comments
68 1.1 rillig
69 1.1 rillig local input_excl_comm = "" -- the input text for indent
70 1.1 rillig local input_incl_comm = "" -- used for duplicate checks
71 1.1 rillig local unused_input_lineno = 0
72 1.1 rillig
73 1.1 rillig local output_excl_comm = "" -- expected output
74 1.1 rillig local output_incl_comm = "" -- used for duplicate checks
75 1.1 rillig local output_lineno = 0
76 1.1 rillig
77 1.1 rillig local expected_out = assert(io.open("expected.out", "w"))
78 1.1 rillig
79 1.1 rillig local function die(ln, msg)
80 1.1 rillig io.stderr:write(("%s:%d: error: %s\n"):format(filename, ln, msg))
81 1.1 rillig os.exit(false)
82 1.1 rillig end
83 1.1 rillig
84 1.1 rillig local function warn(ln, msg)
85 1.1 rillig io.stderr:write(("%s:%d: warning: %s\n"):format(filename, ln, msg))
86 1.1 rillig warned = true
87 1.1 rillig end
88 1.1 rillig
89 1.1 rillig local function init_file(fname)
90 1.1 rillig filename = fname
91 1.1 rillig lineno = 0
92 1.1 rillig
93 1.1 rillig prev_empty_lines = 0
94 1.1 rillig curr_empty_lines = 0
95 1.1 rillig max_empty_lines = 0
96 1.1 rillig seen_input_section = false
97 1.1 rillig
98 1.1 rillig section = ""
99 1.1 rillig section_excl_comm = ""
100 1.1 rillig section_incl_comm = ""
101 1.1 rillig
102 1.1 rillig input_excl_comm = ""
103 1.1 rillig input_incl_comm = ""
104 1.1 rillig unused_input_lineno = 0
105 1.1 rillig
106 1.1 rillig output_excl_comm = ""
107 1.1 rillig output_incl_comm = ""
108 1.1 rillig output_lineno = 0
109 1.1 rillig end
110 1.1 rillig
111 1.1 rillig local function check_empty_lines_block(n)
112 1.1 rillig if max_empty_lines ~= n and seen_input_section then
113 1.1 rillig local lines = n ~= 1 and "lines" or "line"
114 1.1 rillig warn(lineno, ("expecting %d empty %s, got %d")
115 1.1 rillig :format(n, lines, max_empty_lines))
116 1.1 rillig end
117 1.1 rillig end
118 1.1 rillig
119 1.1 rillig local function check_unused_input()
120 1.1 rillig if unused_input_lineno ~= 0 then
121 1.1 rillig warn(unused_input_lineno, "input is not used")
122 1.1 rillig end
123 1.1 rillig end
124 1.1 rillig
125 1.1 rillig local function run_indent(inp, args)
126 1.1 rillig local indent = os.getenv("INDENT") or "indent"
127 1.1 rillig local cmd = indent .. " " .. args .. " indent.in -st"
128 1.1 rillig
129 1.1 rillig local indent_in = assert(io.open("indent.in", "w"))
130 1.1 rillig indent_in:write(inp)
131 1.1 rillig indent_in:close()
132 1.1 rillig ok, kind, info = os.execute(cmd)
133 1.1 rillig if not ok then
134 1.1 rillig print(kind .. " " .. info)
135 1.1 rillig end
136 1.1 rillig os.remove("indent.in")
137 1.1 rillig end
138 1.1 rillig
139 1.1 rillig local function handle_empty_section(line)
140 1.1 rillig if line == "" then
141 1.1 rillig curr_empty_lines = curr_empty_lines + 1
142 1.1 rillig else
143 1.1 rillig if curr_empty_lines > max_empty_lines then
144 1.1 rillig max_empty_lines = curr_empty_lines
145 1.1 rillig end
146 1.1 rillig if curr_empty_lines > 0 then
147 1.1 rillig if prev_empty_lines > 1 then
148 1.1 rillig warn(lineno - curr_empty_lines - 1,
149 1.1 rillig prev_empty_lines .. " empty lines a few "
150 1.1 rillig .. "lines above, should be only 1")
151 1.1 rillig end
152 1.1 rillig prev_empty_lines = curr_empty_lines
153 1.1 rillig end
154 1.1 rillig curr_empty_lines = 0
155 1.1 rillig end
156 1.1 rillig end
157 1.1 rillig
158 1.1 rillig local function handle_indent_directive(line, command, args)
159 1.1 rillig print(line)
160 1.1 rillig expected_out:write(line .. "\n")
161 1.1 rillig
162 1.1 rillig if command == "input" then
163 1.1 rillig if prev_empty_lines ~= 2 and seen_input_section then
164 1.1 rillig warn(lineno, "input section needs 2 empty lines "
165 1.1 rillig .. "above, not " .. prev_empty_lines)
166 1.1 rillig end
167 1.1 rillig check_empty_lines_block(2)
168 1.1 rillig check_unused_input()
169 1.1 rillig section = "input"
170 1.1 rillig section_excl_comm = ""
171 1.1 rillig section_incl_comm = ""
172 1.1 rillig unused_input_lineno = lineno
173 1.1 rillig seen_input_section = true
174 1.1 rillig output_excl_comm = ""
175 1.1 rillig output_incl_comm = ""
176 1.1 rillig output_lineno = 0
177 1.1 rillig
178 1.1 rillig elseif command == "run" then
179 1.1 rillig if section ~= "" then
180 1.1 rillig warn(lineno, "unfinished section '" .. section .. "'")
181 1.1 rillig end
182 1.1 rillig check_empty_lines_block(1)
183 1.1 rillig if prev_empty_lines ~= 1 then
184 1.1 rillig warn(lineno, "run section needs 1 empty line above, "
185 1.1 rillig .. "not " .. prev_empty_lines)
186 1.1 rillig end
187 1.1 rillig section = "run"
188 1.1 rillig output_lineno = lineno
189 1.1 rillig section_excl_comm = ""
190 1.1 rillig section_incl_comm = ""
191 1.1 rillig
192 1.1 rillig run_indent(input_excl_comm, args)
193 1.1 rillig unused_input_lineno = 0
194 1.1 rillig
195 1.1 rillig elseif command == "run-equals-input" then
196 1.1 rillig check_empty_lines_block(1)
197 1.1 rillig run_indent(input_excl_comm, args)
198 1.1 rillig expected_out:write(input_excl_comm)
199 1.1 rillig unused_input_lineno = 0
200 1.1 rillig max_empty_lines = 0
201 1.1 rillig
202 1.1 rillig elseif command == "run-equals-prev-output" then
203 1.1 rillig check_empty_lines_block(1)
204 1.1 rillig run_indent(input_excl_comm, args)
205 1.1 rillig expected_out:write(output_excl_comm)
206 1.1 rillig max_empty_lines = 0
207 1.1 rillig
208 1.1 rillig elseif command == "end" and section == "input" then
209 1.1 rillig if section_incl_comm == input_incl_comm then
210 1.1 rillig warn(lineno, "duplicate input; remove this section")
211 1.1 rillig end
212 1.1 rillig
213 1.1 rillig input_excl_comm = section_excl_comm
214 1.1 rillig input_incl_comm = section_incl_comm
215 1.1 rillig section = ""
216 1.1 rillig max_empty_lines = 0
217 1.1 rillig
218 1.1 rillig elseif command == "end" and section == "run" then
219 1.1 rillig if section_incl_comm == input_incl_comm then
220 1.1 rillig warn(output_lineno,
221 1.1 rillig "output == input; use run-equals-input")
222 1.1 rillig end
223 1.1 rillig if section_incl_comm == output_incl_comm then
224 1.1 rillig warn(output_lineno,
225 1.1 rillig "duplicate output; use run-equals-prev-output")
226 1.1 rillig end
227 1.1 rillig
228 1.1 rillig output_excl_comm = section_excl_comm
229 1.1 rillig output_incl_comm = section_incl_comm
230 1.1 rillig section = ""
231 1.1 rillig max_empty_lines = 0
232 1.1 rillig
233 1.1 rillig elseif command == "end" then
234 1.1 rillig warn(lineno, "misplaced '//indent end'")
235 1.1 rillig
236 1.1 rillig else
237 1.1 rillig die(lineno, "invalid line '" .. line .. "'")
238 1.1 rillig end
239 1.1 rillig
240 1.1 rillig prev_empty_lines = 0
241 1.1 rillig curr_empty_lines = 0
242 1.1 rillig end
243 1.1 rillig
244 1.1 rillig local function handle_line(line)
245 1.1 rillig if section == "" then
246 1.1 rillig handle_empty_section(line)
247 1.1 rillig end
248 1.1 rillig
249 1.1 rillig -- Hide comments starting with dollar from indent; they are used for
250 1.1 rillig -- marking bugs and adding other remarks directly in the input or
251 1.1 rillig -- output sections.
252 1.1 rillig if line:match("^%s*/[*]%s*[$].*[*]/$")
253 1.1 rillig or line:match("^%s*//%s*[$]") then
254 1.1 rillig if section ~= "" then
255 1.1 rillig section_incl_comm = section_incl_comm .. line .. "\n"
256 1.1 rillig end
257 1.1 rillig return
258 1.1 rillig end
259 1.1 rillig
260 1.1 rillig local cmd, args = line:match("^//indent%s+([^%s]+)%s*(.*)$")
261 1.1 rillig if cmd then
262 1.1 rillig handle_indent_directive(line, cmd, args)
263 1.1 rillig return
264 1.1 rillig end
265 1.1 rillig
266 1.1 rillig if section == "input" or section == "run" then
267 1.1 rillig section_excl_comm = section_excl_comm .. line .. "\n"
268 1.1 rillig section_incl_comm = section_incl_comm .. line .. "\n"
269 1.1 rillig end
270 1.1 rillig
271 1.1 rillig if section == "run" then
272 1.1 rillig expected_out:write(line .. "\n")
273 1.1 rillig end
274 1.1 rillig
275 1.1 rillig if section == ""
276 1.1 rillig and line ~= ""
277 1.1 rillig and line:sub(1, 1) ~= "#"
278 1.1 rillig and line:sub(1, 1) ~= "/"
279 1.1 rillig and line:sub(1, 2) ~= " *" then
280 1.1 rillig warn(lineno, "non-comment line outside 'input' or 'run' "
281 1.1 rillig .. "section")
282 1.1 rillig end
283 1.1 rillig end
284 1.1 rillig
285 1.1 rillig local function handle_file(fname)
286 1.1 rillig init_file(fname)
287 1.1 rillig local f = assert(io.open(fname))
288 1.1 rillig for line in f:lines() do
289 1.1 rillig lineno = lineno + 1
290 1.1 rillig handle_line(line)
291 1.1 rillig end
292 1.1 rillig f:close()
293 1.1 rillig end
294 1.1 rillig
295 1.1 rillig local function main()
296 1.1 rillig for _, arg in ipairs(arg) do
297 1.1 rillig handle_file(arg)
298 1.1 rillig end
299 1.1 rillig if section ~= "" then
300 1.1 rillig die(lineno, "still in section '" .. section .. "'")
301 1.1 rillig end
302 1.1 rillig check_unused_input()
303 1.1 rillig expected_out:close()
304 1.1 rillig os.exit(not warned)
305 1.1 rillig end
306 1.1 rillig
307 1.1 rillig main()
308