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 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_wrong_argument' 61option_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 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 'unterminated_char_constant' 218unterminated_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 228atf_test_case 'unterminated_string_literal' 229unterminated_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 239atf_test_case 'in_place_wrong_backup' 240in_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 259atf_test_case 'argument_input_enoent' 260argument_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 267atf_test_case 'argument_output_equals_input_name' 268argument_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 277atf_test_case 'argument_output_equals_input_file' 278argument_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 291atf_test_case 'argument_output_enoent' 292argument_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 299atf_test_case 'argument_too_many' 300argument_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 309atf_test_case 'unexpected_end_of_file' 310unexpected_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 323atf_test_case 'unexpected_closing_brace_top_level' 324unexpected_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 336atf_test_case 'unexpected_closing_brace_decl' 337unexpected_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 351atf_test_case 'unbalanced_parentheses' 352unbalanced_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 370atf_test_case 'gcc_statement_expression' 371gcc_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 390atf_test_case 'crash_comment_after_controlling_expression' 391crash_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} 404EOF 405 406 atf_check -o 'file:code.exp' \ 407 "$indent" code.c -st 408} 409 410atf_test_case 'comment_fits_in_one_line' 411comment_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 417int f(void) 418{ 419 if (0) 420 /* 0123456789012345678901 */; 421} 422EOF 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 427int 428f(void) 429{ 430 if (0) 431 /* 432 * 0123456789012345678901 433 */; 434} 435EOF 436 437 atf_check -o 'file:expected.out' \ 438 "$indent" -l34 code.c -st 439} 440 441atf_test_case 'stack_overflow' 442stack_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 468atf_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