コード例 #1
0
 def test_content_rename_max_files(self):
     blob1 = make_object(Blob, data=b"a\nb\nc\nd")
     blob4 = make_object(Blob, data=b"a\nb\nc\ne\n")
     blob2 = make_object(Blob, data=b"e\nf\ng\nh\n")
     blob3 = make_object(Blob, data=b"e\nf\ng\ni\n")
     tree1 = self.commit_tree([(b"a", blob1), (b"b", blob2)])
     tree2 = self.commit_tree([(b"c", blob3), (b"d", blob4)])
     self.assertEqual(
         [
             TreeChange(CHANGE_RENAME, (b"a", F, blob1.id),
                        (b"d", F, blob4.id)),
             TreeChange(CHANGE_RENAME, (b"b", F, blob2.id),
                        (b"c", F, blob3.id)),
         ],
         self.detect_renames(tree1, tree2),
     )
     self.assertEqual(
         [
             TreeChange.delete((b"a", F, blob1.id)),
             TreeChange.delete((b"b", F, blob2.id)),
             TreeChange.add((b"c", F, blob3.id)),
             TreeChange.add((b"d", F, blob4.id)),
         ],
         self.detect_renames(tree1, tree2, max_files=1),
     )
コード例 #2
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
    def test_tree_changes_rename_detector(self):
        blob_a1 = make_object(Blob, data='a\nb\nc\nd\n')
        blob_a2 = make_object(Blob, data='a\nb\nc\ne\n')
        blob_b = make_object(Blob, data='b')
        tree1 = self.commit_tree([('a', blob_a1), ('b', blob_b)])
        tree2 = self.commit_tree([('c', blob_a2), ('b', blob_b)])
        detector = RenameDetector(self.store)

        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob_a1.id)),
           TreeChange.add(('c', F, blob_a2.id))],
          tree1, tree2)
        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob_a1.id)),
           TreeChange(CHANGE_UNCHANGED, ('b', F, blob_b.id),
                      ('b', F, blob_b.id)),
           TreeChange.add(('c', F, blob_a2.id))],
          tree1, tree2, want_unchanged=True)
        self.assertChangesEqual(
          [TreeChange(CHANGE_RENAME, ('a', F, blob_a1.id),
                      ('c', F, blob_a2.id))],
          tree1, tree2, rename_detector=detector)
        self.assertChangesEqual(
          [TreeChange(CHANGE_RENAME, ('a', F, blob_a1.id),
                      ('c', F, blob_a2.id)),
           TreeChange(CHANGE_UNCHANGED, ('b', F, blob_b.id),
                      ('b', F, blob_b.id))],
          tree1, tree2, rename_detector=detector, want_unchanged=True)
コード例 #3
0
    def test_content_rename_one_to_one_ordering(self):
        blob1 = make_object(Blob, data=b"a\nb\nc\nd\ne\nf\n")
        blob2 = make_object(Blob, data=b"a\nb\nc\nd\ng\nh\n")
        # 6/10 match to blob1, 8/10 match to blob2
        blob3 = make_object(Blob, data=b"a\nb\nc\nd\ng\ni\n")
        tree1 = self.commit_tree([(b"a", blob1), (b"b", blob2)])
        tree2 = self.commit_tree([(b"c", blob3)])
        self.assertEqual(
            [
                TreeChange.delete((b"a", F, blob1.id)),
                TreeChange(CHANGE_RENAME, (b"b", F, blob2.id),
                           (b"c", F, blob3.id)),
            ],
            self.detect_renames(tree1, tree2),
        )

        tree3 = self.commit_tree([(b"a", blob2), (b"b", blob1)])
        tree4 = self.commit_tree([(b"c", blob3)])
        self.assertEqual(
            [
                TreeChange(CHANGE_RENAME, (b"a", F, blob2.id),
                           (b"c", F, blob3.id)),
                TreeChange.delete((b"b", F, blob1.id)),
            ],
            self.detect_renames(tree3, tree4),
        )
コード例 #4
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
    def test_tree_changes_complex(self):
        blob_a_1 = make_object(Blob, data='a1_1')
        blob_bx1_1 = make_object(Blob, data='bx1_1')
        blob_bx2_1 = make_object(Blob, data='bx2_1')
        blob_by1_1 = make_object(Blob, data='by1_1')
        blob_by2_1 = make_object(Blob, data='by2_1')
        tree1 = self.commit_tree([
          ('a', blob_a_1),
          ('b/x/1', blob_bx1_1),
          ('b/x/2', blob_bx2_1),
          ('b/y/1', blob_by1_1),
          ('b/y/2', blob_by2_1),
          ])

        blob_a_2 = make_object(Blob, data='a1_2')
        blob_bx1_2 = blob_bx1_1
        blob_by_2 = make_object(Blob, data='by_2')
        blob_c_2 = make_object(Blob, data='c_2')
        tree2 = self.commit_tree([
          ('a', blob_a_2),
          ('b/x/1', blob_bx1_2),
          ('b/y', blob_by_2),
          ('c', blob_c_2),
          ])

        self.assertChangesEqual(
          [TreeChange(CHANGE_MODIFY, ('a', F, blob_a_1.id),
                      ('a', F, blob_a_2.id)),
           TreeChange.delete(('b/x/2', F, blob_bx2_1.id)),
           TreeChange.add(('b/y', F, blob_by_2.id)),
           TreeChange.delete(('b/y/1', F, blob_by1_1.id)),
           TreeChange.delete(('b/y/2', F, blob_by2_1.id)),
           TreeChange.add(('c', F, blob_c_2.id))],
          tree1, tree2)
