directory rename detection: miscellaneous testcases to complete coverage
I came up with the testcases in the first eight sections before coding up the implementation. The testcases in this section were mostly ones I thought of while coding/debugging, and which I was too lazy to insert into the previous sections because I didn't want to re-label with all the testcase references. :-) Reviewed-by: Stefan Beller <sbeller@google.com> Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Apr 19, 2018 at 10:57 UTC
792e1371d9d10100a7b05bb96efcee96dd03bc43
1 file changed
+564
-1
t/t6043-merge-rename-directories.sh
+564
-1
@@ -305,6 +305,7 @@ test_expect_failure '1d-check: Directory renames cause a rename/rename(2to1) con
305
'
306
307
# Testcase 1e, Renamed directory, with all filenames being renamed too
308
+# (Related to testcases 9f & 9g)
309
# Commit O: z/{oldb,oldc}
310
# Commit A: y/{newb,newc}
311
# Commit B: z/{oldb,oldc,d}
@@ -593,7 +594,7 @@ test_expect_success '2b-check: Directory split into two on one side, with equal
594
###########################################################################
595
596
# Testcase 3a, Avoid implicit rename if involved as source on other side
596
-# (Related to testcases 1c and 1f)
597
+# (Related to testcases 1c, 1f, and 9h)
598
# Commit O: z/{b,c,d}
599
# Commit A: z/{b,c,d} (no change)
600
# Commit B: y/{b,c}, x/d
@@ -2316,4 +2317,566 @@ test_expect_failure '8e-check: Both sides rename, one side adds to original dire
2317
)
2318
'
2319
2320
+###########################################################################
2321
+# SECTION 9: Other testcases
2322
+#
2323
+# This section consists of miscellaneous testcases I thought of during
2324
+# the implementation which round out the testing.
2325
+###########################################################################
2326
+
2327
+# Testcase 9a, Inner renamed directory within outer renamed directory
2328
+# (Related to testcase 1f)
2329
+# Commit O: z/{b,c,d/{e,f,g}}
2330
+# Commit A: y/{b,c}, x/w/{e,f,g}
2331
+# Commit B: z/{b,c,d/{e,f,g,h},i}
2332
+# Expected: y/{b,c,i}, x/w/{e,f,g,h}
2333
+# NOTE: The only reason this one is interesting is because when a directory
2334
+# is split into multiple other directories, we determine by the weight
2335
+# of which one had the most paths going to it. A naive implementation
2336
+# of that could take the new file in commit B at z/i to x/w/i or x/i.
2337
+
2338
+test_expect_success '9a-setup: Inner renamed directory within outer renamed directory' '
2339
+ test_create_repo 9a &&
2340
+ (
2341
+ cd 9a &&
2342
+
2343
+ mkdir -p z/d &&
2344
+ echo b >z/b &&
2345
+ echo c >z/c &&
2346
+ echo e >z/d/e &&
2347
+ echo f >z/d/f &&
2348
+ echo g >z/d/g &&
2349
+ git add z &&
2350
+ test_tick &&
2351
+ git commit -m "O" &&
2352
+
2353
+ git branch O &&
2354
+ git branch A &&
2355
+ git branch B &&
2356
+
2357
+ git checkout A &&
2358
+ mkdir x &&
2359
+ git mv z/d x/w &&
2360
+ git mv z y &&
2361
+ test_tick &&
2362
+ git commit -m "A" &&
2363
+
2364
+ git checkout B &&
2365
+ echo h >z/d/h &&
2366
+ echo i >z/i &&
2367
+ git add z &&
2368
+ test_tick &&
2369
+ git commit -m "B"
2370
+ )
2371
+'
2372
+
2373
+test_expect_failure '9a-check: Inner renamed directory within outer renamed directory' '
2374
+ (
2375
+ cd 9a &&
2376
+
2377
+ git checkout A^0 &&
2378
+
2379
+ git merge -s recursive B^0 &&
2380
+
2381
+ git ls-files -s >out &&
2382
+ test_line_count = 7 out &&
2383
+ git ls-files -u >out &&
2384
+ test_line_count = 0 out &&
2385
+ git ls-files -o >out &&
2386
+ test_line_count = 1 out &&
2387
+
2388
+ git rev-parse >actual \
2389
+ HEAD:y/b HEAD:y/c HEAD:y/i &&
2390
+ git rev-parse >expect \
2391
+ O:z/b O:z/c B:z/i &&
2392
+ test_cmp expect actual &&
2393
+
2394
+ git rev-parse >actual \
2395
+ HEAD:x/w/e HEAD:x/w/f HEAD:x/w/g HEAD:x/w/h &&
2396
+ git rev-parse >expect \
2397
+ O:z/d/e O:z/d/f O:z/d/g B:z/d/h &&
2398
+ test_cmp expect actual
2399
+ )
2400
+'
2401
+
2402
+# Testcase 9b, Transitive rename with content merge
2403
+# (Related to testcase 1c)
2404
+# Commit O: z/{b,c}, x/d_1
2405
+# Commit A: y/{b,c}, x/d_2
2406
+# Commit B: z/{b,c,d_3}
2407
+# Expected: y/{b,c,d_merged}
2408
+
2409
+test_expect_success '9b-setup: Transitive rename with content merge' '
2410
+ test_create_repo 9b &&
2411
+ (
2412
+ cd 9b &&
2413
+
2414
+ mkdir z &&
2415
+ echo b >z/b &&
2416
+ echo c >z/c &&
2417
+ mkdir x &&
2418
+ test_seq 1 10 >x/d &&
2419
+ git add z x &&
2420
+ test_tick &&
2421
+ git commit -m "O" &&
2422
+
2423
+ git branch O &&
2424
+ git branch A &&
2425
+ git branch B &&
2426
+
2427
+ git checkout A &&
2428
+ git mv z y &&
2429
+ test_seq 1 11 >x/d &&
2430
+ git add x/d &&
2431
+ test_tick &&
2432
+ git commit -m "A" &&
2433
+
2434
+ git checkout B &&
2435
+ test_seq 0 10 >x/d &&
2436
+ git mv x/d z/d &&
2437
+ git add z/d &&
2438
+ test_tick &&
2439
+ git commit -m "B"
2440
+ )
2441
+'
2442
+
2443
+test_expect_failure '9b-check: Transitive rename with content merge' '
2444
+ (
2445
+ cd 9b &&
2446
+
2447
+ git checkout A^0 &&
2448
+
2449
+ git merge -s recursive B^0 &&
2450
+
2451
+ git ls-files -s >out &&
2452
+ test_line_count = 3 out &&
2453
+
2454
+ test_seq 0 11 >expected &&
2455
+ test_cmp expected y/d &&
2456
+ git add expected &&
2457
+ git rev-parse >actual \
2458
+ HEAD:y/b HEAD:y/c HEAD:y/d &&
2459
+ git rev-parse >expect \
2460
+ O:z/b O:z/c :0:expected &&
2461
+ test_cmp expect actual &&
2462
+ test_must_fail git rev-parse HEAD:x/d &&
2463
+ test_must_fail git rev-parse HEAD:z/d &&
2464
+ test_path_is_missing z/d &&
2465
+
2466
+ test $(git rev-parse HEAD:y/d) != $(git rev-parse O:x/d) &&
2467
+ test $(git rev-parse HEAD:y/d) != $(git rev-parse A:x/d) &&
2468
+ test $(git rev-parse HEAD:y/d) != $(git rev-parse B:z/d)
2469
+ )
2470
+'
2471
+
2472
+# Testcase 9c, Doubly transitive rename?
2473
+# (Related to testcase 1c, 7e, and 9d)
2474
+# Commit O: z/{b,c}, x/{d,e}, w/f
2475
+# Commit A: y/{b,c}, x/{d,e,f,g}
2476
+# Commit B: z/{b,c,d,e}, w/f
2477
+# Expected: y/{b,c,d,e}, x/{f,g}
2478
+#
2479
+# NOTE: x/f and x/g may be slightly confusing here. The rename from w/f to
2480
+# x/f is clear. Let's look beyond that. Here's the logic:
2481
+# Commit B renamed x/ -> z/
2482
+# Commit A renamed z/ -> y/
2483
+# So, we could possibly further rename x/f to z/f to y/f, a doubly
2484
+# transient rename. However, where does it end? We can chain these
2485
+# indefinitely (see testcase 9d). What if there is a D/F conflict
2486
+# at z/f/ or y/f/? Or just another file conflict at one of those
2487
+# paths? In the case of an N-long chain of transient renamings,
2488
+# where do we "abort" the rename at? Can the user make sense of
2489
+# the resulting conflict and resolve it?
2490
+#
2491
+# To avoid this confusion I use the simple rule that if the other side
2492
+# of history did a directory rename to a path that your side renamed
2493
+# away, then ignore that particular rename from the other side of
2494
+# history for any implicit directory renames.
2495
+
2496
+test_expect_success '9c-setup: Doubly transitive rename?' '
2497
+ test_create_repo 9c &&
2498
+ (
2499
+ cd 9c &&
2500
+
2501
+ mkdir z &&
2502
+ echo b >z/b &&
2503
+ echo c >z/c &&
2504
+ mkdir x &&
2505
+ echo d >x/d &&
2506
+ echo e >x/e &&
2507
+ mkdir w &&
2508
+ echo f >w/f &&
2509
+ git add z x w &&
2510
+ test_tick &&
2511
+ git commit -m "O" &&
2512
+
2513
+ git branch O &&
2514
+ git branch A &&
2515
+ git branch B &&
2516
+
2517
+ git checkout A &&
2518
+ git mv z y &&
2519
+ git mv w/f x/ &&
2520
+ echo g >x/g &&
2521
+ git add x/g &&
2522
+ test_tick &&
2523
+ git commit -m "A" &&
2524
+
2525
+ git checkout B &&
2526
+ git mv x/d z/d &&
2527
+ git mv x/e z/e &&
2528
+ test_tick &&
2529
+ git commit -m "B"
2530
+ )
2531
+'
2532
+
2533
+test_expect_failure '9c-check: Doubly transitive rename?' '
2534
+ (
2535
+ cd 9c &&
2536
+
2537
+ git checkout A^0 &&
2538
+
2539
+ git merge -s recursive B^0 >out &&
2540
+ test_i18ngrep "WARNING: Avoiding applying x -> z rename to x/f" out &&
2541
+
2542
+ git ls-files -s >out &&
2543
+ test_line_count = 6 out &&
2544
+ git ls-files -o >out &&
2545
+ test_line_count = 1 out &&
2546
+
2547
+ git rev-parse >actual \
2548
+ HEAD:y/b HEAD:y/c HEAD:y/d HEAD:y/e HEAD:x/f HEAD:x/g &&
2549
+ git rev-parse >expect \
2550
+ O:z/b O:z/c O:x/d O:x/e O:w/f A:x/g &&
2551
+ test_cmp expect actual
2552
+ )
2553
+'
2554
+
2555
+# Testcase 9d, N-fold transitive rename?
2556
+# (Related to testcase 9c...and 1c and 7e)
2557
+# Commit O: z/a, y/b, x/c, w/d, v/e, u/f
2558
+# Commit A: y/{a,b}, w/{c,d}, u/{e,f}
2559
+# Commit B: z/{a,t}, x/{b,c}, v/{d,e}, u/f
2560
+# Expected: <see NOTE first>
2561
+#
2562
+# NOTE: z/ -> y/ (in commit A)
2563
+# y/ -> x/ (in commit B)
2564
+# x/ -> w/ (in commit A)
2565
+# w/ -> v/ (in commit B)
2566
+# v/ -> u/ (in commit A)
2567
+# So, if we add a file to z, say z/t, where should it end up? In u?
2568
+# What if there's another file or directory named 't' in one of the
2569
+# intervening directories and/or in u itself? Also, shouldn't the
2570
+# same logic that places 't' in u/ also move ALL other files to u/?
2571
+# What if there are file or directory conflicts in any of them? If
2572
+# we attempted to do N-way (N-fold? N-ary? N-uple?) transitive renames
2573
+# like this, would the user have any hope of understanding any
2574
+# conflicts or how their working tree ended up? I think not, so I'm
2575
+# ruling out N-ary transitive renames for N>1.
2576
+#
2577
+# Therefore our expected result is:
2578
+# z/t, y/a, x/b, w/c, u/d, u/e, u/f
2579
+# The reason that v/d DOES get transitively renamed to u/d is that u/ isn't
2580
+# renamed somewhere. A slightly sub-optimal result, but it uses fairly
2581
+# simple rules that are consistent with what we need for all the other
2582
+# testcases and simplifies things for the user.
2583
+
2584
+test_expect_success '9d-setup: N-way transitive rename?' '
2585
+ test_create_repo 9d &&
2586
+ (
2587
+ cd 9d &&
2588
+
2589
+ mkdir z y x w v u &&
2590
+ echo a >z/a &&
2591
+ echo b >y/b &&
2592
+ echo c >x/c &&
2593
+ echo d >w/d &&
2594
+ echo e >v/e &&
2595
+ echo f >u/f &&
2596
+ git add z y x w v u &&
2597
+ test_tick &&
2598
+ git commit -m "O" &&
2599
+
2600
+ git branch O &&
2601
+ git branch A &&
2602
+ git branch B &&
2603
+
2604
+ git checkout A &&
2605
+ git mv z/a y/ &&
2606
+ git mv x/c w/ &&
2607
+ git mv v/e u/ &&
2608
+ test_tick &&
2609
+ git commit -m "A" &&
2610
+
2611
+ git checkout B &&
2612
+ echo t >z/t &&
2613
+ git mv y/b x/ &&
2614
+ git mv w/d v/ &&
2615
+ git add z/t &&
2616
+ test_tick &&
2617
+ git commit -m "B"
2618
+ )
2619
+'
2620
+
2621
+test_expect_failure '9d-check: N-way transitive rename?' '
2622
+ (
2623
+ cd 9d &&
2624
+
2625
+ git checkout A^0 &&
2626
+
2627
+ git merge -s recursive B^0 >out &&
2628
+ test_i18ngrep "WARNING: Avoiding applying z -> y rename to z/t" out &&
2629
+ test_i18ngrep "WARNING: Avoiding applying y -> x rename to y/a" out &&
2630
+ test_i18ngrep "WARNING: Avoiding applying x -> w rename to x/b" out &&
2631
+ test_i18ngrep "WARNING: Avoiding applying w -> v rename to w/c" out &&
2632
+
2633
+ git ls-files -s >out &&
2634
+ test_line_count = 7 out &&
2635
+ git ls-files -o >out &&
2636
+ test_line_count = 1 out &&
2637
+
2638
+ git rev-parse >actual \
2639
+ HEAD:z/t \
2640
+ HEAD:y/a HEAD:x/b HEAD:w/c \
2641
+ HEAD:u/d HEAD:u/e HEAD:u/f &&
2642
+ git rev-parse >expect \
2643
+ B:z/t \
2644
+ O:z/a O:y/b O:x/c \
2645
+ O:w/d O:v/e A:u/f &&
2646
+ test_cmp expect actual
2647
+ )
2648
+'
2649
+
2650
+# Testcase 9e, N-to-1 whammo
2651
+# (Related to testcase 9c...and 1c and 7e)
2652
+# Commit O: dir1/{a,b}, dir2/{d,e}, dir3/{g,h}, dirN/{j,k}
2653
+# Commit A: dir1/{a,b,c,yo}, dir2/{d,e,f,yo}, dir3/{g,h,i,yo}, dirN/{j,k,l,yo}
2654
+# Commit B: combined/{a,b,d,e,g,h,j,k}
2655
+# Expected: combined/{a,b,c,d,e,f,g,h,i,j,k,l}, CONFLICT(Nto1) warnings,
2656
+# dir1/yo, dir2/yo, dir3/yo, dirN/yo
2657
+
2658
+test_expect_success '9e-setup: N-to-1 whammo' '
2659
+ test_create_repo 9e &&
2660
+ (
2661
+ cd 9e &&
2662
+
2663
+ mkdir dir1 dir2 dir3 dirN &&
2664
+ echo a >dir1/a &&
2665
+ echo b >dir1/b &&
2666
+ echo d >dir2/d &&
2667
+ echo e >dir2/e &&
2668
+ echo g >dir3/g &&
2669
+ echo h >dir3/h &&
2670
+ echo j >dirN/j &&
2671
+ echo k >dirN/k &&
2672
+ git add dir* &&
2673
+ test_tick &&
2674
+ git commit -m "O" &&
2675
+
2676
+ git branch O &&
2677
+ git branch A &&
2678
+ git branch B &&
2679
+
2680
+ git checkout A &&
2681
+ echo c >dir1/c &&
2682
+ echo yo >dir1/yo &&
2683
+ echo f >dir2/f &&
2684
+ echo yo >dir2/yo &&
2685
+ echo i >dir3/i &&
2686
+ echo yo >dir3/yo &&
2687
+ echo l >dirN/l &&
2688
+ echo yo >dirN/yo &&
2689
+ git add dir* &&
2690
+ test_tick &&
2691
+ git commit -m "A" &&
2692
+
2693
+ git checkout B &&
2694
+ git mv dir1 combined &&
2695
+ git mv dir2/* combined/ &&
2696
+ git mv dir3/* combined/ &&
2697
+ git mv dirN/* combined/ &&
2698
+ test_tick &&
2699
+ git commit -m "B"
2700
+ )
2701
+'
2702
+
2703
+test_expect_failure C_LOCALE_OUTPUT '9e-check: N-to-1 whammo' '
2704
+ (
2705
+ cd 9e &&
2706
+
2707
+ git checkout A^0 &&
2708
+
2709
+ test_must_fail git merge -s recursive B^0 >out &&
2710
+ grep "CONFLICT (implicit dir rename): Cannot map more than one path to combined/yo" out >error_line &&
2711
+ grep -q dir1/yo error_line &&
2712
+ grep -q dir2/yo error_line &&
2713
+ grep -q dir3/yo error_line &&
2714
+ grep -q dirN/yo error_line &&
2715
+
2716
+ git ls-files -s >out &&
2717
+ test_line_count = 16 out &&
2718
+ git ls-files -u >out &&
2719
+ test_line_count = 0 out &&
2720
+ git ls-files -o >out &&
2721
+ test_line_count = 2 out &&
2722
+
2723
+ git rev-parse >actual \
2724
+ :0:combined/a :0:combined/b :0:combined/c \
2725
+ :0:combined/d :0:combined/e :0:combined/f \
2726
+ :0:combined/g :0:combined/h :0:combined/i \
2727
+ :0:combined/j :0:combined/k :0:combined/l &&
2728
+ git rev-parse >expect \
2729
+ O:dir1/a O:dir1/b A:dir1/c \
2730
+ O:dir2/d O:dir2/e A:dir2/f \
2731
+ O:dir3/g O:dir3/h A:dir3/i \
2732
+ O:dirN/j O:dirN/k A:dirN/l &&
2733
+ test_cmp expect actual &&
2734
+
2735
+ git rev-parse >actual \
2736
+ :0:dir1/yo :0:dir2/yo :0:dir3/yo :0:dirN/yo &&
2737
+ git rev-parse >expect \
2738
+ A:dir1/yo A:dir2/yo A:dir3/yo A:dirN/yo &&
2739
+ test_cmp expect actual
2740
+ )
2741
+'
2742
+
2743
+# Testcase 9f, Renamed directory that only contained immediate subdirs
2744
+# (Related to testcases 1e & 9g)
2745
+# Commit O: goal/{a,b}/$more_files
2746
+# Commit A: priority/{a,b}/$more_files
2747
+# Commit B: goal/{a,b}/$more_files, goal/c
2748
+# Expected: priority/{a,b}/$more_files, priority/c
2749
+
2750
+test_expect_success '9f-setup: Renamed directory that only contained immediate subdirs' '
2751
+ test_create_repo 9f &&
2752
+ (
2753
+ cd 9f &&
2754
+
2755
+ mkdir -p goal/a &&
2756
+ mkdir -p goal/b &&
2757
+ echo foo >goal/a/foo &&
2758
+ echo bar >goal/b/bar &&
2759
+ echo baz >goal/b/baz &&
2760
+ git add goal &&
2761
+ test_tick &&
2762
+ git commit -m "O" &&
2763
+
2764
+ git branch O &&
2765
+ git branch A &&
2766
+ git branch B &&
2767
+
2768
+ git checkout A &&
2769
+ git mv goal/ priority &&
2770
+ test_tick &&
2771
+ git commit -m "A" &&
2772
+
2773
+ git checkout B &&
2774
+ echo c >goal/c &&
2775
+ git add goal/c &&
2776
+ test_tick &&
2777
+ git commit -m "B"
2778
+ )
2779
+'
2780
+
2781
+test_expect_failure '9f-check: Renamed directory that only contained immediate subdirs' '
2782
+ (
2783
+ cd 9f &&
2784
+
2785
+ git checkout A^0 &&
2786
+
2787
+ git merge -s recursive B^0 &&
2788
+
2789
+ git ls-files -s >out &&
2790
+ test_line_count = 4 out &&
2791
+
2792
+ git rev-parse >actual \
2793
+ HEAD:priority/a/foo \
2794
+ HEAD:priority/b/bar \
2795
+ HEAD:priority/b/baz \
2796
+ HEAD:priority/c &&
2797
+ git rev-parse >expect \
2798
+ O:goal/a/foo \
2799
+ O:goal/b/bar \
2800
+ O:goal/b/baz \
2801
+ B:goal/c &&
2802
+ test_cmp expect actual &&
2803
+ test_must_fail git rev-parse HEAD:goal/c
2804
+ )
2805
+'
2806
+
2807
+# Testcase 9g, Renamed directory that only contained immediate subdirs, immediate subdirs renamed
2808
+# (Related to testcases 1e & 9f)
2809
+# Commit O: goal/{a,b}/$more_files
2810
+# Commit A: priority/{alpha,bravo}/$more_files
2811
+# Commit B: goal/{a,b}/$more_files, goal/c
2812
+# Expected: priority/{alpha,bravo}/$more_files, priority/c
2813
+
2814
+test_expect_success '9g-setup: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2815
+ test_create_repo 9g &&
2816
+ (
2817
+ cd 9g &&
2818
+
2819
+ mkdir -p goal/a &&
2820
+ mkdir -p goal/b &&
2821
+ echo foo >goal/a/foo &&
2822
+ echo bar >goal/b/bar &&
2823
+ echo baz >goal/b/baz &&
2824
+ git add goal &&
2825
+ test_tick &&
2826
+ git commit -m "O" &&
2827
+
2828
+ git branch O &&
2829
+ git branch A &&
2830
+ git branch B &&
2831
+
2832
+ git checkout A &&
2833
+ mkdir priority &&
2834
+ git mv goal/a/ priority/alpha &&
2835
+ git mv goal/b/ priority/beta &&
2836
+ rmdir goal/ &&
2837
+ test_tick &&
2838
+ git commit -m "A" &&
2839
+
2840
+ git checkout B &&
2841
+ echo c >goal/c &&
2842
+ git add goal/c &&
2843
+ test_tick &&
2844
+ git commit -m "B"
2845
+ )
2846
+'
2847
+
2848
+test_expect_failure '9g-check: Renamed directory that only contained immediate subdirs, immediate subdirs renamed' '
2849
+ (
2850
+ cd 9g &&
2851
+
2852
+ git checkout A^0 &&
2853
+
2854
+ git merge -s recursive B^0 &&
2855
+
2856
+ git ls-files -s >out &&
2857
+ test_line_count = 4 out &&
2858
+
2859
+ git rev-parse >actual \
2860
+ HEAD:priority/alpha/foo \
2861
+ HEAD:priority/beta/bar \
2862
+ HEAD:priority/beta/baz \
2863
+ HEAD:priority/c &&
2864
+ git rev-parse >expect \
2865
+ O:goal/a/foo \
2866
+ O:goal/b/bar \
2867
+ O:goal/b/baz \
2868
+ B:goal/c &&
2869
+ test_cmp expect actual &&
2870
+ test_must_fail git rev-parse HEAD:goal/c
2871
+ )
2872
+'
2873
+
2874
+###########################################################################
2875
+# Rules suggested by section 9:
2876
+#
2877
+# If the other side of history did a directory rename to a path that your
2878
+# side renamed away, then ignore that particular rename from the other
2879
+# side of history for any implicit directory renames.
2880
+###########################################################################
2881
+
2882
test_done