1module apply23import src.snapshot45fn entry(path string, hash string) snapshot.FileEntry {6 return snapshot.FileEntry{7 path: path8 hash: hash9 }10}1112fn hashes(files []snapshot.FileEntry) map[string]string {13 mut out := map[string]string{}14 for file in files {15 out[file.path] = file.hash16 }17 return out18}1920fn test_clean_apply_takes_the_new_content() {21 current := [entry('a.txt', 'aaa'), entry('b.txt', 'bbb')]22 base := [entry('a.txt', 'aaa'), entry('b.txt', 'bbb')]23 target := [entry('a.txt', 'AAA'), entry('b.txt', 'bbb')]2425 plan := three_way(current, base, target, [], [])26 assert !conflicts(plan)27 assert plan.applied == ['a.txt']28 assert hashes(plan.files) == {29 'a.txt': 'AAA'30 'b.txt': 'bbb'31 }32}3334fn test_already_applied_is_left_alone() {35 current := [entry('a.txt', 'AAA')]36 base := [entry('a.txt', 'aaa')]37 target := [entry('a.txt', 'AAA')]3839 plan := three_way(current, base, target, [], [])40 assert !conflicts(plan)41 assert plan.applied.len == 042 assert hashes(plan.files) == {43 'a.txt': 'AAA'44 }45}4647fn test_a_file_the_user_has_since_edited_is_a_hard_conflict() {48 current := [entry('a.txt', 'mine')]49 base := [entry('a.txt', 'aaa')]50 target := [entry('a.txt', 'theirs')]5152 plan := three_way(current, base, target, [], [])53 assert conflicts(plan)54 assert plan.conflict == 'a.txt'55}5657fn test_additions_removals_and_untouched_paths() {58 current := [entry('kept.txt', 'keep'), entry('gone.txt', 'bye')]59 base := [entry('gone.txt', 'bye')]60 target := [entry('added.txt', 'new')]6162 plan := three_way(current, base, target, [], [])63 assert !conflicts(plan)64 assert plan.applied == ['added.txt', 'gone.txt']65 assert hashes(plan.files) == {66 'added.txt': 'new'67 'kept.txt': 'keep'68 }69}7071fn test_filters_limit_the_change_to_paths_or_folders() {72 current := [entry('src/a.txt', 'aaa'), entry('docs/b.txt', 'bbb')]73 base := [entry('src/a.txt', 'aaa'), entry('docs/b.txt', 'bbb')]74 target := [entry('src/a.txt', 'AAA'), entry('docs/b.txt', 'BBB')]7576 plan := three_way(current, base, target, ['src'], [])77 assert plan.applied == ['src/a.txt']78 assert hashes(plan.files) == {79 'src/a.txt': 'AAA'80 'docs/b.txt': 'bbb'81 }8283 84 85 plan2 := three_way(current, base, target, ['docs/'], [])86 assert plan2.applied == ['docs/b.txt']87}8889fn test_reverse_is_the_same_engine_with_the_sides_swapped() {90 91 92 current := [entry('a.txt', 'AAA')]93 original := [entry('a.txt', 'aaa')]94 changed := [entry('a.txt', 'AAA')]9596 forward := three_way(current, original, changed, [], [])97 assert forward.applied.len == 09899 back := three_way(current, changed, original, [], [])100 assert !conflicts(back)101 assert hashes(back.files) == {102 'a.txt': 'aaa'103 }104}105106fn test_executable_bit_counts_as_a_change() {107 current := [snapshot.FileEntry{108 path: 'run.sh'109 hash: 'same'110 }]111 base := [snapshot.FileEntry{112 path: 'run.sh'113 hash: 'same'114 }]115 target := [116 snapshot.FileEntry{117 path: 'run.sh'118 hash: 'same'119 executable: true120 },121 ]122123 plan := three_way(current, base, target, [], [])124 assert !conflicts(plan)125 assert plan.applied == ['run.sh']126 assert plan.files[0].executable127}