コード例 #5
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
    def test_tree_changes_rename_detector(self):
        blob_a1 = make_object(Blob, data='a\nb\nc\nd\n')
        blob_a2 = make_object(Blob, data='a\nb\nc\ne\n')
        blob_b = make_object(Blob, data='b')
        tree1 = self.commit_tree([('a', blob_a1), ('b', blob_b)])
        tree2 = self.commit_tree([('c', blob_a2), ('b', blob_b)])
        detector = RenameDetector(self.store)

        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob_a1.id)),
           TreeChange.add(('c', F, blob_a2.id))],
          tree1, tree2)
        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob_a1.id)),
           TreeChange(CHANGE_UNCHANGED, ('b', F, blob_b.id),
                      ('b', F, blob_b.id)),
           TreeChange.add(('c', F, blob_a2.id))],
          tree1, tree2, want_unchanged=True)
        self.assertChangesEqual(
          [TreeChange(CHANGE_RENAME, ('a', F, blob_a1.id),
                      ('c', F, blob_a2.id))],
          tree1, tree2, rename_detector=detector)
        self.assertChangesEqual(
          [TreeChange(CHANGE_RENAME, ('a', F, blob_a1.id),
                      ('c', F, blob_a2.id)),
           TreeChange(CHANGE_UNCHANGED, ('b', F, blob_b.id),
                      ('b', F, blob_b.id))],
          tree1, tree2, rename_detector=detector, want_unchanged=True)
コード例 #6
0
    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(
            [
                ("a", blob_a_1),
                ("b/x/1", blob_bx1_1),
                ("b/x/2", blob_bx2_1),
                ("b/y/1", blob_by1_1),
                ("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([("a", blob_a_2), ("b/x/1", blob_bx1_2), ("b/y", blob_by_2), ("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,
        )
コード例 #7
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
    def test_tree_changes_complex(self):
        blob_a_1 = make_object(Blob, data='a1_1')
        blob_bx1_1 = make_object(Blob, data='bx1_1')
        blob_bx2_1 = make_object(Blob, data='bx2_1')
        blob_by1_1 = make_object(Blob, data='by1_1')
        blob_by2_1 = make_object(Blob, data='by2_1')
        tree1 = self.commit_tree([
          ('a', blob_a_1),
          ('b/x/1', blob_bx1_1),
          ('b/x/2', blob_bx2_1),
          ('b/y/1', blob_by1_1),
          ('b/y/2', blob_by2_1),
          ])

        blob_a_2 = make_object(Blob, data='a1_2')
        blob_bx1_2 = blob_bx1_1
        blob_by_2 = make_object(Blob, data='by_2')
        blob_c_2 = make_object(Blob, data='c_2')
        tree2 = self.commit_tree([
          ('a', blob_a_2),
          ('b/x/1', blob_bx1_2),
          ('b/y', blob_by_2),
          ('c', blob_c_2),
          ])

        self.assertChangesEqual(
          [TreeChange(CHANGE_MODIFY, ('a', F, blob_a_1.id),
                      ('a', F, blob_a_2.id)),
           TreeChange.delete(('b/x/2', F, blob_bx2_1.id)),
           TreeChange.add(('b/y', F, blob_by_2.id)),
           TreeChange.delete(('b/y/1', F, blob_by1_1.id)),
           TreeChange.delete(('b/y/2', F, blob_by2_1.id)),
           TreeChange.add(('c', F, blob_c_2.id))],
          tree1, tree2)
コード例 #8
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_tree_changes_for_merge_delete_delete_conflict(self):
     blob1 = make_object(Blob, data='1')
     blob2 = make_object(Blob, data='2')
     parent1 = self.commit_tree([('a', blob1)])
     parent2 = self.commit_tree([('a', blob2)])
     merge = self.commit_tree([])
     self.assertChangesForMergeEqual(
       [[TreeChange.delete(('a', F, blob1.id)),
         TreeChange.delete(('a', F, blob2.id))]],
       [parent1, parent2], merge)
コード例 #9
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_tree_changes_for_merge_delete_delete_conflict(self):
     blob1 = make_object(Blob, data='1')
     blob2 = make_object(Blob, data='2')
     parent1 = self.commit_tree([('a', blob1)])
     parent2 = self.commit_tree([('a', blob2)])
     merge = self.commit_tree([])
     self.assertChangesForMergeEqual(
       [[TreeChange.delete(('a', F, blob1.id)),
         TreeChange.delete(('a', F, blob2.id))]],
       [parent1, parent2], merge)
コード例 #10
0
    def test_tree_changes_rename_detector(self):
        blob_a1 = make_object(Blob, data=b"a\nb\nc\nd\n")
        blob_a2 = make_object(Blob, data=b"a\nb\nc\ne\n")
        blob_b = make_object(Blob, data=b"b")
        tree1 = self.commit_tree([(b"a", blob_a1), (b"b", blob_b)])
        tree2 = self.commit_tree([(b"c", blob_a2), (b"b", blob_b)])
        detector = RenameDetector(self.store)

        self.assertChangesEqual(
            [
                TreeChange.delete((b"a", F, blob_a1.id)),
                TreeChange.add((b"c", F, blob_a2.id)),
            ],
            tree1,
            tree2,
        )
        self.assertChangesEqual(
            [
                TreeChange.delete((b"a", F, blob_a1.id)),
                TreeChange(
                    CHANGE_UNCHANGED,
                    (b"b", F, blob_b.id),
                    (b"b", F, blob_b.id),
                ),
                TreeChange.add((b"c", F, blob_a2.id)),
            ],
            tree1,
            tree2,
            want_unchanged=True,
        )
        self.assertChangesEqual(
            [
                TreeChange(CHANGE_RENAME, (b"a", F, blob_a1.id),
                           (b"c", F, blob_a2.id))
            ],
            tree1,
            tree2,
            rename_detector=detector,
        )
        self.assertChangesEqual(
            [
                TreeChange(CHANGE_RENAME, (b"a", F, blob_a1.id),
                           (b"c", F, blob_a2.id)),
                TreeChange(
                    CHANGE_UNCHANGED,
                    (b"b", F, blob_b.id),
                    (b"b", F, blob_b.id),
                ),
            ],
            tree1,
            tree2,
            rename_detector=detector,
            want_unchanged=True,
        )
コード例 #11
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
    def test_tree_changes_name_order(self):
        blob = make_object(Blob, data='a')
        tree1 = self.commit_tree([('a', blob), ('a.', blob), ('a..', blob)])
        # Tree order is the reverse of this, so if we used tree order, 'a..'
        # would not be merged.
        tree2 = self.commit_tree([('a/x', blob), ('a./x', blob), ('a..', blob)])

        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob.id)),
           TreeChange.add(('a/x', F, blob.id)),
           TreeChange.delete(('a.', F, blob.id)),
           TreeChange.add(('a./x', F, blob.id))],
          tree1, tree2)
