[PATCH] Additional git-rev-list unit tests to demonstrate problems that require fixes
[git.git] / t / t6001-rev-list-merge-order.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Jon Seymour
4 #
5
6 test_description='Tests git-rev-list --merge-order functionality'
7
8 . ./test-lib.sh
9
10 #
11 # TODO: move the following block (upto --- end ...) into testlib.sh
12 #
13 [ -d .git/refs/tags ] || mkdir -p .git/refs/tags
14
15 sed_script="";
16
17 # Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
18 tag()
19 {
20         _tag=$1
21         [ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
22         cat .git/refs/tags/$_tag
23 }
24
25 # Generate a commit using the text specified to make it unique and the tree
26 # named by the tag specified.
27 unique_commit()
28 {
29         _text=$1
30         _tree=$2
31         shift 2
32         echo $_text | git-commit-tree $(tag $_tree) "$@"
33 }
34
35 # Save the output of a command into the tag specified. Prepend
36 # a substitution script for the tag onto the front of $sed_script
37 save_tag()
38 {
39         _tag=$1 
40         [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
41         shift 1
42         "$@" >.git/refs/tags/$_tag
43         sed_script="s/$(tag $_tag)/$_tag/g${sed_script+;}$sed_script"
44 }
45
46 # Replace unhelpful sha1 hashses with their symbolic equivalents 
47 entag()
48 {
49         sed "$sed_script"
50 }
51
52 # Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
53 # tag to a specified value. Restore the original value on return.
54 as_author()
55 {
56         _author=$1
57         shift 1
58         _save=$GIT_AUTHOR_EMAIL
59
60         export GIT_AUTHOR_EMAIL="$_author"
61         "$@"
62         export GIT_AUTHOR_EMAIL="$_save"
63 }
64
65 commit_date()
66 {
67         _commit=$1
68         git-cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" 
69 }
70
71 on_committer_date()
72 {
73     _date=$1
74     shift 1
75     GIT_COMMITTER_DATE=$_date "$@"
76 }
77
78 # Execute a command and suppress any error output.
79 hide_error()
80 {
81         "$@" 2>/dev/null
82 }
83
84 check_output()
85 {
86         _name=$1
87         shift 1
88         if "$@" | entag > $_name.actual
89         then
90                 diff $_name.expected $_name.actual
91         else
92                 return 1;
93         fi
94         
95 }
96
97 # Turn a reasonable test description into a reasonable test name.
98 # All alphanums translated into -'s which are then compressed and stripped
99 # from front and back.
100 name_from_description()
101 {
102         tr "'" '-' | tr '~`!@#$%^&*()_+={}[]|\;:"<>,/? ' '-' | tr -s '-' | tr '[A-Z]' '[a-z]' | sed "s/^-*//;s/-*\$//"
103 }
104
105
106 # Execute the test described by the first argument, by eval'ing
107 # command line specified in the 2nd argument. Check the status code
108 # is zero and that the output matches the stream read from 
109 # stdin.
110 test_output_expect_success()
111 {       
112         _description=$1
113         _test=$2
114         [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
115         _name=$(echo $_description | name_from_description)
116         cat > $_name.expected
117         test_expect_success "$_description" "check_output $_name $_test" 
118 }
119
120 # --- end of stuff to move ---
121
122 # test-case specific test function
123 check_adjacency()
124 {
125     read previous
126     echo "= $previous"
127     while read next
128     do
129         if ! (git-cat-file commit $previous | grep "^parent $next" >/dev/null)
130         then
131             echo "^ $next"
132         else
133             echo "| $next"
134         fi
135         previous=$next
136     done
137 }
138
139 list_duplicates()
140 {
141     "$@" | sort | uniq -d
142 }
143
144 grep_stderr()
145 {
146     args=$1
147     shift 1
148     "$@" 2>&1 | grep "$args"
149 }
150
151 date >path0
152 git-update-cache --add path0
153 save_tag tree git-write-tree
154 on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
155 on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
156 on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
157 on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
158 on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
159 on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
160 on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
161 on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
162 on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
163 on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
164 on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
165 on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
166 on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
167 on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
168 on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
169 on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
170 on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
171 on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
172 on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
173 on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
174 on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
175 #
176 # note: as of 20/6, it isn't possible to create duplicate parents, so this
177 # can't be tested.
178 #
179 #on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
180 hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
181 save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
182 save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
183 save_tag e3 as_author e@example.com unique_commit e3 tree -p e2
184 save_tag f2 as_author f@example.com unique_commit f2 tree -p f1
185 save_tag e4 as_author e@example.com unique_commit e4 tree -p e3 -p f2
186 save_tag e5 as_author e@example.com unique_commit e5 tree -p e4
187 save_tag f3 as_author f@example.com unique_commit f3 tree -p f2
188 save_tag f4 as_author f@example.com unique_commit f4 tree -p f3
189 save_tag e6 as_author e@example.com unique_commit e6 tree -p e5 -p f4
190 save_tag f5 as_author f@example.com unique_commit f5 tree -p f4
191 save_tag f6 as_author f@example.com unique_commit f6 tree -p f5 -p e6
192 save_tag e7 as_author e@example.com unique_commit e7 tree -p e6
193 save_tag e8 as_author e@example.com unique_commit e8 tree -p e7
194 save_tag e9 as_author e@example.com unique_commit e9 tree -p e8
195 save_tag f7 as_author f@example.com unique_commit f7 tree -p f6
196 save_tag f8 as_author f@example.com unique_commit f8 tree -p f7
197 save_tag f9 as_author f@example.com unique_commit f9 tree -p f8
198 save_tag e10 as_author e@example.com unique_commit e1 tree -p e9 -p f8
199
200 hide_error save_tag g0 unique_commit g0 tree
201 save_tag g1 unique_commit g1 tree -p g0
202 save_tag h1 unique_commit g2 tree -p g0
203 save_tag g2 unique_commit g3 tree -p g1 -p h1
204 save_tag h2 unique_commit g4 tree -p g2
205 save_tag g3 unique_commit g5 tree -p g2
206 save_tag g4 unique_commit g6 tree -p g3 -p h2
207
208 tag l5 > .git/HEAD
209
210 #
211 # cd to t/trash and use 
212 #
213 #    git-rev-list ... 2>&1 | sed "$(cat sed.script)" 
214 #
215 # if you ever want to manually debug the operation of git-rev-list
216 #
217 echo $sed_script > sed.script
218
219 test_expect_success 'rev-list has correct number of entries' 'git-rev-list HEAD | wc -l | tr -s " "' <<EOF
220 19
221 EOF
222
223 normal_adjacency_count=$(git-rev-list HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
224 merge_order_adjacency_count=$(git-rev-list --merge-order HEAD | check_adjacency | grep -c "\^" | tr -d ' ')
225 test_expect_success '--merge-order produces as many or fewer discontinuities' '[ $merge_order_adjacency_count -le $normal_adjacency_count ]'
226 test_output_expect_success 'simple merge order' 'git-rev-list --merge-order --show-breaks HEAD' <<EOF
227 = l5
228 | l4
229 | l3
230 = a4
231 | c3
232 | c2
233 | c1
234 ^ b4
235 | b3
236 | b2
237 | b1
238 ^ a3
239 | a2
240 | a1
241 = a0
242 | l2
243 | l1
244 | l0
245 = root
246 EOF
247
248 test_output_expect_success 'two diamonds merge order (g6)' 'git-rev-list --merge-order --show-breaks g4' <<EOF
249 = g4
250 | h2
251 ^ g3
252 = g2
253 | h1
254 ^ g1
255 = g0
256 EOF
257
258 test_output_expect_success 'multiple heads' 'git-rev-list --merge-order a3 b3 c3' <<EOF
259 c3
260 c2
261 c1
262 b3
263 b2
264 b1
265 a3
266 a2
267 a1
268 a0
269 l2
270 l1
271 l0
272 root
273 EOF
274
275 test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --merge-order a3 b3 c3 ^a1' <<EOF
276 c3
277 c2
278 c1
279 b3
280 b2
281 b1
282 a3
283 a2
284 EOF
285
286 test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --merge-order a3 b3 c3 ^l1' <<EOF
287 c3
288 c2
289 c1
290 b3
291 b2
292 b1
293 a3
294 a2
295 a1
296 a0
297 l2
298 EOF
299
300 test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git-rev-list --merge-order l5 ^l1' <<EOF
301 l5
302 l4
303 l3
304 a4
305 c3
306 c2
307 c1
308 b4
309 b3
310 b2
311 b1
312 a3
313 a2
314 a1
315 a0
316 l2
317 EOF
318
319 test_output_expect_success 'duplicated head arguments' 'git-rev-list --merge-order l5 l5 ^l1' <<EOF
320 l5
321 l4
322 l3
323 a4
324 c3
325 c2
326 c1
327 b4
328 b3
329 b2
330 b1
331 a3
332 a2
333 a1
334 a0
335 l2
336 EOF
337
338 test_output_expect_success 'prune near merge' 'git-rev-list --merge-order a4 ^c3' <<EOF
339 a4
340 b4
341 b3
342 a3
343 a2
344 a1
345 EOF
346
347 test_output_expect_success "head has no parent" 'git-rev-list --merge-order --show-breaks root' <<EOF
348 = root
349 EOF
350
351 test_output_expect_success "two nodes - one head, one base" 'git-rev-list --merge-order --show-breaks l0' <<EOF
352 = l0
353 = root
354 EOF
355
356 test_output_expect_success "three nodes one head, one internal, one base" 'git-rev-list --merge-order --show-breaks l1' <<EOF
357 = l1
358 | l0
359 = root
360 EOF
361
362 test_output_expect_success "linear prune l2 ^root" 'git-rev-list --merge-order --show-breaks l2 ^root' <<EOF
363 = l2
364 | l1
365 | l0
366 EOF
367
368 test_output_expect_success "linear prune l2 ^l0" 'git-rev-list --merge-order --show-breaks l2 ^l0' <<EOF
369 = l2
370 | l1
371 EOF
372
373 test_output_expect_success "linear prune l2 ^l1" 'git-rev-list --merge-order --show-breaks l2 ^l1' <<EOF
374 = l2
375 EOF
376
377 test_output_expect_success "linear prune l5 ^a4" 'git-rev-list --merge-order --show-breaks l5 ^a4' <<EOF
378 = l5
379 | l4
380 | l3
381 EOF
382
383 test_output_expect_success "linear prune l5 ^l3" 'git-rev-list --merge-order --show-breaks l5 ^l3' <<EOF
384 = l5
385 | l4
386 EOF
387
388 test_output_expect_success "linear prune l5 ^l4" 'git-rev-list --merge-order --show-breaks l5 ^l4' <<EOF
389 = l5
390 EOF
391
392 test_output_expect_success "max-count 10 - merge order" 'git-rev-list --merge-order --show-breaks --max-count=10 l5' <<EOF
393 = l5
394 | l4
395 | l3
396 = a4
397 | c3
398 | c2
399 | c1
400 ^ b4
401 | b3
402 | b2
403 EOF
404
405 test_output_expect_success "max-count 10 - non merge order" 'git-rev-list --max-count=10 l5 | sort' <<EOF
406 a4
407 b2
408 b3
409 b4
410 c1
411 c2
412 c3
413 l3
414 l4
415 l5
416 EOF
417
418 test_output_expect_success '--max-age=c3, no --merge-order' "git-rev-list --max-age=$(commit_date c3) l5" <<EOF
419 l5
420 l4
421 l3
422 a4
423 b4
424 a3
425 a2
426 c3
427 EOF
428
429 test_output_expect_success '--max-age=c3, --merge-order' "git-rev-list --merge-order --max-age=$(commit_date c3) l5" <<EOF
430 l5
431 l4
432 l3
433 a4
434 c3
435 b4
436 a3
437 a2
438 EOF
439
440 test_output_expect_success 'one specified head reachable from another a4, c3, --merge-order' "list_duplicates git-rev-list --merge-order a4 c3" <<EOF
441 EOF
442
443 test_output_expect_success 'one specified head reachable from another c3, a4, --merge-order' "list_duplicates git-rev-list --merge-order c3 a4" <<EOF
444 EOF
445
446 test_output_expect_success 'one specified head reachable from another a4, c3, no --merge-order' "list_duplicates git-rev-list a4 c3" <<EOF
447 EOF
448
449 test_output_expect_success 'one specified head reachable from another c3, a4, no --merge-order' "list_duplicates git-rev-list c3 a4" <<EOF
450 EOF
451
452 test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git-rev-list m1" <<EOF
453 EOF
454
455 test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git-rev-list m2" <<EOF
456 EOF
457
458 test_expect_success "head ^head --merge-order" 'git-rev-list --merge-order --show-breaks a3 ^a3' <<EOF
459 EOF
460
461 #
462 # can't test this now - duplicate parents can't be created
463 #
464 #test_output_expect_success 'duplicate parents' 'git-rev-list --parents --merge-order --show-breaks m3' <<EOF
465 #= m3 c3 a4 c3
466 #| a4 c3 b4 a3
467 #| b4 a3 b3
468 #| b3 b2
469 #^ a3 a2
470 #| a2 a1
471 #| a1 a0
472 #^ c3 c2
473 #| c2 b2 c1
474 #| b2 b1
475 #^ c1 b1
476 #| b1 a0
477 #= a0 l2
478 #| l2 l1
479 #| l1 l0
480 #| l0 root
481 #= root
482 #EOF
483
484 test_expect_success "head ^head no --merge-order" 'git-rev-list a3 ^a3' <<EOF
485 EOF
486 #
487 #
488
489 test_done