xref: /netbsd-src/tests/usr.bin/indent/t_misc.sh (revision b4747d0de92f417ddff3353b3cb444b3eb92b340)
1122ad694Srillig#! /bin/sh
2*b4747d0dSrillig# $NetBSD: t_misc.sh,v 1.29 2023/12/17 10:02:09 rillig Exp $
3122ad694Srillig#
4122ad694Srillig# Copyright (c) 2021 The NetBSD Foundation, Inc.
5122ad694Srillig# All rights reserved.
6122ad694Srillig#
7122ad694Srillig# Redistribution and use in source and binary forms, with or without
8122ad694Srillig# modification, are permitted provided that the following conditions
9122ad694Srillig# are met:
10122ad694Srillig# 1. Redistributions of source code must retain the above copyright
11122ad694Srillig#    notice, this list of conditions and the following disclaimer.
12122ad694Srillig# 2. Redistributions in binary form must reproduce the above copyright
13122ad694Srillig#    notice, this list of conditions and the following disclaimer in the
14122ad694Srillig#    documentation and/or other materials provided with the distribution.
15122ad694Srillig#
16122ad694Srillig# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17122ad694Srillig# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18122ad694Srillig# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19122ad694Srillig# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20122ad694Srillig# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21122ad694Srillig# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22122ad694Srillig# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23122ad694Srillig# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24122ad694Srillig# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25122ad694Srillig# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26122ad694Srillig# POSSIBILITY OF SUCH DAMAGE.
27122ad694Srillig
28122ad694Srillig# Tests for indent that do not follow the input-profile-output scheme that is
29ff059387Srillig# used in t_options.
30122ad694Srillig
31122ad694Srilligindent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
32656cedf7Srillig
33656cedf7Srilligatf_test_case 'in_place'
34656cedf7Srilligin_place_body()
35656cedf7Srillig{
36656cedf7Srillig	cat <<-\EOF > code.c
37656cedf7Srillig		int decl;
38656cedf7Srillig	EOF
39656cedf7Srillig	cat <<-\EOF > code.c.exp
40656cedf7Srillig		int		decl;
41656cedf7Srillig	EOF
42656cedf7Srillig	cp code.c code.c.orig
43656cedf7Srillig
44656cedf7Srillig	atf_check \
45656cedf7Srillig	    env SIMPLE_BACKUP_SUFFIX=".bak" "$indent" code.c
46656cedf7Srillig	atf_check -o 'file:code.c.exp' \
47656cedf7Srillig	    cat code.c
48656cedf7Srillig	atf_check -o 'file:code.c.orig' \
49656cedf7Srillig	    cat code.c.bak
50656cedf7Srillig}
51122ad694Srillig
525852ffadSrilligatf_test_case 'in_place_parse_error'
535852ffadSrilligin_place_parse_error_body()
545852ffadSrillig{
555852ffadSrillig	# On normal parse errors, indent continues until the end of the file.
565852ffadSrillig	# This means that even in the case of errors, not much is lost.
575852ffadSrillig
585852ffadSrillig	cat <<-\EOF > code.c
595852ffadSrillig		int line1;
605852ffadSrillig		}
615852ffadSrillig		int line3;
625852ffadSrillig	EOF
635852ffadSrillig
645852ffadSrillig	atf_check -s 'exit:1' -e 'ignore' \
655852ffadSrillig	   "$indent" code.c
665852ffadSrillig	atf_check -o 'inline:int\t\tline1;\n}\nint\t\tline3;\n' \
675852ffadSrillig	    cat code.c
685852ffadSrillig}
695852ffadSrillig
70122ad694Srilligatf_test_case 'verbose_profile'
71122ad694Srilligverbose_profile_body()
72122ad694Srillig{
73122ad694Srillig	cat <<-\EOF > .indent.pro
74122ad694Srillig		-/* comment */bacc
75122ad694Srillig		-v
76122ad694Srillig		-fc1
77122ad694Srillig	EOF
78122ad694Srillig	cat <<-\EOF > before.c
79122ad694Srillig		int decl;
80122ad694Srillig	EOF
81122ad694Srillig	cat <<-\EOF > after.c.exp
82122ad694Srillig		int		decl;
83122ad694Srillig	EOF
8424133b79Srillig	cat <<-\EOF > stderr.exp
85122ad694Srillig		profile: -fc1
86122ad694Srillig		profile: -bacc
87122ad694Srillig		profile: -v
88122ad694Srillig		profile: -fc1
89122ad694Srillig	EOF
90122ad694Srillig
9197817c96Srillig	# The code in args.c function load_profile suggests that options from
9297817c96Srillig	# profile files are echoed to stderr during startup. But since the
93122ad694Srillig	# command line options are handled after the profile files, a '-v' in
94122ad694Srillig	# the command line has no effect. That's why '-bacc' is not listed
9597817c96Srillig	# on stderr, but '-fc1' is. The second round of '-bacc', '-v', '-fc1'
9697817c96Srillig	# is listed because when running the test via ATF, $HOME equals $PWD.
97122ad694Srillig
98122ad694Srillig	atf_check \
9924133b79Srillig	    -e 'file:stderr.exp' \
100122ad694Srillig	    "$indent" -v before.c after.c
101122ad694Srillig	atf_check \
102122ad694Srillig	     -o 'file:after.c.exp' \
103122ad694Srillig	     cat after.c
104122ad694Srillig}
105122ad694Srillig
1068c1e5e02Srilligatf_test_case 'nested_struct_declarations'
1078c1e5e02Srillignested_struct_declarations_body()
1088c1e5e02Srillig{
1098c1e5e02Srillig	# Trigger the warning about nested struct declarations.
1108c1e5e02Srillig
1118c1e5e02Srillig	cat <<-\EOF > code.c
1128c1e5e02Srillig		struct s01 { struct s02 { struct s03 { struct s04 {
1138c1e5e02Srillig		struct s05 { struct s06 { struct s07 { struct s08 {
1148c1e5e02Srillig		struct s09 { struct s10 { struct s11 { struct s12 {
1158c1e5e02Srillig		struct s13 { struct s14 { struct s15 { struct s16 {
1168c1e5e02Srillig		struct s17 { struct s18 { struct s19 { struct s20 {
1178c1e5e02Srillig		struct s21 { struct s22 { struct s23 { struct s24 {
1188c1e5e02Srillig		};};};};
1198c1e5e02Srillig		};};};};
1208c1e5e02Srillig		};};};};
1218c1e5e02Srillig		};};};};
1228c1e5e02Srillig		};};};};
1238c1e5e02Srillig		};};};};
1248c1e5e02Srillig	EOF
1258c1e5e02Srillig	cat <<-\EOF > expected.out
1268c1e5e02Srillig		struct s01 {
1278c1e5e02Srillig		 struct s02 {
1288c1e5e02Srillig		  struct s03 {
1298c1e5e02Srillig		   struct s04 {
1308c1e5e02Srillig		    struct s05 {
1318c1e5e02Srillig		     struct s06 {
1328c1e5e02Srillig		      struct s07 {
1338c1e5e02Srillig		       struct s08 {
1348c1e5e02Srillig		        struct s09 {
1358c1e5e02Srillig		         struct s10 {
1368c1e5e02Srillig		          struct s11 {
1378c1e5e02Srillig		           struct s12 {
1388c1e5e02Srillig		            struct s13 {
1398c1e5e02Srillig		             struct s14 {
1408c1e5e02Srillig		              struct s15 {
1418c1e5e02Srillig		               struct s16 {
1428c1e5e02Srillig		                struct s17 {
1438c1e5e02Srillig		                 struct s18 {
1448c1e5e02Srillig		                  struct s19 {
1458c1e5e02Srillig		                   struct s20 {
1468c1e5e02Srillig		                    struct s21 {
1478c1e5e02Srillig		                     struct s22 {
1488c1e5e02Srillig		                      struct s23 {
1498c1e5e02Srillig		                       struct s24 {
1508c1e5e02Srillig		                       };
1518c1e5e02Srillig		                      };
1528c1e5e02Srillig		                     };
1538c1e5e02Srillig		                    };
1548c1e5e02Srillig		                   };
1558c1e5e02Srillig		                  };
1568c1e5e02Srillig		                 };
1578c1e5e02Srillig		                };
1588c1e5e02Srillig		               };
1598c1e5e02Srillig		              };
1608c1e5e02Srillig		             };
1618c1e5e02Srillig		            };
1628c1e5e02Srillig		           };
1638c1e5e02Srillig		          };
1648c1e5e02Srillig		         };
1658c1e5e02Srillig		        };
1668c1e5e02Srillig		       };
1678c1e5e02Srillig		      };
1688c1e5e02Srillig		     };
1698c1e5e02Srillig		    };
1708c1e5e02Srillig		   };
1718c1e5e02Srillig		  };
1728c1e5e02Srillig		 };
1738c1e5e02Srillig		};
1748c1e5e02Srillig	EOF
1758c1e5e02Srillig	cat <<-\EOF > expected.err
176ccfddf6aSrillig		warning: Standard Input:5: Reached internal limit of 20 struct levels
177ccfddf6aSrillig		warning: Standard Input:6: Reached internal limit of 20 struct levels
178ccfddf6aSrillig		warning: Standard Input:6: Reached internal limit of 20 struct levels
179ccfddf6aSrillig		warning: Standard Input:6: Reached internal limit of 20 struct levels
180ccfddf6aSrillig		warning: Standard Input:6: Reached internal limit of 20 struct levels
1818c1e5e02Srillig	EOF
1828c1e5e02Srillig
1838c1e5e02Srillig	atf_check -o 'file:expected.out' -e 'file:expected.err' \
1848c1e5e02Srillig	    "$indent" -i1 -nut < 'code.c'
1858c1e5e02Srillig}
1868c1e5e02Srillig
18732fe626bSrilligatf_test_case 'option_P_in_profile_file'
18832fe626bSrilligoption_P_in_profile_file_body()
18932fe626bSrillig{
19032fe626bSrillig	# Mentioning another profile via -P has no effect since only a single
19132fe626bSrillig	# profile can be specified on the command line, and there is no
19232fe626bSrillig	# 'include' option.
19332fe626bSrillig
19432fe626bSrillig	# It's syntactically possible to specify a profile file inside another
19532fe626bSrillig	# profile file.  Such a profile file is ignored since only a single
19632fe626bSrillig	# profile file is ever loaded.
19732fe626bSrillig	printf '%s\n' '-P/nonexistent' > .indent.pro
19832fe626bSrillig
19932fe626bSrillig	echo 'syntax # error' > code.c
20032fe626bSrillig
20151ce682bSrillig	atf_check -o 'inline:syntax\n# error\n' \
20232fe626bSrillig	    "$indent" < code.c
20332fe626bSrillig}
20432fe626bSrillig
2056134a922Srilligatf_test_case 'option_without_hyphen'
2066134a922Srilligoption_without_hyphen_body()
2076134a922Srillig{
20897817c96Srillig	# Ensure that options in profile files start with '-', just like
20997817c96Srillig	# command line options.
2106134a922Srillig
2116134a922Srillig	printf ' -i3 xi5 +di0\n' > .indent.pro
2126134a922Srillig
2136134a922Srillig	printf '%s\n' 'int var[] = {' '1,' '}' > code.c
2146134a922Srillig
21597817c96Srillig	atf_check \
21697817c96Srillig	    -s 'exit:1' \
21797817c96Srillig	    -e "match:/.indent.pro: option \"xi5\" must start with '-'" \
2186134a922Srillig	    "$indent" < code.c
2196134a922Srillig}
2206134a922Srillig
22119aed58aSrilligatf_test_case 'opt'
22219aed58aSrilligopt_body()
22319aed58aSrillig{
22419aed58aSrillig	# Test parsing of command line options from a profile file.
22519aed58aSrillig
22619aed58aSrillig	cat <<-\EOF > code.c
22719aed58aSrillig		int global_var;
22819aed58aSrillig
22919aed58aSrillig		int function(int expr) {
23019aed58aSrillig		switch (expr) { case 1: return 1; default: return 0; }
23119aed58aSrillig		}
23219aed58aSrillig	EOF
23319aed58aSrillig
23419aed58aSrillig	cat << \EOF > .indent.pro
23519aed58aSrillig/* The latter of the two options wins. */
23619aed58aSrillig-di5
23719aed58aSrillig-di12
23819aed58aSrillig
23919aed58aSrillig/*
24019aed58aSrillig * It is possible to embed comments in the middle of an option, but nobody
24119aed58aSrillig * does that.
24219aed58aSrillig */
24319aed58aSrillig-/* comment */bacc
24419aed58aSrillig-T/* define
24519aed58aSrilliga type */custom_type
24619aed58aSrillig
247499bc8b3Srillig/* For int options, trailing garbage would be an error. */
24819aed58aSrillig-i3
24919aed58aSrillig
250499bc8b3Srillig/* For float options, trailing garbage would be an error. */
251499bc8b3Srillig-cli3.5
25219aed58aSrillig
25319aed58aSrillig-b/*/acc	/* The comment is '/' '*' '/', making the option '-bacc'. */
25419aed58aSrilligEOF
25519aed58aSrillig
25619aed58aSrillig	sed '/[$]/d' << \EOF > code.exp
25719aed58aSrillig/* $ The variable name is indented by 12 characters due to -di12. */
25819aed58aSrilligint	    global_var;
25919aed58aSrillig
26019aed58aSrilligint
26119aed58aSrilligfunction(int expr)
26219aed58aSrillig{
26319aed58aSrillig   switch (expr) {
26419aed58aSrillig/* $ The indentation is 3 + (int)(3.5 * 3), so 3 + 10.5, so 13. */
26519aed58aSrillig/* $ See parse.c, function parse, 'case switch_expr'. */
26619aed58aSrillig	     case 1:
26719aed58aSrillig/* $ The indentation is 3 + (int)3.5 * 3 + 3, so 3 + 9 + 3, so 15. */
26819aed58aSrillig/* $ See parse.c, function parse, 'case switch_expr'. */
26919aed58aSrillig	       return 1;
27019aed58aSrillig	     default:
27119aed58aSrillig	       return 0;
27219aed58aSrillig   }
27319aed58aSrillig}
27419aed58aSrilligEOF
27519aed58aSrillig
27619aed58aSrillig	atf_check -o 'file:code.exp' \
27719aed58aSrillig	    "$indent" code.c -st
27819aed58aSrillig}
27919aed58aSrillig
28019aed58aSrilligatf_test_case 'opt_npro'
28119aed58aSrilligopt_npro_body()
28219aed58aSrillig{
28319aed58aSrillig	# Mentioning the option -npro in a .pro file has no effect since at
28419aed58aSrillig	# that point, indent has already decided to load the .pro file, and
28519aed58aSrillig	# it only decides once.
28619aed58aSrillig
28719aed58aSrillig	echo ' -npro -di8' > .indent.pro
28819aed58aSrillig	echo 'int var;' > code.c
28919aed58aSrillig	printf 'int\tvar;\n' > code.exp
29019aed58aSrillig
29119aed58aSrillig	atf_check -o 'file:code.exp' \
29219aed58aSrillig	    "$indent" code.c -st
29319aed58aSrillig}
29419aed58aSrillig
29519aed58aSrilligatf_test_case 'opt_U'
29619aed58aSrilligopt_U_body()
29719aed58aSrillig{
29819aed58aSrillig	# From each line of this file, the first word is taken to be a type
29919aed58aSrillig	# name.
30019aed58aSrillig	#
30119aed58aSrillig	# Since neither '/*' nor '' are syntactically valid type names, this
30219aed58aSrillig	# means that all kinds of comments are effectively ignored.  When a
30319aed58aSrillig	# type name is indented by whitespace, it is ignored as well.
30419aed58aSrillig	#
30519aed58aSrillig	# Since only the first word of each line is relevant, any remaining
30619aed58aSrillig	# words can be used for comments.
30719aed58aSrillig	cat <<-\EOF > code.types
30819aed58aSrillig		/* Comments are effectively ignored since they never match. */
30919aed58aSrillig		# This comment is ignored as well.
31019aed58aSrillig		; So is this comment.
31119aed58aSrillig		# The following line is empty and adds a type whose name is empty.
31219aed58aSrillig
31319aed58aSrillig		size_t			from stddef.h
31419aed58aSrillig		off_t			for file offsets
31519aed58aSrillig		 ignored_t		is ignored since it is indented
31619aed58aSrillig	EOF
31719aed58aSrillig
31819aed58aSrillig	cat <<-\EOF > code.c
31919aed58aSrillig		int known_1 = (size_t)   *   arg;
32019aed58aSrillig		int known_2 = (off_t)   *   arg;
32119aed58aSrillig		int ignored = (ignored_t)   *   arg;
32219aed58aSrillig	EOF
32319aed58aSrillig	cat <<-\EOF > code.exp
32419aed58aSrillig		int known_1 = (size_t)*arg;
32519aed58aSrillig		int known_2 = (off_t)*arg;
32619aed58aSrillig		int ignored = (ignored_t) * arg;
32719aed58aSrillig	EOF
32819aed58aSrillig
32919aed58aSrillig	atf_check -o 'file:code.exp' \
33019aed58aSrillig	    "$indent" -Ucode.types code.c -di0 -st
33119aed58aSrillig}
33219aed58aSrillig
33367f162ccSrilligatf_test_case 'line_no_counting'
33467f162ccSrilligline_no_counting_body()
33567f162ccSrillig{
33608637ac7Srillig	# Before NetBSD indent.c 1.147 from 2021-10-24, indent reported the
33708637ac7Srillig	# warning in line 2 instead of the correct line 3.
33808637ac7Srillig
33967f162ccSrillig	cat <<-\EOF > code.c
34067f162ccSrillig		void line_no_counting(void)
34167f162ccSrillig		{
34267f162ccSrillig			())
34367f162ccSrillig		}
34467f162ccSrillig	EOF
34567f162ccSrillig
34667f162ccSrillig	cat <<-\EOF > code.err
3478c5268b6Srillig		warning: code.c:3: Extra ')'
34867f162ccSrillig	EOF
34967f162ccSrillig
35067f162ccSrillig	atf_check -o 'ignore' -e 'file:code.err' \
35167f162ccSrillig	    "$indent" code.c -st
35267f162ccSrillig}
35367f162ccSrillig
354b9453ae0Srilligatf_test_case 'default_backup_extension'
355b9453ae0Srilligdefault_backup_extension_body()
356b9453ae0Srillig{
357b9453ae0Srillig	echo 'int var;' > code.c
358b9453ae0Srillig	echo 'int var;' > code.c.orig
359b9453ae0Srillig
360b9453ae0Srillig	atf_check \
361b9453ae0Srillig	    "$indent" code.c
362b9453ae0Srillig	atf_check -o 'file:code.c.orig' \
363b9453ae0Srillig	    cat code.c.BAK
364b9453ae0Srillig}
365b9453ae0Srillig
366cfdb0587Srilligatf_test_case 'several_profiles'
367cfdb0587Srilligseveral_profiles_body()
368cfdb0587Srillig{
369cfdb0587Srillig	# If the option '-P' occurs several times, only the last of the
370cfdb0587Srillig	# profiles is loaded, the others are ignored.
371cfdb0587Srillig
372cfdb0587Srillig	echo ' --invalid-option' > error.pro
373cfdb0587Srillig	echo '' > last.pro
374cfdb0587Srillig	echo '' > code.c
375cfdb0587Srillig
376cfdb0587Srillig	atf_check \
377cfdb0587Srillig	    "$indent" -Pnonexistent.pro -Perror.pro -Plast.pro code.c -st
378cfdb0587Srillig}
379cfdb0587Srillig
3806c6e6473Srillig
3816c6e6473Srilligatf_test_case 'command_line_vs_profile'
3826c6e6473Srilligcommand_line_vs_profile_body()
3836c6e6473Srillig{
3846c6e6473Srillig	# Options from the command line override those from a profile file,
3856c6e6473Srillig	# no matter if they appear earlier or later than the '-P' in the
3866c6e6473Srillig	# command line.
3876c6e6473Srillig
3886c6e6473Srillig	echo ' -di24' > custom.pro
3896c6e6473Srillig	printf 'int\t\tdecl;\n' > code.c
3906c6e6473Srillig
3916c6e6473Srillig	atf_check -o 'inline:int decl;\n' \
3926c6e6473Srillig	    "$indent" -di0 -Pcustom.pro code.c -st
3936c6e6473Srillig	atf_check -o 'inline:int decl;\n' \
3946c6e6473Srillig	    "$indent" -Pcustom.pro -di0 code.c -st
3956c6e6473Srillig	atf_check -o 'inline:int decl;\n' \
3966c6e6473Srillig	    "$indent" -Pcustom.pro code.c -st -di0
3976c6e6473Srillig}
3986c6e6473Srillig
39937331766Srillig
40037331766Srilligatf_test_case 'opt_v_break_line'
40137331766Srilligopt_v_break_line_body()
40237331766Srillig{
40337331766Srillig	printf '%s\n' 'int *function(void)' '{}' > code.c
40437331766Srillig
40524133b79Srillig	atf_check -o 'ignore' \
40637331766Srillig	    "$indent" -v code.c -st
40737331766Srillig}
40837331766Srillig
409a28f6dc6Srillig
410a28f6dc6Srilligatf_test_case 'trailing_whitespace_in_preprocessing_line'
411a28f6dc6Srilligtrailing_whitespace_in_preprocessing_line_body()
412a28f6dc6Srillig{
413a28f6dc6Srillig	printf '#if trailing && space \n#endif\n' > code.c
414a28f6dc6Srillig
415a28f6dc6Srillig	atf_check -o 'inline:#if trailing && space\n#endif\n' \
416a28f6dc6Srillig	    "$indent" code.c -st
417a28f6dc6Srillig}
418a28f6dc6Srillig
419122ad694Srilligatf_init_test_cases()
420122ad694Srillig{
421656cedf7Srillig	atf_add_test_case 'in_place'
422122ad694Srillig	atf_add_test_case 'verbose_profile'
4238c1e5e02Srillig	atf_add_test_case 'nested_struct_declarations'
42432fe626bSrillig	atf_add_test_case 'option_P_in_profile_file'
4256134a922Srillig	atf_add_test_case 'option_without_hyphen'
42619aed58aSrillig	atf_add_test_case 'opt'
42719aed58aSrillig	atf_add_test_case 'opt_npro'
42819aed58aSrillig	atf_add_test_case 'opt_U'
42937331766Srillig	atf_add_test_case 'opt_v_break_line'
43067f162ccSrillig	atf_add_test_case 'line_no_counting'
431b9453ae0Srillig	atf_add_test_case 'default_backup_extension'
432cfdb0587Srillig	atf_add_test_case 'several_profiles'
4336c6e6473Srillig	atf_add_test_case 'command_line_vs_profile'
4345852ffadSrillig	atf_add_test_case 'in_place_parse_error'
435a28f6dc6Srillig	atf_add_test_case 'trailing_whitespace_in_preprocessing_line'
436122ad694Srillig}
437