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