Home | History | Annotate | Line # | Download | only in indent
t_errors.sh revision 1.18
      1 #! /bin/sh
      2 # $NetBSD: t_errors.sh,v 1.18 2021/11/07 10:42:58 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 error handling in indent.
     31 
     32 indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent)
     33 nl='
     34 '
     35 
     36 expect_error()
     37 {
     38 	local msg
     39 
     40 	msg="$1"
     41 	shift
     42 
     43 	atf_check -s 'exit:1' \
     44 	    -e "inline:$msg$nl" \
     45 	    "$indent" "$@"
     46 }
     47 
     48 atf_test_case 'option_unknown'
     49 option_unknown_body()
     50 {
     51 	expect_error \
     52 	    'indent: Command line: unknown option "-Z-unknown"' \
     53 	    -Z-unknown
     54 }
     55 
     56 atf_test_case 'option_bool_trailing_garbage'
     57 option_bool_trailing_garbage_body()
     58 {
     59 	expect_error \
     60 	    'indent: Command line: unknown option "-bacchus"' \
     61 	    -bacchus
     62 }
     63 
     64 atf_test_case 'option_int_missing_argument'
     65 option_int_missing_argument_body()
     66 {
     67 	expect_error \
     68 	    'indent: Command line: argument "x" to option "-ts" must be an integer' \
     69 	    -tsx
     70 }
     71 
     72 atf_test_case 'option_profile_not_found'
     73 option_profile_not_found_body()
     74 {
     75 	expect_error \
     76 	    'indent: profile ./nonexistent: No such file or directory' \
     77 	    -P./nonexistent
     78 }
     79 
     80 atf_test_case 'option_typedefs_not_found'
     81 option_typedefs_not_found_body()
     82 {
     83 	expect_error \
     84 	    'indent: cannot open file ./nonexistent' \
     85 	    -U./nonexistent
     86 }
     87 
     88 atf_test_case 'option_tabsize_negative'
     89 option_tabsize_negative_body()
     90 {
     91 	expect_error \
     92 	    'indent: Command line: argument "-1" to option "-ts" must be between 1 and 80' \
     93 	    -ts-1
     94 }
     95 
     96 atf_test_case 'option_tabsize_zero'
     97 option_tabsize_zero_body()
     98 {
     99 	expect_error \
    100 	    'indent: Command line: argument "0" to option "-ts" must be between 1 and 80' \
    101 	    -ts0
    102 }
    103 
    104 atf_test_case 'option_tabsize_large'
    105 option_tabsize_large_body()
    106 {
    107 	# Integer overflow, on both ILP32 and LP64 platforms.
    108 	expect_error \
    109 	    'indent: Command line: argument "81" to option "-ts" must be between 1 and 80' \
    110 	    -ts81
    111 }
    112 
    113 atf_test_case 'option_tabsize_very_large'
    114 option_tabsize_very_large_body()
    115 {
    116 	# Integer overflow, on both ILP32 and LP64 platforms.
    117 	expect_error \
    118 	    'indent: Command line: argument "3000000000" to option "-ts" must be between 1 and 80' \
    119 	    -ts3000000000
    120 }
    121 
    122 atf_test_case 'option_indent_size_zero'
    123 option_indent_size_zero_body()
    124 {
    125 	expect_error \
    126 	    'indent: Command line: argument "0" to option "-i" must be between 1 and 80' \
    127 	    -i0
    128 }
    129 
    130 atf_test_case 'option_int_trailing_garbage'
    131 option_int_trailing_garbage_body()
    132 {
    133 	expect_error \
    134 	    'indent: Command line: argument "3garbage" to option "-i" must be an integer' \
    135 	    -i3garbage
    136 }
    137 
    138 atf_test_case 'option_cli_trailing_garbage'
    139 option_cli_trailing_garbage_body()
    140 {
    141 	expect_error \
    142 	    'indent: Command line: argument "3garbage" to option "-cli" must be numeric' \
    143 	    -cli3garbage
    144 }
    145 
    146 atf_test_case 'option_buffer_overflow'
    147 option_buffer_overflow_body()
    148 {
    149 	opt='12345678123456781234567812345678'	# 32
    150 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 256
    151 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 2048
    152 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 16384
    153 	printf '%s\n' "-$opt" > indent.pro
    154 
    155 	expect_error \
    156 	    'indent: buffer overflow in indent.pro, starting with '\''-123456781'\''' \
    157 	    -Pindent.pro
    158 }
    159 
    160 atf_test_case 'option_special_missing_param'
    161 option_special_missing_param_body()
    162 {
    163 	# TODO: Write '-cli' instead of only 'cli'.
    164 	expect_error \
    165 	    'indent: Command line: ``cli'\'\'' requires an argument' \
    166 	    -cli
    167 
    168 	expect_error \
    169 	    'indent: Command line: ``T'\'\'' requires an argument' \
    170 	    -T
    171 
    172 	expect_error \
    173 	    'indent: Command line: ``U'\'\'' requires an argument' \
    174 	    -U
    175 }
    176 
    177 atf_test_case 'unterminated_comment_wrap'
    178 unterminated_comment_wrap_body()
    179 {
    180 	echo '/*' > comment.c
    181 
    182 	atf_check -s 'exit:1' \
    183 	    -o 'inline:/*'"$nl"' *'"$nl" \
    184 	    -e 'inline:error: Standard Input:2: Unterminated comment'"$nl" \
    185 	    "$indent" -st < comment.c
    186 }
    187 
    188 atf_test_case 'unterminated_comment_nowrap'
    189 unterminated_comment_nowrap_body()
    190 {
    191 	echo '/*-' > comment.c
    192 
    193 	atf_check -s 'exit:1' \
    194 	    -o 'inline:/*-'"$nl$nl" \
    195 	    -e 'inline:error: Standard Input:2: Unterminated comment'"$nl" \
    196 	    "$indent" -st < comment.c
    197 }
    198 
    199 atf_test_case 'in_place_wrong_backup'
    200 in_place_wrong_backup_body()
    201 {
    202 	cat <<-\EOF > code.c
    203 		int decl;
    204 	EOF
    205 	cp code.c code.c.orig
    206 
    207 	# Due to the strange backup suffix '/subdir', indent tries to create
    208 	# a file named 'code.c/subdir', but 'code.c' is already a regular
    209 	# file, not a directory.
    210 	atf_check -s 'exit:1' \
    211 	    -e 'inline:indent: code.c/subdir: Not a directory'"$nl" \
    212 	    env SIMPLE_BACKUP_SUFFIX="/subdir" "$indent" code.c
    213 
    214 	# Since there was an early error, the original file is kept as is.
    215 	atf_check -o 'file:code.c.orig' \
    216 	    cat code.c
    217 }
    218 
    219 atf_test_case 'argument_input_enoent'
    220 argument_input_enoent_body()
    221 {
    222 	atf_check -s 'exit:1' \
    223 	    -e 'inline:indent: ./nonexistent.c: No such file or directory'"$nl" \
    224 	    "$indent" ./nonexistent.c
    225 }
    226 
    227 atf_test_case 'argument_output_equals_input_name'
    228 argument_output_equals_input_name_body()
    229 {
    230 	echo '/* comment */' > code.c
    231 
    232 	atf_check -s 'exit:1' \
    233 	    -e 'inline:indent: input and output files must be different'"$nl" \
    234 	    "$indent" code.c code.c
    235 }
    236 
    237 atf_test_case 'argument_output_equals_input_file'
    238 argument_output_equals_input_file_body()
    239 {
    240 	echo '/* comment */' > code.c
    241 
    242 	atf_check \
    243 	    "$indent" code.c ./code.c
    244 
    245 	# Oops, the file has become empty since the output is first emptied,
    246 	# before reading any of the input.
    247 	atf_check \
    248 	    cat code.c
    249 }
    250 
    251 atf_test_case 'argument_output_enoent'
    252 argument_output_enoent_body()
    253 {
    254 	expect_error \
    255 	    'indent: subdir/nonexistent.c: No such file or directory' \
    256 	    /dev/null subdir/nonexistent.c
    257 }
    258 
    259 atf_test_case 'argument_too_many'
    260 argument_too_many_body()
    261 {
    262 	echo '/* comment */' > arg1.c
    263 
    264 	expect_error \
    265 	    'indent: too many arguments: arg3.c' \
    266 	    arg1.c arg2.c arg3.c arg4.c
    267 }
    268 
    269 atf_test_case 'unexpected_end_of_file'
    270 unexpected_end_of_file_body()
    271 {
    272 	echo 'struct{' > code.c
    273 
    274 	expect_error \
    275 	    'error: code.c:1: Stuff missing from end of file' \
    276 	    code.c
    277 
    278 	atf_check \
    279 	    -o 'inline:struct {'"$nl" \
    280 	    cat code.c
    281 }
    282 
    283 atf_test_case 'unexpected_closing_brace_top_level'
    284 unexpected_closing_brace_top_level_body()
    285 {
    286 	echo '}' > code.c
    287 
    288 	expect_error \
    289 	    'error: code.c:1: Statement nesting error' \
    290 	    code.c
    291 	atf_check \
    292 	    -o 'inline:}'"$nl" \
    293 	    cat code.c
    294 }
    295 
    296 atf_test_case 'unexpected_closing_brace_decl'
    297 unexpected_closing_brace_decl_body()
    298 {
    299 	echo 'int i = 3};' > code.c
    300 
    301 	expect_error \
    302 	    'error: code.c:1: Statement nesting error' \
    303 	    code.c
    304 	# Despite the error message, the original file got overwritten with a
    305 	# best-effort rewrite of the code.
    306 	atf_check \
    307 	    -o 'inline:int		i = 3};'"$nl" \
    308 	    cat code.c
    309 }
    310 
    311 atf_test_case 'preprocessing_overflow'
    312 preprocessing_overflow_body()
    313 {
    314 	cat <<-\EOF > code.c
    315 		#if 1
    316 		#if 2
    317 		#if 3
    318 		#if 4
    319 		#if 5
    320 		#if 6
    321 		#endif 6
    322 		#endif 5
    323 		#endif 4
    324 		#endif 3
    325 		#endif 2
    326 		#endif 1
    327 		#endif too much
    328 	EOF
    329 	cat <<-\EOF > stderr.exp
    330 		error: code.c:6: #if stack overflow
    331 		error: code.c:12: Unmatched #endif
    332 		error: code.c:13: Unmatched #endif
    333 	EOF
    334 
    335 	atf_check -s 'exit:1' \
    336 	    -e 'file:stderr.exp' \
    337 	    "$indent" code.c
    338 }
    339 
    340 atf_test_case 'preprocessing_unrecognized'
    341 preprocessing_unrecognized_body()
    342 {
    343 	cat <<-\EOF > code.c
    344 		#unknown
    345 		# 3 "file.c"
    346 		#elif 3
    347 		#else
    348 	EOF
    349 	cat <<-\EOF > stderr.exp
    350 		error: code.c:1: Unrecognized cpp directive
    351 		error: code.c:2: Unrecognized cpp directive
    352 		error: code.c:3: Unmatched #elif
    353 		error: code.c:4: Unmatched #else
    354 	EOF
    355 
    356 	atf_check -s 'exit:1' \
    357 	    -e 'file:stderr.exp' \
    358 	    "$indent" code.c
    359 }
    360 
    361 atf_test_case 'unbalanced_parentheses_1'
    362 unbalanced_parentheses_1_body()
    363 {
    364 	cat <<-\EOF > code.c
    365 		int var =
    366 		(
    367 		;
    368 		)
    369 		;
    370 	EOF
    371 	cat <<-\EOF > stderr.exp
    372 		error: code.c:3: Unbalanced parentheses
    373 		warning: code.c:4: Extra ')'
    374 	EOF
    375 
    376 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    377 	    "$indent" code.c
    378 }
    379 
    380 atf_test_case 'unbalanced_parentheses_2'
    381 unbalanced_parentheses_2_body()
    382 {
    383 	# '({...})' is the GCC extension "Statement expression".
    384 	cat <<-\EOF > code.c
    385 		int var =
    386 		(
    387 		{
    388 		1
    389 		}
    390 		)
    391 		;
    392 	EOF
    393 	cat <<-\EOF > stderr.exp
    394 		error: code.c:3: Unbalanced parentheses
    395 		warning: code.c:6: Extra ')'
    396 	EOF
    397 
    398 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    399 	    "$indent" code.c
    400 }
    401 
    402 atf_test_case 'unbalanced_parentheses_3'
    403 unbalanced_parentheses_3_body()
    404 {
    405 	# '({...})' is the GCC extension "Statement expression".
    406 	cat <<-\EOF > code.c
    407 		int var =
    408 		(
    409 		1
    410 		}
    411 		;
    412 	EOF
    413 	cat <<-\EOF > stderr.exp
    414 		error: code.c:4: Unbalanced parentheses
    415 		error: code.c:4: Statement nesting error
    416 	EOF
    417 
    418 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    419 	    "$indent" code.c
    420 }
    421 
    422 atf_test_case 'search_stmt_comment_segv'
    423 search_stmt_comment_segv_body()
    424 {
    425 	# As of NetBSD indent.c 1.188 from 2021-10-30, indent crashes while
    426 	# trying to format the following artificial code.
    427 
    428 	printf '{if(expr\n)/*c*/;}\n' > code.c
    429 
    430 	cat <<\EOF > code.exp
    431 {
    432 	if (expr
    433 		)		/* c */
    434 		;
    435 }
    436 EOF
    437 
    438 	# TODO: actually produce code.exp instead of an assertion failure.
    439 	atf_check -s 'signal' -o 'ignore' -e 'match:assert' \
    440 	    "$indent" code.c -st
    441 }
    442 
    443 atf_test_case 'search_stmt_fits_in_one_line'
    444 search_stmt_fits_in_one_line_body()
    445 {
    446 	# The comment is placed after 'if (0) ...', where it is processed
    447 	# by search_stmt_comment. That function redirects the input buffer to
    448 	# a temporary buffer that is not guaranteed to be terminated by '\n'.
    449 	# Before NetBSD pr_comment.c 1.91 from 2021-10-30, this produced an
    450 	# assertion failure in fits_in_one_line.
    451 	cat <<EOF > code.c
    452 int f(void)
    453 {
    454 	if (0)
    455 		/* 0123456789012345678901 */;
    456 }
    457 EOF
    458 
    459 	# Indent tries hard to make the comment fit to the 34-character line
    460 	# length, but it is just not possible.
    461 	cat <<EOF > expected.out
    462 int
    463 f(void)
    464 {
    465 	if (0)
    466 		/*
    467 		 * 0123456789012345678901
    468 		  */ ;
    469 }
    470 EOF
    471 
    472 	atf_check -o 'file:expected.out' \
    473 	    "$indent" -l34 code.c -st
    474 }
    475 
    476 
    477 atf_init_test_cases()
    478 {
    479 	atf_add_test_case 'option_unknown'
    480 	atf_add_test_case 'option_bool_trailing_garbage'
    481 	atf_add_test_case 'option_int_missing_argument'
    482 	atf_add_test_case 'option_profile_not_found'
    483 	atf_add_test_case 'option_buffer_overflow'
    484 	atf_add_test_case 'option_typedefs_not_found'
    485 	atf_add_test_case 'option_special_missing_param'
    486 	atf_add_test_case 'option_tabsize_negative'
    487 	atf_add_test_case 'option_tabsize_zero'
    488 	atf_add_test_case 'option_tabsize_large'
    489 	atf_add_test_case 'option_tabsize_very_large'
    490 	atf_add_test_case 'option_int_trailing_garbage'
    491 	atf_add_test_case 'option_cli_trailing_garbage'
    492 	atf_add_test_case 'option_indent_size_zero'
    493 	atf_add_test_case 'unterminated_comment_wrap'
    494 	atf_add_test_case 'unterminated_comment_nowrap'
    495 	atf_add_test_case 'in_place_wrong_backup'
    496 	atf_add_test_case 'argument_input_enoent'
    497 	atf_add_test_case 'argument_output_equals_input_name'
    498 	atf_add_test_case 'argument_output_equals_input_file'
    499 	atf_add_test_case 'argument_output_enoent'
    500 	atf_add_test_case 'argument_too_many'
    501 	atf_add_test_case 'unexpected_end_of_file'
    502 	atf_add_test_case 'unexpected_closing_brace_top_level'
    503 	atf_add_test_case 'unexpected_closing_brace_decl'
    504 	atf_add_test_case 'preprocessing_overflow'
    505 	atf_add_test_case 'preprocessing_unrecognized'
    506 	atf_add_test_case 'unbalanced_parentheses_1'
    507 	atf_add_test_case 'unbalanced_parentheses_2'
    508 	atf_add_test_case 'unbalanced_parentheses_3'
    509 	atf_add_test_case 'search_stmt_comment_segv'
    510 	atf_add_test_case 'search_stmt_fits_in_one_line'
    511 }
    512