Home | History | Annotate | Line # | Download | only in indent
t_errors.sh revision 1.19
      1 #! /bin/sh
      2 # $NetBSD: t_errors.sh,v 1.19 2021/11/07 15:54:00 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_npro_trailing_garbage'
    147 option_npro_trailing_garbage_body()
    148 {
    149 	# TODO: reject -npro-garbage, only allow -npro without trailing garbage.
    150 
    151 	atf_check \
    152 	    "$indent" -npro-garbage
    153 }
    154 
    155 atf_test_case 'option_st_trailing_garbage'
    156 option_st_trailing_garbage_body()
    157 {
    158 	# TODO: reject -stdio, only allow -st without trailing garbage.
    159 
    160 	atf_check \
    161 	    "$indent" -stdio
    162 }
    163 
    164 atf_test_case 'option_version_trailing_garbage'
    165 option_version_trailing_garbage_body()
    166 {
    167 	# TODO: reject --version-dump, only allow --version without trailing garbage.
    168 
    169 	atf_check -o 'inline:NetBSD indent 2.1'"$nl" \
    170 	    "$indent" --version-dump
    171 }
    172 
    173 atf_test_case 'option_buffer_overflow'
    174 option_buffer_overflow_body()
    175 {
    176 	opt='12345678123456781234567812345678'	# 32
    177 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 256
    178 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 2048
    179 	opt="$opt$opt$opt$opt$opt$opt$opt$opt"	# 16384
    180 	printf '%s\n' "-$opt" > indent.pro
    181 
    182 	expect_error \
    183 	    'indent: buffer overflow in indent.pro, starting with '\''-123456781'\''' \
    184 	    -Pindent.pro
    185 }
    186 
    187 atf_test_case 'option_special_missing_param'
    188 option_special_missing_param_body()
    189 {
    190 	# TODO: Write '-cli' instead of only 'cli'.
    191 	expect_error \
    192 	    'indent: Command line: ``cli'\'\'' requires an argument' \
    193 	    -cli
    194 
    195 	expect_error \
    196 	    'indent: Command line: ``T'\'\'' requires an argument' \
    197 	    -T
    198 
    199 	expect_error \
    200 	    'indent: Command line: ``U'\'\'' requires an argument' \
    201 	    -U
    202 }
    203 
    204 atf_test_case 'unterminated_comment_wrap'
    205 unterminated_comment_wrap_body()
    206 {
    207 	echo '/*' > comment.c
    208 
    209 	atf_check -s 'exit:1' \
    210 	    -o 'inline:/*'"$nl"' *'"$nl" \
    211 	    -e 'inline:error: Standard Input:2: Unterminated comment'"$nl" \
    212 	    "$indent" -st < comment.c
    213 }
    214 
    215 atf_test_case 'unterminated_comment_nowrap'
    216 unterminated_comment_nowrap_body()
    217 {
    218 	echo '/*-' > comment.c
    219 
    220 	atf_check -s 'exit:1' \
    221 	    -o 'inline:/*-'"$nl$nl" \
    222 	    -e 'inline:error: Standard Input:2: Unterminated comment'"$nl" \
    223 	    "$indent" -st < comment.c
    224 }
    225 
    226 atf_test_case 'in_place_wrong_backup'
    227 in_place_wrong_backup_body()
    228 {
    229 	cat <<-\EOF > code.c
    230 		int decl;
    231 	EOF
    232 	cp code.c code.c.orig
    233 
    234 	# Due to the strange backup suffix '/subdir', indent tries to create
    235 	# a file named 'code.c/subdir', but 'code.c' is already a regular
    236 	# file, not a directory.
    237 	atf_check -s 'exit:1' \
    238 	    -e 'inline:indent: code.c/subdir: Not a directory'"$nl" \
    239 	    env SIMPLE_BACKUP_SUFFIX="/subdir" "$indent" code.c
    240 
    241 	# Since there was an early error, the original file is kept as is.
    242 	atf_check -o 'file:code.c.orig' \
    243 	    cat code.c
    244 }
    245 
    246 atf_test_case 'argument_input_enoent'
    247 argument_input_enoent_body()
    248 {
    249 	atf_check -s 'exit:1' \
    250 	    -e 'inline:indent: ./nonexistent.c: No such file or directory'"$nl" \
    251 	    "$indent" ./nonexistent.c
    252 }
    253 
    254 atf_test_case 'argument_output_equals_input_name'
    255 argument_output_equals_input_name_body()
    256 {
    257 	echo '/* comment */' > code.c
    258 
    259 	atf_check -s 'exit:1' \
    260 	    -e 'inline:indent: input and output files must be different'"$nl" \
    261 	    "$indent" code.c code.c
    262 }
    263 
    264 atf_test_case 'argument_output_equals_input_file'
    265 argument_output_equals_input_file_body()
    266 {
    267 	echo '/* comment */' > code.c
    268 
    269 	atf_check \
    270 	    "$indent" code.c ./code.c
    271 
    272 	# Oops, the file has become empty since the output is first emptied,
    273 	# before reading any of the input.
    274 	atf_check \
    275 	    cat code.c
    276 }
    277 
    278 atf_test_case 'argument_output_enoent'
    279 argument_output_enoent_body()
    280 {
    281 	expect_error \
    282 	    'indent: subdir/nonexistent.c: No such file or directory' \
    283 	    /dev/null subdir/nonexistent.c
    284 }
    285 
    286 atf_test_case 'argument_too_many'
    287 argument_too_many_body()
    288 {
    289 	echo '/* comment */' > arg1.c
    290 
    291 	expect_error \
    292 	    'indent: too many arguments: arg3.c' \
    293 	    arg1.c arg2.c arg3.c arg4.c
    294 }
    295 
    296 atf_test_case 'unexpected_end_of_file'
    297 unexpected_end_of_file_body()
    298 {
    299 	echo 'struct{' > code.c
    300 
    301 	expect_error \
    302 	    'error: code.c:1: Stuff missing from end of file' \
    303 	    code.c
    304 
    305 	atf_check \
    306 	    -o 'inline:struct {'"$nl" \
    307 	    cat code.c
    308 }
    309 
    310 atf_test_case 'unexpected_closing_brace_top_level'
    311 unexpected_closing_brace_top_level_body()
    312 {
    313 	echo '}' > code.c
    314 
    315 	expect_error \
    316 	    'error: code.c:1: Statement nesting error' \
    317 	    code.c
    318 	atf_check \
    319 	    -o 'inline:}'"$nl" \
    320 	    cat code.c
    321 }
    322 
    323 atf_test_case 'unexpected_closing_brace_decl'
    324 unexpected_closing_brace_decl_body()
    325 {
    326 	echo 'int i = 3};' > code.c
    327 
    328 	expect_error \
    329 	    'error: code.c:1: Statement nesting error' \
    330 	    code.c
    331 	# Despite the error message, the original file got overwritten with a
    332 	# best-effort rewrite of the code.
    333 	atf_check \
    334 	    -o 'inline:int		i = 3};'"$nl" \
    335 	    cat code.c
    336 }
    337 
    338 atf_test_case 'preprocessing_overflow'
    339 preprocessing_overflow_body()
    340 {
    341 	cat <<-\EOF > code.c
    342 		#if 1
    343 		#if 2
    344 		#if 3
    345 		#if 4
    346 		#if 5
    347 		#if 6
    348 		#endif 6
    349 		#endif 5
    350 		#endif 4
    351 		#endif 3
    352 		#endif 2
    353 		#endif 1
    354 		#endif too much
    355 	EOF
    356 	cat <<-\EOF > stderr.exp
    357 		error: code.c:6: #if stack overflow
    358 		error: code.c:12: Unmatched #endif
    359 		error: code.c:13: Unmatched #endif
    360 	EOF
    361 
    362 	atf_check -s 'exit:1' \
    363 	    -e 'file:stderr.exp' \
    364 	    "$indent" code.c
    365 }
    366 
    367 atf_test_case 'preprocessing_unrecognized'
    368 preprocessing_unrecognized_body()
    369 {
    370 	cat <<-\EOF > code.c
    371 		#unknown
    372 		# 3 "file.c"
    373 		#elif 3
    374 		#else
    375 	EOF
    376 	cat <<-\EOF > stderr.exp
    377 		error: code.c:1: Unrecognized cpp directive
    378 		error: code.c:2: Unrecognized cpp directive
    379 		error: code.c:3: Unmatched #elif
    380 		error: code.c:4: Unmatched #else
    381 	EOF
    382 
    383 	atf_check -s 'exit:1' \
    384 	    -e 'file:stderr.exp' \
    385 	    "$indent" code.c
    386 }
    387 
    388 atf_test_case 'unbalanced_parentheses_1'
    389 unbalanced_parentheses_1_body()
    390 {
    391 	cat <<-\EOF > code.c
    392 		int var =
    393 		(
    394 		;
    395 		)
    396 		;
    397 	EOF
    398 	cat <<-\EOF > stderr.exp
    399 		error: code.c:3: Unbalanced parentheses
    400 		warning: code.c:4: Extra ')'
    401 	EOF
    402 
    403 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    404 	    "$indent" code.c
    405 }
    406 
    407 atf_test_case 'unbalanced_parentheses_2'
    408 unbalanced_parentheses_2_body()
    409 {
    410 	# '({...})' is the GCC extension "Statement expression".
    411 	cat <<-\EOF > code.c
    412 		int var =
    413 		(
    414 		{
    415 		1
    416 		}
    417 		)
    418 		;
    419 	EOF
    420 	cat <<-\EOF > stderr.exp
    421 		error: code.c:3: Unbalanced parentheses
    422 		warning: code.c:6: Extra ')'
    423 	EOF
    424 
    425 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    426 	    "$indent" code.c
    427 }
    428 
    429 atf_test_case 'unbalanced_parentheses_3'
    430 unbalanced_parentheses_3_body()
    431 {
    432 	# '({...})' is the GCC extension "Statement expression".
    433 	cat <<-\EOF > code.c
    434 		int var =
    435 		(
    436 		1
    437 		}
    438 		;
    439 	EOF
    440 	cat <<-\EOF > stderr.exp
    441 		error: code.c:4: Unbalanced parentheses
    442 		error: code.c:4: Statement nesting error
    443 	EOF
    444 
    445 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    446 	    "$indent" code.c
    447 }
    448 
    449 atf_test_case 'search_stmt_comment_segv'
    450 search_stmt_comment_segv_body()
    451 {
    452 	# As of NetBSD indent.c 1.188 from 2021-10-30, indent crashes while
    453 	# trying to format the following artificial code.
    454 
    455 	printf '{if(expr\n)/*c*/;}\n' > code.c
    456 
    457 	cat <<\EOF > code.exp
    458 {
    459 	if (expr
    460 		)		/* c */
    461 		;
    462 }
    463 EOF
    464 
    465 	# TODO: actually produce code.exp instead of an assertion failure.
    466 	atf_check -s 'signal' -o 'ignore' -e 'match:assert' \
    467 	    "$indent" code.c -st
    468 }
    469 
    470 atf_test_case 'search_stmt_fits_in_one_line'
    471 search_stmt_fits_in_one_line_body()
    472 {
    473 	# The comment is placed after 'if (0) ...', where it is processed
    474 	# by search_stmt_comment. That function redirects the input buffer to
    475 	# a temporary buffer that is not guaranteed to be terminated by '\n'.
    476 	# Before NetBSD pr_comment.c 1.91 from 2021-10-30, this produced an
    477 	# assertion failure in fits_in_one_line.
    478 	cat <<EOF > code.c
    479 int f(void)
    480 {
    481 	if (0)
    482 		/* 0123456789012345678901 */;
    483 }
    484 EOF
    485 
    486 	# Indent tries hard to make the comment fit to the 34-character line
    487 	# length, but it is just not possible.
    488 	cat <<EOF > expected.out
    489 int
    490 f(void)
    491 {
    492 	if (0)
    493 		/*
    494 		 * 0123456789012345678901
    495 		  */ ;
    496 }
    497 EOF
    498 
    499 	atf_check -o 'file:expected.out' \
    500 	    "$indent" -l34 code.c -st
    501 }
    502 
    503 
    504 atf_init_test_cases()
    505 {
    506 	atf_add_test_case 'option_unknown'
    507 	atf_add_test_case 'option_bool_trailing_garbage'
    508 	atf_add_test_case 'option_int_missing_argument'
    509 	atf_add_test_case 'option_profile_not_found'
    510 	atf_add_test_case 'option_buffer_overflow'
    511 	atf_add_test_case 'option_typedefs_not_found'
    512 	atf_add_test_case 'option_special_missing_param'
    513 	atf_add_test_case 'option_tabsize_negative'
    514 	atf_add_test_case 'option_tabsize_zero'
    515 	atf_add_test_case 'option_tabsize_large'
    516 	atf_add_test_case 'option_tabsize_very_large'
    517 	atf_add_test_case 'option_int_trailing_garbage'
    518 	atf_add_test_case 'option_cli_trailing_garbage'
    519 	atf_add_test_case 'option_npro_trailing_garbage'
    520 	atf_add_test_case 'option_st_trailing_garbage'
    521 	atf_add_test_case 'option_version_trailing_garbage'
    522 	atf_add_test_case 'option_indent_size_zero'
    523 	atf_add_test_case 'unterminated_comment_wrap'
    524 	atf_add_test_case 'unterminated_comment_nowrap'
    525 	atf_add_test_case 'in_place_wrong_backup'
    526 	atf_add_test_case 'argument_input_enoent'
    527 	atf_add_test_case 'argument_output_equals_input_name'
    528 	atf_add_test_case 'argument_output_equals_input_file'
    529 	atf_add_test_case 'argument_output_enoent'
    530 	atf_add_test_case 'argument_too_many'
    531 	atf_add_test_case 'unexpected_end_of_file'
    532 	atf_add_test_case 'unexpected_closing_brace_top_level'
    533 	atf_add_test_case 'unexpected_closing_brace_decl'
    534 	atf_add_test_case 'preprocessing_overflow'
    535 	atf_add_test_case 'preprocessing_unrecognized'
    536 	atf_add_test_case 'unbalanced_parentheses_1'
    537 	atf_add_test_case 'unbalanced_parentheses_2'
    538 	atf_add_test_case 'unbalanced_parentheses_3'
    539 	atf_add_test_case 'search_stmt_comment_segv'
    540 	atf_add_test_case 'search_stmt_fits_in_one_line'
    541 }
    542