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