| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description=gitattributes |
| 4 | |
| 5 | TEST_CREATE_REPO_NO_TEMPLATE=1 |
| 6 | . ./test-lib.sh |
| 7 | |
| 8 | attr_check_basic () { |
| 9 | path="$1" expect="$2" git_opts="$3" && |
| 10 | |
| 11 | git $git_opts check-attr test -- "$path" >actual 2>err && |
| 12 | echo "$path: test: $expect" >expect && |
| 13 | test_cmp expect actual |
| 14 | } |
| 15 | |
| 16 | attr_check () { |
| 17 | attr_check_basic "$@" && |
| 18 | test_must_be_empty err |
| 19 | } |
| 20 | |
| 21 | attr_check_object_mode_basic () { |
| 22 | path="$1" && |
| 23 | expect="$2" && |
| 24 | check_opts="$3" && |
| 25 | git check-attr $check_opts builtin_objectmode -- "$path" >actual 2>err && |
| 26 | echo "$path: builtin_objectmode: $expect" >expect && |
| 27 | test_cmp expect actual |
| 28 | } |
| 29 | |
| 30 | attr_check_object_mode () { |
| 31 | attr_check_object_mode_basic "$@" && |
| 32 | test_must_be_empty err |
| 33 | } |
| 34 | |
| 35 | attr_check_quote () { |
| 36 | path="$1" quoted_path="$2" expect="$3" && |
| 37 | |
| 38 | git check-attr test -- "$path" >actual && |
| 39 | echo "\"$quoted_path\": test: $expect" >expect && |
| 40 | test_cmp expect actual |
| 41 | } |
| 42 | |
| 43 | attr_check_source () { |
| 44 | path="$1" expect="$2" source="$3" git_opts="$4" && |
| 45 | |
| 46 | echo "$path: test: $expect" >expect && |
| 47 | |
| 48 | git $git_opts check-attr --source $source test -- "$path" >actual 2>err && |
| 49 | test_cmp expect actual && |
| 50 | test_must_be_empty err && |
| 51 | |
| 52 | git $git_opts --attr-source="$source" check-attr test -- "$path" >actual 2>err && |
| 53 | test_cmp expect actual && |
| 54 | test_must_be_empty err |
| 55 | |
| 56 | git $git_opts -c "attr.tree=$source" check-attr test -- "$path" >actual 2>err && |
| 57 | test_cmp expect actual && |
| 58 | test_must_be_empty err |
| 59 | |
| 60 | GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err && |
| 61 | test_cmp expect actual && |
| 62 | test_must_be_empty err |
| 63 | } |
| 64 | |
| 65 | test_expect_success 'open-quoted pathname' ' |
| 66 | echo "\"a test=a" >.gitattributes && |
| 67 | attr_check a unspecified |
| 68 | ' |
| 69 | |
| 70 | test_expect_success 'setup' ' |
| 71 | mkdir -p a/b/d a/c b && |
| 72 | ( |
| 73 | echo "[attr]notest !test" && |
| 74 | echo "\" d \" test=d" && |
| 75 | echo " e test=e" && |
| 76 | echo " e\" test=e" && |
| 77 | echo "f test=f" && |
| 78 | echo "a/i test=a/i" && |
| 79 | echo "onoff test -test" && |
| 80 | echo "offon -test test" && |
| 81 | echo "no notest" && |
| 82 | echo "A/e/F test=A/e/F" |
| 83 | ) >.gitattributes && |
| 84 | ( |
| 85 | echo "g test=a/g" && |
| 86 | echo "b/g test=a/b/g" |
| 87 | ) >a/.gitattributes && |
| 88 | ( |
| 89 | echo "h test=a/b/h" && |
| 90 | echo "d/* test=a/b/d/*" && |
| 91 | echo "d/yes notest" |
| 92 | ) >a/b/.gitattributes && |
| 93 | ( |
| 94 | echo "global test=global" |
| 95 | ) >"$HOME"/global-gitattributes && |
| 96 | cat <<-EOF >expect-all |
| 97 | f: test: f |
| 98 | a/f: test: f |
| 99 | a/c/f: test: f |
| 100 | a/g: test: a/g |
| 101 | a/b/g: test: a/b/g |
| 102 | b/g: test: unspecified |
| 103 | a/b/h: test: a/b/h |
| 104 | a/b/d/g: test: a/b/d/* |
| 105 | onoff: test: unset |
| 106 | offon: test: set |
| 107 | no: notest: set |
| 108 | no: test: unspecified |
| 109 | a/b/d/no: notest: set |
| 110 | a/b/d/no: test: a/b/d/* |
| 111 | a/b/d/yes: notest: set |
| 112 | a/b/d/yes: test: unspecified |
| 113 | EOF |
| 114 | ' |
| 115 | |
| 116 | test_expect_success 'setup branches' ' |
| 117 | mkdir -p foo/bar && |
| 118 | test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ |
| 119 | "f test=f\na/i test=n\n" tag-1 && |
| 120 | test_commit --printf "add .gitattributes" foo/bar/.gitattributes \ |
| 121 | "g test=g\na/i test=m\n" tag-2 && |
| 122 | rm foo/bar/.gitattributes |
| 123 | ' |
| 124 | |
| 125 | test_expect_success 'command line checks' ' |
| 126 | test_must_fail git check-attr && |
| 127 | test_must_fail git check-attr -- && |
| 128 | test_must_fail git check-attr test && |
| 129 | test_must_fail git check-attr test -- && |
| 130 | test_must_fail git check-attr -- f && |
| 131 | test_must_fail git check-attr --source && |
| 132 | test_must_fail git check-attr --source not-a-valid-ref && |
| 133 | echo "f" | test_must_fail git check-attr --stdin && |
| 134 | echo "f" | test_must_fail git check-attr --stdin -- f && |
| 135 | echo "f" | test_must_fail git check-attr --stdin test -- f && |
| 136 | test_must_fail git check-attr "" -- f |
| 137 | ' |
| 138 | |
| 139 | test_expect_success 'attribute test' ' |
| 140 | |
| 141 | attr_check " d " d && |
| 142 | attr_check e e && |
| 143 | attr_check_quote e\" e\\\" e && |
| 144 | |
| 145 | attr_check f f && |
| 146 | attr_check a/f f && |
| 147 | attr_check a/c/f f && |
| 148 | attr_check a/g a/g && |
| 149 | attr_check a/b/g a/b/g && |
| 150 | attr_check b/g unspecified && |
| 151 | attr_check a/b/h a/b/h && |
| 152 | attr_check a/b/d/g "a/b/d/*" && |
| 153 | attr_check onoff unset && |
| 154 | attr_check offon set && |
| 155 | attr_check no unspecified && |
| 156 | attr_check a/b/d/no "a/b/d/*" && |
| 157 | attr_check a/b/d/yes unspecified |
| 158 | ' |
| 159 | |
| 160 | test_expect_success 'attribute matching is case sensitive when core.ignorecase=0' ' |
| 161 | |
| 162 | attr_check F unspecified "-c core.ignorecase=0" && |
| 163 | attr_check a/F unspecified "-c core.ignorecase=0" && |
| 164 | attr_check a/c/F unspecified "-c core.ignorecase=0" && |
| 165 | attr_check a/G unspecified "-c core.ignorecase=0" && |
| 166 | attr_check a/B/g a/g "-c core.ignorecase=0" && |
| 167 | attr_check a/b/G unspecified "-c core.ignorecase=0" && |
| 168 | attr_check a/b/H unspecified "-c core.ignorecase=0" && |
| 169 | attr_check a/b/D/g a/g "-c core.ignorecase=0" && |
| 170 | attr_check oNoFf unspecified "-c core.ignorecase=0" && |
| 171 | attr_check oFfOn unspecified "-c core.ignorecase=0" && |
| 172 | attr_check NO unspecified "-c core.ignorecase=0" && |
| 173 | attr_check a/b/D/NO unspecified "-c core.ignorecase=0" && |
| 174 | attr_check a/b/d/YES a/b/d/* "-c core.ignorecase=0" && |
| 175 | attr_check a/E/f f "-c core.ignorecase=0" |
| 176 | |
| 177 | ' |
| 178 | |
| 179 | test_expect_success 'attribute matching is case insensitive when core.ignorecase=1' ' |
| 180 | |
| 181 | attr_check F f "-c core.ignorecase=1" && |
| 182 | attr_check a/F f "-c core.ignorecase=1" && |
| 183 | attr_check a/c/F f "-c core.ignorecase=1" && |
| 184 | attr_check a/G a/g "-c core.ignorecase=1" && |
| 185 | attr_check a/B/g a/b/g "-c core.ignorecase=1" && |
| 186 | attr_check a/b/G a/b/g "-c core.ignorecase=1" && |
| 187 | attr_check a/b/H a/b/h "-c core.ignorecase=1" && |
| 188 | attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=1" && |
| 189 | attr_check oNoFf unset "-c core.ignorecase=1" && |
| 190 | attr_check oFfOn set "-c core.ignorecase=1" && |
| 191 | attr_check NO unspecified "-c core.ignorecase=1" && |
| 192 | attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=1" && |
| 193 | attr_check a/b/d/YES unspecified "-c core.ignorecase=1" && |
| 194 | attr_check a/E/f "A/e/F" "-c core.ignorecase=1" |
| 195 | |
| 196 | ' |
| 197 | |
| 198 | test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' ' |
| 199 | attr_check a/B/D/g a/g "-c core.ignorecase=0" && |
| 200 | attr_check A/B/D/NO unspecified "-c core.ignorecase=0" && |
| 201 | attr_check A/b/h a/b/h "-c core.ignorecase=1" && |
| 202 | attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=1" && |
| 203 | attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=1" |
| 204 | ' |
| 205 | |
| 206 | test_expect_success 'unnormalized paths' ' |
| 207 | attr_check ./f f && |
| 208 | attr_check ./a/g a/g && |
| 209 | attr_check a/./g a/g && |
| 210 | attr_check a/c/../b/g a/b/g |
| 211 | ' |
| 212 | |
| 213 | test_expect_success 'relative paths' ' |
| 214 | (cd a && attr_check ../f f) && |
| 215 | (cd a && attr_check f f) && |
| 216 | (cd a && attr_check i a/i) && |
| 217 | (cd a && attr_check g a/g) && |
| 218 | (cd a && attr_check b/g a/b/g) && |
| 219 | (cd b && attr_check ../a/f f) && |
| 220 | (cd b && attr_check ../a/g a/g) && |
| 221 | (cd b && attr_check ../a/b/g a/b/g) |
| 222 | ' |
| 223 | |
| 224 | test_expect_success 'prefixes are not confused with leading directories' ' |
| 225 | attr_check a_plus/g unspecified && |
| 226 | cat >expect <<-\EOF && |
| 227 | a/g: test: a/g |
| 228 | a_plus/g: test: unspecified |
| 229 | EOF |
| 230 | git check-attr test a/g a_plus/g >actual && |
| 231 | test_cmp expect actual |
| 232 | ' |
| 233 | |
| 234 | test_expect_success 'core.attributesfile' ' |
| 235 | attr_check global unspecified && |
| 236 | git config core.attributesfile "$HOME/global-gitattributes" && |
| 237 | attr_check global global && |
| 238 | git config core.attributesfile "~/global-gitattributes" && |
| 239 | attr_check global global && |
| 240 | echo "global test=precedence" >>.gitattributes && |
| 241 | attr_check global precedence |
| 242 | ' |
| 243 | |
| 244 | test_expect_success 'attribute test: read paths from stdin' ' |
| 245 | grep -v notest <expect-all >expect && |
| 246 | sed -e "s/:.*//" <expect | git check-attr --stdin test >actual && |
| 247 | test_cmp expect actual |
| 248 | ' |
| 249 | |
| 250 | test_expect_success 'setup --all option' ' |
| 251 | grep -v unspecified <expect-all | sort >specified-all && |
| 252 | sed -e "s/:.*//" <expect-all | uniq >stdin-all |
| 253 | ' |
| 254 | |
| 255 | test_expect_success 'attribute test: --all option' ' |
| 256 | git check-attr --stdin --all <stdin-all >tmp && |
| 257 | sort tmp >actual && |
| 258 | test_cmp specified-all actual |
| 259 | ' |
| 260 | |
| 261 | test_expect_success 'attribute test: --cached option' ' |
| 262 | git check-attr --cached --stdin --all <stdin-all >tmp && |
| 263 | sort tmp >actual && |
| 264 | test_must_be_empty actual && |
| 265 | git add .gitattributes a/.gitattributes a/b/.gitattributes && |
| 266 | git check-attr --cached --stdin --all <stdin-all >tmp && |
| 267 | sort tmp >actual && |
| 268 | test_cmp specified-all actual |
| 269 | ' |
| 270 | |
| 271 | test_expect_success 'root subdir attribute test' ' |
| 272 | attr_check a/i a/i && |
| 273 | attr_check subdir/a/i unspecified |
| 274 | ' |
| 275 | |
| 276 | test_expect_success 'negative patterns' ' |
| 277 | echo "!f test=bar" >.gitattributes && |
| 278 | git check-attr test -- '"'"'!f'"'"' 2>errors && |
| 279 | test_grep "Negative patterns are ignored" errors |
| 280 | ' |
| 281 | |
| 282 | test_expect_success 'patterns starting with exclamation' ' |
| 283 | echo "\!f test=foo" >.gitattributes && |
| 284 | attr_check "!f" foo |
| 285 | ' |
| 286 | |
| 287 | test_expect_success '"**" test' ' |
| 288 | echo "**/f foo=bar" >.gitattributes && |
| 289 | cat <<\EOF >expect && |
| 290 | f: foo: bar |
| 291 | a/f: foo: bar |
| 292 | a/b/f: foo: bar |
| 293 | a/b/c/f: foo: bar |
| 294 | EOF |
| 295 | git check-attr foo -- "f" >actual 2>err && |
| 296 | git check-attr foo -- "a/f" >>actual 2>>err && |
| 297 | git check-attr foo -- "a/b/f" >>actual 2>>err && |
| 298 | git check-attr foo -- "a/b/c/f" >>actual 2>>err && |
| 299 | test_cmp expect actual && |
| 300 | test_must_be_empty err |
| 301 | ' |
| 302 | |
| 303 | test_expect_success '"**" with no slashes test' ' |
| 304 | echo "a**f foo=bar" >.gitattributes && |
| 305 | git check-attr foo -- "f" >actual && |
| 306 | cat <<\EOF >expect && |
| 307 | f: foo: unspecified |
| 308 | af: foo: bar |
| 309 | axf: foo: bar |
| 310 | a/f: foo: unspecified |
| 311 | a/b/f: foo: unspecified |
| 312 | a/b/c/f: foo: unspecified |
| 313 | EOF |
| 314 | git check-attr foo -- "f" >actual 2>err && |
| 315 | git check-attr foo -- "af" >>actual 2>err && |
| 316 | git check-attr foo -- "axf" >>actual 2>err && |
| 317 | git check-attr foo -- "a/f" >>actual 2>>err && |
| 318 | git check-attr foo -- "a/b/f" >>actual 2>>err && |
| 319 | git check-attr foo -- "a/b/c/f" >>actual 2>>err && |
| 320 | test_cmp expect actual && |
| 321 | test_must_be_empty err |
| 322 | ' |
| 323 | |
| 324 | test_expect_success 'using --git-dir and --work-tree' ' |
| 325 | mkdir unreal real && |
| 326 | git init real && |
| 327 | echo "file test=in-real" >real/.gitattributes && |
| 328 | ( |
| 329 | cd unreal && |
| 330 | attr_check file in-real "--git-dir ../real/.git --work-tree ../real" |
| 331 | ) |
| 332 | ' |
| 333 | |
| 334 | test_expect_success 'using --source' ' |
| 335 | attr_check_source foo/bar/f f tag-1 && |
| 336 | attr_check_source foo/bar/a/i n tag-1 && |
| 337 | attr_check_source foo/bar/f unspecified tag-2 && |
| 338 | attr_check_source foo/bar/a/i m tag-2 && |
| 339 | attr_check_source foo/bar/g g tag-2 && |
| 340 | attr_check_source foo/bar/g unspecified tag-1 |
| 341 | ' |
| 342 | |
| 343 | test_expect_success 'setup bare' ' |
| 344 | git clone --template= --bare . bare.git |
| 345 | ' |
| 346 | |
| 347 | test_expect_success 'bare repository: check that .gitattribute is ignored' ' |
| 348 | ( |
| 349 | cd bare.git && |
| 350 | ( |
| 351 | echo "f test=f" && |
| 352 | echo "a/i test=a/i" |
| 353 | ) >.gitattributes && |
| 354 | attr_check f unspecified && |
| 355 | attr_check a/f unspecified && |
| 356 | attr_check a/c/f unspecified && |
| 357 | attr_check a/i unspecified && |
| 358 | attr_check subdir/a/i unspecified |
| 359 | ) |
| 360 | ' |
| 361 | |
| 362 | bad_attr_source_err="fatal: bad --attr-source or GIT_ATTR_SOURCE" |
| 363 | |
| 364 | test_expect_success '--attr-source is bad' ' |
| 365 | test_when_finished rm -rf empty && |
| 366 | git init empty && |
| 367 | ( |
| 368 | cd empty && |
| 369 | echo "$bad_attr_source_err" >expect_err && |
| 370 | test_must_fail git --attr-source=HEAD check-attr test -- f/path 2>err && |
| 371 | test_cmp expect_err err |
| 372 | ) |
| 373 | ' |
| 374 | |
| 375 | test_expect_success 'attr.tree when HEAD is unborn' ' |
| 376 | test_when_finished rm -rf empty && |
| 377 | git init empty && |
| 378 | ( |
| 379 | cd empty && |
| 380 | echo "f/path: test: unspecified" >expect && |
| 381 | git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err && |
| 382 | test_must_be_empty err && |
| 383 | test_cmp expect actual |
| 384 | ) |
| 385 | ' |
| 386 | |
| 387 | test_expect_success 'bad attr source defaults to reading .gitattributes file' ' |
| 388 | test_when_finished rm -rf empty && |
| 389 | git init empty && |
| 390 | ( |
| 391 | cd empty && |
| 392 | echo "f/path test=val" >.gitattributes && |
| 393 | echo "f/path: test: val" >expect && |
| 394 | git -c attr.tree=HEAD check-attr test -- f/path >actual 2>err && |
| 395 | test_must_be_empty err && |
| 396 | test_cmp expect actual |
| 397 | ) |
| 398 | ' |
| 399 | |
| 400 | test_expect_success 'bare repo no longer defaults to reading .gitattributes from HEAD' ' |
| 401 | test_when_finished rm -rf test bare_with_gitattribute && |
| 402 | git init test && |
| 403 | test_commit -C test gitattributes .gitattributes "f/path test=val" && |
| 404 | git clone --bare test bare_with_gitattribute && |
| 405 | |
| 406 | echo "f/path: test: unspecified" >expect && |
| 407 | git -C bare_with_gitattribute check-attr test -- f/path >actual && |
| 408 | test_cmp expect actual && |
| 409 | |
| 410 | echo "f/path: test: val" >expect && |
| 411 | git -C bare_with_gitattribute -c attr.tree=HEAD \ |
| 412 | check-attr test -- f/path >actual && |
| 413 | test_cmp expect actual |
| 414 | ' |
| 415 | |
| 416 | test_expect_success 'precedence of --attr-source, GIT_ATTR_SOURCE, then attr.tree' ' |
| 417 | test_when_finished rm -rf empty && |
| 418 | git init empty && |
| 419 | ( |
| 420 | cd empty && |
| 421 | git checkout -b attr-source && |
| 422 | test_commit "val1" .gitattributes "f/path test=val1" && |
| 423 | git checkout -b attr-tree && |
| 424 | test_commit "val2" .gitattributes "f/path test=val2" && |
| 425 | git checkout attr-source && |
| 426 | echo "f/path: test: val1" >expect && |
| 427 | GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree --attr-source=attr-source \ |
| 428 | check-attr test -- f/path >actual && |
| 429 | test_cmp expect actual && |
| 430 | GIT_ATTR_SOURCE=attr-source git -c attr.tree=attr-tree \ |
| 431 | check-attr test -- f/path >actual && |
| 432 | test_cmp expect actual |
| 433 | ) |
| 434 | ' |
| 435 | |
| 436 | test_expect_success 'diff without repository with attr source' ' |
| 437 | mkdir -p "$TRASH_DIRECTORY/outside/nongit" && |
| 438 | ( |
| 439 | cd "$TRASH_DIRECTORY/outside/nongit" && |
| 440 | GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/outside" && |
| 441 | export GIT_CEILING_DIRECTORIES && |
| 442 | touch file && |
| 443 | cat >expect <<-EOF && |
| 444 | fatal: cannot use --attr-source or GIT_ATTR_SOURCE without repo |
| 445 | EOF |
| 446 | test_must_fail env GIT_ATTR_SOURCE=HEAD git grep --no-index foo file 2>err && |
| 447 | test_cmp expect err |
| 448 | ) |
| 449 | ' |
| 450 | |
| 451 | test_expect_success 'bare repository: with --source' ' |
| 452 | ( |
| 453 | cd bare.git && |
| 454 | attr_check_source foo/bar/f f tag-1 && |
| 455 | attr_check_source foo/bar/a/i n tag-1 && |
| 456 | attr_check_source foo/bar/f unspecified tag-2 && |
| 457 | attr_check_source foo/bar/a/i m tag-2 && |
| 458 | attr_check_source foo/bar/g g tag-2 && |
| 459 | attr_check_source foo/bar/g unspecified tag-1 |
| 460 | ) |
| 461 | ' |
| 462 | |
| 463 | test_expect_success 'bare repository: check that --cached honors index' ' |
| 464 | ( |
| 465 | cd bare.git && |
| 466 | GIT_INDEX_FILE=../.git/index \ |
| 467 | git check-attr --cached --stdin --all <../stdin-all | |
| 468 | sort >actual && |
| 469 | test_cmp ../specified-all actual |
| 470 | ) |
| 471 | ' |
| 472 | |
| 473 | test_expect_success 'bare repository: test info/attributes' ' |
| 474 | ( |
| 475 | cd bare.git && |
| 476 | mkdir info && |
| 477 | ( |
| 478 | echo "f test=f" && |
| 479 | echo "a/i test=a/i" |
| 480 | ) >info/attributes && |
| 481 | attr_check f f && |
| 482 | attr_check a/f f && |
| 483 | attr_check a/c/f f && |
| 484 | attr_check a/i a/i && |
| 485 | attr_check subdir/a/i unspecified |
| 486 | ) |
| 487 | ' |
| 488 | |
| 489 | test_expect_success 'binary macro expanded by -a' ' |
| 490 | echo "file binary" >.gitattributes && |
| 491 | cat >expect <<-\EOF && |
| 492 | file: binary: set |
| 493 | file: diff: unset |
| 494 | file: merge: unset |
| 495 | file: text: unset |
| 496 | EOF |
| 497 | git check-attr -a file >actual && |
| 498 | test_cmp expect actual |
| 499 | ' |
| 500 | |
| 501 | test_expect_success 'query binary macro directly' ' |
| 502 | echo "file binary" >.gitattributes && |
| 503 | echo file: binary: set >expect && |
| 504 | git check-attr binary file >actual && |
| 505 | test_cmp expect actual |
| 506 | ' |
| 507 | |
| 508 | test_expect_success SYMLINKS 'set up symlink tests' ' |
| 509 | echo "* test" >attr && |
| 510 | rm -f .gitattributes |
| 511 | ' |
| 512 | |
| 513 | test_expect_success SYMLINKS 'symlinks respected in core.attributesFile' ' |
| 514 | test_when_finished "rm symlink" && |
| 515 | ln -s attr symlink && |
| 516 | test_config core.attributesFile "$(pwd)/symlink" && |
| 517 | attr_check file set |
| 518 | ' |
| 519 | |
| 520 | test_expect_success SYMLINKS 'symlinks respected in info/attributes' ' |
| 521 | test_when_finished "rm .git/info/attributes" && |
| 522 | mkdir .git/info && |
| 523 | ln -s ../../attr .git/info/attributes && |
| 524 | attr_check file set |
| 525 | ' |
| 526 | |
| 527 | test_expect_success SYMLINKS 'symlinks not respected in-tree' ' |
| 528 | test_when_finished "rm -rf .gitattributes subdir" && |
| 529 | ln -s attr .gitattributes && |
| 530 | mkdir subdir && |
| 531 | ln -s ../attr subdir/.gitattributes && |
| 532 | attr_check_basic subdir/file unspecified && |
| 533 | test_grep "unable to access.*gitattributes" err |
| 534 | ' |
| 535 | |
| 536 | test_expect_success 'large attributes line ignored in tree' ' |
| 537 | test_when_finished "rm .gitattributes" && |
| 538 | printf "path %02043d" 1 >.gitattributes && |
| 539 | git check-attr --all path >actual 2>err && |
| 540 | echo "warning: ignoring overly long attributes line 1" >expect && |
| 541 | test_cmp expect err && |
| 542 | test_must_be_empty actual |
| 543 | ' |
| 544 | |
| 545 | test_expect_success 'large attributes line ignores trailing content in tree' ' |
| 546 | test_when_finished "rm .gitattributes" && |
| 547 | # older versions of Git broke lines at 2048 bytes; the 2045 bytes |
| 548 | # of 0-padding here is accounting for the three bytes of "a 1", which |
| 549 | # would knock "trailing" to the "next" line, where it would be |
| 550 | # erroneously parsed. |
| 551 | printf "a %02045dtrailing attribute\n" 1 >.gitattributes && |
| 552 | git check-attr --all trailing >actual 2>err && |
| 553 | echo "warning: ignoring overly long attributes line 1" >expect && |
| 554 | test_cmp expect err && |
| 555 | test_must_be_empty actual |
| 556 | ' |
| 557 | |
| 558 | test_expect_success EXPENSIVE 'large attributes file ignored in tree' ' |
| 559 | test_when_finished "rm .gitattributes" && |
| 560 | dd if=/dev/zero of=.gitattributes bs=1048576 count=101 2>/dev/null && |
| 561 | git check-attr --all path >/dev/null 2>err && |
| 562 | echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect && |
| 563 | test_cmp expect err |
| 564 | ' |
| 565 | |
| 566 | test_expect_success 'large attributes line ignored in index' ' |
| 567 | test_when_finished "git update-index --remove .gitattributes" && |
| 568 | blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) && |
| 569 | git update-index --add --cacheinfo 100644,$blob,.gitattributes && |
| 570 | git check-attr --cached --all path >actual 2>err && |
| 571 | echo "warning: ignoring overly long attributes line 1" >expect && |
| 572 | test_cmp expect err && |
| 573 | test_must_be_empty actual |
| 574 | ' |
| 575 | |
| 576 | test_expect_success 'large attributes line ignores trailing content in index' ' |
| 577 | test_when_finished "git update-index --remove .gitattributes" && |
| 578 | blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) && |
| 579 | git update-index --add --cacheinfo 100644,$blob,.gitattributes && |
| 580 | git check-attr --cached --all trailing >actual 2>err && |
| 581 | echo "warning: ignoring overly long attributes line 1" >expect && |
| 582 | test_cmp expect err && |
| 583 | test_must_be_empty actual |
| 584 | ' |
| 585 | |
| 586 | test_expect_success EXPENSIVE 'large attributes file ignored in index' ' |
| 587 | test_when_finished "git update-index --remove .gitattributes" && |
| 588 | blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null | git hash-object -w --stdin) && |
| 589 | git update-index --add --cacheinfo 100644,$blob,.gitattributes && |
| 590 | git check-attr --cached --all path >/dev/null 2>err && |
| 591 | echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect && |
| 592 | test_cmp expect err |
| 593 | ' |
| 594 | |
| 595 | test_expect_success EXPENSIVE 'large attributes blob ignored' ' |
| 596 | test_when_finished "git update-index --remove .gitattributes" && |
| 597 | blob=$(dd if=/dev/zero bs=1048576 count=101 2>/dev/null | git hash-object -w --stdin) && |
| 598 | git update-index --add --cacheinfo 100644,$blob,.gitattributes && |
| 599 | tree="$(git write-tree)" && |
| 600 | git check-attr --cached --all --source="$tree" path >/dev/null 2>err && |
| 601 | echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect && |
| 602 | test_cmp expect err |
| 603 | ' |
| 604 | |
| 605 | test_expect_success 'builtin object mode attributes work (dir and regular paths)' ' |
| 606 | >normal && |
| 607 | attr_check_object_mode normal 100644 && |
| 608 | mkdir dir && |
| 609 | attr_check_object_mode dir 040000 |
| 610 | ' |
| 611 | |
| 612 | test_expect_success POSIXPERM 'builtin object mode attributes work (executable)' ' |
| 613 | >exec && |
| 614 | chmod +x exec && |
| 615 | attr_check_object_mode exec 100755 |
| 616 | ' |
| 617 | |
| 618 | test_expect_success SYMLINKS 'builtin object mode attributes work (symlinks)' ' |
| 619 | ln -s to_sym sym && |
| 620 | attr_check_object_mode sym 120000 |
| 621 | ' |
| 622 | |
| 623 | test_expect_success 'native object mode attributes work with --cached' ' |
| 624 | >normal && |
| 625 | git add normal && |
| 626 | empty_blob=$(git rev-parse :normal) && |
| 627 | git update-index --index-info <<-EOF && |
| 628 | 100755 $empty_blob 0 exec |
| 629 | 120000 $empty_blob 0 symlink |
| 630 | EOF |
| 631 | attr_check_object_mode normal 100644 --cached && |
| 632 | attr_check_object_mode exec 100755 --cached && |
| 633 | attr_check_object_mode symlink 120000 --cached |
| 634 | ' |
| 635 | |
| 636 | test_expect_success 'check object mode attributes work for submodules' ' |
| 637 | mkdir sub && |
| 638 | ( |
| 639 | cd sub && |
| 640 | git init && |
| 641 | mv .git .real && |
| 642 | echo "gitdir: .real" >.git && |
| 643 | test_commit first |
| 644 | ) && |
| 645 | attr_check_object_mode sub 160000 && |
| 646 | attr_check_object_mode sub unspecified --cached && |
| 647 | git add sub && |
| 648 | attr_check_object_mode sub 160000 --cached |
| 649 | ' |
| 650 | |
| 651 | test_expect_success 'we do not allow user defined builtin_* attributes' ' |
| 652 | echo "foo* builtin_foo" >.gitattributes && |
| 653 | git add .gitattributes 2>actual && |
| 654 | echo "builtin_foo is not a valid attribute name: .gitattributes:1" >expect && |
| 655 | test_cmp expect actual |
| 656 | ' |
| 657 | |
| 658 | test_expect_success 'user defined builtin_objectmode values are ignored' ' |
| 659 | echo "foo* builtin_objectmode=12345" >.gitattributes && |
| 660 | git add .gitattributes && |
| 661 | >foo_1 && |
| 662 | attr_check_object_mode_basic foo_1 100644 && |
| 663 | echo "builtin_objectmode is not a valid attribute name: .gitattributes:1" >expect && |
| 664 | test_cmp expect err |
| 665 | ' |
| 666 | |
| 667 | test_expect_success ULIMIT_STACK_SIZE 'deep macro recursion' ' |
| 668 | n=3000 && |
| 669 | { |
| 670 | i=0 && |
| 671 | while test $i -lt $n; do |
| 672 | echo "[attr]a$i a$((i+1))" && |
| 673 | i=$((i+1)) || |
| 674 | return 1 |
| 675 | done && |
| 676 | echo "[attr]a$n -text" && |
| 677 | echo "file a0" |
| 678 | } >.gitattributes && |
| 679 | { |
| 680 | echo "file: text: unset" && |
| 681 | test_seq -f "file: a%d: set" 0 $n |
| 682 | } >expect && |
| 683 | run_with_limited_stack git check-attr -a file >actual && |
| 684 | test_cmp expect actual |
| 685 | ' |
| 686 | |
| 687 | test_done |