(command.CommandList
  children: [
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:test_description)
          op: assign_op.Equal
          rhs: 
            {
              (DQ <'Test whether cache-tree is properly updated\n'> <'\n'> 
                <'Tests whether various commands properly update and/or rewrite the\n'> <'cache-tree extension.\n'>
              )
            }
          spids: [4]
        )
      ]
    )
    (C {<.>} {<'./test-lib.sh'>})
    (command.ShFunction
      name: cmp_cache_tree
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.Pipeline
                  children: [
                    (C {<test-dump-cache-tree>})
                    (command.Simple
                      words: [{<sed>} {<-e>} {(SQ <'/#(ref)/d'>)}]
                      redirects: [
                        (redir
                          op: <Id.Redir_Great '>'>
                          loc: (redir_loc.Fd fd:1)
                          arg: {<actual>}
                        )
                      ]
                      do_fork: T
                    )
                  ]
                  negated: F
                )
                (command.Simple
                  words: [{<sed>} {(DQ <'s/'> ($ Id.VSub_DollarName '$_x40') <'/SHA/'>)}]
                  redirects: [
                    (redir
                      op: <Id.Redir_Less '<'>
                      loc: (redir_loc.Fd fd:0)
                      arg: {<actual>}
                    )
                    (redir
                      op: <Id.Redir_Great '>'>
                      loc: (redir_loc.Fd fd:1)
                      arg: {<filtered>}
                    )
                  ]
                  do_fork: T
                )
                (C {<test_cmp>} {(DQ ($ Id.VSub_Number '$1'))} {<filtered>})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: generate_expected_cache_tree_rec
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:dir)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (DQ ($ Id.VSub_Number '$1') 
                            (braced_var_sub
                              token: <Id.VSub_Number 1>
                              suffix_op: 
                                (suffix_op.Unary
                                  op_id: Id.VTest_ColonPlus
                                  arg_word: {<Id.Lit_Slash '/'>}
                                )
                            )
                          )
                        }
                      spids: [89]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:parent)
                      op: assign_op.Equal
                      rhs: {(DQ ($ Id.VSub_Number '$2'))}
                      spids: [102]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:subtrees)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: 
                              (command.Pipeline
                                children: [
                                  (C {<git>} {<ls-files>})
                                  (C {<grep>} {<'/'>})
                                  (C {<cut>} {<-d>} {<'/'>} {<-f>} {<1>})
                                  (C {<uniq>})
                                ]
                                negated: F
                              )
                          )
                        }
                      spids: [118]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:subtree_count)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: 
                              (command.Pipeline
                                children: [
                                  (C {<echo>} {(DQ ($ Id.VSub_DollarName '$subtrees'))})
                                  (C {<awk>} {<-v>} {<Id.Lit_VarLike 'c='> <0>} 
                                    {(SQ <'$1 != "" {++c} END {print c}'>)}
                                  )
                                ]
                                negated: F
                              )
                          )
                        }
                      spids: [144]
                    )
                  ]
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:entries)
                      op: assign_op.Equal
                      rhs: 
                        {
                          (command_sub
                            left_token: <Id.Left_DollarParen '$('>
                            child: 
                              (command.Pipeline
                                children: [(C {<git>} {<ls-files>}) (C {<wc>} {<-l>})]
                                negated: F
                              )
                          )
                        }
                      spids: [167]
                    )
                  ]
                )
                (C {<printf>} 
                  {
                    (DQ <'SHA '> ($ Id.VSub_DollarName '$dir') <' (%d entries, %d subtrees)'> 
                      <Id.Lit_Other '\\'> <n>
                    )
                  } {(DQ ($ Id.VSub_DollarName '$entries'))} {(DQ ($ Id.VSub_DollarName '$subtree_count'))}
                )
                (command.ForEach
                  iter_name: subtree
                  iter_words: [{($ Id.VSub_DollarName '$subtrees')}]
                  do_arg_iter: F
                  body: 
                    (command.DoGroup
                      children: [
                        (C {<cd>} {(DQ ($ Id.VSub_DollarName '$subtree'))})
                        (command.AndOr
                          ops: [Id.Op_DPipe]
                          children: [
                            (C {<generate_expected_cache_tree_rec>} 
                              {(DQ ($ Id.VSub_DollarName '$dir') ($ Id.VSub_DollarName '$subtree'))} {(DQ ($ Id.VSub_DollarName '$dir'))}
                            )
                            (command.ControlFlow
                              token: <Id.ControlFlow_Return return>
                              arg_word: {<1>}
                            )
                          ]
                        )
                        (C {<cd>} {<..>})
                      ]
                    )
                )
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:dir)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_DollarName '$parent')}
                      spids: [249]
                    )
                  ]
                )
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: generate_expected_cache_tree
      body: (BraceGroup children:[(command.Subshell child:(C {<generate_expected_cache_tree_rec>}))])
    )
    (command.ShFunction
      name: test_cache_tree
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (command.Simple
                  words: [{<generate_expected_cache_tree>}]
                  redirects: [(redir op:<Id.Redir_Great '>'> loc:(redir_loc.Fd fd:1) arg:{<expect>})]
                  do_fork: T
                )
                (C {<cmp_cache_tree>} {<expect>})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: test_invalid_cache_tree
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.Simple
                  words: [
                    {<printf>}
                    {(DQ <'invalid                                  %s ()'> <Id.Lit_Other '\\'> <n>)}
                    {(DQ )}
                    {(DQ ($ Id.VSub_At '$@'))}
                  ]
                  redirects: [(redir op:<Id.Redir_Great '>'> loc:(redir_loc.Fd fd:1) arg:{<expect>})]
                  do_fork: T
                )
                (command.Pipeline
                  children: [
                    (C {<test-dump-cache-tree>})
                    (command.Simple
                      words: [
                        {<sed>}
                        {<-n>}
                        {<-e>}
                        {(DQ <'s/[0-9]* subtrees//'>)}
                        {<-e>}
                        {(SQ <'/#(ref)/d'>)}
                        {<-e>}
                        {(SQ <'/^invalid /p'>)}
                      ]
                      redirects: [
                        (redir
                          op: <Id.Redir_Great '>'>
                          loc: (redir_loc.Fd fd:1)
                          arg: {<actual>}
                        )
                      ]
                      do_fork: T
                    )
                  ]
                  negated: F
                )
                (C {<test_cmp>} {<expect>} {<actual>})
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: test_no_cache_tree
      body: 
        (BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (command.Simple
                  words: [{<Id.Lit_Colon ':'>}]
                  redirects: [(redir op:<Id.Redir_Great '>'> loc:(redir_loc.Fd fd:1) arg:{<expect>})]
                  do_fork: T
                )
                (C {<cmp_cache_tree>} {<expect>})
              ]
            )
          ]
        )
    )
    (C {<test_expect_success>} {(SQ <'initial commit has cache-tree'>)} 
      {(SQ <'\n'> <'\ttest_commit foo &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {(SQ <'read-tree HEAD establishes cache-tree'>)} 
      {(SQ <'\n'> <'\tgit read-tree HEAD &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {(SQ <'git-add invalidates cache-tree'>)} 
      {
        (SQ <'\n'> <'\ttest_when_finished "git reset --hard; git read-tree HEAD" &&\n'> 
          <'\techo "I changed this file" >foo &&\n'> <'\tgit add foo &&\n'> <'\ttest_invalid_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'git-add in subdir invalidates cache-tree'>)} 
      {
        (SQ <'\n'> <'\ttest_when_finished "git reset --hard; git read-tree HEAD" &&\n'> 
          <'\tmkdir dirx &&\n'> <'\techo "I changed this file" >dirx/foo &&\n'> <'\tgit add dirx/foo &&\n'> 
          <'\ttest_invalid_cache_tree\n'>
        )
      }
    )
    (command.Simple
      words: [{<cat>}]
      redirects: [
        (redir op:<Id.Redir_Great '>'> loc:(redir_loc.Fd fd:1) arg:{<before>})
        (redir
          op: <Id.Redir_DLess '<<'>
          loc: (redir_loc.Fd fd:0)
          arg: 
            (redir_param.MultiLine
              here_begin: {(word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\E'>) <OF>}
              here_end_span_id: 460
              stdin_parts: [
                <'SHA  (3 entries, 2 subtrees)\n'>
                <'SHA dir1/ (1 entries, 0 subtrees)\n'>
                <'SHA dir2/ (1 entries, 0 subtrees)\n'>
              ]
            )
        )
      ]
      do_fork: T
    )
    (command.Simple
      words: [{<cat>}]
      redirects: [
        (redir op:<Id.Redir_Great '>'> loc:(redir_loc.Fd fd:1) arg:{<expect>})
        (redir
          op: <Id.Redir_DLess '<<'>
          loc: (redir_loc.Fd fd:0)
          arg: 
            (redir_param.MultiLine
              here_begin: {(word_part.EscapedLiteral token:<Id.Lit_EscapedChar '\\E'>) <OF>}
              here_end_span_id: 474
              stdin_parts: [
                <'invalid                                   (2 subtrees)\n'>
                <'invalid                                  dir1/ (0 subtrees)\n'>
                <'SHA dir2/ (1 entries, 0 subtrees)\n'>
              ]
            )
        )
      ]
      do_fork: T
    )
    (C {<test_expect_success>} {(SQ <'git-add in subdir does not invalidate sibling cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit tag no-children &&\n'> 
          <'\ttest_when_finished "git reset --hard no-children; git read-tree HEAD" &&\n'> <'\tmkdir dir1 dir2 &&\n'> <'\ttest_commit dir1/a &&\n'> <'\ttest_commit dir2/b &&\n'> 
          <'\techo "I changed this file" >dir1/a &&\n'> <'\tcmp_cache_tree before &&\n'> <'\techo "I changed this file" >dir1/a &&\n'> 
          <'\tgit add dir1/a &&\n'> <'\tcmp_cache_tree expect\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'update-index invalidates cache-tree'>)} 
      {
        (SQ <'\n'> <'\ttest_when_finished "git reset --hard; git read-tree HEAD" &&\n'> 
          <'\techo "I changed this file" >foo &&\n'> <'\tgit update-index --add foo &&\n'> <'\ttest_invalid_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'write-tree establishes cache-tree'>)} 
      {(SQ <'\n'> <'\ttest-scrap-cache-tree &&\n'> <'\tgit write-tree &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {(SQ <'test-scrap-cache-tree works'>)} 
      {
        (SQ <'\n'> <'\tgit read-tree HEAD &&\n'> <'\ttest-scrap-cache-tree &&\n'> 
          <'\ttest_no_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'second commit has cache-tree'>)} 
      {(SQ <'\n'> <'\ttest_commit bar &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {<PERL>} 
      {(SQ <'commit --interactive gives cache-tree on partial commit'>)} 
      {
        (SQ <'\n'> <'\tcat <<-\\EOT >foo.c &&\n'> <'\tint foo()\n'> <'\t{\n'> <'\t\treturn 42;\n'> 
          <'\t}\n'> <'\tint bar()\n'> <'\t{\n'> <'\t\treturn 42;\n'> <'\t}\n'> <'\tEOT\n'> <'\tgit add foo.c &&\n'> 
          <'\ttest_invalid_cache_tree &&\n'> <'\tgit commit -m "add a file" &&\n'> <'\ttest_cache_tree &&\n'> <'\tcat <<-\\EOT >foo.c &&\n'> 
          <'\tint foo()\n'> <'\t{\n'> <'\t\treturn 43;\n'> <'\t}\n'> <'\tint bar()\n'> <'\t{\n'> <'\t\treturn 44;\n'> <'\t}\n'> 
          <'\tEOT\n'> <'\t(echo p; echo 1; echo; echo s; echo n; echo y; echo q) |\n'> 
          <'\tgit commit --interactive -m foo &&\n'> <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'commit in child dir has cache-tree'>)} 
      {
        (SQ <'\n'> <'\tmkdir dir &&\n'> <'\t>dir/child.t &&\n'> <'\tgit add dir/child.t &&\n'> 
          <'\tgit commit -m dir/child.t &&\n'> <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'reset --hard gives cache-tree'>)} 
      {
        (SQ <'\n'> <'\ttest-scrap-cache-tree &&\n'> <'\tgit reset --hard &&\n'> <'\ttest_cache_tree\n'>)
      }
    )
    (C {<test_expect_success>} {(SQ <'reset --hard without index gives cache-tree'>)} 
      {(SQ <'\n'> <'\trm -f .git/index &&\n'> <'\tgit reset --hard &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {(SQ <'checkout gives cache-tree'>)} 
      {(SQ <'\n'> <'\tgit tag current &&\n'> <'\tgit checkout HEAD^ &&\n'> <'\ttest_cache_tree\n'>)}
    )
    (C {<test_expect_success>} {(SQ <'checkout -b gives cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit checkout current &&\n'> <'\tgit checkout -b prev HEAD^ &&\n'> 
          <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'checkout -B gives cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit checkout current &&\n'> <'\tgit checkout -B prev HEAD^ &&\n'> 
          <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'merge --ff-only maintains cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit checkout current &&\n'> <'\tgit checkout -b changes &&\n'> 
          <'\ttest_commit llamas &&\n'> <'\ttest_commit pachyderm &&\n'> <'\ttest_cache_tree &&\n'> <'\tgit checkout current &&\n'> 
          <'\ttest_cache_tree &&\n'> <'\tgit merge --ff-only changes &&\n'> <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'merge maintains cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit checkout current &&\n'> <'\tgit checkout -b changes2 &&\n'> 
          <'\ttest_commit alpacas &&\n'> <'\ttest_cache_tree &&\n'> <'\tgit checkout current &&\n'> <'\ttest_commit struthio &&\n'> 
          <'\ttest_cache_tree &&\n'> <'\tgit merge changes2 &&\n'> <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'partial commit gives cache-tree'>)} 
      {
        (SQ <'\n'> <'\tgit checkout -b partial no-children &&\n'> <'\ttest_commit one &&\n'> 
          <'\ttest_commit two &&\n'> <'\techo "some change" >one.t &&\n'> <'\tgit add one.t &&\n'> 
          <'\techo "some other change" >two.t &&\n'> <'\tgit commit two.t -m partial &&\n'> <'\ttest_cache_tree\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'no phantom error when switching trees'>)} 
      {
        (SQ <'\n'> <'\tmkdir newdir &&\n'> <'\t>newdir/one &&\n'> <'\tgit add newdir/one &&\n'> 
          <'\tgit checkout 2>errors &&\n'> <'\t! test -s errors\n'>
        )
      }
    )
    (C {<test_expect_success>} {(SQ <'switching trees does not invalidate shared index'>)} 
      {
        (SQ <'\n'> <'\tgit update-index --split-index &&\n'> <'\t>split &&\n'> <'\tgit add split &&\n'> 
          <'\ttest-dump-split-index .git/index | grep -v ^own >before &&\n'> <'\tgit commit -m "as-is" &&\n'> <'\ttest-dump-split-index .git/index | grep -v ^own >after &&\n'> 
          <'\ttest_cmp before after\n'>
        )
      }
    )
    (C {<test_done>})
  ]
)