コード例 #12
0
ファイル: test_diff_tree.py プロジェクト: KrissN/dulwich
 def test_content_rename_gitlink(self):
     blob1 = make_object(Blob, data='blob1')
     blob2 = make_object(Blob, data='blob2')
     link1 = '1' * 40
     link2 = '2' * 40
     tree1 = self.commit_tree([('a', blob1), ('b', link1, 0o160000)])
     tree2 = self.commit_tree([('c', blob2), ('d', link2, 0o160000)])
     self.assertEqual(
       [TreeChange.delete(('a', 0o100644, blob1.id)),
        TreeChange.delete(('b', 0o160000, link1)),
        TreeChange.add(('c', 0o100644, blob2.id)),
        TreeChange.add(('d', 0o160000, link2))],
       self.detect_renames(tree1, tree2))
コード例 #13
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_tree_changes_add_delete(self):
     blob_a = make_object(Blob, data='a')
     blob_b = make_object(Blob, data='b')
     tree = self.commit_tree([('a', blob_a, 0o100644),
                              ('x/b', blob_b, 0o100755)])
     self.assertChangesEqual(
       [TreeChange.add(('a', 0o100644, blob_a.id)),
        TreeChange.add(('x/b', 0o100755, blob_b.id))],
       self.empty_tree, tree)
     self.assertChangesEqual(
       [TreeChange.delete(('a', 0o100644, blob_a.id)),
        TreeChange.delete(('x/b', 0o100755, blob_b.id))],
       tree, self.empty_tree)
コード例 #14
0
ファイル: test_diff_tree.py プロジェクト: KrissN/dulwich
 def test_tree_changes_add_delete(self):
     blob_a = make_object(Blob, data='a')
     blob_b = make_object(Blob, data='b')
     tree = self.commit_tree([('a', blob_a, 0o100644),
                              ('x/b', blob_b, 0o100755)])
     self.assertChangesEqual(
       [TreeChange.add(('a', 0o100644, blob_a.id)),
        TreeChange.add(('x/b', 0o100755, blob_b.id))],
       self.empty_tree, tree)
     self.assertChangesEqual(
       [TreeChange.delete(('a', 0o100644, blob_a.id)),
        TreeChange.delete(('x/b', 0o100755, blob_b.id))],
       tree, self.empty_tree)
コード例 #15
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
    def test_tree_changes_name_order(self):
        blob = make_object(Blob, data='a')
        tree1 = self.commit_tree([('a', blob), ('a.', blob), ('a..', blob)])
        # Tree order is the reverse of this, so if we used tree order, 'a..'
        # would not be merged.
        tree2 = self.commit_tree([('a/x', blob), ('a./x', blob), ('a..', blob)])

        self.assertChangesEqual(
          [TreeChange.delete(('a', F, blob.id)),
           TreeChange.add(('a/x', F, blob.id)),
           TreeChange.delete(('a.', F, blob.id)),
           TreeChange.add(('a./x', F, blob.id))],
          tree1, tree2)
コード例 #16
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_content_rename_gitlink(self):
     blob1 = make_object(Blob, data='blob1')
     blob2 = make_object(Blob, data='blob2')
     link1 = '1' * 40
     link2 = '2' * 40
     tree1 = self.commit_tree([('a', blob1), ('b', link1, 0o160000)])
     tree2 = self.commit_tree([('c', blob2), ('d', link2, 0o160000)])
     self.assertEqual(
       [TreeChange.delete(('a', 0o100644, blob1.id)),
        TreeChange.delete(('b', 0o160000, link1)),
        TreeChange.add(('c', 0o100644, blob2.id)),
        TreeChange.add(('d', 0o160000, link2))],
       self.detect_renames(tree1, tree2))
