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