t_misc.sh revision 1.28 1 #! /bin/sh
2 # $NetBSD: t_misc.sh,v 1.28 2023/12/10 17:45:35 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_options.
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 > stderr.exp
85 profile: -fc1
86 profile: -bacc
87 profile: -v
88 profile: -fc1
89 EOF
90
91 # The code in args.c function load_profile suggests that options from
92 # profile files are echoed to stderr 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 # on stderr, but '-fc1' is. The second round of '-bacc', '-v', '-fc1'
96 # is listed because when running the test via ATF, $HOME equals $PWD.
97
98 atf_check \
99 -e 'file:stderr.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 # Ensure that options in profile files start with '-', just like
209 # command line options.
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 \
217 -s 'exit:1' \
218 -e "match:/.indent.pro: option \"xi5\" must start with '-'" \
219 "$indent" < code.c
220 }
221
222 atf_test_case 'opt'
223 opt_body()
224 {
225 # Test parsing of command line options from a profile file.
226
227 cat <<-\EOF > code.c
228 int global_var;
229
230 int function(int expr) {
231 switch (expr) { case 1: return 1; default: return 0; }
232 }
233 EOF
234
235 cat << \EOF > .indent.pro
236 /* The latter of the two options wins. */
237 -di5
238 -di12
239
240 /*
241 * It is possible to embed comments in the middle of an option, but nobody
242 * does that.
243 */
244 -/* comment */bacc
245 -T/* define
246 a type */custom_type
247
248 /* For int options, trailing garbage would be an error. */
249 -i3
250
251 /* For float options, trailing garbage would be an error. */
252 -cli3.5
253
254 -b/*/acc /* The comment is '/' '*' '/', making the option '-bacc'. */
255 EOF
256
257 sed '/[$]/d' << \EOF > code.exp
258 /* $ The variable name is indented by 12 characters due to -di12. */
259 int global_var;
260
261 int
262 function(int expr)
263 {
264 switch (expr) {
265 /* $ The indentation is 3 + (int)(3.5 * 3), so 3 + 10.5, so 13. */
266 /* $ See parse.c, function parse, 'case switch_expr'. */
267 case 1:
268 /* $ The indentation is 3 + (int)3.5 * 3 + 3, so 3 + 9 + 3, so 15. */
269 /* $ See parse.c, function parse, 'case switch_expr'. */
270 return 1;
271 default:
272 return 0;
273 }
274 }
275 EOF
276
277 atf_check -o 'file:code.exp' \
278 "$indent" code.c -st
279 }
280
281 atf_test_case 'opt_npro'
282 opt_npro_body()
283 {
284 # Mentioning the option -npro in a .pro file has no effect since at
285 # that point, indent has already decided to load the .pro file, and
286 # it only decides once.
287
288 echo ' -npro -di8' > .indent.pro
289 echo 'int var;' > code.c
290 printf 'int\tvar;\n' > code.exp
291
292 atf_check -o 'file:code.exp' \
293 "$indent" code.c -st
294 }
295
296 atf_test_case 'opt_U'
297 opt_U_body()
298 {
299 # From each line of this file, the first word is taken to be a type
300 # name.
301 #
302 # Since neither '/*' nor '' are syntactically valid type names, this
303 # means that all kinds of comments are effectively ignored. When a
304 # type name is indented by whitespace, it is ignored as well.
305 #
306 # Since only the first word of each line is relevant, any remaining
307 # words can be used for comments.
308 cat <<-\EOF > code.types
309 /* Comments are effectively ignored since they never match. */
310 # This comment is ignored as well.
311 ; So is this comment.
312 # The following line is empty and adds a type whose name is empty.
313
314 size_t from stddef.h
315 off_t for file offsets
316 ignored_t is ignored since it is indented
317 EOF
318
319 cat <<-\EOF > code.c
320 int known_1 = (size_t) * arg;
321 int known_2 = (off_t) * arg;
322 int ignored = (ignored_t) * arg;
323 EOF
324 cat <<-\EOF > code.exp
325 int known_1 = (size_t)*arg;
326 int known_2 = (off_t)*arg;
327 int ignored = (ignored_t) * arg;
328 EOF
329
330 atf_check -o 'file:code.exp' \
331 "$indent" -Ucode.types code.c -di0 -st
332 }
333
334 atf_test_case 'line_no_counting'
335 line_no_counting_body()
336 {
337 # Before NetBSD indent.c 1.147 from 2021-10-24, indent reported the
338 # warning in line 2 instead of the correct line 3.
339
340 cat <<-\EOF > code.c
341 void line_no_counting(void)
342 {
343 ())
344 }
345 EOF
346
347 cat <<-\EOF > code.err
348 warning: code.c:3: Extra ')'
349 EOF
350
351 atf_check -o 'ignore' -e 'file:code.err' \
352 "$indent" code.c -st
353 }
354
355 atf_test_case 'default_backup_extension'
356 default_backup_extension_body()
357 {
358 echo 'int var;' > code.c
359 echo 'int var;' > code.c.orig
360
361 atf_check \
362 "$indent" code.c
363 atf_check -o 'file:code.c.orig' \
364 cat code.c.BAK
365 }
366
367 atf_test_case 'several_profiles'
368 several_profiles_body()
369 {
370 # If the option '-P' occurs several times, only the last of the
371 # profiles is loaded, the others are ignored.
372
373 echo ' --invalid-option' > error.pro
374 echo '' > last.pro
375 echo '' > code.c
376
377 atf_check \
378 "$indent" -Pnonexistent.pro -Perror.pro -Plast.pro code.c -st
379 }
380
381
382 atf_test_case 'command_line_vs_profile'
383 command_line_vs_profile_body()
384 {
385 # Options from the command line override those from a profile file,
386 # no matter if they appear earlier or later than the '-P' in the
387 # command line.
388
389 echo ' -di24' > custom.pro
390 printf 'int\t\tdecl;\n' > code.c
391
392 atf_check -o 'inline:int decl;\n' \
393 "$indent" -di0 -Pcustom.pro code.c -st
394 atf_check -o 'inline:int decl;\n' \
395 "$indent" -Pcustom.pro -di0 code.c -st
396 atf_check -o 'inline:int decl;\n' \
397 "$indent" -Pcustom.pro code.c -st -di0
398 }
399
400
401 atf_test_case 'opt_v_break_line'
402 opt_v_break_line_body()
403 {
404 printf '%s\n' 'int *function(void)' '{}' > code.c
405
406 atf_check -o 'ignore' \
407 "$indent" -v code.c -st
408 }
409
410
411 atf_test_case 'trailing_whitespace_in_preprocessing_line'
412 trailing_whitespace_in_preprocessing_line_body()
413 {
414 printf '#if trailing && space \n#endif\n' > code.c
415
416 atf_check -o 'inline:#if trailing && space\n#endif\n' \
417 "$indent" code.c -st
418 }
419
420 atf_init_test_cases()
421 {
422 atf_add_test_case 'in_place'
423 atf_add_test_case 'verbose_profile'
424 atf_add_test_case 'nested_struct_declarations'
425 atf_add_test_case 'option_P_in_profile_file'
426 atf_add_test_case 'option_without_hyphen'
427 atf_add_test_case 'opt'
428 atf_add_test_case 'opt_npro'
429 atf_add_test_case 'opt_U'
430 atf_add_test_case 'opt_v_break_line'
431 atf_add_test_case 'line_no_counting'
432 atf_add_test_case 'default_backup_extension'
433 atf_add_test_case 'several_profiles'
434 atf_add_test_case 'command_line_vs_profile'
435 atf_add_test_case 'in_place_parse_error'
436 atf_add_test_case 'trailing_whitespace_in_preprocessing_line'
437 }
438