コード例 #17
0
 def test_tree_changes_for_merge_octopus_delete(self):
     blob1 = make_object(Blob, data='1')
     blob2 = make_object(Blob, data='3')
     parent1 = self.commit_tree([('a', blob1)])
     parent2 = self.commit_tree([('a', blob2)])
     parent3 = merge = self.commit_tree([])
     self.assertChangesForMergeEqual([], [parent1, parent1, parent1], merge)
     self.assertChangesForMergeEqual([], [parent1, parent1, parent3], merge)
     self.assertChangesForMergeEqual([], [parent1, parent3, parent3], merge)
     self.assertChangesForMergeEqual([[
         TreeChange.delete(('a', F, blob1.id)),
         TreeChange.delete(('a', F, blob2.id)), None
     ]], [parent1, parent2, parent3], merge)
コード例 #18
0
 def test_tree_changes_add_delete(self):
     blob_a = make_object(Blob, data=b"a")
     blob_b = make_object(Blob, data=b"b")
     tree = self.commit_tree([("a", blob_a, 0o100644), ("x/b", blob_b, 0o100755)])
     self.assertChangesEqual(
         [TreeChange.add((b"a", 0o100644, blob_a.id)), TreeChange.add((b"x/b", 0o100755, blob_b.id))],
         self.empty_tree,
         tree,
     )
     self.assertChangesEqual(
         [TreeChange.delete((b"a", 0o100644, blob_a.id)), TreeChange.delete((b"x/b", 0o100755, blob_b.id))],
         tree,
         self.empty_tree,
     )
コード例 #19
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_tree_changes_for_merge_octopus_delete(self):
     blob1 = make_object(Blob, data='1')
     blob2 = make_object(Blob, data='3')
     parent1 = self.commit_tree([('a', blob1)])
     parent2 = self.commit_tree([('a', blob2)])
     parent3 = merge = self.commit_tree([])
     self.assertChangesForMergeEqual([], [parent1, parent1, parent1], merge)
     self.assertChangesForMergeEqual([], [parent1, parent1, parent3], merge)
     self.assertChangesForMergeEqual([], [parent1, parent3, parent3], merge)
     self.assertChangesForMergeEqual(
       [[TreeChange.delete(('a', F, blob1.id)),
         TreeChange.delete(('a', F, blob2.id)),
         None]],
       [parent1, parent2, parent3], merge)
コード例 #20
0
 def test_content_rename_gitlink(self):
     blob1 = make_object(Blob, data=b"blob1")
     blob2 = make_object(Blob, data=b"blob2")
     link1 = b"1" * 40
     link2 = b"2" * 40
     tree1 = self.commit_tree([(b"a", blob1), (b"b", link1, 0o160000)])
     tree2 = self.commit_tree([(b"c", blob2), (b"d", link2, 0o160000)])
     self.assertEqual(
         [
             TreeChange.delete((b"a", 0o100644, blob1.id)),
             TreeChange.delete((b"b", 0o160000, link1)),
             TreeChange.add((b"c", 0o100644, blob2.id)),
             TreeChange.add((b"d", 0o160000, link2)),
         ],
         self.detect_renames(tree1, tree2),
     )
コード例 #21
0
 def test_content_rename_gitlink(self):
     blob1 = make_object(Blob, data=b"blob1")
     blob2 = make_object(Blob, data=b"blob2")
     link1 = Sha1Sum("1" * 40)
     link2 = Sha1Sum("2" * 40)
     tree1 = self.commit_tree([("a", blob1), ("b", link1, 0o160000)])
     tree2 = self.commit_tree([("c", blob2), ("d", link2, 0o160000)])
     self.assertEqual(
         [
             TreeChange.delete((b"a", 0o100644, blob1.id)),
             TreeChange.delete((b"b", 0o160000, link1)),
             TreeChange.add((b"c", 0o100644, blob2.id)),
             TreeChange.add((b"d", 0o160000, link2)),
         ],
         self.detect_renames(tree1, tree2),
     )
コード例 #22
0
    def test_tree_entry_sort(self):
        sha = "abcd" * 10
        expected_entries = [
            TreeChange.add(TreeEntry(b"aaa", F, sha)),
            TreeChange(
                CHANGE_COPY,
                TreeEntry(b"bbb", F, sha),
                TreeEntry(b"aab", F, sha),
            ),
            TreeChange(
                CHANGE_MODIFY,
                TreeEntry(b"bbb", F, sha),
                TreeEntry(b"bbb", F, b"dabc" * 10),
            ),
            TreeChange(
                CHANGE_RENAME,
                TreeEntry(b"bbc", F, sha),
                TreeEntry(b"ddd", F, sha),
            ),
            TreeChange.delete(TreeEntry(b"ccc", F, sha)),
        ]

        for perm in permutations(expected_entries):
            self.assertEqual(expected_entries,
                             sorted(perm, key=_tree_change_key))
コード例 #23
0
ファイル: test_walk.py プロジェクト: timmy61109/dulwich
 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,
     )
