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 30indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent) 31 32expect_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 44atf_test_case 'option_unknown' 45option_unknown_body() 46{ 47 expect_error \ 48 'indent: Command line: unknown option "-Z-unknown"' \ 49 -Z-unknown 50} 51 52atf_test_case 'option_bool_trailing_garbage' 53option_bool_trailing_garbage_body() 54{ 55 expect_error \ 56 'indent: Command line: unknown option "-bacchus"' \ 57 -bacchus 58} 59 60atf_test_case 'option_int_missing_argument' 61option_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 68atf_test_case 'option_profile_not_found' 69option_profile_not_found_body() 70{ 71 expect_error \ 72 'indent: profile ./nonexistent: No such file or directory' \ 73 -P./nonexistent 74} 75 76atf_test_case 'option_typedefs_not_found' 77option_typedefs_not_found_body() 78{ 79 expect_error \ 80 'indent: cannot open file ./nonexistent' \ 81 -U./nonexistent 82} 83 84atf_test_case 'option_tabsize_negative' 85option_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 92atf_test_case 'option_tabsize_zero' 93option_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 100atf_test_case 'option_tabsize_large' 101option_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 108atf_test_case 'option_tabsize_very_large' 109option_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 117atf_test_case 'option_indent_size_zero' 118option_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 125atf_test_case 'option_int_trailing_garbage' 126option_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 133atf_test_case 'option_cli_trailing_garbage' 134option_cli_trailing_garbage_body() 135{ 136 expect_error \ 137 'indent: Command line: argument "3garbage" to option "-cli" must be numeric' \ 138 -cli3garbage 139} 140 141atf_test_case 'option_npro_trailing_garbage' 142option_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 149atf_test_case 'option_st_trailing_garbage' 150option_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 157atf_test_case 'option_version_trailing_garbage' 158option_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 165atf_test_case 'option_buffer_overflow' 166option_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 179atf_test_case 'option_special_missing_param' 180option_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 195atf_test_case 'unterminated_comment_wrap' 196unterminated_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 206atf_test_case 'unterminated_comment_nowrap' 207unterminated_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 217atf_test_case 'in_place_wrong_backup' 218in_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 237atf_test_case 'argument_input_enoent' 238argument_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 245atf_test_case 'argument_output_equals_input_name' 246argument_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 255atf_test_case 'argument_output_equals_input_file' 256argument_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 269atf_test_case 'argument_output_enoent' 270argument_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 277atf_test_case 'argument_too_many' 278argument_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 287atf_test_case 'unexpected_end_of_file' 288unexpected_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 301atf_test_case 'unexpected_closing_brace_top_level' 302unexpected_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 314atf_test_case 'unexpected_closing_brace_decl' 315unexpected_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 329atf_test_case 'preprocessing_overflow' 330preprocessing_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 358atf_test_case 'preprocessing_unrecognized' 359preprocessing_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 377atf_test_case 'unbalanced_parentheses_1' 378unbalanced_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 396atf_test_case 'unbalanced_parentheses_2' 397unbalanced_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 418atf_test_case 'unbalanced_parentheses_3' 419unbalanced_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 438atf_test_case 'crash_comment_after_controlling_expression' 439crash_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} 451EOF 452 453 atf_check -o 'file:code.exp' \ 454 "$indent" code.c -st 455} 456 457atf_test_case 'comment_fits_in_one_line' 458comment_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 464int f(void) 465{ 466 if (0) 467 /* 0123456789012345678901 */; 468} 469EOF 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 474int 475f(void) 476{ 477 if (0) 478 /* 479 * 0123456789012345678901 480 */ ; 481} 482EOF 483 484 atf_check -o 'file:expected.out' \ 485 "$indent" -l34 code.c -st 486} 487 488 489atf_test_case 'compound_literal' 490compound_literal_body() 491{ 492 # Test handling of compound literals (C99 6.5.2.5), as well as casts. 493 494 cat <<EOF > code.c 495void 496function(void) 497{ 498 origin = 499 ((int) 500 ((-1)* 501 (struct point){0,0} 502 ) 503 ); 504} 505EOF 506 507 sed '/^#/d' <<EOF > expected.out 508void 509function(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} 523EOF 524 sed '/^#/d' <<EOF > expected.err 525# FIXME: The parentheses _are_ balanced, the '}' does not end the block. 526error: code.c:7: Unbalanced parentheses 527warning: code.c:8: Extra ')' 528warning: code.c:9: Extra ')' 529EOF 530 531 atf_check -s 'exit:1' -o 'file:expected.out' -e 'file:expected.err' \ 532 "$indent" -nfc1 -ci12 code.c -st 533} 534 535atf_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