Raw
1 #!/bin/sh
2
3 test_description='diff.<driver>.process: oid-only hunk requests'
4
5 TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7
8 # See t/helper/test-diff-process-backend.c for the process implementation
9 # and available --mode= options.
10
11 BACKEND="test-tool diff-process-backend"
12
13 test_expect_success 'setup' '
14 echo "*.c diff=cdiff" >.gitattributes &&
15 git add .gitattributes &&
16
17 # 10 lines, changes at 5-6 and 9-10 between the two commits.
18 cat >pair.c <<-\EOF &&
19 line1
20 line2
21 line3
22 line4
23 original5
24 original6
25 line7
26 line8
27 line9
28 line10
29 EOF
30 git add pair.c &&
31 git commit -m "add pair.c" &&
32
33 cat >pair.c <<-\EOF &&
34 line1
35 line2
36 line3
37 line4
38 changed5
39 changed6
40 line7
41 line8
42 changed9
43 changed10
44 EOF
45 git add pair.c &&
46 git commit -m "change pair.c"
47 '
48
49 test_expect_success 'an oid-capable process answers blame by object names alone' '
50 test_when_finished "rm -f backend.log" &&
51 ORIG=$(git rev-parse --short HEAD~1) &&
52 CHANGE=$(git rev-parse --short HEAD) &&
53 # The process reports only lines 5-6 as changed, so blame attributes
54 # lines 9-10 to the original commit even though the builtin diff
55 # would show them as changed.
56 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
57 blame pair.c >actual &&
58 sed -n "9p" actual >line9 &&
59 sed -n "10p" actual >line10 &&
60 test_grep "$ORIG" line9 &&
61 test_grep "$ORIG" line10 &&
62 sed -n "5p" actual >line5 &&
63 test_grep "$CHANGE" line5 &&
64 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
65 '
66
67 test_expect_success 'an oid-capable process answers --numstat by object names alone' '
68 test_when_finished "rm -f backend.log" &&
69 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
70 log -1 --format= --numstat -- pair.c >actual &&
71 printf "2\t2\tpair.c\n" >expect &&
72 test_cmp expect actual &&
73 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
74 '
75
76 test_expect_success 'need-content falls through to the builtin diff' '
77 test_when_finished "rm -f backend.log" &&
78 git -c diff.cdiff.process="$BACKEND --mode=oid-need-content --log=backend.log" \
79 log -1 --format= --numstat -- pair.c >actual &&
80 printf "4\t4\tpair.c\n" >expect &&
81 test_cmp expect actual &&
82 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
83 '
84
85 test_expect_success 'a warmed hunk store does not override process hunks' '
86 test_when_finished "git diff-hunks clear" &&
87 ORIG=$(git rev-parse --short HEAD~1) &&
88 GIT_DIFF_HUNKS_WRITE=1 git log -2 --stat -- pair.c >/dev/null &&
89
90 # Control: without a process, blame is served from the store.
91 git blame --show-stats pair.c >stats &&
92 test_grep "num precomputed hits: 1" stats &&
93
94 # The store holds the builtin hunks, but a process-capable driver
95 # makes the process authoritative, so blame must reflect the
96 # process hunks (only lines 5-6), not a store hit.
97 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed" \
98 blame pair.c >actual &&
99 sed -n "9p" actual >line9 &&
100 test_grep "$ORIG" line9
101 '
102
103 test_expect_success 'a worktree side is not asked by object names' '
104 test_when_finished "rm -f backend.log && git checkout -- pair.c" &&
105 echo "worktree edit" >>pair.c &&
106 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
107 diff --numstat -- pair.c >actual &&
108 printf "1\t0\tpair.c\n" >expect &&
109 test_cmp expect actual &&
110 test_path_is_missing backend.log
111 '
112
113 test_expect_success 'diff process bypassed by --no-ext-diff' '
114 test_when_finished "rm -f backend.log" &&
115 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
116 log -1 --format= --numstat --no-ext-diff -- pair.c >actual &&
117 printf "4\t4\tpair.c\n" >expect &&
118 test_cmp expect actual &&
119 test_path_is_missing backend.log
120 '
121
122 test_expect_success 'format-patch keeps its diffstat off the process' '
123 test_when_finished "rm -f backend.log" &&
124 # format-patch emits a diffstat, and a diffstat consults the
125 # process, but the gate keeps it builtin so a generated patch
126 # applies for recipients without the process.
127 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
128 format-patch -1 --stdout --stat -- pair.c >actual &&
129 test_grep "^+changed9" actual &&
130 test_path_is_missing backend.log
131 '
132
133 test_expect_success 'format-patch --ext-diff keeps its diffstat off the process' '
134 test_when_finished "rm -f backend.log" &&
135 # The gate holds even when --ext-diff enables the external command.
136 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
137 format-patch -1 --stdout --ext-diff --stat -- pair.c >actual &&
138 test_grep "^+changed9" actual &&
139 test_path_is_missing backend.log
140 '
141
142 test_expect_success 'diff process not consulted by plumbing diff commands' '
143 test_when_finished "rm -f backend.log && git checkout -f HEAD -- pair.c" &&
144 # diff-tree diffs the two commits, a real pair a defeated gate would
145 # consult the process for.
146 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
147 diff-tree --numstat HEAD >actual &&
148 test_grep "pair.c" actual &&
149 # diff-index needs a change to diff, or there is no pair and a
150 # missing log proves nothing; stage one and diff it against HEAD.
151 echo "staged change" >>pair.c &&
152 git add pair.c &&
153 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
154 diff-index --cached --numstat HEAD -- pair.c >actual &&
155 test_grep "pair.c" actual &&
156 test_path_is_missing backend.log
157 '
158
159 test_expect_success 'add -p stages from the builtin diff with a process configured' '
160 test_when_finished "rm -f backend.log" &&
161 cat >gate.c <<-\EOF &&
162 int gate(void) { return 1; }
163 EOF
164 git add gate.c &&
165 git commit -m "add gate.c" &&
166 cat >gate.c <<-\EOF &&
167 int gate(void) { return 2; }
168 EOF
169 # add -p builds its hunks from patch text, which is not a provider
170 # consumer today, so a configured process cannot shape what it
171 # offers. This pins that interactive patch stays builtin for the
172 # current consumers, rather than exercising the plumbing gate.
173 test_write_lines y |
174 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
175 add -p gate.c &&
176 git diff --cached -- gate.c >staged &&
177 test_grep "return 2" staged &&
178 test_path_is_missing backend.log &&
179 git commit -m "gate.c v2"
180 '
181
182 test_expect_success 'blame withholds identity for the working-tree pair' '
183 test_when_finished "rm -f backend.log && git checkout -- pair.c" &&
184 echo "uncommitted" >>pair.c &&
185 wt=$(git hash-object pair.c) &&
186 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
187 blame pair.c >actual &&
188 # The dirty working-tree side is not a stored blob: no request
189 # may name its bytes by object id.
190 test_grep ! "new-oid=$wt" backend.log
191 '
192
193 test_expect_success 'a replaced blob makes the process step aside' '
194 new_blob=$(git rev-parse HEAD:pair.c) &&
195 test_when_finished "rm -f backend.log && git replace -d $new_blob" &&
196 # Replacing the new-side blob redirects the content the diff reads
197 # under the id the process would be sent, so a raw-id request would
198 # name bytes other than the ones diffed. Identity is withheld: the
199 # process is not consulted and the builtin computes the pair from
200 # the replaced content.
201 repl=$(printf "just one line\n" | git hash-object -w --stdin) &&
202 git replace "$new_blob" "$repl" &&
203 git log -1 --format= --numstat -- pair.c >expect &&
204 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
205 log -1 --format= --numstat -- pair.c >actual &&
206 test_cmp expect actual &&
207 test_path_is_missing backend.log
208 '
209
210 test_expect_success 'an equivalence answer omits the pair from the stat' '
211 test_when_finished "rm -f backend.log" &&
212 git -c diff.cdiff.process="$BACKEND --mode=oid-equal --log=backend.log" \
213 log -1 --format= --numstat -- pair.c >actual &&
214 # An equivalent pair sums to a zero-count entry, and the stat
215 # code omits zero-count modified entries, the same way a
216 # whitespace-only pair prints nothing under -w. The builtin
217 # diff would print nonzero counts here, and the log proves the
218 # process was consulted.
219 test_must_be_empty actual &&
220 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
221 '
222
223 test_expect_success 'blame passes equivalent pairs through to the boundary' '
224 ORIG=$(git rev-parse --short ":/add pair.c") &&
225 # The process asserts every consulted pair equal, so no line is
226 # ever treated as changed: every line passes through to the
227 # commit that added the file, marked as the blame boundary.
228 git -c diff.cdiff.process="$BACKEND --mode=oid-equal" \
229 blame pair.c >actual &&
230 sed -n "5p" actual >line5 &&
231 test_grep "^\^$ORIG" line5 &&
232 sed -n "10p" actual >line10 &&
233 test_grep "^\^$ORIG" line10
234 '
235
236 test_expect_success 'a warming run records a pair the process defers' '
237 test_when_finished "git diff-hunks clear" &&
238 git diff-hunks clear &&
239 # The process owns the path but defers this pair with
240 # need-content, so the pair gets the builtin diff; that is the
241 # result the store holds, so the warming run records it and a
242 # later read is served from the store.
243 GIT_DIFF_HUNKS_WRITE=1 git -c core.diffHunks=true \
244 -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \
245 log -1 --format= --stat -- pair.c >/dev/null &&
246 git -c core.diffHunks=true blame --show-stats pair.c >stats 2>&1 &&
247 test_grep "num precomputed hits: 1" stats
248 '
249
250 # The protocol error paths: each adversarial response shape must warn,
251 # fall back to the builtin output, and either keep the process alive
252 # (a per-pair rejection) or disable it for the rest of the command (a
253 # protocol error). The request log tells the two apart: the log walk
254 # below consults two pairs (gate.c first, then pair.c), so a disabled
255 # process shows one logged request and a live one shows two.
256
257 test_expect_success 'a malformed hunk line disables the process for the command' '
258 test_when_finished "rm -f backend.log err" &&
259 git log --format= --numstat -- "*.c" >expect &&
260 git -c diff.cdiff.process="$BACKEND --mode=oid-malformed --log=backend.log" \
261 log --format= --numstat -- "*.c" >actual 2>err &&
262 test_cmp expect actual &&
263 test_grep "disabling it for the remainder" err &&
264 test_line_count = 1 backend.log
265 '
266
267 test_expect_success 'coordinates past the blob size skip the pair, process stays alive' '
268 test_when_finished "rm -f backend.log err" &&
269 git log --format= --numstat -- "*.c" >expect &&
270 git -c diff.cdiff.process="$BACKEND --mode=oid-huge --log=backend.log" \
271 log --format= --numstat -- "*.c" >actual 2>err &&
272 test_cmp expect actual &&
273 test_grep "past the end" err &&
274 test_line_count = 2 backend.log
275 '
276
277 test_expect_success 'a count that overflows long skips the pair, process stays alive' '
278 test_when_finished "rm -f backend.log err" &&
279 git log --format= --numstat -- "*.c" >expect &&
280 git -c diff.cdiff.process="$BACKEND --mode=oid-erange --log=backend.log" \
281 log --format= --numstat -- "*.c" >actual 2>err &&
282 test_cmp expect actual &&
283 test_grep "out-of-range coordinates" err &&
284 test_line_count = 2 backend.log
285 '
286
287 test_expect_success 'overlapping hunks are rejected per pair' '
288 test_when_finished "rm -f backend.log err" &&
289 git log --format= --numstat -- "*.c" >expect &&
290 git -c diff.cdiff.process="$BACKEND --mode=oid-overlap --log=backend.log" \
291 log --format= --numstat -- "*.c" >actual 2>err &&
292 test_cmp expect actual &&
293 test_grep "overlapping hunks" err &&
294 test_line_count = 2 backend.log
295 '
296
297 test_expect_success 'misaligned hunks are rejected per pair' '
298 test_when_finished "rm -f backend.log err" &&
299 git log --format= --numstat -- "*.c" >expect &&
300 git -c diff.cdiff.process="$BACKEND --mode=oid-misaligned --log=backend.log" \
301 log --format= --numstat -- "*.c" >actual 2>err &&
302 test_cmp expect actual &&
303 test_grep "misaligned" err &&
304 test_line_count = 2 backend.log
305 '
306
307 test_expect_success 'a start of zero with a nonzero count is rejected per pair' '
308 test_when_finished "rm -f backend.log err" &&
309 git log --format= --numstat -- "*.c" >expect &&
310 # A start of 0 names an empty side, so a nonzero count beside it
311 # names no line; the coordinate is rejected and the pair falls back
312 # to the builtin diff while the process stays alive.
313 git -c diff.cdiff.process="$BACKEND --mode=oid-badstart --log=backend.log" \
314 log --format= --numstat -- "*.c" >actual 2>err &&
315 test_cmp expect actual &&
316 test_grep "out-of-range coordinates" err &&
317 test_line_count = 2 backend.log
318 '
319
320 test_expect_success 'an unrecognized status disables the process for the command' '
321 test_when_finished "rm -f backend.log err" &&
322 git log --format= --numstat -- "*.c" >expect &&
323 git -c diff.cdiff.process="$BACKEND --mode=oid-unknown-status --log=backend.log" \
324 log --format= --numstat -- "*.c" >actual 2>err &&
325 test_cmp expect actual &&
326 test_grep "unrecognized status .frobnicate." err &&
327 test_line_count = 1 backend.log
328 '
329
330 test_expect_success 'status=abort withdraws the capability without a warning' '
331 test_when_finished "rm -f backend.log err" &&
332 git log --format= --numstat -- "*.c" >expect &&
333 git -c diff.cdiff.process="$BACKEND --mode=oid-abort --log=backend.log" \
334 log --format= --numstat -- "*.c" >actual 2>err &&
335 test_cmp expect actual &&
336 test_grep ! "disabling" err &&
337 test_line_count = 1 backend.log
338 '
339
340 test_expect_success 'a bare status without the hunk-section flush is a protocol error' '
341 test_when_finished "rm -f backend.log err" &&
342 git log --format= --numstat -- "*.c" >expect &&
343 git -c diff.cdiff.process="$BACKEND --mode=oid-bare-status --log=backend.log" \
344 log --format= --numstat -- "*.c" >actual 2>err &&
345 test_cmp expect actual &&
346 test_grep "disabling it for the remainder" err &&
347 test_line_count = 1 backend.log
348 '
349
350 test_expect_success 'an empty packet in the hunk section is a protocol error' '
351 test_when_finished "rm -f backend.log err" &&
352 git log --format= --numstat -- "*.c" >expect &&
353 git -c diff.cdiff.process="$BACKEND --mode=oid-empty-packet --log=backend.log" \
354 log --format= --numstat -- "*.c" >actual 2>err &&
355 test_cmp expect actual &&
356 test_grep "disabling it for the remainder" err &&
357 test_line_count = 1 backend.log
358 '
359
360 test_expect_success 'a process that dies mid-response fails the command over to builtin' '
361 test_when_finished "rm -f backend.log err" &&
362 git log --format= --numstat -- "*.c" >expect &&
363 git -c diff.cdiff.process="$BACKEND --mode=oid-crash --log=backend.log" \
364 log --format= --numstat -- "*.c" >actual 2>err &&
365 test_cmp expect actual &&
366 test_grep "disabling it for the remainder" err &&
367 test_line_count = 1 backend.log
368 '
369
370 test_expect_success 'garbage bytes on stdout fail the command over to builtin' '
371 test_when_finished "rm -f backend.log err" &&
372 git log --format= --numstat -- "*.c" >expect &&
373 git -c diff.cdiff.process="$BACKEND --mode=oid-garbage --log=backend.log" \
374 log --format= --numstat -- "*.c" >actual 2>err &&
375 test_cmp expect actual &&
376 test_grep "disabling it for the remainder" err &&
377 test_line_count = 1 backend.log
378 '
379
380 test_expect_success 'a process announcing no capability is never asked' '
381 test_when_finished "rm -f backend.log" &&
382 git log --format= --numstat -- "*.c" >expect &&
383 git -c diff.cdiff.process="$BACKEND --mode=cap-none --log=backend.log" \
384 log --format= --numstat -- "*.c" >actual &&
385 test_cmp expect actual &&
386 test_must_be_empty backend.log
387 '
388
389 test_expect_success 'a trailing token on a hunk line is ignored' '
390 test_when_finished "rm -f backend.log" &&
391 git -c diff.cdiff.process="$BACKEND --mode=oid-trailing --log=backend.log" \
392 log -1 --format= --numstat -- pair.c >actual &&
393 printf "2\t2\tpair.c\n" >expect &&
394 test_cmp expect actual &&
395 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
396 '
397
398 test_expect_success 'a failed start warns once and the store may serve the path' '
399 git init failrepo &&
400 (
401 cd failrepo &&
402 echo "*.c diff=cdiff" >.gitattributes &&
403 git add .gitattributes &&
404 test_commit f1 f.c "one" &&
405 test_commit f2 f.c "one
406 two" &&
407 test_commit f3 f.c "one
408 two
409 three" &&
410 GIT_DIFF_HUNKS_WRITE=1 git log --format= --stat -- f.c >/dev/null &&
411 # The command has no shell metacharacters, so it fails at
412 # exec time; a shell-wrapped command would fail at the
413 # handshake, which the gentle handshake in the base
414 # (061a68e443) likewise degrades to the builtin diff.
415 git blame f.c >expect &&
416 git -c diff.cdiff.process=/does-not-exist-diff-backend \
417 blame f.c >actual 2>err &&
418 test_cmp expect actual &&
419 # One warning even though the blame consults two pairs.
420 test $(grep -c "failed to start" err) = 1 &&
421 # A failure is a non-answer like any other: the request
422 # that observes it and every later request pass to the
423 # store, so the warmed store serves both pairs.
424 git -c diff.cdiff.process=/does-not-exist-diff-backend \
425 blame --show-stats f.c >stats 2>&1 &&
426 test_grep "num precomputed hits: 2" stats
427 )
428 '
429
430 test_expect_success 'the store serves a pair the process defers' '
431 test_when_finished "git diff-hunks clear" &&
432 git diff-hunks clear &&
433 GIT_DIFF_HUNKS_WRITE=1 git log --format= --stat -- pair.c >/dev/null &&
434 git blame pair.c >expect &&
435 # need-content defers the pair to the builtin diff, which is
436 # what the store holds, so the walk continues past the process
437 # and the store serves the pair.
438 git -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \
439 blame pair.c >actual &&
440 test_cmp expect actual &&
441 git -c diff.cdiff.process="$BACKEND --mode=oid-need-content" \
442 blame --show-stats pair.c >stats 2>&1 &&
443 test_grep "num precomputed hits: 1" stats
444 '
445
446 test_expect_success 'git diff between commits consults the process' '
447 test_when_finished "rm -f backend.log" &&
448 ORIG=$(git rev-parse ":/add pair.c") &&
449 CHANGE=$(git rev-parse ":/change pair.c") &&
450 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
451 diff --numstat $ORIG $CHANGE -- pair.c >actual &&
452 printf "2\t2\tpair.c\n" >expect &&
453 test_cmp expect actual &&
454 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
455 '
456
457 test_expect_success 'git show consults the process' '
458 test_when_finished "rm -f backend.log" &&
459 CHANGE=$(git rev-parse ":/change pair.c") &&
460 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
461 show --format= --numstat $CHANGE -- pair.c >actual &&
462 printf "2\t2\tpair.c\n" >expect &&
463 test_cmp expect actual &&
464 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
465 '
466
467 test_expect_success 'diff-tree --ext-diff consults the process' '
468 test_when_finished "rm -f backend.log" &&
469 CHANGE=$(git rev-parse ":/change pair.c") &&
470 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
471 diff-tree --ext-diff --no-commit-id --numstat $CHANGE >actual &&
472 printf "2\t2\tpair.c\n" >expect &&
473 test_cmp expect actual &&
474 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
475 '
476
477 test_expect_success '--no-diff-process forbids consulting alone' '
478 test_when_finished "rm -f backend.log" &&
479 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
480 log -1 --no-diff-process --format= --numstat -- pair.c >actual &&
481 printf "4\t4\tpair.c\n" >expect &&
482 test_cmp expect actual &&
483 test_path_is_missing backend.log
484 '
485
486 test_expect_success '--diff-process allows plumbing to consult' '
487 test_when_finished "rm -f backend.log" &&
488 CHANGE=$(git rev-parse ":/change pair.c") &&
489 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
490 diff-tree --diff-process --no-commit-id --numstat $CHANGE >actual &&
491 printf "2\t2\tpair.c\n" >expect &&
492 test_cmp expect actual &&
493 test_grep "command=hunks-by-oid pathname=pair.c" backend.log
494 '
495
496 test_expect_success 'a forced blame diff algorithm bypasses the process' '
497 test_when_finished "rm -f backend.log" &&
498 CHANGE=$(git rev-parse --short ":/change pair.c") &&
499 # The process would attribute lines 9-10 to the original commit
500 # (see the oid-fixed blame test above); a forced builtin
501 # algorithm must produce the builtin attribution and never start
502 # the process.
503 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
504 blame --histogram pair.c >actual &&
505 sed -n "9p" actual >line9 &&
506 test_grep "$CHANGE" line9 &&
507 test_path_is_missing backend.log
508 '
509
510 test_expect_success 'textconv output is never identified to the process' '
511 test_when_finished "rm -f backend.log" &&
512 echo "*.tcv diff=tcv" >>.gitattributes &&
513 git add .gitattributes &&
514 git commit -m tcv-attr &&
515 test_config diff.tcv.textconv cat &&
516 test_commit tcv1 file.tcv "alpha" &&
517 test_commit tcv2 file.tcv "alpha
518 beta" &&
519 git blame file.tcv >expect &&
520 git -c diff.tcv.process="$BACKEND --mode=oid-fixed --log=backend.log" \
521 blame file.tcv >actual &&
522 test_cmp expect actual &&
523 test_path_is_missing backend.log
524 '
525
526 test_expect_success 'a gitlink side is never identified to the process' '
527 test_when_finished "rm -f backend.log" &&
528 echo "sub diff=cdiff" >>.gitattributes &&
529 git add .gitattributes &&
530 git commit -m sub-attr &&
531 C1=$(git rev-parse HEAD) &&
532 C2=$(git rev-parse HEAD~1) &&
533 git update-index --add --cacheinfo 160000,$C1,sub &&
534 git commit -m sub-1 &&
535 git update-index --add --cacheinfo 160000,$C2,sub &&
536 git commit -m sub-2 &&
537 git -c diff.cdiff.process="$BACKEND --mode=oid-fixed --log=backend.log" \
538 log -1 --format= --numstat -- sub >actual &&
539 printf "1\t1\tsub\n" >expect &&
540 test_cmp expect actual &&
541 test_path_is_missing backend.log
542 '
543
544 test_expect_success 'a relative diff consults by the repo-relative path' '
545 test_when_finished "rm -f backend.log" &&
546 echo "reldir/*.rel diff=rdrv" >>.gitattributes &&
547 git add .gitattributes &&
548 git commit -m rel-attr &&
549 mkdir reldir &&
550 test_write_lines line1 line2 line3 line4 original5 original6 \
551 line7 line8 line9 line10 >reldir/x.rel &&
552 git add reldir/x.rel &&
553 git commit -m "add x.rel" &&
554 test_write_lines line1 line2 line3 line4 changed5 changed6 \
555 line7 line8 changed9 changed10 >reldir/x.rel &&
556 git add reldir/x.rel &&
557 git commit -m "change x.rel" &&
558 # diff.relative strips the prefix from the displayed name; the
559 # driver lookup and the request pathname must still use the
560 # repo-relative path, or the directory-scoped attribute above
561 # would not match and the process would never be consulted.
562 # The process runs at the repository root, so its log lands there.
563 (
564 cd reldir &&
565 git -c diff.relative=true \
566 -c diff.rdrv.process="$BACKEND --mode=oid-fixed --log=backend.log" \
567 log -1 --format= --numstat -- x.rel
568 ) >actual &&
569 printf "2\t2\tx.rel\n" >expect &&
570 test_cmp expect actual &&
571 test_grep "command=hunks-by-oid pathname=reldir/x.rel" backend.log
572 '
573
574 test_expect_success 'an empty file side is answered with a start of zero' '
575 test_when_finished "rm -f backend.log" &&
576 >empty.c &&
577 git add empty.c &&
578 git commit -m "add empty.c" &&
579 printf "x\ny\nz\n" >empty.c &&
580 git add empty.c &&
581 git commit -m "fill empty.c" &&
582 # The process addresses the empty old side with a start of 0 and a
583 # count of 0, and claims two of the three added lines. The answer is
584 # used as sent, so the stat shows the two lines it named, not the
585 # three the builtin would.
586 git -c diff.cdiff.process="$BACKEND --mode=oid-empty --log=backend.log" \
587 log -1 --format= --numstat -- empty.c >actual &&
588 printf "2\t0\tempty.c\n" >expect &&
589 test_cmp expect actual &&
590 test_grep "command=hunks-by-oid pathname=empty.c" backend.log
591 '
592
593 test_done