コード例 #24
0
 def test_tree_changes_to_tree(self):
     blob_a = make_object(Blob, data=b"a")
     blob_x = make_object(Blob, data=b"x")
     tree1 = self.commit_tree([("a", blob_a)])
     tree2 = self.commit_tree([("a/x", blob_x)])
     self.assertChangesEqual(
         [TreeChange.delete((b"a", F, blob_a.id)), TreeChange.add((b"a/x", F, blob_x.id))], tree1, tree2
     )
コード例 #25
0
 def test_exact_rename_split_different_type(self):
     blob = make_object(Blob, data=b"/foo")
     tree1 = self.commit_tree([("a", blob, 0o100644)])
     tree2 = self.commit_tree([("a", blob, 0o120000)])
     self.assertEqual(
         [TreeChange.add((b"a", 0o120000, blob.id)), TreeChange.delete((b"a", 0o100644, blob.id))],
         self.detect_renames(tree1, tree2),
     )
コード例 #26
0
 def test_exact_rename_many_to_one(self):
     blob = make_object(Blob, data=b"1")
     tree1 = self.commit_tree([("a", blob), ("b", blob)])
     tree2 = self.commit_tree([("c", blob)])
     self.assertEqual(
         [TreeChange(CHANGE_RENAME, (b"a", F, blob.id), (b"c", F, blob.id)), TreeChange.delete((b"b", F, blob.id))],
         self.detect_renames(tree1, tree2),
     )
コード例 #27
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_content_rename_max_files(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd')
     blob4 = make_object(Blob, data='a\nb\nc\ne\n')
     blob2 = make_object(Blob, data='e\nf\ng\nh\n')
     blob3 = make_object(Blob, data='e\nf\ng\ni\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3), ('d', blob4)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('d', F, blob4.id)),
        TreeChange(CHANGE_RENAME, ('b', F, blob2.id), ('c', F, blob3.id))],
       self.detect_renames(tree1, tree2))
     self.assertEqual(
       [TreeChange.delete(('a', F, blob1.id)),
        TreeChange.delete(('b', F, blob2.id)),
        TreeChange.add(('c', F, blob3.id)),
        TreeChange.add(('d', F, blob4.id))],
       self.detect_renames(tree1, tree2, max_files=1))
コード例 #28
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_exact_rename_many_to_one(self):
     blob = make_object(Blob, data='1')
     tree1 = self.commit_tree([('a', blob), ('b', blob)])
     tree2 = self.commit_tree([('c', blob)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob.id), ('c', F, blob.id)),
        TreeChange.delete(('b', F, blob.id))],
       self.detect_renames(tree1, tree2))
コード例 #29
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_exact_rename_split_different_type(self):
     blob = make_object(Blob, data='/foo')
     tree1 = self.commit_tree([('a', blob, 0o100644)])
     tree2 = self.commit_tree([('a', blob, 0o120000)])
     self.assertEqual(
       [TreeChange.add(('a', 0o120000, blob.id)),
        TreeChange.delete(('a', 0o100644, blob.id))],
       self.detect_renames(tree1, tree2))
コード例 #30
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_exact_rename_many_to_one(self):
     blob = make_object(Blob, data='1')
     tree1 = self.commit_tree([('a', blob), ('b', blob)])
     tree2 = self.commit_tree([('c', blob)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob.id), ('c', F, blob.id)),
        TreeChange.delete(('b', F, blob.id))],
       self.detect_renames(tree1, tree2))
コード例 #31
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_content_rename_max_files(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd')
     blob4 = make_object(Blob, data='a\nb\nc\ne\n')
     blob2 = make_object(Blob, data='e\nf\ng\nh\n')
     blob3 = make_object(Blob, data='e\nf\ng\ni\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3), ('d', blob4)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('d', F, blob4.id)),
        TreeChange(CHANGE_RENAME, ('b', F, blob2.id), ('c', F, blob3.id))],
       self.detect_renames(tree1, tree2))
     self.assertEqual(
       [TreeChange.delete(('a', F, blob1.id)),
        TreeChange.delete(('b', F, blob2.id)),
        TreeChange.add(('c', F, blob3.id)),
        TreeChange.add(('d', F, blob4.id))],
       self.detect_renames(tree1, tree2, max_files=1))
コード例 #32
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
    def test_content_rename_one_to_one_ordering(self):
        blob1 = make_object(Blob, data='a\nb\nc\nd\ne\nf\n')
        blob2 = make_object(Blob, data='a\nb\nc\nd\ng\nh\n')
        # 6/10 match to blob1, 8/10 match to blob2
        blob3 = make_object(Blob, data='a\nb\nc\nd\ng\ni\n')
        tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
        tree2 = self.commit_tree([('c', blob3)])
        self.assertEqual(
          [TreeChange.delete(('a', F, blob1.id)),
           TreeChange(CHANGE_RENAME, ('b', F, blob2.id), ('c', F, blob3.id))],
          self.detect_renames(tree1, tree2))

        tree3 = self.commit_tree([('a', blob2), ('b', blob1)])
        tree4 = self.commit_tree([('c', blob3)])
        self.assertEqual(
          [TreeChange(CHANGE_RENAME, ('a', F, blob2.id), ('c', F, blob3.id)),
           TreeChange.delete(('b', F, blob1.id))],
          self.detect_renames(tree3, tree4))
