(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:'diff function context' span_id:6))} spids: [4] ) ] ) (C {(.)} {(./test-lib.sh)}) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:dir) op: assign_op.Equal rhs: {(DQ ($ Id.VSub_DollarName '$TEST_DIRECTORY') (/t4051))} spids: [15] ) ] ) (command.ShFunction name: commit_and_tag body: (command.BraceGroup children: [ (command.AndOr ops: [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:tag) op: assign_op.Equal rhs: {($ Id.VSub_Number '$1')} spids: [30] ) ] ) (C {(shift)}) (C {(git)} {(add)} {(DQ ($ Id.VSub_At '$@'))}) (C {(test_tick)}) (C {(git)} {(commit)} {(-m)} {(DQ ($ Id.VSub_DollarName '$tag'))}) (C {(git)} {(tag)} {(DQ ($ Id.VSub_DollarName '$tag'))}) ] ) ] ) ) (command.ShFunction name: first_context_line body: (command.BraceGroup children: [ (C {(awk)} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:92) (Token id: Id.Lit_Chars val: '\t\tfound {print; exit}\n' span_id: 93 ) (Token id:Id.Lit_Chars val:'\t\t/^@@/ {found = 1}\n' span_id:94) (Token id:Id.Lit_Chars val:'\t' span_id:95) ) } ) ] ) ) (command.ShFunction name: last_context_line body: (command.BraceGroup children: [ (C {(sed)} {(-ne)} {(word_part.EscapedLiteral token:(Token id:Id.Lit_EscapedChar val:'\\$' span_id:113)) (p) } ) ] ) ) (command.ShFunction name: check_diff body: (command.BraceGroup children: [ (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:name) op: assign_op.Equal rhs: {($ Id.VSub_Number '$1')} spids: [127] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:desc) op: assign_op.Equal rhs: {($ Id.VSub_Number '$2')} spids: [131] ) ] ) (command.ShAssignment pairs: [ (assign_pair lhs: (sh_lhs_expr.Name name:options) op: assign_op.Equal rhs: {(DQ ('-W ') ($ Id.VSub_Number '$3'))} spids: [135] ) ] ) (C {(test_expect_success)} {(DQ ($ Id.VSub_DollarName '$desc'))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:150) (Token id: Id.Lit_Chars val: '\t\tgit diff $options "$name^" "$name" >"$name.diff"\n' span_id: 151 ) (Token id:Id.Lit_Chars val:'\t' span_id:152) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' diff applies' span_id:160))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:164) (Token id: Id.Lit_Chars val: '\t\ttest_when_finished "git reset --hard" &&\n' span_id: 165 ) (Token id:Id.Lit_Chars val:'\t\tgit checkout --detach "$name^" &&\n' span_id:166) (Token id: Id.Lit_Chars val: '\t\tgit apply --index "$name.diff" &&\n' span_id: 167 ) (Token id:Id.Lit_Chars val:'\t\tgit diff --exit-code "$name"\n' span_id:168) (Token id:Id.Lit_Chars val:'\t' span_id:169) ) } ) ] ) ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:setup span_id:178))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:182) (Token id: Id.Lit_Chars val: '\tcat "$dir/includes.c" "$dir/dummy.c" "$dir/dummy.c" "$dir/hello.c" \\\n' span_id: 183 ) (Token id:Id.Lit_Chars val:'\t\t"$dir/dummy.c" "$dir/dummy.c" >file.c &&\n' span_id:184) (Token id:Id.Lit_Chars val:'\tcommit_and_tag initial file.c &&\n' span_id:185) (Token id:Id.Lit_Chars val:'\n' span_id:186) (Token id: Id.Lit_Chars val: '\tgrep -v "delete me from hello" <file.c >file.c.new &&\n' span_id: 187 ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:188) (Token id: Id.Lit_Chars val: '\tcommit_and_tag changed_hello file.c &&\n' span_id: 189 ) (Token id:Id.Lit_Chars val:'\n' span_id:190) (Token id: Id.Lit_Chars val: '\tgrep -v "delete me from includes" <file.c >file.c.new &&\n' span_id: 191 ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:192) (Token id: Id.Lit_Chars val: '\tcommit_and_tag changed_includes file.c &&\n' span_id: 193 ) (Token id:Id.Lit_Chars val:'\n' span_id:194) (Token id:Id.Lit_Chars val:'\tcat "$dir/appended1.c" >>file.c &&\n' span_id:195) (Token id:Id.Lit_Chars val:'\tcommit_and_tag appended file.c &&\n' span_id:196) (Token id:Id.Lit_Chars val:'\n' span_id:197) (Token id:Id.Lit_Chars val:'\tcat "$dir/appended2.c" >>file.c &&\n' span_id:198) (Token id:Id.Lit_Chars val:'\tcommit_and_tag extended file.c &&\n' span_id:199) (Token id:Id.Lit_Chars val:'\n' span_id:200) (Token id: Id.Lit_Chars val: '\tgrep -v "Begin of second part" <file.c >file.c.new &&\n' span_id: 201 ) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:202) (Token id: Id.Lit_Chars val: '\tcommit_and_tag long_common_tail file.c &&\n' span_id: 203 ) (Token id:Id.Lit_Chars val:'\n' span_id:204) (Token id:Id.Lit_Chars val:'\tgit checkout initial &&\n' span_id:205) (Token id:Id.Lit_Chars val:'\tcat "$dir/hello.c" "$dir/dummy.c" >file.c &&\n' span_id:206) (Token id: Id.Lit_Chars val: '\tcommit_and_tag hello_dummy file.c &&\n' span_id: 207 ) (Token id:Id.Lit_Chars val:'\n' span_id:208) (Token id: Id.Lit_Chars val: '\t# overlap function context of 1st change and -u context of 2nd change\n' span_id: 209 ) (Token id: Id.Lit_Chars val: '\tgrep -v "delete me from hello" <"$dir/hello.c" >file.c &&\n' span_id: 210 ) (Token id:Id.Lit_Chars val:'\tsed 2p <"$dir/dummy.c" >>file.c &&\n' span_id:211) (Token id: Id.Lit_Chars val: '\tcommit_and_tag changed_hello_dummy file.c &&\n' span_id: 212 ) (Token id:Id.Lit_Chars val:'\n' span_id:213) (Token id:Id.Lit_Chars val:'\tgit checkout initial &&\n' span_id:214) (Token id:Id.Lit_Chars val:'\tgrep -v "delete me from hello" <file.c >file.c.new &&\n' span_id:215) (Token id:Id.Lit_Chars val:'\tmv file.c.new file.c &&\n' span_id:216) (Token id:Id.Lit_Chars val:'\tcat "$dir/appended1.c" >>file.c &&\n' span_id:217) (Token id: Id.Lit_Chars val: '\tcommit_and_tag changed_hello_appended file.c\n' span_id: 218 ) ) } ) (C {(check_diff)} {(changed_hello)} {(SQ (Token id:Id.Lit_Chars val:'changed function' span_id:227))}) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:234))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:238) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin of hello" changed_hello.diff\n' span_id: 239 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:246))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:250) (Token id: Id.Lit_Chars val: '\tgrep "^ .*End of hello" changed_hello.diff\n' span_id: 251 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:258))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:262) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" changed_hello.diff) -le 1\n' span_id: 263 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:270))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:274) (Token id: Id.Lit_Chars val: '\ttest "$(first_context_line <changed_hello.diff)" != " "\n' span_id: 275 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include trailing empty lines' span_id:282))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:286) (Token id: Id.Lit_Chars val: '\ttest "$(last_context_line <changed_hello.diff)" != " "\n' span_id: 287 ) ) } ) (C {(check_diff)} {(changed_includes)} {(SQ (Token id:Id.Lit_Chars val:'changed includes' span_id:296))} ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:303))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:307) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin.h" changed_includes.diff\n' span_id: 308 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:315))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:319) (Token id: Id.Lit_Chars val: '\tgrep "^ .*End.h" changed_includes.diff\n' span_id: 320 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:327))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:331) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" changed_includes.diff) -le 1\n' span_id: 332 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include trailing empty lines' span_id:339))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:343) (Token id: Id.Lit_Chars val: '\ttest "$(last_context_line <changed_includes.diff)" != " "\n' span_id: 344 ) ) } ) (C {(check_diff)} {(appended)} {(SQ (Token id:Id.Lit_Chars val:'appended function' span_id:353))}) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:360))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:364) (Token id: Id.Lit_Chars val: '\tgrep "^[+].*Begin of first part" appended.diff\n' span_id: 365 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:372))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:376) (Token id: Id.Lit_Chars val: '\tgrep "^[+].*End of first part" appended.diff\n' span_id: 377 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:384))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:388) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" appended.diff) -le 1\n' span_id: 389 ) ) } ) (C {(check_diff)} {(extended)} {(SQ (Token id:Id.Lit_Chars val:'appended function part' span_id:398))} ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:405))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:409) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin of first part" extended.diff\n' span_id: 410 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:417))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:421) (Token id: Id.Lit_Chars val: '\tgrep "^[+].*End of second part" extended.diff\n' span_id: 422 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:429))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:433) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" extended.diff) -le 2\n' span_id: 434 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:441))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:445) (Token id: Id.Lit_Chars val: '\ttest "$(first_context_line <extended.diff)" != " "\n' span_id: 446 ) ) } ) (C {(check_diff)} {(long_common_tail)} {(SQ (Token id:Id.Lit_Chars val:'change with long common tail and no context' span_id:455))} {(-U0)} ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:464))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:468) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin of first part" long_common_tail.diff\n' span_id: 469 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:476))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:480) (Token id: Id.Lit_Chars val: '\tgrep "^ .*End of second part" long_common_tail.diff\n' span_id: 481 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:488))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:492) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" long_common_tail.diff) -le 2\n' span_id: 493 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include preceding empty lines' span_id:500))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:504) (Token id: Id.Lit_Chars val: '\ttest "$(first_context_line <long_common_tail.diff.diff)" != " "\n' span_id: 505 ) ) } ) (C {(check_diff)} {(changed_hello_appended)} {(SQ (Token id:Id.Lit_Chars val:'changed function plus appended function' span_id:514))} ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:521))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:525) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin of hello" changed_hello_appended.diff &&\n' span_id: 526 ) (Token id: Id.Lit_Chars val: '\tgrep "^[+].*Begin of first part" changed_hello_appended.diff\n' span_id: 527 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:534))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:538) (Token id: Id.Lit_Chars val: '\tgrep "^ .*End of hello" changed_hello_appended.diff &&\n' span_id: 539 ) (Token id: Id.Lit_Chars val: '\tgrep "^[+].*End of first part" changed_hello_appended.diff\n' span_id: 540 ) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context does not include other functions' span_id:547))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:551) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^[ +-].*Begin" changed_hello_appended.diff) -le 2\n' span_id: 552 ) ) } ) (C {(check_diff)} {(changed_hello_dummy)} {(SQ (Token id:Id.Lit_Chars val:'changed two consecutive functions' span_id:561))} ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes begin' span_id:568))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:572) (Token id: Id.Lit_Chars val: '\tgrep "^ .*Begin of hello" changed_hello_dummy.diff &&\n' span_id: 573 ) (Token id:Id.Lit_Chars val:'\tgrep "^ .*Begin of dummy" changed_hello_dummy.diff\n' span_id:574) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' context includes end' span_id:581))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:585) (Token id: Id.Lit_Chars val: '\tgrep "^ .*End of hello" changed_hello_dummy.diff &&\n' span_id: 586 ) (Token id:Id.Lit_Chars val:'\tgrep "^ .*End of dummy" changed_hello_dummy.diff\n' span_id:587) ) } ) (C {(test_expect_success)} {(SQ (Token id:Id.Lit_Chars val:' overlapping hunks are merged' span_id:594))} { (SQ (Token id:Id.Lit_Chars val:'\n' span_id:598) (Token id: Id.Lit_Chars val: '\ttest $(grep -c "^@@" changed_hello_dummy.diff) -eq 1\n' span_id: 599 ) ) } ) (C {(test_done)}) ] )