t_misc.sh revision 1.24
1259694Spfg#! /bin/sh
2259694Spfg# $NetBSD: t_misc.sh,v 1.24 2023/05/13 08:33:39 rillig Exp $
3259694Spfg#
4259694Spfg# Copyright (c) 2021 The NetBSD Foundation, Inc.
5259694Spfg# All rights reserved.
6259694Spfg#
7259694Spfg# Redistribution and use in source and binary forms, with or without
8259694Spfg# modification, are permitted provided that the following conditions
9259694Spfg# are met:
10260074Spfg# 1. Redistributions of source code must retain the above copyright
11260074Spfg#    notice, this list of conditions and the following disclaimer.
12260074Spfg# 2. Redistributions in binary form must reproduce the above copyright
13260074Spfg#    notice, this list of conditions and the following disclaimer in the
14260074Spfg#    documentation and/or other materials provided with the distribution.
15260074Spfg#
16260074Spfg# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17258428Spfg# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18258428Spfg# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19258428Spfg# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20258428Spfg# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21258428Spfg# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22258428Spfg# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23258428Spfg# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24258428Spfg# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25258428Spfg# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26258428Spfg# POSSIBILITY OF SUCH DAMAGE.
27258428Spfg
28259947Spfg# Tests for indent that do not follow the input-profile-output scheme that is
29259947Spfg# used in t_options.
30259947Spfg
31259947Spfgindent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
32259947Spfg
33259947Spfgatf_test_case 'in_place'
34259947Spfgin_place_body()
35259947Spfg{
36260230Spfg	cat <<-\EOF > code.c
37260230Spfg		int decl;
38260230Spfg	EOF
39260230Spfg	cat <<-\EOF > code.c.exp
40260230Spfg		int		decl;
41260230Spfg	EOF
42259694Spfg	cp code.c code.c.orig
43259694Spfg
44259694Spfg	atf_check \
45259694Spfg	    env SIMPLE_BACKUP_SUFFIX=".bak" "$indent" code.c
46259694Spfg	atf_check -o 'file:code.c.exp' \
47259694Spfg	    cat code.c
48259694Spfg	atf_check -o 'file:code.c.orig' \
49258428Spfg	    cat code.c.bak
50258428Spfg}
51258428Spfg
52258428Spfgatf_test_case 'in_place_parse_error'
53260074Spfgin_place_parse_error_body()
54258428Spfg{
55260074Spfg	# On normal parse errors, indent continues until the end of the file.
56260074Spfg	# This means that even in the case of errors, not much is lost.
57260074Spfg
58260074Spfg	cat <<-\EOF > code.c
59260074Spfg		int line1;
60260074Spfg		}
61260074Spfg		int line3;
62260074Spfg	EOF
63260074Spfg
64258428Spfg	atf_check -s 'exit:1' -e 'ignore' \
65258428Spfg	   "$indent" code.c
66258428Spfg	atf_check -o 'inline:int\t\tline1;\n}\nint\t\tline3;\n' \
67258428Spfg	    cat code.c
68258428Spfg}
69260074Spfg
70259584Spfgatf_test_case 'verbose_profile'
71259584Spfgverbose_profile_body()
72259584Spfg{
73259584Spfg	cat <<-\EOF > .indent.pro
74259584Spfg		-/* comment */bacc
75260139Spfg		-v
76260139Spfg		-fc1
77260139Spfg	EOF
78260139Spfg	cat <<-\EOF > before.c
79260139Spfg		int decl;
80260139Spfg	EOF
81260139Spfg	cat <<-\EOF > after.c.exp
82260139Spfg		int		decl;
83260139Spfg	EOF
84260139Spfg	cat <<-\EOF > stdout.exp
85260139Spfg		profile: -fc1
86260139Spfg		profile: -bacc
87258428Spfg		profile: -v
88258428Spfg		profile: -fc1
89258428Spfg	EOF
90258428Spfg
91258428Spfg	# The code in args.c function set_profile suggests that options from
92258428Spfg	# 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
106atf_test_case 'nested_struct_declarations'
107nested_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
187atf_test_case 'option_P_in_profile_file'
188option_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
205atf_test_case 'option_without_hyphen'
206option_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
220atf_test_case 'opt'
221opt_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
244a 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'. */
253EOF
254
255	sed '/[$]/d' << \EOF > code.exp
256/* $ The variable name is indented by 12 characters due to -di12. */
257int	    global_var;
258
259int
260function(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}
273EOF
274
275	atf_check -o 'file:code.exp' \
276	    "$indent" code.c -st
277}
278
279atf_test_case 'opt_npro'
280opt_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
294atf_test_case 'opt_U'
295opt_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
332atf_test_case 'line_no_counting'
333line_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
353atf_test_case 'default_backup_extension'
354default_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
365atf_test_case 'several_profiles'
366several_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
380atf_test_case 'command_line_vs_profile'
381command_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
399atf_test_case 'opt_v_break_line'
400opt_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
408atf_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