(command.CommandList
  children: [
    (command.ShAssignment
      pairs: [
        (assign_pair
          lhs: (sh_lhs_expr.Name name:test_description)
          op: assign_op.Equal
          rhs: {(SQ (Token id:Id.Lit_Chars val:'git p4 preserve users' span_id:6))}
          spids: [4]
        )
      ]
    )
    (C {(.)} {(./lib-git-p4.sh)})
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:'start p4d' span_id:18))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:22) 
          (Token id:Id.Lit_Chars val:'\tstart_p4d\n' span_id:23)
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:'create files' span_id:30))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:34) (Token id:Id.Lit_Chars val:'\t(\n' span_id:35) 
          (Token id:Id.Lit_Chars val:'\t\tcd "$cli" &&\n' span_id:36) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tp4 client -o | sed "/LineEnd/s/:.*/:unix/" | p4 client -i &&\n'
            span_id: 37
          ) (Token id:Id.Lit_Chars val:'\t\techo file1 >file1 &&\n' span_id:38) 
          (Token id:Id.Lit_Chars val:'\t\techo file2 >file2 &&\n' span_id:39) (Token id:Id.Lit_Chars val:'\t\tp4 add file1 file2 &&\n' span_id:40) 
          (Token id:Id.Lit_Chars val:'\t\tp4 submit -d "add files"\n' span_id:41) (Token id:Id.Lit_Chars val:'\t)\n' span_id:42)
        )
      }
    )
    (command.ShFunction
      name: p4_grant_admin
      body: 
        (command.BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:name)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$1')}
                      spids: [53]
                    )
                  ]
                )
                (command.Pipeline
                  children: [
                    (command.BraceGroup
                      children: [
                        (command.AndOr
                          ops: [Id.Op_DAmp]
                          children: [
                            (C {(p4)} {(protect)} {(-o)})
                            (C {(echo)} 
                              {
                                (DQ ('    admin user ') ($ Id.VSub_DollarName '$name') 
                                  (' * //depot/...')
                                )
                              }
                            )
                          ]
                        )
                      ]
                    )
                    (C {(p4)} {(protect)} {(-i)})
                  ]
                  negated: F
                )
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: p4_check_commit_author
      body: 
        (command.BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:file)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$1')}
                      spids: [100]
                    )
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:user)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$2')}
                      spids: [103]
                    )
                  ]
                )
                (command.Pipeline
                  children: [
                    (C {(p4)} {(changes)} {(-m)} {(1)} {(//depot/) ($ Id.VSub_DollarName '$file')})
                    (C {(grep)} {(-q)} {($ Id.VSub_DollarName '$user')})
                  ]
                  negated: F
                )
              ]
            )
          ]
        )
    )
    (command.ShFunction
      name: make_change_by_user
      body: 
        (command.BraceGroup
          children: [
            (command.AndOr
              ops: [Id.Op_DAmp Id.Op_DAmp Id.Op_DAmp]
              children: [
                (command.ShAssignment
                  pairs: [
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:file)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$1')}
                      spids: [138]
                    )
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:name)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$2')}
                      spids: [141]
                    )
                    (assign_pair
                      lhs: (sh_lhs_expr.Name name:email)
                      op: assign_op.Equal
                      rhs: {($ Id.VSub_Number '$3')}
                      spids: [144]
                    )
                  ]
                )
                (command.Simple
                  words: [{(echo)} {(DQ ('username: a change by ') ($ Id.VSub_DollarName '$name'))}]
                  redirects: [
                    (redir.Redir
                      op: (Token id:Id.Redir_DGreat val:'>>' span_id:157)
                      fd: -1
                      arg_word: {(DQ ($ Id.VSub_DollarName '$file'))}
                    )
                  ]
                )
                (C {(git)} {(add)} {(DQ ($ Id.VSub_DollarName '$file'))})
                (C {(git)} {(commit)} {(--author)} 
                  {(DQ ($ Id.VSub_DollarName '$name') (' <') ($ Id.VSub_DollarName '$email') ('>'))} {(-m)} {(DQ ('a change by ') ($ Id.VSub_DollarName '$name'))}
                )
              ]
            )
          ]
        )
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:'preserve users' span_id:205))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:209) 
          (Token id:Id.Lit_Chars val:'\tp4_add_user alice &&\n' span_id:210) (Token id:Id.Lit_Chars val:'\tp4_add_user bob &&\n' span_id:211) 
          (Token id:Id.Lit_Chars val:'\tp4_grant_admin alice &&\n' span_id:212) (Token id:Id.Lit_Chars val:'\tgit p4 clone --dest="$git" //depot &&\n' span_id:213) 
          (Token id:Id.Lit_Chars val:'\ttest_when_finished cleanup_git &&\n' span_id:214) (Token id:Id.Lit_Chars val:'\t(\n' span_id:215) 
          (Token id:Id.Lit_Chars val:'\t\tcd "$git" &&\n' span_id:216) (Token id:Id.Lit_Chars val:'\t\techo "username: a change by alice" >>file1 &&\n' span_id:217) 
          (Token
            id: Id.Lit_Chars
            val: '\t\techo "username: a change by bob" >>file2 &&\n'
            span_id: 218
          ) 
          (Token
            id: Id.Lit_Chars
            val: 
'\t\tgit commit --author "Alice <alice@example.com>" -m "a change by alice" file1 &&\n'
            span_id: 219
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit commit --author "Bob <bob@example.com>" -m "a change by bob" file2 &&\n'
            span_id: 220
          ) (Token id:Id.Lit_Chars val:'\t\tgit config git-p4.skipSubmitEditCheck true &&\n' span_id:221) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tP4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret &&\n'
            span_id: 222
          ) (Token id:Id.Lit_Chars val:'\t\texport P4EDITOR P4USER P4PASSWD &&\n' span_id:223) 
          (Token id:Id.Lit_Chars val:'\t\tgit p4 commit --preserve-user &&\n' span_id:224) (Token id:Id.Lit_Chars val:'\t\tp4_check_commit_author file1 alice &&\n' span_id:225) 
          (Token id:Id.Lit_Chars val:'\t\tp4_check_commit_author file2 bob\n' span_id:226) (Token id:Id.Lit_Chars val:'\t)\n' span_id:227)
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:'refuse to preserve users without perms' span_id:240))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:244) 
          (Token
            id: Id.Lit_Chars
            val: '\tgit p4 clone --dest="$git" //depot &&\n'
            span_id: 245
          ) (Token id:Id.Lit_Chars val:'\ttest_when_finished cleanup_git &&\n' span_id:246) 
          (Token id:Id.Lit_Chars val:'\t(\n' span_id:247) (Token id:Id.Lit_Chars val:'\t\tcd "$git" &&\n' span_id:248) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit config git-p4.skipSubmitEditCheck true &&\n'
            span_id: 249
          ) (Token id:Id.Lit_Chars val:'\t\techo "username-noperms: a change by alice" >>file1 &&\n' span_id:250) 
          (Token
            id: Id.Lit_Chars
            val: 
'\t\tgit commit --author "Alice <alice@example.com>" -m "perms: a change by alice" file1 &&\n'
            span_id: 251
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tP4EDITOR="test-chmtime +5" P4USER=bob P4PASSWD=secret &&\n'
            span_id: 252
          ) (Token id:Id.Lit_Chars val:'\t\texport P4EDITOR P4USER P4PASSWD &&\n' span_id:253) 
          (Token
            id: Id.Lit_Chars
            val: '\t\ttest_must_fail git p4 commit --preserve-user &&\n'
            span_id: 254
          ) (Token id:Id.Lit_Chars val:'\t\t! git diff --exit-code HEAD..p4/master\n' span_id:255) 
          (Token id:Id.Lit_Chars val:'\t)\n' span_id:256)
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:'preserve user where author is unknown to p4' span_id:266))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:270) 
          (Token
            id: Id.Lit_Chars
            val: '\tgit p4 clone --dest="$git" //depot &&\n'
            span_id: 271
          ) (Token id:Id.Lit_Chars val:'\ttest_when_finished cleanup_git &&\n' span_id:272) 
          (Token id:Id.Lit_Chars val:'\t(\n' span_id:273) (Token id:Id.Lit_Chars val:'\t\tcd "$git" &&\n' span_id:274) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit config git-p4.skipSubmitEditCheck true &&\n'
            span_id: 275
          ) (Token id:Id.Lit_Chars val:'\t\techo "username-bob: a change by bob" >>file1 &&\n' span_id:276) 
          (Token
            id: Id.Lit_Chars
            val: 
'\t\tgit commit --author "Bob <bob@example.com>" -m "preserve: a change by bob" file1 &&\n'
            span_id: 277
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\t\techo "username-unknown: a change by charlie" >>file1 &&\n'
            span_id: 278
          ) 
          (Token
            id: Id.Lit_Chars
            val: 
'\t\tgit commit --author "Charlie <charlie@example.com>" -m "preserve: a change by charlie" file1 &&\n'
            span_id: 279
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tP4EDITOR="test-chmtime +5" P4USER=alice P4PASSWD=secret &&\n'
            span_id: 280
          ) (Token id:Id.Lit_Chars val:'\t\texport P4EDITOR P4USER P4PASSWD &&\n' span_id:281) 
          (Token
            id: Id.Lit_Chars
            val: '\t\ttest_must_fail git p4 commit --preserve-user &&\n'
            span_id: 282
          ) (Token id:Id.Lit_Chars val:'\t\t! git diff --exit-code HEAD..p4/master &&\n' span_id:283) 
          (Token id:Id.Lit_Chars val:'\n' span_id:284) (Token id:Id.Lit_Chars val:'\t\techo "$0: repeat with allowMissingP4Users enabled" &&\n' span_id:285) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit config git-p4.allowMissingP4Users true &&\n'
            span_id: 286
          ) (Token id:Id.Lit_Chars val:'\t\tgit config git-p4.preserveUser true &&\n' span_id:287) 
          (Token id:Id.Lit_Chars val:'\t\tgit p4 commit &&\n' span_id:288) (Token id:Id.Lit_Chars val:'\t\tgit diff --exit-code HEAD..p4/master &&\n' span_id:289) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tp4_check_commit_author file1 alice\n'
            span_id: 290
          ) (Token id:Id.Lit_Chars val:'\t)\n' span_id:291)
        )
      }
    )
    (C {(test_expect_success)} 
      {(SQ (Token id:Id.Lit_Chars val:'not preserving user with mixed authorship' span_id:310))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:314) 
          (Token
            id: Id.Lit_Chars
            val: '\tgit p4 clone --dest="$git" //depot &&\n'
            span_id: 315
          ) (Token id:Id.Lit_Chars val:'\ttest_when_finished cleanup_git &&\n' span_id:316) 
          (Token id:Id.Lit_Chars val:'\t(\n' span_id:317) (Token id:Id.Lit_Chars val:'\t\tcd "$git" &&\n' span_id:318) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit config git-p4.skipSubmitEditCheck true &&\n'
            span_id: 319
          ) (Token id:Id.Lit_Chars val:'\t\tp4_add_user derek &&\n' span_id:320) 
          (Token id:Id.Lit_Chars val:'\n' span_id:321) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tmake_change_by_user usernamefile3 Derek derek@example.com &&\n'
            span_id: 322
          ) (Token id:Id.Lit_Chars val:'\t\tP4EDITOR=cat P4USER=alice P4PASSWD=secret &&\n' span_id:323) 
          (Token
            id: Id.Lit_Chars
            val: '\t\texport P4EDITOR P4USER P4PASSWD &&\n'
            span_id: 324
          ) (Token id:Id.Lit_Chars val:'\t\tgit p4 commit |\\\n' span_id:325) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgrep "git author derek@example.com does not match" &&\n'
            span_id: 326
          ) (Token id:Id.Lit_Chars val:'\n' span_id:327) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tmake_change_by_user usernamefile3 Charlie charlie@example.com &&\n'
            span_id: 328
          ) (Token id:Id.Lit_Chars val:'\t\tgit p4 commit |\\\n' span_id:329) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgrep "git author charlie@example.com does not match" &&\n'
            span_id: 330
          ) (Token id:Id.Lit_Chars val:'\n' span_id:331) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tmake_change_by_user usernamefile3 alice alice@example.com &&\n'
            span_id: 332
          ) (Token id:Id.Lit_Chars val:'\t\tgit p4 commit |\\\n' span_id:333) 
          (Token
            id: Id.Lit_Chars
            val: '\t\ttest_must_fail grep "git author.*does not match" &&\n'
            span_id: 334
          ) (Token id:Id.Lit_Chars val:'\n' span_id:335) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tgit config git-p4.skipUserNameCheck true &&\n'
            span_id: 336
          ) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tmake_change_by_user usernamefile3 Charlie charlie@example.com &&\n'
            span_id: 337
          ) (Token id:Id.Lit_Chars val:'\t\tgit p4 commit |\\\n' span_id:338) 
          (Token
            id: Id.Lit_Chars
            val: '\t\ttest_must_fail grep "git author.*does not match" &&\n'
            span_id: 339
          ) (Token id:Id.Lit_Chars val:'\n' span_id:340) 
          (Token
            id: Id.Lit_Chars
            val: '\t\tp4_check_commit_author usernamefile3 alice\n'
            span_id: 341
          ) (Token id:Id.Lit_Chars val:'\t)\n' span_id:342)
        )
      }
    )
    (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:'kill p4d' span_id:349))} 
      {
        (SQ (Token id:Id.Lit_Chars val:'\n' span_id:353) 
          (Token id:Id.Lit_Chars val:'\tkill_p4d\n' span_id:354)
        )
      }
    )
    (C {(test_done)})
  ]
)