コード例 #33
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_tree_changes_change_type(self):
     blob_a1 = make_object(Blob, data='a')
     blob_a2 = make_object(Blob, data='/foo/bar')
     tree1 = self.commit_tree([('a', blob_a1, 0o100644)])
     tree2 = self.commit_tree([('a', blob_a2, 0o120000)])
     self.assertChangesEqual(
       [TreeChange.delete(('a', 0o100644, blob_a1.id)),
        TreeChange.add(('a', 0o120000, blob_a2.id))],
       tree1, tree2)
コード例 #34
0
ファイル: test_diff_tree.py プロジェクト: KrissN/dulwich
 def test_tree_changes_change_type(self):
     blob_a1 = make_object(Blob, data='a')
     blob_a2 = make_object(Blob, data='/foo/bar')
     tree1 = self.commit_tree([('a', blob_a1, 0o100644)])
     tree2 = self.commit_tree([('a', blob_a2, 0o120000)])
     self.assertChangesEqual(
       [TreeChange.delete(('a', 0o100644, blob_a1.id)),
        TreeChange.add(('a', 0o120000, blob_a2.id))],
       tree1, tree2)
コード例 #35
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_tree_changes_to_tree(self):
     blob_a = make_object(Blob, data='a')
     blob_x = make_object(Blob, data='x')
     tree1 = self.commit_tree([('a', blob_a)])
     tree2 = self.commit_tree([('a/x', blob_x)])
     self.assertChangesEqual(
       [TreeChange.delete(('a', F, blob_a.id)),
        TreeChange.add(('a/x', F, blob_x.id))],
       tree1, tree2)
コード例 #36
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_tree_changes_to_tree(self):
     blob_a = make_object(Blob, data='a')
     blob_x = make_object(Blob, data='x')
     tree1 = self.commit_tree([('a', blob_a)])
     tree2 = self.commit_tree([('a/x', blob_x)])
     self.assertChangesEqual(
       [TreeChange.delete(('a', F, blob_a.id)),
        TreeChange.add(('a/x', F, blob_x.id))],
       tree1, tree2)
コード例 #37
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_content_rename_many_to_one(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd\n')
     blob2 = make_object(Blob, data='a\nb\nc\ne\n')
     blob3 = make_object(Blob, data='a\nb\nc\nf\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('c', F, blob3.id)),
        TreeChange.delete(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2))
コード例 #38
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_content_rename_many_to_one(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd\n')
     blob2 = make_object(Blob, data='a\nb\nc\ne\n')
     blob3 = make_object(Blob, data='a\nb\nc\nf\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('c', F, blob3.id)),
        TreeChange.delete(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2))
コード例 #39
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_content_rename_with_more_deletions(self):
     blob1 = make_object(Blob, data='')
     tree1 = self.commit_tree([('a', blob1), ('b', blob1), ('c', blob1), ('d', blob1)])
     tree2 = self.commit_tree([('e', blob1), ('f', blob1), ('g', blob1)])
     self.maxDiff = None
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('e', F, blob1.id)),
        TreeChange(CHANGE_RENAME, ('b', F, blob1.id), ('f', F, blob1.id)),
        TreeChange(CHANGE_RENAME, ('c', F, blob1.id), ('g', F, blob1.id)),
        TreeChange.delete(('d', F, blob1.id))],
       self.detect_renames(tree1, tree2))
コード例 #40
0
ファイル: test_diff_tree.py プロジェクト: PKRoma/dulwich
 def test_content_rename_with_more_deletions(self):
     blob1 = make_object(Blob, data='')
     tree1 = self.commit_tree([('a', blob1), ('b', blob1), ('c', blob1), ('d', blob1)])
     tree2 = self.commit_tree([('e', blob1), ('f', blob1), ('g', blob1)])
     self.maxDiff = None
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('e', F, blob1.id)),
        TreeChange(CHANGE_RENAME, ('b', F, blob1.id), ('f', F, blob1.id)),
        TreeChange(CHANGE_RENAME, ('c', F, blob1.id), ('g', F, blob1.id)),
        TreeChange.delete(('d', F, blob1.id))],
       self.detect_renames(tree1, tree2))
コード例 #41
0
    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,
        )
コード例 #42
0
 def test_exact_rename_many_to_one(self):
     blob = make_object(Blob, data=b"1")
     tree1 = self.commit_tree([(b"a", blob), (b"b", blob)])
     tree2 = self.commit_tree([(b"c", blob)])
     self.assertEqual(
         [
             TreeChange(CHANGE_RENAME, (b"a", F, blob.id),
                        (b"c", F, blob.id)),
             TreeChange.delete((b"b", F, blob.id)),
         ],
         self.detect_renames(tree1, tree2),
     )
コード例 #43
0
    def test_tree_entry_sort(self):
        sha = Sha1Sum("abcd" * 10)
        expected_entries = [
            TreeChange.add(TreeEntry(b"aaa", F, sha)),
            TreeChange(CHANGE_COPY, TreeEntry(b"bbb", F, sha), TreeEntry(b"aab", F, sha)),
            TreeChange(CHANGE_MODIFY, TreeEntry(b"bbb", F, sha), TreeEntry(b"bbb", F, Sha1Sum("dabc" * 10))),
            TreeChange(CHANGE_RENAME, TreeEntry(b"bbc", F, sha), TreeEntry(b"ddd", F, sha)),
            TreeChange.delete(TreeEntry(b"ccc", F, sha)),
        ]

        for perm in permutations(expected_entries):
            self.assertEqual(expected_entries, sorted(perm, key=_tree_change_key))
