1 #! /bin/sh 2 # $NetBSD: t_errors.sh,v 1.39 2025/01/03 23:37:18 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_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