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