def test_changes_multiple_parents(self): blob_a1 = make_object(Blob, data='a1') blob_b2 = make_object(Blob, data='b2') blob_a3 = make_object(Blob, data='a3') c1, c2, c3 = self.make_commits( [[1], [2], [3, 1, 2]], trees={1: [('a', blob_a1)], 2: [('b', blob_b2)], 3: [('a', blob_a3), ('b', blob_b2)]}) # a is a modify/add conflict and b is not conflicted. changes = [[ TreeChange(CHANGE_MODIFY, ('a', F, blob_a1.id), ('a', F, blob_a3.id)), TreeChange.add(('a', F, blob_a3.id)), ]] self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id], exclude=[c1.id, c2.id])
def test_all_with_merge(self): blob_a = make_object(Blob, data=b'a') blob_a2 = make_object(Blob, data=b'a2') blob_b = make_object(Blob, data=b'b') blob_b2 = make_object(Blob, data=b'b2') x1, y2, m3 = self.make_commits( [[1], [2], [3, 1, 2]], trees={ 1: [(b'x/a', blob_a)], 2: [(b'y/b', blob_b)], 3: [(b'x/a', blob_a2), (b'y/b', blob_b2)] }) # Get the WalkEntry for the merge commit. walker = Walker(self.store, m3.id) entries = list(walker) walker_entry = entries[0] self.assertEqual(walker_entry.commit.id, m3.id) changes = walker_entry.changes() self.assertEqual(2, len(changes)) entry_a = (b'x/a', F, blob_a.id) entry_a2 = (b'x/a', F, blob_a2.id) entry_b = (b'y/b', F, blob_b.id) entry_b2 = (b'y/b', F, blob_b2.id) self.assertEqual( [[ TreeChange(CHANGE_MODIFY, entry_a, entry_a2), TreeChange.add(entry_a2) ], [ TreeChange.add(entry_b2), TreeChange(CHANGE_MODIFY, entry_b, entry_b2) ]], changes, )
def test_follow_rename_remove_path(self): blob = make_object(Blob, data=b'blob') _, _, _, c4, c5, c6 = self.make_linear_commits(6, trees={ 1: [(b'a', blob), (b'c', blob)], 2: [], 3: [], 4: [(b'b', blob)], 5: [(b'a', blob)], 6: [(b'c', blob)] }) def e(n): return (n, F, blob.id) # Once the path changes to b, we aren't interested in a or c anymore. self.assertWalkYields([ TestWalkEntry(c6, [TreeChange(CHANGE_RENAME, e(b'a'), e(b'c'))]), TestWalkEntry(c5, [TreeChange(CHANGE_RENAME, e(b'b'), e(b'a'))]), TestWalkEntry(c4, [TreeChange.add(e(b'b'))]) ], [c6.id], paths=[b'c'], follow=True)
def test_tree_changes_prune(self): blob_a1 = make_object(Blob, data='a1') blob_a2 = make_object(Blob, data='a2') blob_x = make_object(Blob, data='x') tree1 = self.commit_tree([('a', blob_a1), ('b/x', blob_x)]) tree2 = self.commit_tree([('a', blob_a2), ('b/x', blob_x)]) # Remove identical items so lookups will fail unless we prune. subtree = self.store[tree1['b'][1]] for entry in subtree.iteritems(): del self.store[entry.sha] del self.store[subtree.id] self.assertChangesEqual( [TreeChange(CHANGE_MODIFY, ('a', F, blob_a1.id), ('a', F, blob_a2.id))], tree1, tree2)
def test_tree_changes_for_merge_add_content_rename_conflict(self): blob1 = make_object(Blob, data=b"a\nb\nc\nd\n") blob2 = make_object(Blob, data=b"a\nb\nc\ne\n") parent1 = self.commit_tree([(b"a", blob1)]) parent2 = self.commit_tree([]) merge = self.commit_tree([(b"b", blob2)]) self.assertChangesForMergeEqual( [[ TreeChange(CHANGE_RENAME, (b"a", F, blob1.id), (b"b", F, blob2.id)), TreeChange.add((b"b", F, blob2.id)), ]], [parent1, parent2], merge, rename_detector=self.detector, )
def test_find_copies_harder_content(self): blob1 = make_object(Blob, data=b"a\nb\nc\nd\n") blob2 = make_object(Blob, data=b"a\nb\nc\ne\n") tree1 = self.commit_tree([(b"a", blob1)]) tree2 = self.commit_tree([(b"a", blob1), (b"b", blob2)]) self.assertEqual( [TreeChange.add((b"b", F, blob2.id))], self.detect_renames(tree1, tree2), ) self.assertEqual( [ TreeChange(CHANGE_COPY, (b"a", F, blob1.id), (b"b", F, blob2.id)) ], self.detect_renames(tree1, tree2, find_copies_harder=True), )
def test_changes_one_parent(self): blob_a1 = make_object(Blob, data=b'a1') blob_a2 = make_object(Blob, data=b'a2') blob_b2 = make_object(Blob, data=b'b2') c1, c2 = self.make_linear_commits(2, trees={ 1: [(b'a', blob_a1)], 2: [(b'a', blob_a2), (b'b', blob_b2)] }) e1 = TestWalkEntry(c1, [TreeChange.add((b'a', F, blob_a1.id))]) e2 = TestWalkEntry(c2, [ TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id), (b'a', F, blob_a2.id)), TreeChange.add((b'b', F, blob_b2.id)) ]) self.assertWalkYields([e2, e1], [c2.id])
def test_tree_changes_for_merge_octopus_modify_conflict(self): # Because the octopus merge strategy is limited, I doubt it's possible # to create this with the git command line. But the output is well- # defined, so test it anyway. r = list(range(5)) parent_blobs = [make_object(Blob, data=bytes(i)) for i in r] merge_blob = make_object(Blob, data=b"merge") parents = [self.commit_tree([(b"a", parent_blobs[i])]) for i in r] merge = self.commit_tree([(b"a", merge_blob)]) expected = [[ TreeChange( CHANGE_MODIFY, (b"a", F, parent_blobs[i].id), (b"a", F, merge_blob.id), ) for i in r ]] self.assertChangesForMergeEqual(expected, parents, merge)
def test_tree_changes_change_type_same(self): blob_a1 = make_object(Blob, data=b"a") blob_a2 = make_object(Blob, data=b"/foo/bar") tree1 = self.commit_tree([(b"a", blob_a1, 0o100644)]) tree2 = self.commit_tree([(b"a", blob_a2, 0o120000)]) self.assertChangesEqual( [ TreeChange( CHANGE_MODIFY, (b"a", 0o100644, blob_a1.id), (b"a", 0o120000, blob_a2.id), ) ], tree1, tree2, change_type_same=True, )
def test_rename_threshold(self): blob1 = make_object(Blob, data=b"a\nb\nc\n") blob2 = make_object(Blob, data=b"a\nb\nd\n") tree1 = self.commit_tree([(b"a", blob1)]) tree2 = self.commit_tree([(b"b", blob2)]) self.assertEqual( [ TreeChange(CHANGE_RENAME, (b"a", F, blob1.id), (b"b", F, blob2.id)) ], self.detect_renames(tree1, tree2, rename_threshold=50), ) self.assertEqual( [ TreeChange.delete((b"a", F, blob1.id)), TreeChange.add((b"b", F, blob2.id)), ], self.detect_renames(tree1, tree2, rename_threshold=75), )
def test_tree_changes_prune(self): blob_a1 = make_object(Blob, data=b"a1") blob_a2 = make_object(Blob, data=b"a2") blob_x = make_object(Blob, data=b"x") tree1 = self.commit_tree([(b"a", blob_a1), (b"b/x", blob_x)]) tree2 = self.commit_tree([(b"a", blob_a2), (b"b/x", blob_x)]) # Remove identical items so lookups will fail unless we prune. subtree = self.store[tree1[b"b"][1]] for entry in subtree.items(): del self.store[entry.sha] del self.store[subtree.id] self.assertChangesEqual( [ TreeChange(CHANGE_MODIFY, (b"a", F, blob_a1.id), (b"a", F, blob_a2.id)) ], tree1, tree2, )
def test_tree_changes_complex(self): blob_a_1 = make_object(Blob, data=b"a1_1") blob_bx1_1 = make_object(Blob, data=b"bx1_1") blob_bx2_1 = make_object(Blob, data=b"bx2_1") blob_by1_1 = make_object(Blob, data=b"by1_1") blob_by2_1 = make_object(Blob, data=b"by2_1") tree1 = self.commit_tree([ (b"a", blob_a_1), (b"b/x/1", blob_bx1_1), (b"b/x/2", blob_bx2_1), (b"b/y/1", blob_by1_1), (b"b/y/2", blob_by2_1), ]) blob_a_2 = make_object(Blob, data=b"a1_2") blob_bx1_2 = blob_bx1_1 blob_by_2 = make_object(Blob, data=b"by_2") blob_c_2 = make_object(Blob, data=b"c_2") tree2 = self.commit_tree([ (b"a", blob_a_2), (b"b/x/1", blob_bx1_2), (b"b/y", blob_by_2), (b"c", blob_c_2), ]) self.assertChangesEqual( [ TreeChange( CHANGE_MODIFY, (b"a", F, blob_a_1.id), (b"a", F, blob_a_2.id), ), TreeChange.delete((b"b/x/2", F, blob_bx2_1.id)), TreeChange.add((b"b/y", F, blob_by_2.id)), TreeChange.delete((b"b/y/1", F, blob_by1_1.id)), TreeChange.delete((b"b/y/2", F, blob_by2_1.id)), TreeChange.add((b"c", F, blob_c_2.id)), ], tree1, tree2, )
def test_changes_with_renames(self): blob = make_object(Blob, data=b'blob') c1, c2 = self.make_linear_commits(2, trees={ 1: [(b'a', blob)], 2: [(b'b', blob)] }) entry_a = (b'a', F, blob.id) entry_b = (b'b', F, blob.id) changes_without_renames = [ TreeChange.delete(entry_a), TreeChange.add(entry_b) ] changes_with_renames = [TreeChange(CHANGE_RENAME, entry_a, entry_b)] self.assertWalkYields([TestWalkEntry(c2, changes_without_renames)], [c2.id], max_entries=1) detector = RenameDetector(self.store) self.assertWalkYields([TestWalkEntry(c2, changes_with_renames)], [c2.id], max_entries=1, rename_detector=detector)