1#! /bin/sh 2# $NetBSD: t_errors.sh,v 1.22 2021/11/25 21:48:23 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# $FreeBSD$ 29 30# Tests for error handling in indent. 31 32indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent) 33 34expect_error() 35{ 36 local msg 37 38 msg="$1" 39 shift 40 41 atf_check -s 'exit:1' \ 42 -e "inline:$msg\n" \ 43 "$indent" "$@" 44} 45 46atf_test_case 'option_unknown' 47option_unknown_body() 48{ 49 expect_error \ 50 'indent: Command line: unknown option "-Z-unknown"' \ 51 -Z-unknown 52} 53 54atf_test_case 'option_bool_trailing_garbage' 55option_bool_trailing_garbage_body() 56{ 57 expect_error \ 58 'indent: Command line: unknown option "-bacchus"' \ 59 -bacchus 60} 61 62atf_test_case 'option_int_missing_argument' 63option_int_missing_argument_body() 64{ 65 expect_error \ 66 'indent: Command line: argument "x" to option "-ts" must be an integer' \ 67 -tsx 68} 69 70atf_test_case 'option_profile_not_found' 71option_profile_not_found_body() 72{ 73 expect_error \ 74 'indent: profile ./nonexistent: No such file or directory' \ 75 -P./nonexistent 76} 77 78atf_test_case 'option_typedefs_not_found' 79option_typedefs_not_found_body() 80{ 81 expect_error \ 82 'indent: cannot open file ./nonexistent' \ 83 -U./nonexistent 84} 85 86atf_test_case 'option_tabsize_negative' 87option_tabsize_negative_body() 88{ 89 expect_error \ 90 'indent: Command line: argument "-1" to option "-ts" must be between 1 and 80' \ 91 -ts-1 92} 93 94atf_test_case 'option_tabsize_zero' 95option_tabsize_zero_body() 96{ 97 expect_error \ 98 'indent: Command line: argument "0" to option "-ts" must be between 1 and 80' \ 99 -ts0 100} 101 102atf_test_case 'option_tabsize_large' 103option_tabsize_large_body() 104{ 105 # Integer overflow, on both ILP32 and LP64 platforms. 106 expect_error \ 107 'indent: Command line: argument "81" to option "-ts" must be between 1 and 80' \ 108 -ts81 109} 110 111atf_test_case 'option_tabsize_very_large' 112option_tabsize_very_large_body() 113{ 114 # Integer overflow, on both ILP32 and LP64 platforms. 115 expect_error \ 116 'indent: Command line: argument "3000000000" to option "-ts" must be between 1 and 80' \ 117 -ts3000000000 118} 119 120atf_test_case 'option_indent_size_zero' 121option_indent_size_zero_body() 122{ 123 expect_error \ 124 'indent: Command line: argument "0" to option "-i" must be between 1 and 80' \ 125 -i0 126} 127 128atf_test_case 'option_int_trailing_garbage' 129option_int_trailing_garbage_body() 130{ 131 expect_error \ 132 'indent: Command line: argument "3garbage" to option "-i" must be an integer' \ 133 -i3garbage 134} 135 136atf_test_case 'option_cli_trailing_garbage' 137option_cli_trailing_garbage_body() 138{ 139 expect_error \ 140 'indent: Command line: argument "3garbage" to option "-cli" must be numeric' \ 141 -cli3garbage 142} 143 144atf_test_case 'option_npro_trailing_garbage' 145option_npro_trailing_garbage_body() 146{ 147 atf_check -s 'exit:1' \ 148 -e 'inline:indent: Command line: unknown option "-npro-garbage"\n' \ 149 "$indent" -npro-garbage 150} 151 152atf_test_case 'option_st_trailing_garbage' 153option_st_trailing_garbage_body() 154{ 155 atf_check -s 'exit:1' \ 156 -e 'inline:indent: Command line: unknown option "-stdio"\n' \ 157 "$indent" -stdio 158} 159 160atf_test_case 'option_version_trailing_garbage' 161option_version_trailing_garbage_body() 162{ 163 atf_check -s 'exit:1' \ 164 -e 'inline:indent: Command line: unknown option "--version-dump"\n' \ 165 "$indent" --version-dump 166} 167 168atf_test_case 'option_buffer_overflow' 169option_buffer_overflow_body() 170{ 171 opt='12345678123456781234567812345678' # 32 172 opt="$opt$opt$opt$opt$opt$opt$opt$opt" # 256 173 opt="$opt$opt$opt$opt$opt$opt$opt$opt" # 2048 174 opt="$opt$opt$opt$opt$opt$opt$opt$opt" # 16384 175 printf '%s\n' "-$opt" > indent.pro 176 177 expect_error \ 178 'indent: buffer overflow in indent.pro, starting with '\''-123456781'\''' \ 179 -Pindent.pro 180} 181 182atf_test_case 'option_special_missing_param' 183option_special_missing_param_body() 184{ 185 expect_error \ 186 'indent: Command line: ``-cli'\'\'' requires an argument' \ 187 -cli 188 189 expect_error \ 190 'indent: Command line: ``-T'\'\'' requires an argument' \ 191 -T 192 193 expect_error \ 194 'indent: Command line: ``-U'\'\'' requires an argument' \ 195 -U 196} 197 198atf_test_case 'unterminated_comment_wrap' 199unterminated_comment_wrap_body() 200{ 201 echo '/*' > comment.c 202 203 atf_check -s 'exit:1' \ 204 -o 'inline:/*\n *\n' \ 205 -e 'inline:error: Standard Input:2: Unterminated comment\n' \ 206 "$indent" -st < comment.c 207} 208 209atf_test_case 'unterminated_comment_nowrap' 210unterminated_comment_nowrap_body() 211{ 212 echo '/*-' > comment.c 213 214 atf_check -s 'exit:1' \ 215 -o 'inline:/*-\n\n' \ 216 -e 'inline:error: Standard Input:2: Unterminated comment\n' \ 217 "$indent" -st < comment.c 218} 219 220atf_test_case 'in_place_wrong_backup' 221in_place_wrong_backup_body() 222{ 223 cat <<-\EOF > code.c 224 int decl; 225 EOF 226 cp code.c code.c.orig 227 228 # Due to the strange backup suffix '/subdir', indent tries to create 229 # a file named 'code.c/subdir', but 'code.c' is already a regular 230 # file, not a directory. 231 atf_check -s 'exit:1' \ 232 -e 'inline:indent: code.c/subdir: Not a directory\n' \ 233 env SIMPLE_BACKUP_SUFFIX="/subdir" "$indent" code.c 234 235 # Since there was an early error, the original file is kept as is. 236 atf_check -o 'file:code.c.orig' \ 237 cat code.c 238} 239 240atf_test_case 'argument_input_enoent' 241argument_input_enoent_body() 242{ 243 atf_check -s 'exit:1' \ 244 -e 'inline:indent: ./nonexistent.c: No such file or directory\n' \ 245 "$indent" ./nonexistent.c 246} 247 248atf_test_case 'argument_output_equals_input_name' 249argument_output_equals_input_name_body() 250{ 251 echo '/* comment */' > code.c 252 253 atf_check -s 'exit:1' \ 254 -e 'inline:indent: input and output files must be different\n' \ 255 "$indent" code.c code.c 256} 257 258atf_test_case 'argument_output_equals_input_file' 259argument_output_equals_input_file_body() 260{ 261 echo '/* comment */' > code.c 262 263 atf_check \ 264 "$indent" code.c ./code.c 265 266 # Oops, the file has become empty since the output is first emptied, 267 # before reading any of the input. 268 atf_check \ 269 cat code.c 270} 271 272atf_test_case 'argument_output_enoent' 273argument_output_enoent_body() 274{ 275 expect_error \ 276 'indent: subdir/nonexistent.c: No such file or directory' \ 277 /dev/null subdir/nonexistent.c 278} 279 280atf_test_case 'argument_too_many' 281argument_too_many_body() 282{ 283 echo '/* comment */' > arg1.c 284 285 expect_error \ 286 'indent: too many arguments: arg3.c' \ 287 arg1.c arg2.c arg3.c arg4.c 288} 289 290atf_test_case 'unexpected_end_of_file' 291unexpected_end_of_file_body() 292{ 293 echo 'struct{' > code.c 294 295 expect_error \ 296 'error: code.c:1: Stuff missing from end of file' \ 297 code.c 298 299 atf_check \ 300 -o 'inline:struct {\n' \ 301 cat code.c 302} 303 304atf_test_case 'unexpected_closing_brace_top_level' 305unexpected_closing_brace_top_level_body() 306{ 307 echo '}' > code.c 308 309 expect_error \ 310 'error: code.c:1: Statement nesting error' \ 311 code.c 312 atf_check \ 313 -o 'inline:}\n' \ 314 cat code.c 315} 316 317atf_test_case 'unexpected_closing_brace_decl' 318unexpected_closing_brace_decl_body() 319{ 320 echo 'int i = 3};' > code.c 321 322 expect_error \ 323 'error: code.c:1: Statement nesting error' \ 324 code.c 325 # Despite the error message, the original file got overwritten with a 326 # best-effort rewrite of the code. 327 atf_check \ 328 -o 'inline:int i = 3};\n' \ 329 cat code.c 330} 331 332atf_test_case 'preprocessing_overflow' 333preprocessing_overflow_body() 334{ 335 cat <<-\EOF > code.c 336 #if 1 337 #if 2 338 #if 3 339 #if 4 340 #if 5 341 #if 6 342 #endif 6 343 #endif 5 344 #endif 4 345 #endif 3 346 #endif 2 347 #endif 1 348 #endif too much 349 EOF 350 cat <<-\EOF > stderr.exp 351 error: code.c:6: #if stack overflow 352 error: code.c:12: Unmatched #endif 353 error: code.c:13: Unmatched #endif 354 EOF 355 356 atf_check -s 'exit:1' \ 357 -e 'file:stderr.exp' \ 358 "$indent" code.c 359} 360 361atf_test_case 'preprocessing_unrecognized' 362preprocessing_unrecognized_body() 363{ 364 cat <<-\EOF > code.c 365 #unknown 366 # 3 "file.c" 367 #elif 3 368 #else 369 EOF 370 cat <<-\EOF > stderr.exp 371 error: code.c:1: Unrecognized cpp directive 372 error: code.c:2: Unrecognized cpp directive 373 error: code.c:3: Unmatched #elif 374 error: code.c:4: Unmatched #else 375 EOF 376 377 atf_check -s 'exit:1' \ 378 -e 'file:stderr.exp' \ 379 "$indent" code.c 380} 381 382atf_test_case 'unbalanced_parentheses_1' 383unbalanced_parentheses_1_body() 384{ 385 cat <<-\EOF > code.c 386 int var = 387 ( 388 ; 389 ) 390 ; 391 EOF 392 cat <<-\EOF > stderr.exp 393 error: code.c:3: Unbalanced parentheses 394 warning: code.c:4: Extra ')' 395 EOF 396 397 atf_check -s 'exit:1' -e 'file:stderr.exp' \ 398 "$indent" code.c 399} 400 401atf_test_case 'unbalanced_parentheses_2' 402unbalanced_parentheses_2_body() 403{ 404 # '({...})' is the GCC extension "Statement expression". 405 cat <<-\EOF > code.c 406 int var = 407 ( 408 { 409 1 410 } 411 ) 412 ; 413 EOF 414 cat <<-\EOF > stderr.exp 415 error: code.c:3: Unbalanced parentheses 416 warning: code.c:6: Extra ')' 417 EOF 418 419 atf_check -s 'exit:1' -e 'file:stderr.exp' \ 420 "$indent" code.c 421} 422 423atf_test_case 'unbalanced_parentheses_3' 424unbalanced_parentheses_3_body() 425{ 426 # '({...})' is the GCC extension "Statement expression". 427 cat <<-\EOF > code.c 428 int var = 429 ( 430 1 431 } 432 ; 433 EOF 434 cat <<-\EOF > stderr.exp 435 error: code.c:4: Unbalanced parentheses 436 error: code.c:4: Statement nesting error 437 EOF 438 439 atf_check -s 'exit:1' -e 'file:stderr.exp' \ 440 "$indent" code.c 441} 442 443atf_test_case 'search_stmt_comment_segv' 444search_stmt_comment_segv_body() 445{ 446 # As of NetBSD indent.c 1.188 from 2021-10-30, indent crashes while 447 # trying to format the following artificial code. 448 449 printf '{if(expr\n)/*c*/;}\n' > code.c 450 451 cat <<\EOF > code.exp 452{ 453 if (expr 454 ) /* c */ 455 ; 456} 457EOF 458 459 # TODO: actually produce code.exp instead of an assertion failure. 460 atf_check -s 'signal' -o 'ignore' -e 'match:assert' \ 461 "$indent" code.c -st 462} 463 464atf_test_case 'search_stmt_fits_in_one_line' 465search_stmt_fits_in_one_line_body() 466{ 467 # The comment is placed after 'if (0) ...', where it is processed 468 # by search_stmt_comment. That function redirects the input buffer to 469 # a temporary buffer that is not guaranteed to be terminated by '\n'. 470 # Before NetBSD pr_comment.c 1.91 from 2021-10-30, this produced an 471 # assertion failure in fits_in_one_line. 472 cat <<EOF > code.c 473int f(void) 474{ 475 if (0) 476 /* 0123456789012345678901 */; 477} 478EOF 479 480 # Indent tries hard to make the comment fit to the 34-character line 481 # length, but it is just not possible. 482 cat <<EOF > expected.out 483int 484f(void) 485{ 486 if (0) 487 /* 488 * 0123456789012345678901 489 */ ; 490} 491EOF 492 493 atf_check -o 'file:expected.out' \ 494 "$indent" -l34 code.c -st 495} 496 497 498atf_init_test_cases() 499{ 500 atf_add_test_case 'option_unknown' 501 atf_add_test_case 'option_bool_trailing_garbage' 502 atf_add_test_case 'option_int_missing_argument' 503 atf_add_test_case 'option_profile_not_found' 504 atf_add_test_case 'option_buffer_overflow' 505 atf_add_test_case 'option_typedefs_not_found' 506 atf_add_test_case 'option_special_missing_param' 507 atf_add_test_case 'option_tabsize_negative' 508 atf_add_test_case 'option_tabsize_zero' 509 atf_add_test_case 'option_tabsize_large' 510 atf_add_test_case 'option_tabsize_very_large' 511 atf_add_test_case 'option_int_trailing_garbage' 512 atf_add_test_case 'option_cli_trailing_garbage' 513 atf_add_test_case 'option_npro_trailing_garbage' 514 atf_add_test_case 'option_st_trailing_garbage' 515 atf_add_test_case 'option_version_trailing_garbage' 516 atf_add_test_case 'option_indent_size_zero' 517 atf_add_test_case 'unterminated_comment_wrap' 518 atf_add_test_case 'unterminated_comment_nowrap' 519 atf_add_test_case 'in_place_wrong_backup' 520 atf_add_test_case 'argument_input_enoent' 521 atf_add_test_case 'argument_output_equals_input_name' 522 atf_add_test_case 'argument_output_equals_input_file' 523 atf_add_test_case 'argument_output_enoent' 524 atf_add_test_case 'argument_too_many' 525 atf_add_test_case 'unexpected_end_of_file' 526 atf_add_test_case 'unexpected_closing_brace_top_level' 527 atf_add_test_case 'unexpected_closing_brace_decl' 528 atf_add_test_case 'preprocessing_overflow' 529 atf_add_test_case 'preprocessing_unrecognized' 530 atf_add_test_case 'unbalanced_parentheses_1' 531 atf_add_test_case 'unbalanced_parentheses_2' 532 atf_add_test_case 'unbalanced_parentheses_3' 533 atf_add_test_case 'search_stmt_comment_segv' 534 atf_add_test_case 'search_stmt_fits_in_one_line' 535} 536