1#! /bin/sh 2# $NetBSD: t_errors.sh,v 1.24 2022/04/22 21:21:20 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 # 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 109atf_test_case 'option_tabsize_very_large' 110option_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 118atf_test_case 'option_indent_size_zero' 119option_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 126atf_test_case 'option_int_trailing_garbage' 127option_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 134atf_test_case 'option_cli_trailing_garbage' 135option_cli_trailing_garbage_body() 136{ 137 expect_error \ 138 'indent: Command line: argument "3garbage" to option "-cli" must be numeric' \ 139 -cli3garbage 140} 141 142atf_test_case 'option_npro_trailing_garbage' 143option_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 150atf_test_case 'option_st_trailing_garbage' 151option_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 158atf_test_case 'option_version_trailing_garbage' 159option_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 166atf_test_case 'option_buffer_overflow' 167option_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 180atf_test_case 'option_special_missing_param' 181option_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 196atf_test_case 'unterminated_comment_wrap' 197unterminated_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 207atf_test_case 'unterminated_comment_nowrap' 208unterminated_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 218atf_test_case 'in_place_wrong_backup' 219in_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 238atf_test_case 'argument_input_enoent' 239argument_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 246atf_test_case 'argument_output_equals_input_name' 247argument_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 256atf_test_case 'argument_output_equals_input_file' 257argument_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 270atf_test_case 'argument_output_enoent' 271argument_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 278atf_test_case 'argument_too_many' 279argument_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 288atf_test_case 'unexpected_end_of_file' 289unexpected_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 302atf_test_case 'unexpected_closing_brace_top_level' 303unexpected_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 315atf_test_case 'unexpected_closing_brace_decl' 316unexpected_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 330atf_test_case 'preprocessing_overflow' 331preprocessing_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 359atf_test_case 'preprocessing_unrecognized' 360preprocessing_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 380atf_test_case 'unbalanced_parentheses_1' 381unbalanced_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 399atf_test_case 'unbalanced_parentheses_2' 400unbalanced_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 421atf_test_case 'unbalanced_parentheses_3' 422unbalanced_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 441atf_test_case 'search_stmt_comment_segv' 442search_stmt_comment_segv_body() 443{ 444 # As of NetBSD indent.c 1.188 from 2021-10-30, indent crashes 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} 455EOF 456 457 # TODO: actually produce code.exp instead of an assertion failure. 458 atf_check -s 'signal' -o 'ignore' -e 'match:assert' \ 459 "$indent" code.c -st 460} 461 462atf_test_case 'search_stmt_fits_in_one_line' 463search_stmt_fits_in_one_line_body() 464{ 465 # The comment is placed after 'if (0) ...', where it is processed 466 # by search_stmt_comment. That function redirects the input buffer to 467 # a temporary buffer that is not guaranteed to be terminated by '\n'. 468 # Before NetBSD pr_comment.c 1.91 from 2021-10-30, this produced an 469 # assertion failure in fits_in_one_line. 470 cat <<EOF > code.c 471int f(void) 472{ 473 if (0) 474 /* 0123456789012345678901 */; 475} 476EOF 477 478 # Indent tries hard to make the comment fit to the 34-character line 479 # length, but it is just not possible. 480 cat <<EOF > expected.out 481int 482f(void) 483{ 484 if (0) 485 /* 486 * 0123456789012345678901 487 */ ; 488} 489EOF 490 491 atf_check -o 'file:expected.out' \ 492 "$indent" -l34 code.c -st 493} 494 495 496atf_test_case 'compound_literal' 497compound_literal_body() 498{ 499 # Test handling of compound literals (C99 6.5.2.5), as well as casts. 500 501 cat <<EOF > code.c 502void 503function(void) 504{ 505 origin = 506 ((int) 507 ((-1)* 508 (struct point){0,0} 509 ) 510 ); 511} 512EOF 513 514 sed '/^#/d' <<EOF > expected.out 515void 516function(void) 517{ 518 origin = 519 ((int) 520 ((-1) * 521 (struct point){ 522# FIXME: the '{' is part of the expression, not a separate block. 523 0, 0 524# FIXME: the '}' is part of the expression, not a separate block. 525 } 526# FIXME: the ')' must be aligned with the corresponding '('. 527 ) 528 ); 529} 530EOF 531 sed '/^#/d' <<EOF > expected.err 532# FIXME: The parentheses _are_ balanced, the '}' does not end the block. 533error: code.c:9: Unbalanced parentheses 534warning: code.c:10: Extra ')' 535# FIXME: There is no line 12 in the input file. 536warning: code.c:12: Extra ')' 537EOF 538 539 atf_check -s 'exit:1' -o 'file:expected.out' -e 'file:expected.err' \ 540 "$indent" -nfc1 -ci12 code.c -st 541} 542 543atf_init_test_cases() 544{ 545 atf_add_test_case 'option_unknown' 546 atf_add_test_case 'option_bool_trailing_garbage' 547 atf_add_test_case 'option_int_missing_argument' 548 atf_add_test_case 'option_profile_not_found' 549 atf_add_test_case 'option_buffer_overflow' 550 atf_add_test_case 'option_typedefs_not_found' 551 atf_add_test_case 'option_special_missing_param' 552 atf_add_test_case 'option_tabsize_negative' 553 atf_add_test_case 'option_tabsize_zero' 554 atf_add_test_case 'option_tabsize_large' 555 atf_add_test_case 'option_tabsize_very_large' 556 atf_add_test_case 'option_int_trailing_garbage' 557 atf_add_test_case 'option_cli_trailing_garbage' 558 atf_add_test_case 'option_npro_trailing_garbage' 559 atf_add_test_case 'option_st_trailing_garbage' 560 atf_add_test_case 'option_version_trailing_garbage' 561 atf_add_test_case 'option_indent_size_zero' 562 atf_add_test_case 'unterminated_comment_wrap' 563 atf_add_test_case 'unterminated_comment_nowrap' 564 atf_add_test_case 'in_place_wrong_backup' 565 atf_add_test_case 'argument_input_enoent' 566 atf_add_test_case 'argument_output_equals_input_name' 567 atf_add_test_case 'argument_output_equals_input_file' 568 atf_add_test_case 'argument_output_enoent' 569 atf_add_test_case 'argument_too_many' 570 atf_add_test_case 'unexpected_end_of_file' 571 atf_add_test_case 'unexpected_closing_brace_top_level' 572 atf_add_test_case 'unexpected_closing_brace_decl' 573 atf_add_test_case 'preprocessing_overflow' 574 atf_add_test_case 'preprocessing_unrecognized' 575 atf_add_test_case 'unbalanced_parentheses_1' 576 atf_add_test_case 'unbalanced_parentheses_2' 577 atf_add_test_case 'unbalanced_parentheses_3' 578 atf_add_test_case 'search_stmt_comment_segv' 579 atf_add_test_case 'search_stmt_fits_in_one_line' 580 atf_add_test_case 'compound_literal' 581} 582