(CommandList
  children: [
    (Assignment
      keyword: Assign_None
      pairs: [
        (assign_pair
          lhs: (LhsName name:test_description)
          op: Equal
          rhs: {(gitattributes)}
          spids: [4]
        )
      ]
      spids: [4]
    )
    (C {(.)} {(./test-lib.sh)})
    (FuncDef
      name: attr_check
      body: 
        (BraceGroup
          children: [
            (Assignment
              keyword: Assign_None
              pairs: [
                (assign_pair
                  lhs: (LhsName name:path)
                  op: Equal
                  rhs: {(DQ ($ VSub_Number '$1'))}
                  spids: [21]
                )
                (assign_pair
                  lhs: (LhsName name:expect)
                  op: Equal
                  rhs: {(DQ ($ VSub_Number '$2'))}
                  spids: [26]
                )
              ]
              spids: [21]
            )
            (AndOr
              children: [
                (SimpleCommand
                  words: [
                    {(git)}
                    {($ VSub_Number '$3')}
                    {(check-attr)}
                    {(test)}
                    {(--)}
                    {(DQ ($ VSub_Name '$path'))}
                  ]
                  redirects: [
                    (Redir
                      op_id: Redir_Great
                      fd: 16777215
                      arg_word: {(actual)}
                      spids: [47]
                    )
                    (Redir op_id:Redir_Great fd:2 arg_word:{(err)} spids:[50])
                  ]
                )
                (AndOr
                  children: [
                    (SimpleCommand
                      words: [{(echo)} {(DQ ($ VSub_Name '$path') (': test: ') ($ VSub_Number '$2'))}]
                      redirects: [
                        (Redir
                          op_id: Redir_Great
                          fd: 16777215
                          arg_word: {(expect)}
                          spids: [64]
                        )
                      ]
                    )
                    (AndOr
                      children: [
                        (C {(test_cmp)} {(expect)} {(actual)})
                        (C {(test_line_count)} {(Lit_Other '=')} {(0)} {(err)})
                      ]
                      op_id: Op_DAmp
                    )
                  ]
                  op_id: Op_DAmp
                )
              ]
              op_id: Op_DAmp
            )
          ]
          spids: [18]
        )
      spids: [13 17]
    )
    (C {(test_expect_success)} {(SQ <setup>)} 
      {
        (SQ <'\n'> <'\tmkdir -p a/b/d a/c b &&\n'> <'\t(\n'> <'\t\techo "[attr]notest !test"\n'> 
          <'\t\techo "f\ttest=f"\n'> <'\t\techo "a/i test=a/i"\n'> <'\t\techo "onoff test -test"\n'> <'\t\techo "offon -test test"\n'> 
          <'\t\techo "no notest"\n'> <'\t\techo "A/e/F test=A/e/F"\n'> <'\t) >.gitattributes &&\n'> <'\t(\n'> <'\t\techo "g test=a/g" &&\n'> 
          <'\t\techo "b/g test=a/b/g"\n'> <'\t) >a/.gitattributes &&\n'> <'\t(\n'> <'\t\techo "h test=a/b/h" &&\n'> 
          <'\t\techo "d/* test=a/b/d/*"\n'> <'\t\techo "d/yes notest"\n'> <'\t) >a/b/.gitattributes &&\n'> <'\t(\n'> 
          <'\t\techo "global test=global"\n'> <'\t) >"$HOME"/global-gitattributes &&\n'> <'\tcat <<-EOF >expect-all\n'> <'\tf: test: f\n'> 
          <'\ta/f: test: f\n'> <'\ta/c/f: test: f\n'> <'\ta/g: test: a/g\n'> <'\ta/b/g: test: a/b/g\n'> <'\tb/g: test: unspecified\n'> 
          <'\ta/b/h: test: a/b/h\n'> <'\ta/b/d/g: test: a/b/d/*\n'> <'\tonoff: test: unset\n'> <'\toffon: test: set\n'> 
          <'\tno: notest: set\n'> <'\tno: test: unspecified\n'> <'\ta/b/d/no: notest: set\n'> <'\ta/b/d/no: test: a/b/d/*\n'> 
          <'\ta/b/d/yes: notest: set\n'> <'\ta/b/d/yes: test: unspecified\n'> <'\tEOF\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'command line checks'>)} 
      {
        (SQ <'\n'> <'\ttest_must_fail git check-attr &&\n'> <'\ttest_must_fail git check-attr -- &&\n'> 
          <'\ttest_must_fail git check-attr test &&\n'> <'\ttest_must_fail git check-attr test -- &&\n'> <'\ttest_must_fail git check-attr -- f &&\n'> 
          <'\techo "f" | test_must_fail git check-attr --stdin &&\n'> <'\techo "f" | test_must_fail git check-attr --stdin -- f &&\n'> 
          <'\techo "f" | test_must_fail git check-attr --stdin test -- f &&\n'> <'\ttest_must_fail git check-attr "" -- f\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute test'>)} 
      {
        (SQ <'\n'> <'\tattr_check f f &&\n'> <'\tattr_check a/f f &&\n'> <'\tattr_check a/c/f f &&\n'> 
          <'\tattr_check a/g a/g &&\n'> <'\tattr_check a/b/g a/b/g &&\n'> <'\tattr_check b/g unspecified &&\n'> 
          <'\tattr_check a/b/h a/b/h &&\n'> <'\tattr_check a/b/d/g "a/b/d/*" &&\n'> <'\tattr_check onoff unset &&\n'> 
          <'\tattr_check offon set &&\n'> <'\tattr_check no unspecified &&\n'> <'\tattr_check a/b/d/no "a/b/d/*" &&\n'> 
          <'\tattr_check a/b/d/yes unspecified\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute matching is case sensitive when core.ignorecase=0'>)} 
      {
        (SQ <'\n'> <'\n'> <'\ttest_must_fail attr_check F f "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/F f "-c core.ignorecase=0" &&\n'> <'\ttest_must_fail attr_check a/c/F f "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/G a/g "-c core.ignorecase=0" &&\n'> <'\ttest_must_fail attr_check a/B/g a/b/g "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/b/G a/b/g "-c core.ignorecase=0" &&\n'> <'\ttest_must_fail attr_check a/b/H a/b/h "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=0" &&\n'> <'\ttest_must_fail attr_check oNoFf unset "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check oFfOn set "-c core.ignorecase=0" &&\n'> <'\tattr_check NO unspecified "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=0" &&\n'> <'\tattr_check a/b/d/YES a/b/d/* "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check a/E/f "A/e/F" "-c core.ignorecase=0"\n'> <'\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute matching is case insensitive when core.ignorecase=1'>)} 
      {
        (SQ <'\n'> <'\n'> <'\tattr_check F f "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/F f "-c core.ignorecase=1" &&\n'> <'\tattr_check a/c/F f "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/G a/g "-c core.ignorecase=1" &&\n'> <'\tattr_check a/B/g a/b/g "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/b/G a/b/g "-c core.ignorecase=1" &&\n'> <'\tattr_check a/b/H a/b/h "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/b/D/g "a/b/d/*" "-c core.ignorecase=1" &&\n'> <'\tattr_check oNoFf unset "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check oFfOn set "-c core.ignorecase=1" &&\n'> <'\tattr_check NO unspecified "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/b/D/NO "a/b/d/*" "-c core.ignorecase=1" &&\n'> <'\tattr_check a/b/d/YES unspecified "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/E/f "A/e/F" "-c core.ignorecase=1"\n'> <'\n'>
        )
      }
    )
    (C {(test_expect_success)} {(CASE_INSENSITIVE_FS)} {(SQ <'additional case insensitivity tests'>)} 
      {
        (SQ <'\n'> <'\ttest_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&\n'> 
          <'\ttest_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&\n'> <'\tattr_check A/b/h a/b/h "-c core.ignorecase=1" &&\n'> 
          <'\tattr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=1" &&\n'> <'\tattr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=1"\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'unnormalized paths'>)} 
      {
        (SQ <'\n'> <'\tattr_check ./f f &&\n'> <'\tattr_check ./a/g a/g &&\n'> 
          <'\tattr_check a/./g a/g &&\n'> <'\tattr_check a/c/../b/g a/b/g\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'relative paths'>)} 
      {
        (SQ <'\n'> <'\t(cd a && attr_check ../f f) &&\n'> <'\t(cd a && attr_check f f) &&\n'> 
          <'\t(cd a && attr_check i a/i) &&\n'> <'\t(cd a && attr_check g a/g) &&\n'> <'\t(cd a && attr_check b/g a/b/g) &&\n'> 
          <'\t(cd b && attr_check ../a/f f) &&\n'> <'\t(cd b && attr_check ../a/g a/g) &&\n'> <'\t(cd b && attr_check ../a/b/g a/b/g)\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'prefixes are not confused with leading directories'>)} 
      {
        (SQ <'\n'> <'\tattr_check a_plus/g unspecified &&\n'> <'\tcat >expect <<-\\EOF &&\n'> 
          <'\ta/g: test: a/g\n'> <'\ta_plus/g: test: unspecified\n'> <'\tEOF\n'> <'\tgit check-attr test a/g a_plus/g >actual &&\n'> 
          <'\ttest_cmp expect actual\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <core.attributesfile>)} 
      {
        (SQ <'\n'> <'\tattr_check global unspecified &&\n'> 
          <'\tgit config core.attributesfile "$HOME/global-gitattributes" &&\n'> <'\tattr_check global global &&\n'> <'\tgit config core.attributesfile "~/global-gitattributes" &&\n'> 
          <'\tattr_check global global &&\n'> <'\techo "global test=precedence" >>.gitattributes &&\n'> <'\tattr_check global precedence\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute test: read paths from stdin'>)} 
      {
        (SQ <'\n'> <'\tgrep -v notest <expect-all >expect &&\n'> 
          <'\tsed -e "s/:.*//" <expect | git check-attr --stdin test >actual &&\n'> <'\ttest_cmp expect actual\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute test: --all option'>)} 
      {
        (SQ <'\n'> <'\tgrep -v unspecified <expect-all | sort >specified-all &&\n'> 
          <'\tsed -e "s/:.*//" <expect-all | uniq >stdin-all &&\n'> <'\tgit check-attr --stdin --all <stdin-all | sort >actual &&\n'> 
          <'\ttest_cmp specified-all actual\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'attribute test: --cached option'>)} 
      {
        (SQ <'\n'> <'\t: >empty &&\n'> 
          <'\tgit check-attr --cached --stdin --all <stdin-all | sort >actual &&\n'> <'\ttest_cmp empty actual &&\n'> <'\tgit add .gitattributes a/.gitattributes a/b/.gitattributes &&\n'> 
          <'\tgit check-attr --cached --stdin --all <stdin-all | sort >actual &&\n'> <'\ttest_cmp specified-all actual\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'root subdir attribute test'>)} 
      {(SQ <'\n'> <'\tattr_check a/i a/i &&\n'> <'\tattr_check subdir/a/i unspecified\n'>)}
    )
    (C {(test_expect_success)} {(SQ <'negative patterns'>)} 
      {(SQ <'\n'> <'\techo "!f test=bar" >.gitattributes &&\n'> <'\tgit check-attr test -- '>) 
        (DQ ("'")) (SQ <'!f'>) (DQ ("'")) 
        (SQ <' 2>errors &&\n'> <'\ttest_i18ngrep "Negative patterns are ignored" errors\n'>)
      }
    )
    (C {(test_expect_success)} {(SQ <'patterns starting with exclamation'>)} 
      {(SQ <'\n'> <'\techo "\\!f test=foo" >.gitattributes &&\n'> <'\tattr_check "!f" foo\n'>)}
    )
    (C {(test_expect_success)} {(SQ <'"**" test'>)} 
      {
        (SQ <'\n'> <'\techo "**/f foo=bar" >.gitattributes &&\n'> <'\tcat <<\\EOF >expect &&\n'> 
          <'f: foo: bar\n'> <'a/f: foo: bar\n'> <'a/b/f: foo: bar\n'> <'a/b/c/f: foo: bar\n'> <'EOF\n'> 
          <'\tgit check-attr foo -- "f" >actual 2>err &&\n'> <'\tgit check-attr foo -- "a/f" >>actual 2>>err &&\n'> 
          <'\tgit check-attr foo -- "a/b/f" >>actual 2>>err &&\n'> <'\tgit check-attr foo -- "a/b/c/f" >>actual 2>>err &&\n'> <'\ttest_cmp expect actual &&\n'> 
          <'\ttest_line_count = 0 err\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'"**" with no slashes test'>)} 
      {
        (SQ <'\n'> <'\techo "a**f foo=bar" >.gitattributes &&\n'> 
          <'\tgit check-attr foo -- "f" >actual &&\n'> <'\tcat <<\\EOF >expect &&\n'> <'f: foo: unspecified\n'> <'af: foo: bar\n'> <'axf: foo: bar\n'> 
          <'a/f: foo: unspecified\n'> <'a/b/f: foo: unspecified\n'> <'a/b/c/f: foo: unspecified\n'> <'EOF\n'> 
          <'\tgit check-attr foo -- "f" >actual 2>err &&\n'> <'\tgit check-attr foo -- "af" >>actual 2>err &&\n'> 
          <'\tgit check-attr foo -- "axf" >>actual 2>err &&\n'> <'\tgit check-attr foo -- "a/f" >>actual 2>>err &&\n'> 
          <'\tgit check-attr foo -- "a/b/f" >>actual 2>>err &&\n'> <'\tgit check-attr foo -- "a/b/c/f" >>actual 2>>err &&\n'> <'\ttest_cmp expect actual &&\n'> 
          <'\ttest_line_count = 0 err\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'using --git-dir and --work-tree'>)} 
      {
        (SQ <'\n'> <'\tmkdir unreal real &&\n'> <'\tgit init real &&\n'> 
          <'\techo "file test=in-real" >real/.gitattributes &&\n'> <'\t(\n'> <'\t\tcd unreal &&\n'> 
          <'\t\tattr_check file in-real "--git-dir ../real/.git --work-tree ../real"\n'> <'\t)\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'setup bare'>)} {(SQ <'\n'> <'\tgit clone --bare . bare.git\n'>)})
    (C {(test_expect_success)} {(SQ <'bare repository: check that .gitattribute is ignored'>)} 
      {
        (SQ <'\n'> <'\t(\n'> <'\t\tcd bare.git &&\n'> <'\t\t(\n'> <'\t\t\techo "f\ttest=f"\n'> 
          <'\t\t\techo "a/i test=a/i"\n'> <'\t\t) >.gitattributes &&\n'> <'\t\tattr_check f unspecified &&\n'> 
          <'\t\tattr_check a/f unspecified &&\n'> <'\t\tattr_check a/c/f unspecified &&\n'> <'\t\tattr_check a/i unspecified &&\n'> 
          <'\t\tattr_check subdir/a/i unspecified\n'> <'\t)\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'bare repository: check that --cached honors index'>)} 
      {
        (SQ <'\n'> <'\t(\n'> <'\t\tcd bare.git &&\n'> <'\t\tGIT_INDEX_FILE=../.git/index \\\n'> 
          <'\t\tgit check-attr --cached --stdin --all <../stdin-all |\n'> <'\t\tsort >actual &&\n'> <'\t\ttest_cmp ../specified-all actual\n'> <'\t)\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <'bare repository: test info/attributes'>)} 
      {
        (SQ <'\n'> <'\t(\n'> <'\t\tcd bare.git &&\n'> <'\t\t(\n'> <'\t\t\techo "f\ttest=f"\n'> 
          <'\t\t\techo "a/i test=a/i"\n'> <'\t\t) >info/attributes &&\n'> <'\t\tattr_check f f &&\n'> <'\t\tattr_check a/f f &&\n'> 
          <'\t\tattr_check a/c/f f &&\n'> <'\t\tattr_check a/i a/i &&\n'> <'\t\tattr_check subdir/a/i unspecified\n'> <'\t)\n'>
        )
      }
    )
    (C {(test_done)})
  ]
)