t_misc.sh revision 1.20
1#! /bin/sh
2# $NetBSD: t_misc.sh,v 1.20 2022/04/22 21:21:20 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
31indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
32
33atf_test_case 'in_place'
34in_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
52atf_test_case 'in_place_parse_error'
53in_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
70atf_test_case 'verbose_profile'
71verbose_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		There were 1 output lines and 0 comments
90		(Lines with comments)/(Lines with code):  0.000
91	EOF
92
93	# The code in args.c function set_profile suggests that options from
94	# profile files are echoed to stdout during startup. But since the
95	# command line options are handled after the profile files, a '-v' in
96	# the command line has no effect. That's why '-bacc' is not listed
97	# in stdout, but '-fc1' is. The second round of '-bacc', '-v', '-fc1'
98	# is listed because when running ATF, $HOME equals $PWD.
99
100	atf_check \
101	    -o 'file:stdout.exp' \
102	    "$indent" -v before.c after.c
103	atf_check \
104	     -o 'file:after.c.exp' \
105	     cat after.c
106}
107
108atf_test_case 'nested_struct_declarations'
109nested_struct_declarations_body()
110{
111	# Trigger the warning about nested struct declarations.
112
113	cat <<-\EOF > code.c
114		struct s01 { struct s02 { struct s03 { struct s04 {
115		struct s05 { struct s06 { struct s07 { struct s08 {
116		struct s09 { struct s10 { struct s11 { struct s12 {
117		struct s13 { struct s14 { struct s15 { struct s16 {
118		struct s17 { struct s18 { struct s19 { struct s20 {
119		struct s21 { struct s22 { struct s23 { struct s24 {
120		};};};};
121		};};};};
122		};};};};
123		};};};};
124		};};};};
125		};};};};
126	EOF
127	cat <<-\EOF > expected.out
128		struct s01 {
129		 struct s02 {
130		  struct s03 {
131		   struct s04 {
132		    struct s05 {
133		     struct s06 {
134		      struct s07 {
135		       struct s08 {
136		        struct s09 {
137		         struct s10 {
138		          struct s11 {
139		           struct s12 {
140		            struct s13 {
141		             struct s14 {
142		              struct s15 {
143		               struct s16 {
144		                struct s17 {
145		                 struct s18 {
146		                  struct s19 {
147		                   struct s20 {
148		                    struct s21 {
149		                     struct s22 {
150		                      struct s23 {
151		                       struct s24 {
152		                       };
153		                      };
154		                     };
155		                    };
156		                   };
157		                  };
158		                 };
159		                };
160		               };
161		              };
162		             };
163		            };
164		           };
165		          };
166		         };
167		        };
168		       };
169		      };
170		     };
171		    };
172		   };
173		  };
174		 };
175		};
176	EOF
177	cat <<-\EOF > expected.err
178		warning: Standard Input:5: 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		warning: Standard Input:6: Reached internal limit of 20 struct levels
182		warning: Standard Input:6: Reached internal limit of 20 struct levels
183	EOF
184
185	atf_check -o 'file:expected.out' -e 'file:expected.err' \
186	    "$indent" -i1 -nut < 'code.c'
187}
188
189atf_test_case 'option_P_in_profile_file'
190option_P_in_profile_file_body()
191{
192	# Mentioning another profile via -P has no effect since only a single
193	# profile can be specified on the command line, and there is no
194	# 'include' option.
195
196	# It's syntactically possible to specify a profile file inside another
197	# profile file.  Such a profile file is ignored since only a single
198	# profile file is ever loaded.
199	printf '%s\n' '-P/nonexistent' > .indent.pro
200
201	echo 'syntax # error' > code.c
202
203	atf_check -o 'inline:syntax\n#error\n' \
204	    "$indent" < code.c
205}
206
207atf_test_case 'option_without_hyphen'
208option_without_hyphen_body()
209{
210	# TODO: Options in profile files should be required to start with
211	#  '-', just like in the command line arguments.
212
213	printf ' -i3 xi5 +di0\n' > .indent.pro
214
215	printf '%s\n' 'int var[] = {' '1,' '}' > code.c
216	printf '%s\n' 'int var[] = {' '     1,' '}' > code.exp
217
218	atf_check -o 'file:code.exp' \
219	    "$indent" < code.c
220}
221
222atf_test_case 'opt'
223opt_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
246a 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'. */
255EOF
256
257	sed '/[$]/d' << \EOF > code.exp
258/* $ The variable name is indented by 12 characters due to -di12. */
259int	    global_var;
260
261int
262function(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}
275EOF
276
277	atf_check -o 'file:code.exp' \
278	    "$indent" code.c -st
279}
280
281atf_test_case 'opt_npro'
282opt_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
296atf_test_case 'opt_U'
297opt_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
334atf_test_case 'line_no_counting'
335line_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
355atf_test_case 'default_backup_extension'
356default_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
367atf_test_case 'several_profiles'
368several_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
382atf_test_case 'command_line_vs_profile'
383command_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
400atf_init_test_cases()
401{
402	atf_add_test_case 'in_place'
403	atf_add_test_case 'verbose_profile'
404	atf_add_test_case 'nested_struct_declarations'
405	atf_add_test_case 'option_P_in_profile_file'
406	atf_add_test_case 'option_without_hyphen'
407	atf_add_test_case 'opt'
408	atf_add_test_case 'opt_npro'
409	atf_add_test_case 'opt_U'
410	atf_add_test_case 'line_no_counting'
411	atf_add_test_case 'default_backup_extension'
412	atf_add_test_case 'several_profiles'
413	atf_add_test_case 'command_line_vs_profile'
414	atf_add_test_case 'in_place_parse_error'
415}
416