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