コード例 #44
0
 def test_tree_changes_add_delete(self):
     blob_a = make_object(Blob, data=b"a")
     blob_b = make_object(Blob, data=b"b")
     tree = self.commit_tree([(b"a", blob_a, 0o100644),
                              (b"x/b", blob_b, 0o100755)])
     self.assertChangesEqual(
         [
             TreeChange.add((b"a", 0o100644, blob_a.id)),
             TreeChange.add((b"x/b", 0o100755, blob_b.id)),
         ],
         self.empty_tree,
         tree,
     )
     self.assertChangesEqual(
         [
             TreeChange.delete((b"a", 0o100644, blob_a.id)),
             TreeChange.delete((b"x/b", 0o100755, blob_b.id)),
         ],
         tree,
         self.empty_tree,
     )
コード例 #45
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_rename_threshold(self):
     blob1 = make_object(Blob, data='a\nb\nc\n')
     blob2 = make_object(Blob, data='a\nb\nd\n')
     tree1 = self.commit_tree([('a', blob1)])
     tree2 = self.commit_tree([('b', blob2)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('b', F, blob2.id))],
       self.detect_renames(tree1, tree2, rename_threshold=50))
     self.assertEqual(
       [TreeChange.delete(('a', F, blob1.id)),
        TreeChange.add(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2, rename_threshold=75))
コード例 #46
0
ファイル: test_walk.py プロジェクト: pombredanne/dulwich
 def test_changes_with_renames(self):
     blob = make_object(Blob, data="blob")
     c1, c2 = self.make_linear_commits(2, trees={1: [("a", blob)], 2: [("b", blob)]})
     entry_a = ("a", F, blob.id)
     entry_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
     )
