(CommandList
  children: [
    (Assignment
      keyword: Assign_None
      pairs: [
        (assign_pair
          lhs: (LhsName name:test_description)
          op: Equal
          rhs: {(SQ <'diff function context'>)}
          spids: [4]
        )
      ]
      spids: [4]
    )
    (C {(.)} {(./test-lib.sh)})
    (Assignment
      keyword: Assign_None
      pairs: [
        (assign_pair
          lhs: (LhsName name:dir)
          op: Equal
          rhs: {(DQ ($ VSub_Name '$TEST_DIRECTORY') (/t4051))}
          spids: [15]
        )
      ]
      spids: [15]
    )
    (FuncDef
      name: commit_and_tag
      body: 
        (BraceGroup
          children: [
            (AndOr
              children: [
                (Assignment
                  keyword: Assign_None
                  pairs: [
                    (assign_pair
                      lhs: (LhsName name:tag)
                      op: Equal
                      rhs: {($ VSub_Number '$1')}
                      spids: [30]
                    )
                  ]
                  spids: [30]
                )
                (AndOr
                  children: [
                    (C {(shift)})
                    (AndOr
                      children: [
                        (C {(git)} {(add)} {(DQ ($ VSub_At '$@'))})
                        (AndOr
                          children: [
                            (C {(test_tick)})
                            (AndOr
                              children: [
                                (C {(git)} {(commit)} {(-m)} {(DQ ($ VSub_Name '$tag'))})
                                (C {(git)} {(tag)} {(DQ ($ VSub_Name '$tag'))})
                              ]
                              op_id: Op_DAmp
                            )
                          ]
                          op_id: Op_DAmp
                        )
                      ]
                      op_id: Op_DAmp
                    )
                  ]
                  op_id: Op_DAmp
                )
              ]
              op_id: Op_DAmp
            )
          ]
          spids: [27]
        )
      spids: [22 26]
    )
    (FuncDef
      name: first_context_line
      body: 
        (BraceGroup
          children: [
            (C {(awk)} {(SQ <'\n'> <'\t\tfound {print; exit}\n'> <'\t\t/^@@/ {found = 1}\n'> <'\t'>)})
          ]
          spids: [86]
        )
      spids: [81 85]
    )
    (FuncDef
      name: last_context_line
      body: 
        (BraceGroup
          children: [(C {(sed)} {(-ne)} {(EscapedLiteralPart token:<Lit_EscapedChar '\\$'>) (p)})]
          spids: [106]
        )
      spids: [101 105]
    )
    (FuncDef
      name: check_diff
      body: 
        (BraceGroup
          children: [
            (Assignment
              keyword: Assign_None
              pairs: [
                (assign_pair
                  lhs: (LhsName name:name)
                  op: Equal
                  rhs: {($ VSub_Number '$1')}
                  spids: [127]
                )
              ]
              spids: [127]
            )
            (Assignment
              keyword: Assign_None
              pairs: [
                (assign_pair
                  lhs: (LhsName name:desc)
                  op: Equal
                  rhs: {($ VSub_Number '$2')}
                  spids: [131]
                )
              ]
              spids: [131]
            )
            (Assignment
              keyword: Assign_None
              pairs: [
                (assign_pair
                  lhs: (LhsName name:options)
                  op: Equal
                  rhs: {(DQ ('-W ') ($ VSub_Number '$3'))}
                  spids: [135]
                )
              ]
              spids: [135]
            )
            (C {(test_expect_success)} {(DQ ($ VSub_Name '$desc'))} 
              {(SQ <'\n'> <'\t\tgit diff $options "$name^" "$name" >"$name.diff"\n'> <'\t'>)}
            )
            (C {(test_expect_success)} {(SQ <' diff applies'>)} 
              {
                (SQ <'\n'> <'\t\ttest_when_finished "git reset --hard" &&\n'> 
                  <'\t\tgit checkout --detach "$name^" &&\n'> <'\t\tgit apply --index "$name.diff" &&\n'> <'\t\tgit diff --exit-code "$name"\n'> <'\t'>
                )
              }
            )
          ]
          spids: [124]
        )
      spids: [119 123]
    )
    (C {(test_expect_success)} {(SQ <setup>)} 
      {
        (SQ <'\n'> <'\tcat "$dir/includes.c" "$dir/dummy.c" "$dir/dummy.c" "$dir/hello.c" \\\n'> 
          <'\t\t"$dir/dummy.c" "$dir/dummy.c" >file.c &&\n'> <'\tcommit_and_tag initial file.c &&\n'> <'\n'> 
          <'\tgrep -v "delete me from hello" <file.c >file.c.new &&\n'> <'\tmv file.c.new file.c &&\n'> <'\tcommit_and_tag changed_hello file.c &&\n'> <'\n'> 
          <'\tgrep -v "delete me from includes" <file.c >file.c.new &&\n'> <'\tmv file.c.new file.c &&\n'> <'\tcommit_and_tag changed_includes file.c &&\n'> <'\n'> 
          <'\tcat "$dir/appended1.c" >>file.c &&\n'> <'\tcommit_and_tag appended file.c &&\n'> <'\n'> <'\tcat "$dir/appended2.c" >>file.c &&\n'> 
          <'\tcommit_and_tag extended file.c &&\n'> <'\n'> <'\tgrep -v "Begin of second part" <file.c >file.c.new &&\n'> <'\tmv file.c.new file.c &&\n'> 
          <'\tcommit_and_tag long_common_tail file.c &&\n'> <'\n'> <'\tgit checkout initial &&\n'> <'\tcat "$dir/hello.c" "$dir/dummy.c" >file.c &&\n'> 
          <'\tcommit_and_tag hello_dummy file.c &&\n'> <'\n'> <'\t# overlap function context of 1st change and -u context of 2nd change\n'> 
          <'\tgrep -v "delete me from hello" <"$dir/hello.c" >file.c &&\n'> <'\tsed 2p <"$dir/dummy.c" >>file.c &&\n'> <'\tcommit_and_tag changed_hello_dummy file.c &&\n'> <'\n'> 
          <'\tgit checkout initial &&\n'> <'\tgrep -v "delete me from hello" <file.c >file.c.new &&\n'> <'\tmv file.c.new file.c &&\n'> 
          <'\tcat "$dir/appended1.c" >>file.c &&\n'> <'\tcommit_and_tag changed_hello_appended file.c\n'>
        )
      }
    )
    (C {(check_diff)} {(changed_hello)} {(SQ <'changed function'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*Begin of hello" changed_hello.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*End of hello" changed_hello.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" changed_hello.diff) -le 1\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include preceding empty lines'>)} 
      {(SQ <'\n'> <'\ttest "$(first_context_line <changed_hello.diff)" != " "\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include trailing empty lines'>)} 
      {(SQ <'\n'> <'\ttest "$(last_context_line <changed_hello.diff)" != " "\n'>)}
    )
    (C {(check_diff)} {(changed_includes)} {(SQ <'changed includes'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*Begin.h" changed_includes.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*End.h" changed_includes.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" changed_includes.diff) -le 1\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include trailing empty lines'>)} 
      {(SQ <'\n'> <'\ttest "$(last_context_line <changed_includes.diff)" != " "\n'>)}
    )
    (C {(check_diff)} {(appended)} {(SQ <'appended function'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {(SQ <'\n'> <'\tgrep "^[+].*Begin of first part" appended.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {(SQ <'\n'> <'\tgrep "^[+].*End of first part" appended.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" appended.diff) -le 1\n'>)}
    )
    (C {(check_diff)} {(extended)} {(SQ <'appended function part'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*Begin of first part" extended.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {(SQ <'\n'> <'\tgrep "^[+].*End of second part" extended.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" extended.diff) -le 2\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include preceding empty lines'>)} 
      {(SQ <'\n'> <'\ttest "$(first_context_line <extended.diff)" != " "\n'>)}
    )
    (C {(check_diff)} {(long_common_tail)} {(SQ <'change with long common tail and no context'>)} {(-U0)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*Begin of first part" long_common_tail.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {(SQ <'\n'> <'\tgrep "^ .*End of second part" long_common_tail.diff\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" long_common_tail.diff) -le 2\n'>)}
    )
    (C {(test_expect_success)} {(SQ <' context does not include preceding empty lines'>)} 
      {(SQ <'\n'> <'\ttest "$(first_context_line <long_common_tail.diff.diff)" != " "\n'>)}
    )
    (C {(check_diff)} {(changed_hello_appended)} {(SQ <'changed function plus appended function'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {
        (SQ <'\n'> <'\tgrep "^ .*Begin of hello" changed_hello_appended.diff &&\n'> 
          <'\tgrep "^[+].*Begin of first part" changed_hello_appended.diff\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {
        (SQ <'\n'> <'\tgrep "^ .*End of hello" changed_hello_appended.diff &&\n'> 
          <'\tgrep "^[+].*End of first part" changed_hello_appended.diff\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <' context does not include other functions'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^[ +-].*Begin" changed_hello_appended.diff) -le 2\n'>)}
    )
    (C {(check_diff)} {(changed_hello_dummy)} {(SQ <'changed two consecutive functions'>)})
    (C {(test_expect_success)} {(SQ <' context includes begin'>)} 
      {
        (SQ <'\n'> <'\tgrep "^ .*Begin of hello" changed_hello_dummy.diff &&\n'> 
          <'\tgrep "^ .*Begin of dummy" changed_hello_dummy.diff\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <' context includes end'>)} 
      {
        (SQ <'\n'> <'\tgrep "^ .*End of hello" changed_hello_dummy.diff &&\n'> 
          <'\tgrep "^ .*End of dummy" changed_hello_dummy.diff\n'>
        )
      }
    )
    (C {(test_expect_success)} {(SQ <' overlapping hunks are merged'>)} 
      {(SQ <'\n'> <'\ttest $(grep -c "^@@" changed_hello_dummy.diff) -eq 1\n'>)}
    )
    (C {(test_done)})
  ]
)