Home | History | Annotate | Line # | Download | only in indent
t_errors.sh revision 1.38.2.1
      1 #! /bin/sh
      2 # $NetBSD: t_errors.sh,v 1.38.2.1 2025/08/02 05:58:13 perseant 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_wrong_argument'
     61 option_int_wrong_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 'unterminated_char_constant'
    218 unterminated_char_constant_body()
    219 {
    220 	echo "char ch = 'x" > char.c
    221 
    222 	atf_check -s 'exit:1' \
    223 	    -o "inline:char ch = 'x\n" \
    224 	    -e 'inline:error: Standard Input:1: Unterminated literal\n' \
    225 	    "$indent" -st -di0 < char.c
    226 }
    227 
    228 atf_test_case 'unterminated_string_literal'
    229 unterminated_string_literal_body()
    230 {
    231 	echo 'const char str[] = "x' > string.c
    232 
    233 	atf_check -s 'exit:1' \
    234 	    -o 'inline:const char str[] = "x\n' \
    235 	    -e 'inline:error: Standard Input:1: Unterminated literal\n' \
    236 	    "$indent" -st -di0 < string.c
    237 }
    238 
    239 atf_test_case 'in_place_wrong_backup'
    240 in_place_wrong_backup_body()
    241 {
    242 	cat <<-\EOF > code.c
    243 		int decl;
    244 	EOF
    245 	cp code.c code.c.orig
    246 
    247 	# Due to the strange backup suffix '/subdir', indent tries to create
    248 	# a file named 'code.c/subdir', but 'code.c' is already a regular
    249 	# file, not a directory.
    250 	atf_check -s 'exit:1' \
    251 	    -e 'inline:indent: code.c/subdir: Not a directory\n' \
    252 	    env SIMPLE_BACKUP_SUFFIX="/subdir" "$indent" code.c
    253 
    254 	# Since there was an early error, the original file is kept as is.
    255 	atf_check -o 'file:code.c.orig' \
    256 	    cat code.c
    257 }
    258 
    259 atf_test_case 'argument_input_enoent'
    260 argument_input_enoent_body()
    261 {
    262 	atf_check -s 'exit:1' \
    263 	    -e 'inline:indent: ./nonexistent.c: No such file or directory\n' \
    264 	    "$indent" ./nonexistent.c
    265 }
    266 
    267 atf_test_case 'argument_output_equals_input_name'
    268 argument_output_equals_input_name_body()
    269 {
    270 	echo '/* comment */' > code.c
    271 
    272 	atf_check -s 'exit:1' \
    273 	    -e 'inline:indent: input and output files must be different\n' \
    274 	    "$indent" code.c code.c
    275 }
    276 
    277 atf_test_case 'argument_output_equals_input_file'
    278 argument_output_equals_input_file_body()
    279 {
    280 	echo '/* comment */' > code.c
    281 
    282 	atf_check \
    283 	    "$indent" code.c ./code.c
    284 
    285 	# Oops, the file has become empty since the output is first emptied,
    286 	# before reading any of the input.
    287 	atf_check \
    288 	    cat code.c
    289 }
    290 
    291 atf_test_case 'argument_output_enoent'
    292 argument_output_enoent_body()
    293 {
    294 	expect_error \
    295 	    'indent: subdir/nonexistent.c: No such file or directory' \
    296 	    /dev/null subdir/nonexistent.c
    297 }
    298 
    299 atf_test_case 'argument_too_many'
    300 argument_too_many_body()
    301 {
    302 	echo '/* comment */' > arg1.c
    303 
    304 	expect_error \
    305 	    'indent: too many arguments: arg3.c' \
    306 	    arg1.c arg2.c arg3.c arg4.c
    307 }
    308 
    309 atf_test_case 'unexpected_end_of_file'
    310 unexpected_end_of_file_body()
    311 {
    312 	echo 'struct{' > code.c
    313 
    314 	expect_error \
    315 	    'error: code.c:1: Stuff missing from end of file' \
    316 	    code.c
    317 
    318 	atf_check \
    319 	    -o 'inline:struct {\n' \
    320 	    cat code.c
    321 }
    322 
    323 atf_test_case 'unexpected_closing_brace_top_level'
    324 unexpected_closing_brace_top_level_body()
    325 {
    326 	echo '}' > code.c
    327 
    328 	expect_error \
    329 	    'error: code.c:1: Statement nesting error' \
    330 	    code.c
    331 	atf_check \
    332 	    -o 'inline:}\n' \
    333 	    cat code.c
    334 }
    335 
    336 atf_test_case 'unexpected_closing_brace_decl'
    337 unexpected_closing_brace_decl_body()
    338 {
    339 	echo 'int i = 3};' > code.c
    340 
    341 	expect_error \
    342 	    'error: code.c:1: Statement nesting error' \
    343 	    code.c
    344 	# Despite the error message, the original file got overwritten with a
    345 	# best-effort rewrite of the code.
    346 	atf_check \
    347 	    -o 'inline:int		i = 3};\n' \
    348 	    cat code.c
    349 }
    350 
    351 atf_test_case 'unbalanced_parentheses'
    352 unbalanced_parentheses_body()
    353 {
    354 	cat <<-\EOF > code.c
    355 		int var =
    356 		(
    357 		;
    358 		)
    359 		;
    360 	EOF
    361 	cat <<-\EOF > stderr.exp
    362 		error: code.c:3: Unbalanced parentheses
    363 		warning: code.c:4: Extra ')'
    364 	EOF
    365 
    366 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    367 	    "$indent" code.c
    368 }
    369 
    370 atf_test_case 'gcc_statement_expression'
    371 gcc_statement_expression_body()
    372 {
    373 	# '({...})' is the GCC extension "Statement expression".
    374 	cat <<-\EOF > code.c
    375 		int var =
    376 		(
    377 		1
    378 		}
    379 		;
    380 	EOF
    381 	cat <<-\EOF > stderr.exp
    382 		error: code.c:4: Unbalanced parentheses
    383 		error: code.c:4: Statement nesting error
    384 	EOF
    385 
    386 	atf_check -s 'exit:1' -e 'file:stderr.exp' \
    387 	    "$indent" code.c
    388 }
    389 
    390 atf_test_case 'crash_comment_after_controlling_expression'
    391 crash_comment_after_controlling_expression_body()
    392 {
    393 	# Before 2023-05-11, indent crashed while
    394 	# trying to format the following artificial code.
    395 
    396 	printf '{if(expr\n)/*c*/;}\n' > code.c
    397 
    398 	cat <<\EOF > code.exp
    399 {
    400 	if (expr
    401 		)		/* c */
    402 		;
    403 }
    404 EOF
    405 
    406 	atf_check -o 'file:code.exp' \
    407 	    "$indent" code.c -st
    408 }
    409 
    410 atf_test_case 'comment_fits_in_one_line'
    411 comment_fits_in_one_line_body()
    412 {
    413 	# The comment is placed after 'if (0) ...'. Before NetBSD pr_comment.c
    414 	# 1.91 from 2021-10-30, this produced an assertion failure in
    415 	# fits_in_one_line.
    416 	cat <<EOF > code.c
    417 int f(void)
    418 {
    419 	if (0)
    420 		/* 0123456789012345678901 */;
    421 }
    422 EOF
    423 
    424 	# Indent tries hard to make the comment fit to the 34-character line
    425 	# length, but it is just not possible.
    426 	cat <<EOF > expected.out
    427 int
    428 f(void)
    429 {
    430 	if (0)
    431 		/*
    432 		 * 0123456789012345678901
    433 		 */;
    434 }
    435 EOF
    436 
    437 	atf_check -o 'file:expected.out' \
    438 	    "$indent" -l34 code.c -st
    439 }
    440 
    441 atf_test_case 'stack_overflow'
    442 stack_overflow_body()
    443 {
    444 	cat <<-EOF > code.c
    445 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
    446 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
    447 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{
    448 	EOF
    449 
    450 	atf_check \
    451 	    -s 'exit:1' \
    452 	    -e 'inline:error: code.c:3: Stuff missing from end of file\n' \
    453 	    "$indent" code.c
    454 
    455 	cat <<-EOF > code.c
    456 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
    457 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
    458 		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{ {
    459 	EOF
    460 
    461 	atf_check \
    462 	    -s 'exit:1' \
    463 	    -e 'inline:error: code.c:3: Stuff missing from end of file\n' \
    464 	    "$indent" code.c
    465 }
    466 
    467 
    468 atf_init_test_cases()
    469 {
    470 	atf_add_test_case 'option_unknown'
    471 	atf_add_test_case 'option_bool_trailing_garbage'
    472 	atf_add_test_case 'option_int_wrong_argument'
    473 	atf_add_test_case 'option_profile_not_found'
    474 	atf_add_test_case 'option_buffer_overflow'
    475 	atf_add_test_case 'option_typedefs_not_found'
    476 	atf_add_test_case 'option_special_missing_param'
    477 	atf_add_test_case 'option_tabsize_negative'
    478 	atf_add_test_case 'option_tabsize_zero'
    479 	atf_add_test_case 'option_tabsize_large'
    480 	atf_add_test_case 'option_tabsize_very_large'
    481 	atf_add_test_case 'option_int_trailing_garbage'
    482 	atf_add_test_case 'option_cli_trailing_garbage'
    483 	atf_add_test_case 'option_npro_trailing_garbage'
    484 	atf_add_test_case 'option_st_trailing_garbage'
    485 	atf_add_test_case 'option_version_trailing_garbage'
    486 	atf_add_test_case 'option_indent_size_zero'
    487 	atf_add_test_case 'unterminated_comment_wrap'
    488 	atf_add_test_case 'unterminated_comment_nowrap'
    489 	atf_add_test_case 'unterminated_char_constant'
    490 	atf_add_test_case 'unterminated_string_literal'
    491 	atf_add_test_case 'in_place_wrong_backup'
    492 	atf_add_test_case 'argument_input_enoent'
    493 	atf_add_test_case 'argument_output_equals_input_name'
    494 	atf_add_test_case 'argument_output_equals_input_file'
    495 	atf_add_test_case 'argument_output_enoent'
    496 	atf_add_test_case 'argument_too_many'
    497 	atf_add_test_case 'unexpected_end_of_file'
    498 	atf_add_test_case 'unexpected_closing_brace_top_level'
    499 	atf_add_test_case 'unexpected_closing_brace_decl'
    500 	atf_add_test_case 'unbalanced_parentheses'
    501 	atf_add_test_case 'gcc_statement_expression'
    502 	atf_add_test_case 'crash_comment_after_controlling_expression'
    503 	atf_add_test_case 'comment_fits_in_one_line'
    504 	atf_add_test_case 'stack_overflow'
    505 }
    506