1#! /bin/sh 2# $NetBSD: t_misc.sh,v 1.29 2023/12/17 10:02:09 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 indent that do not follow the input-profile-output scheme that is 29# used in t_options. 30 31indent=$(atf_config_get usr.bin.indent.test_indent /usr/bin/indent) 32 33atf_test_case 'in_place' 34in_place_body() 35{ 36 cat <<-\EOF > code.c 37 int decl; 38 EOF 39 cat <<-\EOF > code.c.exp 40 int decl; 41 EOF 42 cp code.c code.c.orig 43 44 atf_check \ 45 env SIMPLE_BACKUP_SUFFIX=".bak" "$indent" code.c 46 atf_check -o 'file:code.c.exp' \ 47 cat code.c 48 atf_check -o 'file:code.c.orig' \ 49 cat code.c.bak 50} 51 52atf_test_case 'in_place_parse_error' 53in_place_parse_error_body() 54{ 55 # On normal parse errors, indent continues until the end of the file. 56 # This means that even in the case of errors, not much is lost. 57 58 cat <<-\EOF > code.c 59 int line1; 60 } 61 int line3; 62 EOF 63 64 atf_check -s 'exit:1' -e 'ignore' \ 65 "$indent" code.c 66 atf_check -o 'inline:int\t\tline1;\n}\nint\t\tline3;\n' \ 67 cat code.c 68} 69 70atf_test_case 'verbose_profile' 71verbose_profile_body() 72{ 73 cat <<-\EOF > .indent.pro 74 -/* comment */bacc 75 -v 76 -fc1 77 EOF 78 cat <<-\EOF > before.c 79 int decl; 80 EOF 81 cat <<-\EOF > after.c.exp 82 int decl; 83 EOF 84 cat <<-\EOF > stderr.exp 85 profile: -fc1 86 profile: -bacc 87 profile: -v 88 profile: -fc1 89 EOF 90 91 # The code in args.c function load_profile suggests that options from 92 # profile files are echoed to stderr during startup. But since the 93 # command line options are handled after the profile files, a '-v' in 94 # the command line has no effect. That's why '-bacc' is not listed 95 # on stderr, but '-fc1' is. The second round of '-bacc', '-v', '-fc1' 96 # is listed because when running the test via ATF, $HOME equals $PWD. 97 98 atf_check \ 99 -e 'file:stderr.exp' \ 100 "$indent" -v before.c after.c 101 atf_check \ 102 -o 'file:after.c.exp' \ 103 cat after.c 104} 105 106atf_test_case 'nested_struct_declarations' 107nested_struct_declarations_body() 108{ 109 # Trigger the warning about nested struct declarations. 110 111 cat <<-\EOF > code.c 112 struct s01 { struct s02 { struct s03 { struct s04 { 113 struct s05 { struct s06 { struct s07 { struct s08 { 114 struct s09 { struct s10 { struct s11 { struct s12 { 115 struct s13 { struct s14 { struct s15 { struct s16 { 116 struct s17 { struct s18 { struct s19 { struct s20 { 117 struct s21 { struct s22 { struct s23 { struct s24 { 118 };};};}; 119 };};};}; 120 };};};}; 121 };};};}; 122 };};};}; 123 };};};}; 124 EOF 125 cat <<-\EOF > expected.out 126 struct s01 { 127 struct s02 { 128 struct s03 { 129 struct s04 { 130 struct s05 { 131 struct s06 { 132 struct s07 { 133 struct s08 { 134 struct s09 { 135 struct s10 { 136 struct s11 { 137 struct s12 { 138 struct s13 { 139 struct s14 { 140 struct s15 { 141 struct s16 { 142 struct s17 { 143 struct s18 { 144 struct s19 { 145 struct s20 { 146 struct s21 { 147 struct s22 { 148 struct s23 { 149 struct s24 { 150 }; 151 }; 152 }; 153 }; 154 }; 155 }; 156 }; 157 }; 158 }; 159 }; 160 }; 161 }; 162 }; 163 }; 164 }; 165 }; 166 }; 167 }; 168 }; 169 }; 170 }; 171 }; 172 }; 173 }; 174 EOF 175 cat <<-\EOF > expected.err 176 warning: Standard Input:5: Reached internal limit of 20 struct levels 177 warning: Standard Input:6: Reached internal limit of 20 struct levels 178 warning: Standard Input:6: Reached internal limit of 20 struct levels 179 warning: Standard Input:6: Reached internal limit of 20 struct levels 180 warning: Standard Input:6: Reached internal limit of 20 struct levels 181 EOF 182 183 atf_check -o 'file:expected.out' -e 'file:expected.err' \ 184 "$indent" -i1 -nut < 'code.c' 185} 186 187atf_test_case 'option_P_in_profile_file' 188option_P_in_profile_file_body() 189{ 190 # Mentioning another profile via -P has no effect since only a single 191 # profile can be specified on the command line, and there is no 192 # 'include' option. 193 194 # It's syntactically possible to specify a profile file inside another 195 # profile file. Such a profile file is ignored since only a single 196 # profile file is ever loaded. 197 printf '%s\n' '-P/nonexistent' > .indent.pro 198 199 echo 'syntax # error' > code.c 200 201 atf_check -o 'inline:syntax\n# error\n' \ 202 "$indent" < code.c 203} 204 205atf_test_case 'option_without_hyphen' 206option_without_hyphen_body() 207{ 208 # Ensure that options in profile files start with '-', just like 209 # command line options. 210 211 printf ' -i3 xi5 +di0\n' > .indent.pro 212 213 printf '%s\n' 'int var[] = {' '1,' '}' > code.c 214 215 atf_check \ 216 -s 'exit:1' \ 217 -e "match:/.indent.pro: option \"xi5\" must start with '-'" \ 218 "$indent" < code.c 219} 220 221atf_test_case 'opt' 222opt_body() 223{ 224 # Test parsing of command line options from a profile file. 225 226 cat <<-\EOF > code.c 227 int global_var; 228 229 int function(int expr) { 230 switch (expr) { case 1: return 1; default: return 0; } 231 } 232 EOF 233 234 cat << \EOF > .indent.pro 235/* The latter of the two options wins. */ 236-di5 237-di12 238 239/* 240 * It is possible to embed comments in the middle of an option, but nobody 241 * does that. 242 */ 243-/* comment */bacc 244-T/* define 245a type */custom_type 246 247/* For int options, trailing garbage would be an error. */ 248-i3 249 250/* For float options, trailing garbage would be an error. */ 251-cli3.5 252 253-b/*/acc /* The comment is '/' '*' '/', making the option '-bacc'. */ 254EOF 255 256 sed '/[$]/d' << \EOF > code.exp 257/* $ The variable name is indented by 12 characters due to -di12. */ 258int global_var; 259 260int 261function(int expr) 262{ 263 switch (expr) { 264/* $ The indentation is 3 + (int)(3.5 * 3), so 3 + 10.5, so 13. */ 265/* $ See parse.c, function parse, 'case switch_expr'. */ 266 case 1: 267/* $ The indentation is 3 + (int)3.5 * 3 + 3, so 3 + 9 + 3, so 15. */ 268/* $ See parse.c, function parse, 'case switch_expr'. */ 269 return 1; 270 default: 271 return 0; 272 } 273} 274EOF 275 276 atf_check -o 'file:code.exp' \ 277 "$indent" code.c -st 278} 279 280atf_test_case 'opt_npro' 281opt_npro_body() 282{ 283 # Mentioning the option -npro in a .pro file has no effect since at 284 # that point, indent has already decided to load the .pro file, and 285 # it only decides once. 286 287 echo ' -npro -di8' > .indent.pro 288 echo 'int var;' > code.c 289 printf 'int\tvar;\n' > code.exp 290 291 atf_check -o 'file:code.exp' \ 292 "$indent" code.c -st 293} 294 295atf_test_case 'opt_U' 296opt_U_body() 297{ 298 # From each line of this file, the first word is taken to be a type 299 # name. 300 # 301 # Since neither '/*' nor '' are syntactically valid type names, this 302 # means that all kinds of comments are effectively ignored. When a 303 # type name is indented by whitespace, it is ignored as well. 304 # 305 # Since only the first word of each line is relevant, any remaining 306 # words can be used for comments. 307 cat <<-\EOF > code.types 308 /* Comments are effectively ignored since they never match. */ 309 # This comment is ignored as well. 310 ; So is this comment. 311 # The following line is empty and adds a type whose name is empty. 312 313 size_t from stddef.h 314 off_t for file offsets 315 ignored_t is ignored since it is indented 316 EOF 317 318 cat <<-\EOF > code.c 319 int known_1 = (size_t) * arg; 320 int known_2 = (off_t) * arg; 321 int ignored = (ignored_t) * arg; 322 EOF 323 cat <<-\EOF > code.exp 324 int known_1 = (size_t)*arg; 325 int known_2 = (off_t)*arg; 326 int ignored = (ignored_t) * arg; 327 EOF 328 329 atf_check -o 'file:code.exp' \ 330 "$indent" -Ucode.types code.c -di0 -st 331} 332 333atf_test_case 'line_no_counting' 334line_no_counting_body() 335{ 336 # Before NetBSD indent.c 1.147 from 2021-10-24, indent reported the 337 # warning in line 2 instead of the correct line 3. 338 339 cat <<-\EOF > code.c 340 void line_no_counting(void) 341 { 342 ()) 343 } 344 EOF 345 346 cat <<-\EOF > code.err 347 warning: code.c:3: Extra ')' 348 EOF 349 350 atf_check -o 'ignore' -e 'file:code.err' \ 351 "$indent" code.c -st 352} 353 354atf_test_case 'default_backup_extension' 355default_backup_extension_body() 356{ 357 echo 'int var;' > code.c 358 echo 'int var;' > code.c.orig 359 360 atf_check \ 361 "$indent" code.c 362 atf_check -o 'file:code.c.orig' \ 363 cat code.c.BAK 364} 365 366atf_test_case 'several_profiles' 367several_profiles_body() 368{ 369 # If the option '-P' occurs several times, only the last of the 370 # profiles is loaded, the others are ignored. 371 372 echo ' --invalid-option' > error.pro 373 echo '' > last.pro 374 echo '' > code.c 375 376 atf_check \ 377 "$indent" -Pnonexistent.pro -Perror.pro -Plast.pro code.c -st 378} 379 380 381atf_test_case 'command_line_vs_profile' 382command_line_vs_profile_body() 383{ 384 # Options from the command line override those from a profile file, 385 # no matter if they appear earlier or later than the '-P' in the 386 # command line. 387 388 echo ' -di24' > custom.pro 389 printf 'int\t\tdecl;\n' > code.c 390 391 atf_check -o 'inline:int decl;\n' \ 392 "$indent" -di0 -Pcustom.pro code.c -st 393 atf_check -o 'inline:int decl;\n' \ 394 "$indent" -Pcustom.pro -di0 code.c -st 395 atf_check -o 'inline:int decl;\n' \ 396 "$indent" -Pcustom.pro code.c -st -di0 397} 398 399 400atf_test_case 'opt_v_break_line' 401opt_v_break_line_body() 402{ 403 printf '%s\n' 'int *function(void)' '{}' > code.c 404 405 atf_check -o 'ignore' \ 406 "$indent" -v code.c -st 407} 408 409 410atf_test_case 'trailing_whitespace_in_preprocessing_line' 411trailing_whitespace_in_preprocessing_line_body() 412{ 413 printf '#if trailing && space \n#endif\n' > code.c 414 415 atf_check -o 'inline:#if trailing && space\n#endif\n' \ 416 "$indent" code.c -st 417} 418 419atf_init_test_cases() 420{ 421 atf_add_test_case 'in_place' 422 atf_add_test_case 'verbose_profile' 423 atf_add_test_case 'nested_struct_declarations' 424 atf_add_test_case 'option_P_in_profile_file' 425 atf_add_test_case 'option_without_hyphen' 426 atf_add_test_case 'opt' 427 atf_add_test_case 'opt_npro' 428 atf_add_test_case 'opt_U' 429 atf_add_test_case 'opt_v_break_line' 430 atf_add_test_case 'line_no_counting' 431 atf_add_test_case 'default_backup_extension' 432 atf_add_test_case 'several_profiles' 433 atf_add_test_case 'command_line_vs_profile' 434 atf_add_test_case 'in_place_parse_error' 435 atf_add_test_case 'trailing_whitespace_in_preprocessing_line' 436} 437