t_misc.sh revision 1.22 1 #! /bin/sh
2 # $NetBSD: t_misc.sh,v 1.22 2023/05/12 10:53:33 rillig Exp $
3 #
4 # Copyright (c) 2021 The NetBSD Foundation, Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 # 1. Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 # POSSIBILITY OF SUCH DAMAGE.
27
28 # Tests for indent that do not follow the input-profile-output scheme that is
29 # used in t_indent.
30
31 indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
32
33 atf_test_case 'in_place'
34 in_place_body()
35 {
36 cat <<-\EOF > code.c
37 int decl;
38 EOF
39 cat <<-\EOF > code.c.exp
40 int decl;
41 EOF
42 cp code.c code.c.orig
43
44 atf_check \
45 env SIMPLE_BACKUP_SUFFIX=".bak" "$indent" code.c
46 atf_check -o 'file:code.c.exp' \
47 cat code.c
48 atf_check -o 'file:code.c.orig' \
49 cat code.c.bak
50 }
51
52 atf_test_case 'in_place_parse_error'
53 in_place_parse_error_body()
54 {
55 # On normal parse errors, indent continues until the end of the file.
56 # This means that even in the case of errors, not much is lost.
57
58 cat <<-\EOF > code.c
59 int line1;
60 }
61 int line3;
62 EOF
63
64 atf_check -s 'exit:1' -e 'ignore' \
65 "$indent" code.c
66 atf_check -o 'inline:int\t\tline1;\n}\nint\t\tline3;\n' \
67 cat code.c
68 }
69
70 atf_test_case 'verbose_profile'
71 verbose_profile_body()
72 {
73 cat <<-\EOF > .indent.pro
74 -/* comment */bacc
75 -v
76 -fc1
77 EOF
78 cat <<-\EOF > before.c
79 int decl;
80 EOF
81 cat <<-\EOF > after.c.exp
82 int decl;
83 EOF
84 cat <<-\EOF > stdout.exp
85 profile: -fc1
86 profile: -bacc
87 profile: -v
88 profile: -fc1
89 EOF
90
91 # The code in args.c function set_profile suggests that options from
92 # profile files are echoed to stdout during startup. But since the
93 # command line options are handled after the profile files, a '-v' in
94 # the command line has no effect. That's why '-bacc' is not listed
95 # in stdout, but '-fc1' is. The second round of '-bacc', '-v', '-fc1'
96 # is listed because when running ATF, $HOME equals $PWD.
97
98 atf_check \
99 -o 'file:stdout.exp' \
100 "$indent" -v before.c after.c
101 atf_check \
102 -o 'file:after.c.exp' \
103 cat after.c
104 }
105
106 atf_test_case 'nested_struct_declarations'
107 nested_struct_declarations_body()
108 {
109 # Trigger the warning about nested struct declarations.
110
111 cat <<-\EOF > code.c
112 struct s01 { struct s02 { struct s03 { struct s04 {
113 struct s05 { struct s06 { struct s07 { struct s08 {
114 struct s09 { struct s10 { struct s11 { struct s12 {
115 struct s13 { struct s14 { struct s15 { struct s16 {
116 struct s17 { struct s18 { struct s19 { struct s20 {
117 struct s21 { struct s22 { struct s23 { struct s24 {
118 };};};};
119 };};};};
120 };};};};
121 };};};};
122 };};};};
123 };};};};
124 EOF
125 cat <<-\EOF > expected.out
126 struct s01 {
127 struct s02 {
128 struct s03 {
129 struct s04 {
130 struct s05 {
131 struct s06 {
132 struct s07 {
133 struct s08 {
134 struct s09 {
135 struct s10 {
136 struct s11 {
137 struct s12 {
138 struct s13 {
139 struct s14 {
140 struct s15 {
141 struct s16 {
142 struct s17 {
143 struct s18 {
144 struct s19 {
145 struct s20 {
146 struct s21 {
147 struct s22 {
148 struct s23 {
149 struct s24 {
150 };
151 };
152 };
153 };
154 };
155 };
156 };
157 };
158 };
159 };
160 };
161 };
162 };
163 };
164 };
165 };
166 };
167 };
168 };
169 };
170 };
171 };
172 };
173 };
174 EOF
175 cat <<-\EOF > expected.err
176 warning: Standard Input:5: Reached internal limit of 20 struct levels
177 warning: Standard Input:6: Reached internal limit of 20 struct levels
178 warning: Standard Input:6: Reached internal limit of 20 struct levels
179 warning: Standard Input:6: Reached internal limit of 20 struct levels
180 warning: Standard Input:6: Reached internal limit of 20 struct levels
181 EOF
182
183 atf_check -o 'file:expected.out' -e 'file:expected.err' \
184 "$indent" -i1 -nut < 'code.c'
185 }
186
187 atf_test_case 'option_P_in_profile_file'
188 option_P_in_profile_file_body()
189 {
190 # Mentioning another profile via -P has no effect since only a single
191 # profile can be specified on the command line, and there is no
192 # 'include' option.
193
194 # It's syntactically possible to specify a profile file inside another
195 # profile file. Such a profile file is ignored since only a single
196 # profile file is ever loaded.
197 printf '%s\n' '-P/nonexistent' > .indent.pro
198
199 echo 'syntax # error' > code.c
200
201 atf_check -o 'inline:syntax\n#error\n' \
202 "$indent" < code.c
203 }
204
205 atf_test_case 'option_without_hyphen'
206 option_without_hyphen_body()
207 {
208 # TODO: Options in profile files should be required to start with
209 # '-', just like in the command line arguments.
210
211 printf ' -i3 xi5 +di0\n' > .indent.pro
212
213 printf '%s\n' 'int var[] = {' '1,' '}' > code.c
214 printf '%s\n' 'int var[] = {' ' 1,' '}' > code.exp
215
216 atf_check -o 'file:code.exp' \
217 "$indent" < code.c
218 }
219
220 atf_test_case 'opt'
221 opt_body()
222 {
223 # Test parsing of command line options from a profile file.
224
225 cat <<-\EOF > code.c
226 int global_var;
227
228 int function(int expr) {
229 switch (expr) { case 1: return 1; default: return 0; }
230 }
231 EOF
232
233 cat << \EOF > .indent.pro
234 /* The latter of the two options wins. */
235 -di5
236 -di12
237
238 /*
239 * It is possible to embed comments in the middle of an option, but nobody
240 * does that.
241 */
242 -/* comment */bacc
243 -T/* define
244 a type */custom_type
245
246 /* For int options, trailing garbage would be an error. */
247 -i3
248
249 /* For float options, trailing garbage would be an error. */
250 -cli3.5
251
252 -b/*/acc /* The comment is '/' '*' '/', making the option '-bacc'. */
253 EOF
254
255 sed '/[$]/d' << \EOF > code.exp
256 /* $ The variable name is indented by 12 characters due to -di12. */
257 int global_var;
258
259 int
260 function(int expr)
261 {
262 switch (expr) {
263 /* $ The indentation is 3 + (int)(3.5 * 3), so 3 + 10.5, so 13. */
264 /* $ See parse.c, function parse, 'case switch_expr'. */
265 case 1:
266 /* $ The indentation is 3 + (int)3.5 * 3 + 3, so 3 + 9 + 3, so 15. */
267 /* $ See parse.c, function parse, 'case switch_expr'. */
268 return 1;
269 default:
270 return 0;
271 }
272 }
273 EOF
274
275 atf_check -o 'file:code.exp' \
276 "$indent" code.c -st
277 }
278
279 atf_test_case 'opt_npro'
280 opt_npro_body()
281 {
282 # Mentioning the option -npro in a .pro file has no effect since at
283 # that point, indent has already decided to load the .pro file, and
284 # it only decides once.
285
286 echo ' -npro -di8' > .indent.pro
287 echo 'int var;' > code.c
288 printf 'int\tvar;\n' > code.exp
289
290 atf_check -o 'file:code.exp' \
291 "$indent" code.c -st
292 }
293
294 atf_test_case 'opt_U'
295 opt_U_body()
296 {
297 # From each line of this file, the first word is taken to be a type
298 # name.
299 #
300 # Since neither '/*' nor '' are syntactically valid type names, this
301 # means that all kinds of comments are effectively ignored. When a
302 # type name is indented by whitespace, it is ignored as well.
303 #
304 # Since only the first word of each line is relevant, any remaining
305 # words can be used for comments.
306 cat <<-\EOF > code.types
307 /* Comments are effectively ignored since they never match. */
308 # This comment is ignored as well.
309 ; So is this comment.
310 # The following line is empty and adds a type whose name is empty.
311
312 size_t from stddef.h
313 off_t for file offsets
314 ignored_t is ignored since it is indented
315 EOF
316
317 cat <<-\EOF > code.c
318 int known_1 = (size_t) * arg;
319 int known_2 = (off_t) * arg;
320 int ignored = (ignored_t) * arg;
321 EOF
322 cat <<-\EOF > code.exp
323 int known_1 = (size_t)*arg;
324 int known_2 = (off_t)*arg;
325 int ignored = (ignored_t) * arg;
326 EOF
327
328 atf_check -o 'file:code.exp' \
329 "$indent" -Ucode.types code.c -di0 -st
330 }
331
332 atf_test_case 'line_no_counting'
333 line_no_counting_body()
334 {
335 # Before NetBSD indent.c 1.147 from 2021-10-24, indent reported the
336 # warning in line 2 instead of the correct line 3.
337
338 cat <<-\EOF > code.c
339 void line_no_counting(void)
340 {
341 ())
342 }
343 EOF
344
345 cat <<-\EOF > code.err
346 warning: code.c:3: Extra ')'
347 EOF
348
349 atf_check -o 'ignore' -e 'file:code.err' \
350 "$indent" code.c -st
351 }
352
353 atf_test_case 'default_backup_extension'
354 default_backup_extension_body()
355 {
356 echo 'int var;' > code.c
357 echo 'int var;' > code.c.orig
358
359 atf_check \
360 "$indent" code.c
361 atf_check -o 'file:code.c.orig' \
362 cat code.c.BAK
363 }
364
365 atf_test_case 'several_profiles'
366 several_profiles_body()
367 {
368 # If the option '-P' occurs several times, only the last of the
369 # profiles is loaded, the others are ignored.
370
371 echo ' --invalid-option' > error.pro
372 echo '' > last.pro
373 echo '' > code.c
374
375 atf_check \
376 "$indent" -Pnonexistent.pro -Perror.pro -Plast.pro code.c -st
377 }
378
379
380 atf_test_case 'command_line_vs_profile'
381 command_line_vs_profile_body()
382 {
383 # Options from the command line override those from a profile file,
384 # no matter if they appear earlier or later than the '-P' in the
385 # command line.
386
387 echo ' -di24' > custom.pro
388 printf 'int\t\tdecl;\n' > code.c
389
390 atf_check -o 'inline:int decl;\n' \
391 "$indent" -di0 -Pcustom.pro code.c -st
392 atf_check -o 'inline:int decl;\n' \
393 "$indent" -Pcustom.pro -di0 code.c -st
394 atf_check -o 'inline:int decl;\n' \
395 "$indent" -Pcustom.pro code.c -st -di0
396 }
397
398
399 atf_test_case 'opt_v_break_line'
400 opt_v_break_line_body()
401 {
402 printf '%s\n' 'int *function(void)' '{}' > code.c
403
404 atf_check -o 'ignore' -e 'inline:warning: code.c:2: Line broken\n' \
405 "$indent" -v code.c -st
406 }
407
408 atf_init_test_cases()
409 {
410 atf_add_test_case 'in_place'
411 atf_add_test_case 'verbose_profile'
412 atf_add_test_case 'nested_struct_declarations'
413 atf_add_test_case 'option_P_in_profile_file'
414 atf_add_test_case 'option_without_hyphen'
415 atf_add_test_case 'opt'
416 atf_add_test_case 'opt_npro'
417 atf_add_test_case 'opt_U'
418 atf_add_test_case 'opt_v_break_line'
419 atf_add_test_case 'line_no_counting'
420 atf_add_test_case 'default_backup_extension'
421 atf_add_test_case 'several_profiles'
422 atf_add_test_case 'command_line_vs_profile'
423 atf_add_test_case 'in_place_parse_error'
424 }
425