コード例 #47
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_rename_threshold(self):
     blob1 = make_object(Blob, data='a\nb\nc\n')
     blob2 = make_object(Blob, data='a\nb\nd\n')
     tree1 = self.commit_tree([('a', blob1)])
     tree2 = self.commit_tree([('b', blob2)])
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('b', F, blob2.id))],
       self.detect_renames(tree1, tree2, rename_threshold=50))
     self.assertEqual(
       [TreeChange.delete(('a', F, blob1.id)),
        TreeChange.add(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2, rename_threshold=75))
コード例 #48
0
 def test_content_rename_many_to_one(self):
     blob1 = make_object(Blob, data=b"a\nb\nc\nd\n")
     blob2 = make_object(Blob, data=b"a\nb\nc\ne\n")
     blob3 = make_object(Blob, data=b"a\nb\nc\nf\n")
     tree1 = self.commit_tree([("a", blob1), ("b", blob2)])
     tree2 = self.commit_tree([("c", blob3)])
     self.assertEqual(
         [
             TreeChange(CHANGE_RENAME, (b"a", F, blob1.id), (b"c", F, blob3.id)),
             TreeChange.delete((b"b", F, blob2.id)),
         ],
         self.detect_renames(tree1, tree2),
     )
コード例 #49
0
 def test_tree_changes_to_tree(self):
     blob_a = make_object(Blob, data=b"a")
     blob_x = make_object(Blob, data=b"x")
     tree1 = self.commit_tree([(b"a", blob_a)])
     tree2 = self.commit_tree([(b"a/x", blob_x)])
     self.assertChangesEqual(
         [
             TreeChange.delete((b"a", F, blob_a.id)),
             TreeChange.add((b"a/x", F, blob_x.id)),
         ],
         tree1,
         tree2,
     )
コード例 #50
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
 def test_content_rename_many_to_many(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd\n')
     blob2 = make_object(Blob, data='a\nb\nc\ne\n')
     blob3 = make_object(Blob, data='a\nb\nc\nf\n')
     blob4 = make_object(Blob, data='a\nb\nc\ng\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3), ('d', blob4)])
     # TODO(dborowitz): Distribute renames rather than greedily choosing
     # copies.
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('c', F, blob3.id)),
        TreeChange(CHANGE_COPY, ('a', F, blob1.id), ('d', F, blob4.id)),
        TreeChange.delete(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2))
コード例 #51
0
 def test_content_rename_max_files(self):
     blob1 = make_object(Blob, data=b"a\nb\nc\nd")
     blob4 = make_object(Blob, data=b"a\nb\nc\ne\n")
     blob2 = make_object(Blob, data=b"e\nf\ng\nh\n")
     blob3 = make_object(Blob, data=b"e\nf\ng\ni\n")
     tree1 = self.commit_tree([("a", blob1), ("b", blob2)])
     tree2 = self.commit_tree([("c", blob3), ("d", blob4)])
     self.assertEqual(
         [
             TreeChange(CHANGE_RENAME, (b"a", F, blob1.id), (b"d", F, blob4.id)),
             TreeChange(CHANGE_RENAME, (b"b", F, blob2.id), (b"c", F, blob3.id)),
         ],
         self.detect_renames(tree1, tree2),
     )
     self.assertEqual(
         [
             TreeChange.delete((b"a", F, blob1.id)),
             TreeChange.delete((b"b", F, blob2.id)),
             TreeChange.add((b"c", F, blob3.id)),
             TreeChange.add((b"d", F, blob4.id)),
         ],
         self.detect_renames(tree1, tree2, max_files=1),
     )
コード例 #52
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
 def test_content_rename_many_to_many(self):
     blob1 = make_object(Blob, data='a\nb\nc\nd\n')
     blob2 = make_object(Blob, data='a\nb\nc\ne\n')
     blob3 = make_object(Blob, data='a\nb\nc\nf\n')
     blob4 = make_object(Blob, data='a\nb\nc\ng\n')
     tree1 = self.commit_tree([('a', blob1), ('b', blob2)])
     tree2 = self.commit_tree([('c', blob3), ('d', blob4)])
     # TODO(dborowitz): Distribute renames rather than greedily choosing
     # copies.
     self.assertEqual(
       [TreeChange(CHANGE_RENAME, ('a', F, blob1.id), ('c', F, blob3.id)),
        TreeChange(CHANGE_COPY, ('a', F, blob1.id), ('d', F, blob4.id)),
        TreeChange.delete(('b', F, blob2.id))],
       self.detect_renames(tree1, tree2))
コード例 #53
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
    def test_tree_entry_sort(self):
        sha = 'abcd' * 10
        expected_entries = [
          TreeChange.add(TreeEntry('aaa', F, sha)),
          TreeChange(CHANGE_COPY, TreeEntry('bbb', F, sha),
                     TreeEntry('aab', F, sha)),
          TreeChange(CHANGE_MODIFY, TreeEntry('bbb', F, sha),
                     TreeEntry('bbb', F, 'dabc' * 10)),
          TreeChange(CHANGE_RENAME, TreeEntry('bbc', F, sha),
                     TreeEntry('ddd', F, sha)),
          TreeChange.delete(TreeEntry('ccc', F, sha)),
          ]

        for perm in permutations(expected_entries):
            self.assertEqual(expected_entries,
                             sorted(perm, key=_tree_change_key))
コード例 #54
0
ファイル: test_diff_tree.py プロジェクト: tylerbutler/dulwich
    def test_tree_entry_sort(self):
        sha = 'abcd' * 10
        expected_entries = [
          TreeChange.add(TreeEntry('aaa', F, sha)),
          TreeChange(CHANGE_COPY, TreeEntry('bbb', F, sha),
                     TreeEntry('aab', F, sha)),
          TreeChange(CHANGE_MODIFY, TreeEntry('bbb', F, sha),
                     TreeEntry('bbb', F, 'dabc' * 10)),
          TreeChange(CHANGE_RENAME, TreeEntry('bbc', F, sha),
                     TreeEntry('ddd', F, sha)),
          TreeChange.delete(TreeEntry('ccc', F, sha)),
          ]

        for perm in permutations(expected_entries):
            self.assertEqual(expected_entries,
                             sorted(perm, key=_tree_change_key))
コード例 #55
0
 def test_content_rename_with_more_deletions(self):
     blob1 = make_object(Blob, data=b"")
     tree1 = self.commit_tree([(b"a", blob1), (b"b", blob1), (b"c", blob1),
                               (b"d", blob1)])
     tree2 = self.commit_tree([(b"e", blob1), (b"f", blob1), (b"g", blob1)])
     self.maxDiff = None
     self.assertEqual(
         [
             TreeChange(CHANGE_RENAME, (b"a", F, blob1.id),
                        (b"e", F, blob1.id)),
             TreeChange(CHANGE_RENAME, (b"b", F, blob1.id),
                        (b"f", F, blob1.id)),
             TreeChange(CHANGE_RENAME, (b"c", F, blob1.id),
                        (b"g", F, blob1.id)),
             TreeChange.delete((b"d", F, blob1.id)),
         ],
         self.detect_renames(tree1, tree2),
     )
コード例 #56
0
ファイル: test_diff_tree.py プロジェクト: AaronO/dulwich
          [TreeChange(CHANGE_UNCHANGED, ('a', F, blob.id), ('a', F, blob.id)),
           TreeChange(CHANGE_UNCHANGED, ('b/c', F, blob.id),
                      ('b/c', F, blob.id))],
          tree, tree, want_unchanged=True)

    def test_tree_changes_add_delete(self):
        blob_a = make_object(Blob, data='a')
        blob_b = make_object(Blob, data='b')
        tree = self.commit_tree([('a', blob_a, 0100644),
                                 ('x/b', blob_b, 0100755)])
        self.assertChangesEqual(
          [TreeChange.add(('a', 0100644, blob_a.id)),
           TreeChange.add(('x/b', 0100755, blob_b.id))],
          self.empty_tree, tree)
        self.assertChangesEqual(
          [TreeChange.delete(('a', 0100644, blob_a.id)),
           TreeChange.delete(('x/b', 0100755, blob_b.id))],
          tree, self.empty_tree)

    def test_tree_changes_modify_contents(self):
        blob_a1 = make_object(Blob, data='a1')
        blob_a2 = make_object(Blob, data='a2')
        tree1 = self.commit_tree([('a', blob_a1)])
        tree2 = self.commit_tree([('a', blob_a2)])
        self.assertChangesEqual(
          [TreeChange(CHANGE_MODIFY, ('a', F, blob_a1.id),
                      ('a', F, blob_a2.id))], tree1, tree2)

    def test_tree_changes_modify_mode(self):
        blob_a = make_object(Blob, data='a')
        tree1 = self.commit_tree([('a', blob_a, 0100644)])