Home | History | Annotate | Line # | Download | only in indent
      1 #! /bin/sh
      2 # $NetBSD: t_misc.sh,v 1.29 2023/12/17 10:02:09 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_options.
     30 
     31 indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
     32 
     33 atf_test_case 'in_place'
     34 in_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 
     52 atf_test_case 'in_place_parse_error'
     53 in_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 
     70 atf_test_case 'verbose_profile'
     71 verbose_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 > stderr.exp
     85 		profile: -fc1
     86 		profile: -bacc
     87 		profile: -v
     88 		profile: -fc1
     89 	EOF
     90 
     91 	# The code in args.c function load_profile suggests that options from
     92 	# profile files are echoed to stderr 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 	# on stderr, but '-fc1' is. The second round of '-bacc', '-v', '-fc1'
     96 	# is listed because when running the test via ATF, $HOME equals $PWD.
     97 
     98 	atf_check \
     99 	    -e 'file:stderr.exp' \
    100 	    "$indent" -v before.c after.c
    101 	atf_check \
    102 	     -o 'file:after.c.exp' \
    103 	     cat after.c
    104 }
    105 
    106 atf_test_case 'nested_struct_declarations'
    107 nested_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 
    187 atf_test_case 'option_P_in_profile_file'
    188 option_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 
    205 atf_test_case 'option_without_hyphen'
    206 option_without_hyphen_body()
    207 {
    208 	# Ensure that options in profile files start with '-', just like
    209 	# command line options.
    210 
    211 	printf ' -i3 xi5 +di0\n' > .indent.pro
    212 
    213 	printf '%s\n' 'int var[] = {' '1,' '}' > code.c
    214 
    215 	atf_check \
    216 	    -s 'exit:1' \
    217 	    -e "match:/.indent.pro: option \"xi5\" must start with '-'" \
    218 	    "$indent" < code.c
    219 }
    220 
    221 atf_test_case 'opt'
    222 opt_body()
    223 {
    224 	# Test parsing of command line options from a profile file.
    225 
    226 	cat <<-\EOF > code.c
    227 		int global_var;
    228 
    229 		int function(int expr) {
    230 		switch (expr) { case 1: return 1; default: return 0; }
    231 		}
    232 	EOF
    233 
    234 	cat << \EOF > .indent.pro
    235 /* The latter of the two options wins. */
    236 -di5
    237 -di12
    238 
    239 /*
    240  * It is possible to embed comments in the middle of an option, but nobody
    241  * does that.
    242  */
    243 -/* comment */bacc
    244 -T/* define
    245 a type */custom_type
    246 
    247 /* For int options, trailing garbage would be an error. */
    248 -i3
    249 
    250 /* For float options, trailing garbage would be an error. */
    251 -cli3.5
    252 
    253 -b/*/acc	/* The comment is '/' '*' '/', making the option '-bacc'. */
    254 EOF
    255 
    256 	sed '/[$]/d' << \EOF > code.exp
    257 /* $ The variable name is indented by 12 characters due to -di12. */
    258 int	    global_var;
    259 
    260 int
    261 function(int expr)
    262 {
    263    switch (expr) {
    264 /* $ The indentation is 3 + (int)(3.5 * 3), so 3 + 10.5, so 13. */
    265 /* $ See parse.c, function parse, 'case switch_expr'. */
    266 	     case 1:
    267 /* $ The indentation is 3 + (int)3.5 * 3 + 3, so 3 + 9 + 3, so 15. */
    268 /* $ See parse.c, function parse, 'case switch_expr'. */
    269 	       return 1;
    270 	     default:
    271 	       return 0;
    272    }
    273 }
    274 EOF
    275 
    276 	atf_check -o 'file:code.exp' \
    277 	    "$indent" code.c -st
    278 }
    279 
    280 atf_test_case 'opt_npro'
    281 opt_npro_body()
    282 {
    283 	# Mentioning the option -npro in a .pro file has no effect since at
    284 	# that point, indent has already decided to load the .pro file, and
    285 	# it only decides once.
    286 
    287 	echo ' -npro -di8' > .indent.pro
    288 	echo 'int var;' > code.c
    289 	printf 'int\tvar;\n' > code.exp
    290 
    291 	atf_check -o 'file:code.exp' \
    292 	    "$indent" code.c -st
    293 }
    294 
    295 atf_test_case 'opt_U'
    296 opt_U_body()
    297 {
    298 	# From each line of this file, the first word is taken to be a type
    299 	# name.
    300 	#
    301 	# Since neither '/*' nor '' are syntactically valid type names, this
    302 	# means that all kinds of comments are effectively ignored.  When a
    303 	# type name is indented by whitespace, it is ignored as well.
    304 	#
    305 	# Since only the first word of each line is relevant, any remaining
    306 	# words can be used for comments.
    307 	cat <<-\EOF > code.types
    308 		/* Comments are effectively ignored since they never match. */
    309 		# This comment is ignored as well.
    310 		; So is this comment.
    311 		# The following line is empty and adds a type whose name is empty.
    312 
    313 		size_t			from stddef.h
    314 		off_t			for file offsets
    315 		 ignored_t		is ignored since it is indented
    316 	EOF
    317 
    318 	cat <<-\EOF > code.c
    319 		int known_1 = (size_t)   *   arg;
    320 		int known_2 = (off_t)   *   arg;
    321 		int ignored = (ignored_t)   *   arg;
    322 	EOF
    323 	cat <<-\EOF > code.exp
    324 		int known_1 = (size_t)*arg;
    325 		int known_2 = (off_t)*arg;
    326 		int ignored = (ignored_t) * arg;
    327 	EOF
    328 
    329 	atf_check -o 'file:code.exp' \
    330 	    "$indent" -Ucode.types code.c -di0 -st
    331 }
    332 
    333 atf_test_case 'line_no_counting'
    334 line_no_counting_body()
    335 {
    336 	# Before NetBSD indent.c 1.147 from 2021-10-24, indent reported the
    337 	# warning in line 2 instead of the correct line 3.
    338 
    339 	cat <<-\EOF > code.c
    340 		void line_no_counting(void)
    341 		{
    342 			())
    343 		}
    344 	EOF
    345 
    346 	cat <<-\EOF > code.err
    347 		warning: code.c:3: Extra ')'
    348 	EOF
    349 
    350 	atf_check -o 'ignore' -e 'file:code.err' \
    351 	    "$indent" code.c -st
    352 }
    353 
    354 atf_test_case 'default_backup_extension'
    355 default_backup_extension_body()
    356 {
    357 	echo 'int var;' > code.c
    358 	echo 'int var;' > code.c.orig
    359 
    360 	atf_check \
    361 	    "$indent" code.c
    362 	atf_check -o 'file:code.c.orig' \
    363 	    cat code.c.BAK
    364 }
    365 
    366 atf_test_case 'several_profiles'
    367 several_profiles_body()
    368 {
    369 	# If the option '-P' occurs several times, only the last of the
    370 	# profiles is loaded, the others are ignored.
    371 
    372 	echo ' --invalid-option' > error.pro
    373 	echo '' > last.pro
    374 	echo '' > code.c
    375 
    376 	atf_check \
    377 	    "$indent" -Pnonexistent.pro -Perror.pro -Plast.pro code.c -st
    378 }
    379 
    380 
    381 atf_test_case 'command_line_vs_profile'
    382 command_line_vs_profile_body()
    383 {
    384 	# Options from the command line override those from a profile file,
    385 	# no matter if they appear earlier or later than the '-P' in the
    386 	# command line.
    387 
    388 	echo ' -di24' > custom.pro
    389 	printf 'int\t\tdecl;\n' > code.c
    390 
    391 	atf_check -o 'inline:int decl;\n' \
    392 	    "$indent" -di0 -Pcustom.pro code.c -st
    393 	atf_check -o 'inline:int decl;\n' \
    394 	    "$indent" -Pcustom.pro -di0 code.c -st
    395 	atf_check -o 'inline:int decl;\n' \
    396 	    "$indent" -Pcustom.pro code.c -st -di0
    397 }
    398 
    399 
    400 atf_test_case 'opt_v_break_line'
    401 opt_v_break_line_body()
    402 {
    403 	printf '%s\n' 'int *function(void)' '{}' > code.c
    404 
    405 	atf_check -o 'ignore' \
    406 	    "$indent" -v code.c -st
    407 }
    408 
    409 
    410 atf_test_case 'trailing_whitespace_in_preprocessing_line'
    411 trailing_whitespace_in_preprocessing_line_body()
    412 {
    413 	printf '#if trailing && space \n#endif\n' > code.c
    414 
    415 	atf_check -o 'inline:#if trailing && space\n#endif\n' \
    416 	    "$indent" code.c -st
    417 }
    418 
    419 atf_init_test_cases()
    420 {
    421 	atf_add_test_case 'in_place'
    422 	atf_add_test_case 'verbose_profile'
    423 	atf_add_test_case 'nested_struct_declarations'
    424 	atf_add_test_case 'option_P_in_profile_file'
    425 	atf_add_test_case 'option_without_hyphen'
    426 	atf_add_test_case 'opt'
    427 	atf_add_test_case 'opt_npro'
    428 	atf_add_test_case 'opt_U'
    429 	atf_add_test_case 'opt_v_break_line'
    430 	atf_add_test_case 'line_no_counting'
    431 	atf_add_test_case 'default_backup_extension'
    432 	atf_add_test_case 'several_profiles'
    433 	atf_add_test_case 'command_line_vs_profile'
    434 	atf_add_test_case 'in_place_parse_error'
    435 	atf_add_test_case 'trailing_whitespace_in_preprocessing_line'
    436 }
    437