| #!/bin/sh |
| |
| test_description='diff.<driver>.process: oid-only hunk requests' |
| |
| TEST_PASSES_SANITIZE_LEAK=true |
| . ./test-lib.sh |
| |
| # See t/helper/test-diff-process-backend.c for the process implementation |
| # and available --mode= options. |
| |
| BACKEND="test-tool diff-process-backend" |
| |
| test_expect_success 'setup' ' |
| echo "*.c diff=cdiff" >.gitattributes && |
| git add .gitattributes && |
| |
| # 10 lines, changes at 5-6 and 9-10 between the two commits. |
| cat >pair.c <<-\EOF && |
| line1 |
| line2 |
| line3 |
| line4 |
| original5 |
| original6 |
| line7 |
| line8 |
| line9 |
| line10 |
| EOF |
| git add pair.c && |
| git commit -m "add pair.c" && |
| |
| cat >pair.c <<-\EOF && |
| line1 |
| line2 |
| line3 |
| line4 |
| changed5 |
| changed6 |
| line7 |
| line8 |
| changed9 |
| changed10 |
| EOF |
| git add pair.c && |
| git commit -m "change pair.c" |
| ' |
| |
| test_expect_success 'an oid-capable process answers blame by object names alone' ' |
| test_when_finished "rm -f backend.log" && |
| ORIG=$(git rev-parse --short HEAD~1) && |
| CHANGE=$(git rev-parse --short HEAD) && |
| # The process reports only lines 5-6 as changed, so blame attributes |
| # lines 9-10 to the original commit even though the builtin diff |
| # would show them as changed. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| blame pair.c >actual && |
| sed -n "9p" actual >line9 && |
| sed -n "10p" actual >line10 && |
| test_grep "$ORIG" line9 && |
| test_grep "$ORIG" line10 && |
| sed -n "5p" actual >line5 && |
| test_grep "$CHANGE" line5 && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'an oid-capable process answers --numstat by object names alone' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --format= --numstat -- pair.c >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'need-content falls through to the builtin diff' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-need-content --log=backend.log" \ |
| log -1 --format= --numstat -- pair.c >actual && |
| printf "4\t4\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'a warmed hunk store does not override process hunks' ' |
| test_when_finished "git diff-hunks clear" && |
| ORIG=$(git rev-parse --short HEAD~1) && |
| GIT_DIFF_HUNKS_WRITE=1 git log -2 --stat -- pair.c >/dev/null && |
| |
| # Control: without a process, blame is served from the store. |
| git blame --show-stats pair.c >stats && |
| test_grep "num precomputed hits: 1" stats && |
| |
| # The store holds the builtin hunks, but a process-capable driver |
| # makes the process authoritative, so blame must reflect the |
| # process hunks (only lines 5-6), not a store hit. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed" \ |
| blame pair.c >actual && |
| sed -n "9p" actual >line9 && |
| test_grep "$ORIG" line9 |
| ' |
| |
| test_expect_success 'a worktree side is not asked by object names' ' |
| test_when_finished "rm -f backend.log && git checkout -- pair.c" && |
| echo "worktree edit" >>pair.c && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff --numstat -- pair.c >actual && |
| printf "1\t0\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'diff process bypassed by --no-ext-diff' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --format= --numstat --no-ext-diff -- pair.c >actual && |
| printf "4\t4\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'format-patch keeps its diffstat off the process' ' |
| test_when_finished "rm -f backend.log" && |
| # format-patch emits a diffstat, and a diffstat consults the |
| # process, but the gate keeps it builtin so a generated patch |
| # applies for recipients without the process. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| format-patch -1 --stdout --stat -- pair.c >actual && |
| test_grep "^+changed9" actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'format-patch --ext-diff keeps its diffstat off the process' ' |
| test_when_finished "rm -f backend.log" && |
| # The gate holds even when --ext-diff enables the external command. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| format-patch -1 --stdout --ext-diff --stat -- pair.c >actual && |
| test_grep "^+changed9" actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'diff process not consulted by plumbing diff commands' ' |
| test_when_finished "rm -f backend.log && git checkout -f HEAD -- pair.c" && |
| # diff-tree diffs the two commits, a real pair a defeated gate would |
| # consult the process for. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff-tree --numstat HEAD >actual && |
| test_grep "pair.c" actual && |
| # diff-index needs a change to diff, or there is no pair and a |
| # missing log proves nothing; stage one and diff it against HEAD. |
| echo "staged change" >>pair.c && |
| git add pair.c && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff-index --cached --numstat HEAD -- pair.c >actual && |
| test_grep "pair.c" actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'add -p stages from the builtin diff with a process configured' ' |
| test_when_finished "rm -f backend.log" && |
| cat >gate.c <<-\EOF && |
| int gate(void) { return 1; } |
| EOF |
| git add gate.c && |
| git commit -m "add gate.c" && |
| cat >gate.c <<-\EOF && |
| int gate(void) { return 2; } |
| EOF |
| # add -p builds its hunks from patch text, which is not a provider |
| # consumer today, so a configured process cannot shape what it |
| # offers. This pins that interactive patch stays builtin for the |
| # current consumers, rather than exercising the plumbing gate. |
| test_write_lines y | |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| add -p gate.c && |
| git diff --cached -- gate.c >staged && |
| test_grep "return 2" staged && |
| test_path_is_missing backend.log && |
| git commit -m "gate.c v2" |
| ' |
| |
| test_expect_success 'blame withholds identity for the working-tree pair' ' |
| test_when_finished "rm -f backend.log && git checkout -- pair.c" && |
| echo "uncommitted" >>pair.c && |
| wt=$(git hash-object pair.c) && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| blame pair.c >actual && |
| # The dirty working-tree side is not a stored blob: no request |
| # may name its bytes by object id. |
| test_grep ! "new-oid=$wt" backend.log |
| ' |
| |
| test_expect_success 'a replaced blob makes the process step aside' ' |
| new_blob=$(git rev-parse HEAD:pair.c) && |
| test_when_finished "rm -f backend.log && git replace -d $new_blob" && |
| # Replacing the new-side blob redirects the content the diff reads |
| # under the id the process would be sent, so a raw-id request would |
| # name bytes other than the ones diffed. Identity is withheld: the |
| # process is not consulted and the builtin computes the pair from |
| # the replaced content. |
| repl=$(printf "just one line\n" | git hash-object -w --stdin) && |
| git replace "$new_blob" "$repl" && |
| git log -1 --format= --numstat -- pair.c >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --format= --numstat -- pair.c >actual && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'an equivalence answer omits the pair from the stat' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-equal --log=backend.log" \ |
| log -1 --format= --numstat -- pair.c >actual && |
| # An equivalent pair sums to a zero-count entry, and the stat |
| # code omits zero-count modified entries, the same way a |
| # whitespace-only pair prints nothing under -w. The builtin |
| # diff would print nonzero counts here, and the log proves the |
| # process was consulted. |
| test_must_be_empty actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'blame passes equivalent pairs through to the boundary' ' |
| ORIG=$(git rev-parse --short ":/add pair.c") && |
| # The process asserts every consulted pair equal, so no line is |
| # ever treated as changed: every line passes through to the |
| # commit that added the file, marked as the blame boundary. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-equal" \ |
| blame pair.c >actual && |
| sed -n "5p" actual >line5 && |
| test_grep "^\^$ORIG" line5 && |
| sed -n "10p" actual >line10 && |
| test_grep "^\^$ORIG" line10 |
| ' |
| |
| test_expect_success 'a warming run records a pair the process defers' ' |
| test_when_finished "git diff-hunks clear" && |
| git diff-hunks clear && |
| # The process owns the path but defers this pair with |
| # need-content, so the pair gets the builtin diff; that is the |
| # result the store holds, so the warming run records it and a |
| # later read is served from the store. |
| GIT_DIFF_HUNKS_WRITE=1 git -c core.diffHunks=true \ |
| -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \ |
| log -1 --format= --stat -- pair.c >/dev/null && |
| git -c core.diffHunks=true blame --show-stats pair.c >stats 2>&1 && |
| test_grep "num precomputed hits: 1" stats |
| ' |
| |
| # The protocol error paths: each adversarial response shape must warn, |
| # fall back to the builtin output, and either keep the process alive |
| # (a per-pair rejection) or disable it for the rest of the command (a |
| # protocol error). The request log tells the two apart: the log walk |
| # below consults two pairs (gate.c first, then pair.c), so a disabled |
| # process shows one logged request and a live one shows two. |
| |
| test_expect_success 'a malformed hunk line disables the process for the command' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-malformed --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "disabling it for the remainder" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'coordinates past the blob size skip the pair, process stays alive' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-huge --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "past the end" err && |
| test_line_count = 2 backend.log |
| ' |
| |
| test_expect_success 'a count that overflows long skips the pair, process stays alive' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-erange --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "out-of-range coordinates" err && |
| test_line_count = 2 backend.log |
| ' |
| |
| test_expect_success 'overlapping hunks are rejected per pair' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-overlap --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "overlapping hunks" err && |
| test_line_count = 2 backend.log |
| ' |
| |
| test_expect_success 'misaligned hunks are rejected per pair' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-misaligned --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "misaligned" err && |
| test_line_count = 2 backend.log |
| ' |
| |
| test_expect_success 'a start of zero with a nonzero count is rejected per pair' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| # A start of 0 names an empty side, so a nonzero count beside it |
| # names no line; the coordinate is rejected and the pair falls back |
| # to the builtin diff while the process stays alive. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-badstart --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "out-of-range coordinates" err && |
| test_line_count = 2 backend.log |
| ' |
| |
| test_expect_success 'an unrecognized status disables the process for the command' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-unknown-status --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "unrecognized status .frobnicate." err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'status=abort withdraws the capability without a warning' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-abort --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep ! "disabling" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'a bare status without the hunk-section flush is a protocol error' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-bare-status --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "disabling it for the remainder" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'an empty packet in the hunk section is a protocol error' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-empty-packet --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "disabling it for the remainder" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'a process that dies mid-response fails the command over to builtin' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-crash --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "disabling it for the remainder" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'garbage bytes on stdout fail the command over to builtin' ' |
| test_when_finished "rm -f backend.log err" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-garbage --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual 2>err && |
| test_cmp expect actual && |
| test_grep "disabling it for the remainder" err && |
| test_line_count = 1 backend.log |
| ' |
| |
| test_expect_success 'a process announcing no capability is never asked' ' |
| test_when_finished "rm -f backend.log" && |
| git log --format= --numstat -- "*.c" >expect && |
| git -c diff.cdiff.process="$BACKEND --mode=cap-none --log=backend.log" \ |
| log --format= --numstat -- "*.c" >actual && |
| test_cmp expect actual && |
| test_must_be_empty backend.log |
| ' |
| |
| test_expect_success 'a trailing token on a hunk line is ignored' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-trailing --log=backend.log" \ |
| log -1 --format= --numstat -- pair.c >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'a failed start warns once and the store may serve the path' ' |
| git init failrepo && |
| ( |
| cd failrepo && |
| echo "*.c diff=cdiff" >.gitattributes && |
| git add .gitattributes && |
| test_commit f1 f.c "one" && |
| test_commit f2 f.c "one |
| two" && |
| test_commit f3 f.c "one |
| two |
| three" && |
| GIT_DIFF_HUNKS_WRITE=1 git log --format= --stat -- f.c >/dev/null && |
| # The command has no shell metacharacters, so it fails at |
| # exec time; a shell-wrapped command would fail at the |
| # handshake, which the gentle handshake in the base |
| # (061a68e443) likewise degrades to the builtin diff. |
| git blame f.c >expect && |
| git -c diff.cdiff.process=/does-not-exist-diff-backend \ |
| blame f.c >actual 2>err && |
| test_cmp expect actual && |
| # One warning even though the blame consults two pairs. |
| test $(grep -c "failed to start" err) = 1 && |
| # A failure is a non-answer like any other: the request |
| # that observes it and every later request pass to the |
| # store, so the warmed store serves both pairs. |
| git -c diff.cdiff.process=/does-not-exist-diff-backend \ |
| blame --show-stats f.c >stats 2>&1 && |
| test_grep "num precomputed hits: 2" stats |
| ) |
| ' |
| |
| test_expect_success 'the store serves a pair the process defers' ' |
| test_when_finished "git diff-hunks clear" && |
| git diff-hunks clear && |
| GIT_DIFF_HUNKS_WRITE=1 git log --format= --stat -- pair.c >/dev/null && |
| git blame pair.c >expect && |
| # need-content defers the pair to the builtin diff, which is |
| # what the store holds, so the walk continues past the process |
| # and the store serves the pair. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \ |
| blame pair.c >actual && |
| test_cmp expect actual && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \ |
| blame --show-stats pair.c >stats 2>&1 && |
| test_grep "num precomputed hits: 1" stats |
| ' |
| |
| test_expect_success 'git diff between commits consults the process' ' |
| test_when_finished "rm -f backend.log" && |
| ORIG=$(git rev-parse ":/add pair.c") && |
| CHANGE=$(git rev-parse ":/change pair.c") && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff --numstat $ORIG $CHANGE -- pair.c >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'git show consults the process' ' |
| test_when_finished "rm -f backend.log" && |
| CHANGE=$(git rev-parse ":/change pair.c") && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| show --format= --numstat $CHANGE -- pair.c >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'diff-tree --ext-diff consults the process' ' |
| test_when_finished "rm -f backend.log" && |
| CHANGE=$(git rev-parse ":/change pair.c") && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff-tree --ext-diff --no-commit-id --numstat $CHANGE >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success '--no-diff-process forbids consulting alone' ' |
| test_when_finished "rm -f backend.log" && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --no-diff-process --format= --numstat -- pair.c >actual && |
| printf "4\t4\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success '--diff-process allows plumbing to consult' ' |
| test_when_finished "rm -f backend.log" && |
| CHANGE=$(git rev-parse ":/change pair.c") && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| diff-tree --diff-process --no-commit-id --numstat $CHANGE >actual && |
| printf "2\t2\tpair.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=pair.c" backend.log |
| ' |
| |
| test_expect_success 'a forced blame diff algorithm bypasses the process' ' |
| test_when_finished "rm -f backend.log" && |
| CHANGE=$(git rev-parse --short ":/change pair.c") && |
| # The process would attribute lines 9-10 to the original commit |
| # (see the oid-fixed blame test above); a forced builtin |
| # algorithm must produce the builtin attribution and never start |
| # the process. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| blame --histogram pair.c >actual && |
| sed -n "9p" actual >line9 && |
| test_grep "$CHANGE" line9 && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'textconv output is never identified to the process' ' |
| test_when_finished "rm -f backend.log" && |
| echo "*.tcv diff=tcv" >>.gitattributes && |
| git add .gitattributes && |
| git commit -m tcv-attr && |
| test_config diff.tcv.textconv cat && |
| test_commit tcv1 file.tcv "alpha" && |
| test_commit tcv2 file.tcv "alpha |
| beta" && |
| git blame file.tcv >expect && |
| git -c diff.tcv.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| blame file.tcv >actual && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'a gitlink side is never identified to the process' ' |
| test_when_finished "rm -f backend.log" && |
| echo "sub diff=cdiff" >>.gitattributes && |
| git add .gitattributes && |
| git commit -m sub-attr && |
| C1=$(git rev-parse HEAD) && |
| C2=$(git rev-parse HEAD~1) && |
| git update-index --add --cacheinfo 160000,$C1,sub && |
| git commit -m sub-1 && |
| git update-index --add --cacheinfo 160000,$C2,sub && |
| git commit -m sub-2 && |
| git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --format= --numstat -- sub >actual && |
| printf "1\t1\tsub\n" >expect && |
| test_cmp expect actual && |
| test_path_is_missing backend.log |
| ' |
| |
| test_expect_success 'a relative diff consults by the repo-relative path' ' |
| test_when_finished "rm -f backend.log" && |
| echo "reldir/*.rel diff=rdrv" >>.gitattributes && |
| git add .gitattributes && |
| git commit -m rel-attr && |
| mkdir reldir && |
| test_write_lines line1 line2 line3 line4 original5 original6 \ |
| line7 line8 line9 line10 >reldir/x.rel && |
| git add reldir/x.rel && |
| git commit -m "add x.rel" && |
| test_write_lines line1 line2 line3 line4 changed5 changed6 \ |
| line7 line8 changed9 changed10 >reldir/x.rel && |
| git add reldir/x.rel && |
| git commit -m "change x.rel" && |
| # diff.relative strips the prefix from the displayed name; the |
| # driver lookup and the request pathname must still use the |
| # repo-relative path, or the directory-scoped attribute above |
| # would not match and the process would never be consulted. |
| # The process runs at the repository root, so its log lands there. |
| ( |
| cd reldir && |
| git -c diff.relative=true \ |
| -c diff.rdrv.process="$BACKEND --mode=oid-fixed --log=backend.log" \ |
| log -1 --format= --numstat -- x.rel |
| ) >actual && |
| printf "2\t2\tx.rel\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=reldir/x.rel" backend.log |
| ' |
| |
| test_expect_success 'an empty file side is answered with a start of zero' ' |
| test_when_finished "rm -f backend.log" && |
| >empty.c && |
| git add empty.c && |
| git commit -m "add empty.c" && |
| printf "x\ny\nz\n" >empty.c && |
| git add empty.c && |
| git commit -m "fill empty.c" && |
| # The process addresses the empty old side with a start of 0 and a |
| # count of 0, and claims two of the three added lines. The answer is |
| # used as sent, so the stat shows the two lines it named, not the |
| # three the builtin would. |
| git -c diff.cdiff.process="$BACKEND --mode=oid-empty --log=backend.log" \ |
| log -1 --format= --numstat -- empty.c >actual && |
| printf "2\t0\tempty.c\n" >expect && |
| test_cmp expect actual && |
| test_grep "command=hunks-by-oid pathname=empty.c" backend.log |
| ' |
| |
| test_done |