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