def test_object_diff_kind_change(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(
         f,
         store,
         (b"bar.txt", 0o644, b1.id),
         (
             b"bar.txt",
             0o160000,
             b"06d0bdd9e2e20377b3180e4986b14c8549b393e4",
         ),
     )
     self.assertEqual(
         [
             b"diff --git a/bar.txt b/bar.txt",
             b"old file mode 644",
             b"new file mode 160000",
             b"index a116b51..06d0bdd 160000",
             b"--- a/bar.txt",
             b"+++ b/bar.txt",
             b"@@ -1,2 +1 @@",
             b"-new",
             b"-same",
             b"+Subproject commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4",
         ],
         f.getvalue().splitlines(),
     )
예제 #2
0
class CommitTreeTests(TestCase):
    def setUp(self):
        super(CommitTreeTests, self).setUp()
        self.store = MemoryObjectStore()

    def test_single_blob(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"1a1e80437220f9312e855c37ac4398b68e5c1d50")
        self.assertEqual((stat.S_IFREG, blob.id), self.store[rootid][b"bla"])
        self.assertEqual(set([rootid, blob.id]), set(self.store._data.keys()))

    def test_nested(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla/bar", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"d92b959b216ad0d044671981196781b3258fa537")
        dirid = self.store[rootid][b"bla"][1]
        self.assertEqual(dirid, b"c1a1deb9788150829579a8b4efa6311e7b638650")
        self.assertEqual((stat.S_IFDIR, dirid), self.store[rootid][b"bla"])
        self.assertEqual((stat.S_IFREG, blob.id), self.store[dirid][b"bar"])
        self.assertEqual(set([rootid, dirid, blob.id]),
                         set(self.store._data.keys()))
예제 #3
0
class CommitTreeTests(TestCase):

    def setUp(self):
        super(CommitTreeTests, self).setUp()
        self.store = MemoryObjectStore()

    def test_single_blob(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"1a1e80437220f9312e855c37ac4398b68e5c1d50")
        self.assertEqual((stat.S_IFREG, blob.id), self.store[rootid][b"bla"])
        self.assertEqual(set([rootid, blob.id]), set(self.store._data.keys()))

    def test_nested(self):
        blob = Blob()
        blob.data = b"foo"
        self.store.add_object(blob)
        blobs = [(b"bla/bar", blob.id, stat.S_IFREG)]
        rootid = commit_tree(self.store, blobs)
        self.assertEqual(rootid, b"d92b959b216ad0d044671981196781b3258fa537")
        dirid = self.store[rootid][b"bla"][1]
        self.assertEqual(dirid, b"c1a1deb9788150829579a8b4efa6311e7b638650")
        self.assertEqual((stat.S_IFDIR, dirid), self.store[rootid][b"bla"])
        self.assertEqual((stat.S_IFREG, blob.id), self.store[dirid][b"bar"])
        self.assertEqual(set([rootid, dirid, blob.id]),
                          set(self.store._data.keys()))
예제 #4
0
 def _get_example_tar_stream(self, *tar_stream_args, **tar_stream_kwargs):
     store = MemoryObjectStore()
     b1 = Blob.from_string(b"somedata")
     store.add_object(b1)
     t1 = Tree()
     t1.add(b"somename", 0o100644, b1.id)
     store.add_object(t1)
     stream = b"".join(tar_stream(store, t1, *tar_stream_args, **tar_stream_kwargs))
     return BytesIO(stream)
예제 #5
0
class TestThinPack(PackTests):

    def setUp(self):
        super(TestThinPack, self).setUp()
        self.store = MemoryObjectStore()
        self.blobs = {}
        for blob in ('foo', 'bar', 'foo1234', 'bar2468'):
            self.blobs[blob] = make_object(Blob, data=blob)
        self.store.add_object(self.blobs['foo'])
        self.store.add_object(self.blobs['bar'])

        # Build a thin pack. 'foo' is as an external reference, 'bar' an
        # internal reference.
        self.pack_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.pack_dir)
        self.pack_prefix = os.path.join(self.pack_dir, 'pack')

        f = open(self.pack_prefix + '.pack', 'wb')
        try:
            build_pack(f, [
                (REF_DELTA, (self.blobs['foo'].id, 'foo1234')),
                (Blob.type_num, 'bar'),
                (REF_DELTA, (self.blobs['bar'].id, 'bar2468'))],
                store=self.store)
        finally:
            f.close()

        # Index the new pack.
        with self.make_pack(True) as pack:
            with PackData(pack._data_path) as data:
                data.pack = pack
                data.create_index(self.pack_prefix + '.idx')

        del self.store[self.blobs['bar'].id]

    def make_pack(self, resolve_ext_ref):
        return Pack(
            self.pack_prefix,
            resolve_ext_ref=self.store.get_raw if resolve_ext_ref else None)

    def test_get_raw(self):
        with self.make_pack(False) as p:
            self.assertRaises(
                KeyError, p.get_raw, self.blobs['foo1234'].id)
        with self.make_pack(True) as p:
            self.assertEqual(
                (3, 'foo1234'),
                p.get_raw(self.blobs['foo1234'].id))

    def test_iterobjects(self):
        with self.make_pack(False) as p:
            self.assertRaises(KeyError, list, p.iterobjects())
        with self.make_pack(True) as p:
            self.assertEqual(
                sorted([self.blobs['foo1234'].id, self.blobs[b'bar'].id,
                        self.blobs['bar2468'].id]),
                sorted(o.id for o in p.iterobjects()))
예제 #6
0
 def _get_example_tar_stream(self, *tar_stream_args, **tar_stream_kwargs):
     store = MemoryObjectStore()
     b1 = Blob.from_string(b"somedata")
     store.add_object(b1)
     t1 = Tree()
     t1.add(b"somename", 0o100644, b1.id)
     store.add_object(t1)
     stream = b''.join(
         tar_stream(store, t1, *tar_stream_args, **tar_stream_kwargs))
     return BytesIO(stream)
예제 #7
0
 def test_simple(self):
     store = MemoryObjectStore()
     b1 = Blob.from_string(b"somedata")
     store.add_object(b1)
     t1 = Tree()
     t1.add(b"somename", 0o100644, b1.id)
     store.add_object(t1)
     stream = b''.join(tar_stream(store, t1, 10))
     out = BytesIO(stream)
     tf = tarfile.TarFile(fileobj=out)
     self.addCleanup(tf.close)
     self.assertEqual(["somename"], tf.getnames())
예제 #8
0
 def test_simple(self):
     store = MemoryObjectStore()
     b1 = Blob.from_string(b"somedata")
     store.add_object(b1)
     t1 = Tree()
     t1.add(b"somename", 0o100644, b1.id)
     store.add_object(t1)
     stream = b''.join(tar_stream(store, t1, 10))
     out = BytesIO(stream)
     tf = tarfile.TarFile(fileobj=out)
     self.addCleanup(tf.close)
     self.assertEqual(["somename"], tf.getnames())
예제 #9
0
class TreeLookupPathTests(TestCase):
    def setUp(self):
        TestCase.setUp(self)
        self.store = MemoryObjectStore()
        blob_a = make_object(Blob, data=b"a")
        blob_b = make_object(Blob, data=b"b")
        blob_c = make_object(Blob, data=b"c")
        for blob in [blob_a, blob_b, blob_c]:
            self.store.add_object(blob)

        blobs = [
            (b"a", blob_a.id, 0o100644),
            (b"ad/b", blob_b.id, 0o100644),
            (b"ad/bd/c", blob_c.id, 0o100755),
            (b"ad/c", blob_c.id, 0o100644),
            (b"c", blob_c.id, 0o100644),
            (b"d", blob_c.id, S_IFGITLINK),
        ]
        self.tree_id = commit_tree(self.store, blobs)

    def get_object(self, sha):
        return self.store[sha]

    def test_lookup_blob(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b"a")[1]
        self.assertIsInstance(self.store[o_id], Blob)

    def test_lookup_tree(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b"ad")[1]
        self.assertIsInstance(self.store[o_id], Tree)
        o_id = tree_lookup_path(self.get_object, self.tree_id, b"ad/bd")[1]
        self.assertIsInstance(self.store[o_id], Tree)
        o_id = tree_lookup_path(self.get_object, self.tree_id, b"ad/bd/")[1]
        self.assertIsInstance(self.store[o_id], Tree)

    def test_lookup_submodule(self):
        tree_lookup_path(self.get_object, self.tree_id, b"d")[1]
        self.assertRaises(SubmoduleEncountered, tree_lookup_path,
                          self.get_object, self.tree_id, b"d/a")

    def test_lookup_nonexistent(self):
        self.assertRaises(KeyError, tree_lookup_path, self.get_object,
                          self.tree_id, b"j")

    def test_lookup_not_tree(self):
        self.assertRaises(
            NotTreeError,
            tree_lookup_path,
            self.get_object,
            self.tree_id,
            b"ad/b/j",
        )
예제 #10
0
 def test_object_diff_remove_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"bar.txt", 0o644, b1.id),
                       (None, None, None))
     self.assertEqual([
         b'diff --git a/bar.txt /dev/null', b'deleted mode 644',
         b'index a116b51..0000000', b'--- a/bar.txt', b'+++ /dev/null',
         b'@@ -1,2 +1,0 @@', b'-new', b'-same'
     ],
                      f.getvalue().splitlines())
예제 #11
0
    def test_add_thin_pack(self):
        o = MemoryObjectStore()
        blob = make_object(Blob, data=b'yummy data')
        o.add_object(blob)

        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (blob.id, b'more yummy data')),
            ], store=o)
        o.add_thin_pack(f.read, None)
        packed_blob_sha = sha_to_hex(entries[0][3])
        self.assertEqual((Blob.type_num, b'more yummy data'),
                         o.get_raw(packed_blob_sha))
예제 #12
0
 def test_object_diff_add_blob(self):
     f = BytesIO()
     store = MemoryObjectStore()
     b2 = Blob.from_string(b"new\nsame\n")
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       (b"bar.txt", 0o644, b2.id))
     self.assertEqual([
         b'diff --git /dev/null b/bar.txt', b'new mode 644',
         b'index 0000000..a116b51 644', b'--- /dev/null', b'+++ b/bar.txt',
         b'@@ -1,0 +1,2 @@', b'+new', b'+same'
     ],
                      f.getvalue().splitlines())
예제 #13
0
    def test_add_thin_pack(self):
        o = MemoryObjectStore()
        blob = make_object(Blob, data=b'yummy data')
        o.add_object(blob)

        f = BytesIO()
        entries = build_pack(f, [
            (REF_DELTA, (blob.id, b'more yummy data')),
            ], store=o)
        o.add_thin_pack(f.read, None)
        packed_blob_sha = sha_to_hex(entries[0][3])
        self.assertEqual((Blob.type_num, b'more yummy data'),
                         o.get_raw(packed_blob_sha))
예제 #14
0
 def test_object_diff_add_bin_blob(self):
     f = BytesIO()
     b2 = Blob.from_string(
         '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
         '\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3')
     store = MemoryObjectStore()
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                                 ('bar.png', 0o644, b2.id))
     self.assertEqual([
         'diff --git /dev/null b/bar.png',
         'new mode 644',
         'index 0000000..06364b7 644',
         'Binary files /dev/null and b/bar.png differ'
         ], f.getvalue().splitlines())
예제 #15
0
 def test_object_diff_add_bin_blob(self):
     f = BytesIO()
     b2 = Blob.from_string(
         '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
         '\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3')
     store = MemoryObjectStore()
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       ('bar.png', 0o644, b2.id))
     self.assertEqual([
         'diff --git /dev/null b/bar.png', 'new mode 644',
         'index 0000000..06364b7 644',
         'Binary files /dev/null and b/bar.png differ'
     ],
                      f.getvalue().splitlines())
예제 #16
0
 def test_object_diff_remove_bin_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(
         '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
         '\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b')
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, ('foo.png', 0o644, b1.id),
                                 (None, None, None))
     self.assertEqual([
         'diff --git a/foo.png /dev/null',
         'deleted mode 644',
         'index f73e47d..0000000',
         'Binary files a/foo.png and /dev/null differ'
         ], f.getvalue().splitlines())
예제 #17
0
 def test_object_diff_remove_bin_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(
         '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52'
         '\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b')
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, ('foo.png', 0o644, b1.id),
                       (None, None, None))
     self.assertEqual([
         'diff --git a/foo.png /dev/null', 'deleted mode 644',
         'index f73e47d..0000000',
         'Binary files a/foo.png and /dev/null differ'
     ],
                      f.getvalue().splitlines())
예제 #18
0
 def test_object_diff_add_blob(self):
     f = BytesIO()
     store = MemoryObjectStore()
     b2 = Blob.from_string(b"new\nsame\n")
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                                 ("bar.txt", 0o644, b2.id))
     self.assertEqual([
         b'diff --git /dev/null b/bar.txt',
         b'new mode 644',
         b'index 0000000..a116b51 644',
         b'--- /dev/null',
         b'+++ b/bar.txt',
         b'@@ -1,0 +1,2 @@',
         b'+new',
         b'+same'
         ], f.getvalue().splitlines())
예제 #19
0
 def test_object_diff_remove_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, ("bar.txt", 0o644, b1.id),
                                 (None, None, None))
     self.assertEqual([
         b'diff --git a/bar.txt /dev/null',
         b'deleted mode 644',
         b'index a116b51..0000000',
         b'--- a/bar.txt',
         b'+++ /dev/null',
         b'@@ -1,2 +1,0 @@',
         b'-new',
         b'-same'
         ], f.getvalue().splitlines())
 def test_object_diff_remove_bin_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x04\x00\x00\x00\x05\x04\x8b")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"foo.png", 0o644, b1.id),
                       (None, None, None))
     self.assertEqual(
         [
             b"diff --git a/foo.png b/foo.png",
             b"deleted file mode 644",
             b"index f73e47d..0000000",
             b"Binary files a/foo.png and /dev/null differ",
         ],
         f.getvalue().splitlines(),
     )
예제 #21
0
class TreeLookupPathTests(TestCase):

    def setUp(self):
        TestCase.setUp(self)
        self.store = MemoryObjectStore()
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        blob_c = make_object(Blob, data=b'c')
        for blob in [blob_a, blob_b, blob_c]:
            self.store.add_object(blob)

        blobs = [
          (b'a', blob_a.id, 0o100644),
          (b'ad/b', blob_b.id, 0o100644),
          (b'ad/bd/c', blob_c.id, 0o100755),
          (b'ad/c', blob_c.id, 0o100644),
          (b'c', blob_c.id, 0o100644),
          ]
        self.tree_id = commit_tree(self.store, blobs)

    def get_object(self, sha):
        return self.store[sha]

    def test_lookup_blob(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'a')[1]
        self.assertTrue(isinstance(self.store[o_id], Blob))

    def test_lookup_tree(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad/bd')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad/bd/')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))

    def test_lookup_nonexistent(self):
        self.assertRaises(
            KeyError, tree_lookup_path, self.get_object, self.tree_id, b'j')

    def test_lookup_not_tree(self):
        self.assertRaises(
            NotTreeError, tree_lookup_path, self.get_object, self.tree_id,
            b'ad/b/j')
예제 #22
0
 def test_object_diff_kind_change(self):
     f = BytesIO()
     b1 = Blob.from_string("new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, ("bar.txt", 0o644, b1.id),
         ("bar.txt", 0o160000, "06d0bdd9e2e20377b3180e4986b14c8549b393e4"))
     self.assertEqual([
         'diff --git a/bar.txt b/bar.txt',
         'old mode 644',
         'new mode 160000',
         'index a116b51..06d0bdd 160000',
         '--- a/bar.txt',
         '+++ b/bar.txt',
         '@@ -1,2 +1,1 @@',
         '-new',
         '-same',
         '+Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',
         ], f.getvalue().splitlines())
 def test_object_diff_add_bin_blob(self):
     f = BytesIO()
     b2 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
                           b"\x00\x00\x00\x0d\x49\x48\x44\x52"
                           b"\x00\x00\x01\xd5\x00\x00\x00\x9f"
                           b"\x08\x03\x00\x00\x00\x98\xd3\xb3")
     store = MemoryObjectStore()
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       (b"bar.png", 0o644, b2.id))
     self.assertEqual(
         [
             b"diff --git a/bar.png b/bar.png",
             b"new file mode 644",
             b"index 0000000..06364b7",
             b"Binary files /dev/null and b/bar.png differ",
         ],
         f.getvalue().splitlines(),
     )
예제 #24
0
 def test_object_diff_kind_change(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, ("bar.txt", 0o644, b1.id),
         ("bar.txt", 0o160000, "06d0bdd9e2e20377b3180e4986b14c8549b393e4"))
     self.assertEqual([
         b'diff --git a/bar.txt b/bar.txt',
         b'old mode 644',
         b'new mode 160000',
         b'index a116b51..06d0bdd 160000',
         b'--- a/bar.txt',
         b'+++ b/bar.txt',
         b'@@ -1,2 +1,1 @@',
         b'-new',
         b'-same',
         b'+Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',
         ], f.getvalue().splitlines())
예제 #25
0
class TreeLookupPathTests(TestCase):

    def setUp(self):
        TestCase.setUp(self)
        self.store = MemoryObjectStore()
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        blob_c = make_object(Blob, data=b'c')
        for blob in [blob_a, blob_b, blob_c]:
            self.store.add_object(blob)

        blobs = [
          (b'a', blob_a.id, 0o100644),
          (b'ad/b', blob_b.id, 0o100644),
          (b'ad/bd/c', blob_c.id, 0o100755),
          (b'ad/c', blob_c.id, 0o100644),
          (b'c', blob_c.id, 0o100644),
          ]
        self.tree_id = commit_tree(self.store, blobs)

    def get_object(self, sha):
        return self.store[sha]

    def test_lookup_blob(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'a')[1]
        self.assertTrue(isinstance(self.store[o_id], Blob))

    def test_lookup_tree(self):
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad/bd')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))
        o_id = tree_lookup_path(self.get_object, self.tree_id, b'ad/bd/')[1]
        self.assertTrue(isinstance(self.store[o_id], Tree))

    def test_lookup_nonexistent(self):
        self.assertRaises(
            KeyError, tree_lookup_path, self.get_object, self.tree_id, b'j')

    def test_lookup_not_tree(self):
        self.assertRaises(
            NotTreeError, tree_lookup_path, self.get_object, self.tree_id,
            b'ad/b/j')
예제 #26
0
 def test_object_diff_add_blob(self):
     f = BytesIO()
     store = MemoryObjectStore()
     b2 = Blob.from_string(b"new\nsame\n")
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None), (b"bar.txt", 0o644, b2.id))
     self.assertEqual(
         [
             b"diff --git /dev/null b/bar.txt",
             b"new mode 644",
             b"index 0000000..a116b51 644",
             b"--- /dev/null",
             b"+++ b/bar.txt",
             b"@@ -1,0 +1,2 @@",
             b"+new",
             b"+same",
         ],
         f.getvalue().splitlines(),
     )
예제 #27
0
 def test_object_diff_remove_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"bar.txt", 0o644, b1.id), (None, None, None))
     self.assertEqual(
         [
             b"diff --git a/bar.txt /dev/null",
             b"deleted mode 644",
             b"index a116b51..0000000",
             b"--- a/bar.txt",
             b"+++ /dev/null",
             b"@@ -1,2 +1,0 @@",
             b"-new",
             b"-same",
         ],
         f.getvalue().splitlines(),
     )
 def test_object_diff_remove_blob(self):
     f = BytesIO()
     b1 = Blob.from_string(b"new\nsame\n")
     store = MemoryObjectStore()
     store.add_object(b1)
     write_object_diff(f, store, (b"bar.txt", 0o644, b1.id),
                       (None, None, None))
     self.assertEqual(
         [
             b"diff --git a/bar.txt b/bar.txt",
             b"deleted file mode 644",
             b"index a116b51..0000000",
             b"--- a/bar.txt",
             b"+++ /dev/null",
             b"@@ -1,2 +0,0 @@",
             b"-new",
             b"-same",
         ],
         f.getvalue().splitlines(),
     )
 def test_object_diff_add_blob(self):
     f = BytesIO()
     store = MemoryObjectStore()
     b2 = Blob.from_string(b"new\nsame\n")
     store.add_object(b2)
     write_object_diff(f, store, (None, None, None),
                       (b"bar.txt", 0o644, b2.id))
     self.assertEqual(
         [
             b"diff --git a/bar.txt b/bar.txt",
             b"new file mode 644",
             b"index 0000000..a116b51",
             b"--- /dev/null",
             b"+++ b/bar.txt",
             b"@@ -0,0 +1,2 @@",
             b"+new",
             b"+same",
         ],
         f.getvalue().splitlines(),
     )
예제 #30
0
class DiffTestCase(TestCase):
    def setUp(self):
        super(DiffTestCase, self).setUp()
        self.store = MemoryObjectStore()
        self.empty_tree = self.commit_tree([])

    def commit_tree(self, entries):
        commit_blobs = []
        for entry in entries:
            if len(entry) == 2:
                path, obj = entry
                mode = F
            else:
                path, obj, mode = entry
            if isinstance(obj, Blob):
                self.store.add_object(obj)
                sha = obj.id
            else:
                sha = obj
            commit_blobs.append((path, sha, mode))
        return self.store[commit_tree(self.store, commit_blobs)]
예제 #31
0
class DiffTestCase(TestCase):
    def setUp(self):
        super(DiffTestCase, self).setUp()
        self.store = MemoryObjectStore()
        self.empty_tree = self.commit_tree([])

    def commit_tree(self, entries):
        commit_blobs = []
        for entry in entries:
            if len(entry) == 2:
                path, obj = entry
                mode = F
            else:
                path, obj, mode = entry
            if isinstance(obj, Blob):
                self.store.add_object(obj)
                sha = obj.id
            else:
                sha = obj
            commit_blobs.append((path, sha, mode))
        return self.store[commit_tree(self.store, commit_blobs)]
예제 #32
0
class CommitTreeChangesTests(TestCase):

    def setUp(self):
        super(CommitTreeChangesTests, self).setUp()
        self.store = MemoryObjectStore()
        self.blob_a = make_object(Blob, data=b'a')
        self.blob_b = make_object(Blob, data=b'b')
        self.blob_c = make_object(Blob, data=b'c')
        for blob in [self.blob_a, self.blob_b, self.blob_c]:
            self.store.add_object(blob)

        blobs = [
          (b'a', self.blob_a.id, 0o100644),
          (b'ad/b', self.blob_b.id, 0o100644),
          (b'ad/bd/c', self.blob_c.id, 0o100755),
          (b'ad/c', self.blob_c.id, 0o100644),
          (b'c', self.blob_c.id, 0o100644),
          ]
        self.tree_id = commit_tree(self.store, blobs)

    def test_no_changes(self):
        self.assertEqual(
                self.store[self.tree_id],
                commit_tree_changes(self.store, self.store[self.tree_id], []))

    def test_add_blob(self):
        blob_d = make_object(Blob, data=b'd')
        new_tree = commit_tree_changes(
                self.store, self.store[self.tree_id], [
                    (b'd', 0o100644, blob_d.id)])
        self.assertEqual(
            new_tree[b'd'],
            (33188, b'c59d9b6344f1af00e504ba698129f07a34bbed8d'))

    def test_add_blob_in_dir(self):
        blob_d = make_object(Blob, data=b'd')
        new_tree = commit_tree_changes(
                self.store, self.store[self.tree_id], [
                    (b'e/f/d', 0o100644, blob_d.id)])
        self.assertEqual(
            new_tree.items(), [
                TreeEntry(path=b'a', mode=stat.S_IFREG | 0o100644,
                          sha=self.blob_a.id),
                TreeEntry(path=b'ad', mode=stat.S_IFDIR,
                          sha=b'0e2ce2cd7725ff4817791be31ccd6e627e801f4a'),
                TreeEntry(path=b'c', mode=stat.S_IFREG | 0o100644,
                          sha=self.blob_c.id),
                TreeEntry(path=b'e', mode=stat.S_IFDIR,
                          sha=b'6ab344e288724ac2fb38704728b8896e367ed108')
                ])
        e_tree = self.store[new_tree[b'e'][1]]
        self.assertEqual(
            e_tree.items(), [
                TreeEntry(path=b'f', mode=stat.S_IFDIR,
                          sha=b'24d2c94d8af232b15a0978c006bf61ef4479a0a5')
                ])
        f_tree = self.store[e_tree[b'f'][1]]
        self.assertEqual(
            f_tree.items(), [
                TreeEntry(path=b'd', mode=stat.S_IFREG | 0o100644,
                          sha=blob_d.id)
                ])

    def test_delete_blob(self):
        new_tree = commit_tree_changes(
                self.store, self.store[self.tree_id], [
                    (b'ad/bd/c', None, None)])
        self.assertEqual(set(new_tree), {b'a', b'ad', b'c'})
        ad_tree = self.store[new_tree[b'ad'][1]]
        self.assertEqual(set(ad_tree), {b'b', b'c'})
예제 #33
0
class WalkerTest(TestCase):

    def setUp(self):
        super(WalkerTest, self).setUp()
        self.store = MemoryObjectStore()

    def make_commits(self, commit_spec, **kwargs):
        times = kwargs.pop('times', [])
        attrs = kwargs.pop('attrs', {})
        for i, t in enumerate(times):
            attrs.setdefault(i + 1, {})['commit_time'] = t
        return build_commit_graph(self.store, commit_spec, attrs=attrs,
                                  **kwargs)

    def make_linear_commits(self, num_commits, **kwargs):
        commit_spec = []
        for i in range(1, num_commits + 1):
            c = [i]
            if i > 1:
                c.append(i - 1)
            commit_spec.append(c)
        return self.make_commits(commit_spec, **kwargs)

    def assertWalkYields(self, expected, *args, **kwargs):
        walker = Walker(self.store, *args, **kwargs)
        expected = list(expected)
        for i, entry in enumerate(expected):
            if isinstance(entry, Commit):
                expected[i] = TestWalkEntry(entry, None)
        actual = list(walker)
        self.assertEqual(expected, actual)

    def test_tag(self):
        c1, c2, c3 = self.make_linear_commits(3)
        t2 = make_tag(target=c2)
        self.store.add_object(t2)
        self.assertWalkYields([c2, c1], [t2.id])

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1], [c1.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c2, c1], [c3.id, c1.id])
        self.assertWalkYields([c3, c2], [c3.id], exclude=[c1.id])
        self.assertWalkYields([c3, c2], [c3.id, c1.id], exclude=[c1.id])
        self.assertWalkYields([c3], [c3.id, c1.id], exclude=[c2.id])

    def test_missing(self):
        cs = list(reversed(self.make_linear_commits(20)))
        self.assertWalkYields(cs, [cs[0].id])

        # Exactly how close we can get to a missing commit depends on our
        # implementation (in particular the choice of _MAX_EXTRA_COMMITS), but
        # we should at least be able to walk some history in a broken repo.
        del self.store[cs[-1].id]
        for i in range(1, 11):
            self.assertWalkYields(cs[:i], [cs[0].id], max_entries=i)
        self.assertRaises(MissingCommitError, Walker, self.store, [cs[-1].id])

    def test_branch(self):
        c1, x2, x3, y4 = self.make_commits([[1], [2, 1], [3, 2], [4, 1]])
        self.assertWalkYields([x3, x2, c1], [x3.id])
        self.assertWalkYields([y4, c1], [y4.id])
        self.assertWalkYields([y4, x2, c1], [y4.id, x2.id])
        self.assertWalkYields([y4, x2], [y4.id, x2.id], exclude=[c1.id])
        self.assertWalkYields([y4, x3], [y4.id, x3.id], exclude=[x2.id])
        self.assertWalkYields([y4], [y4.id], exclude=[x3.id])
        self.assertWalkYields([x3, x2], [x3.id], exclude=[y4.id])

    def test_merge(self):
        c1, c2, c3, c4 = self.make_commits([[1], [2, 1], [3, 1], [4, 2, 3]])
        self.assertWalkYields([c4, c3, c2, c1], [c4.id])
        self.assertWalkYields([c3, c1], [c3.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c4, c3], [c4.id], exclude=[c2.id])
        self.assertWalkYields([c4, c2], [c4.id], exclude=[c3.id])

    def test_merge_of_new_branch_from_old_base(self):
        # The commit on the branch was made at a time after any of the
        # commits on master, but the branch was from an older commit.
        # See also test_merge_of_old_branch
        self.maxDiff = None
        c1, c2, c3, c4, c5 = self.make_commits(
            [[1], [2, 1], [3, 2], [4, 1], [5, 3, 4]],
            times=[1, 2, 3, 4, 5],
        )
        self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id])
        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c2, c1], [c2.id])

    @expectedFailure
    def test_merge_of_old_branch(self):
        # The commit on the branch was made at a time before any of
        # the commits on master, but it was merged into master after
        # those commits.
        # See also test_merge_of_new_branch_from_old_base
        self.maxDiff = None
        c1, c2, c3, c4, c5 = self.make_commits(
            [[1], [2, 1], [3, 2], [4, 1], [5, 3, 4]],
            times=[1, 3, 4, 2, 5],
        )
        self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id])
        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c2, c1], [c2.id])

    def test_reverse(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id], reverse=True)

    def test_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], max_entries=3)
        self.assertWalkYields([c3, c2], [c3.id], max_entries=2)
        self.assertWalkYields([c3], [c3.id], max_entries=1)

    def test_reverse_after_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id], max_entries=3,
                              reverse=True)
        self.assertWalkYields([c2, c3], [c3.id], max_entries=2, reverse=True)
        self.assertWalkYields([c3], [c3.id], max_entries=1, reverse=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_changes_multiple_parents(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        c1, c2, c3 = self.make_commits(
            [[1], [2], [3, 1, 2]],
            trees={1: [(b'a', blob_a1)], 2: [(b'b', blob_b2)],
                   3: [(b'a', blob_a3), (b'b', blob_b2)]})
        # a is a modify/add conflict and b is not conflicted.
        changes = [[
                TreeChange(CHANGE_MODIFY,
                           (b'a', F, blob_a1.id), (b'a', F, blob_a3.id)),
                TreeChange.add((b'a', F, blob_a3.id)),
        ]]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              exclude=[c1.id, c2.id])

    def test_path_matches(self):
        walker = Walker(None, [], paths=[b'foo', b'bar', b'baz/quux'])
        self.assertTrue(walker._path_matches(b'foo'))
        self.assertTrue(walker._path_matches(b'foo/a'))
        self.assertTrue(walker._path_matches(b'foo/a/b'))
        self.assertTrue(walker._path_matches(b'bar'))
        self.assertTrue(walker._path_matches(b'baz/quux'))
        self.assertTrue(walker._path_matches(b'baz/quux/a'))

        self.assertFalse(walker._path_matches(None))
        self.assertFalse(walker._path_matches(b'oops'))
        self.assertFalse(walker._path_matches(b'fool'))
        self.assertFalse(walker._path_matches(b'baz'))
        self.assertFalse(walker._path_matches(b'baz/quu'))

    def test_paths(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        blob_b3 = make_object(Blob, data=b'b3')
        c1, c2, c3 = self.make_linear_commits(
            3, trees={1: [(b'a', blob_a1)],
                      2: [(b'a', blob_a1), (b'x/b', blob_b2)],
                      3: [(b'a', blob_a3), (b'x/b', blob_b3)]})

        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'a'])
        self.assertWalkYields([c3, c2], [c3.id], paths=[b'x/b'])

        # All changes are included, not just for requested paths.
        changes = [
            TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id),
                       (b'a', F, blob_a3.id)),
            TreeChange(CHANGE_MODIFY, (b'x/b', F, blob_b2.id),
                       (b'x/b', F, blob_b3.id)),
        ]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              max_entries=1, paths=[b'a'])

    def test_paths_subtree(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2, c3 = self.make_linear_commits(
            3, trees={1: [(b'x/a', blob_a)],
                      2: [(b'b', blob_b), (b'x/a', blob_a)],
                      3: [(b'b', blob_b), (b'x/a', blob_a), (b'x/b', blob_b)]})
        self.assertWalkYields([c2], [c3.id], paths=[b'b'])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'x'])

    def test_paths_max_entries(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2 = self.make_linear_commits(
            2, trees={1: [(b'a', blob_a)],
                      2: [(b'a', blob_a), (b'b', blob_b)]})
        self.assertWalkYields([c2], [c2.id], paths=[b'b'], max_entries=1)
        self.assertWalkYields([c1], [c1.id], paths=[b'a'], max_entries=1)

    def test_paths_merge(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_a2 = make_object(Blob, data=b'a2')
        blob_a3 = make_object(Blob, data=b'a3')
        x1, y2, m3, m4 = self.make_commits(
            [[1], [2], [3, 1, 2], [4, 1, 2]],
            trees={1: [(b'a', blob_a1)],
                   2: [(b'a', blob_a2)],
                   3: [(b'a', blob_a3)],
                   4: [(b'a', blob_a1)]})  # Non-conflicting
        self.assertWalkYields([m3, y2, x1], [m3.id], paths=[b'a'])
        self.assertWalkYields([y2, x1], [m4.id], paths=[b'a'])

    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)

    def test_follow_rename(self):
        blob = make_object(Blob, data=b'blob')
        names = [b'a', b'a', b'b', b'b', b'c', b'c']

        trees = dict((i + 1, [(n, blob, F)]) for i, n in enumerate(names))
        c1, c2, c3, c4, c5, c6 = self.make_linear_commits(6, trees=trees)
        self.assertWalkYields([c5], [c6.id], paths=[b'c'])

        def e(n):
            return (n, F, blob.id)
        self.assertWalkYields(
            [TestWalkEntry(c5, [TreeChange(CHANGE_RENAME, e(b'b'), e(b'c'))]),
             TestWalkEntry(c3, [TreeChange(CHANGE_RENAME, e(b'a'), e(b'b'))]),
             TestWalkEntry(c1, [TreeChange.add(e(b'a'))])],
            [c6.id], paths=[b'c'], follow=True)

    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_since(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=0)
        self.assertWalkYields([c3, c2], [c3.id], since=1)
        self.assertWalkYields([c3, c2], [c3.id], since=99)
        self.assertWalkYields([c3, c2], [c3.id], since=100)
        self.assertWalkYields([c3], [c3.id], since=101)
        self.assertWalkYields([c3], [c3.id], since=199)
        self.assertWalkYields([c3], [c3.id], since=200)
        self.assertWalkYields([], [c3.id], since=201)
        self.assertWalkYields([], [c3.id], since=300)

    def test_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], until=-1)
        self.assertWalkYields([c1], [c3.id], until=0)
        self.assertWalkYields([c1], [c3.id], until=1)
        self.assertWalkYields([c1], [c3.id], until=99)
        self.assertWalkYields([c2, c1], [c3.id], until=100)
        self.assertWalkYields([c2, c1], [c3.id], until=101)
        self.assertWalkYields([c2, c1], [c3.id], until=199)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=200)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=201)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=300)

    def test_since_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], since=100, until=99)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1, until=201)
        self.assertWalkYields([c2], [c3.id], since=100, until=100)
        self.assertWalkYields([c2], [c3.id], since=50, until=150)

    def test_since_over_scan(self):
        commits = self.make_linear_commits(
          11, times=[9, 0, 1, 2, 3, 4, 5, 8, 6, 7, 9])
        c8, _, c10, c11 = commits[-4:]
        del self.store[commits[0].id]
        # c9 is older than we want to walk, but is out of order with its
        # parent, so we need to walk past it to get to c8.
        # c1 would also match, but we've deleted it, and it should get pruned
        # even with over-scanning.
        self.assertWalkYields([c11, c10, c8], [c11.id], since=7)

    def assertTopoOrderEqual(self, expected_commits, commits):
        entries = [TestWalkEntry(c, None) for c in commits]
        actual_ids = [e.commit.id for e in list(_topo_reorder(entries))]
        self.assertEqual([c.id for c in expected_commits], actual_ids)

    def test_topo_reorder_linear(self):
        commits = self.make_linear_commits(5)
        commits.reverse()
        for perm in permutations(commits):
            self.assertTopoOrderEqual(commits, perm)

    def test_topo_reorder_multiple_parents(self):
        c1, c2, c3 = self.make_commits([[1], [2], [3, 1, 2]])
        # Already sorted, so totally FIFO.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c3, c1, c2])

        # c3 causes one parent to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c1, c3, c2])

        # c3 causes both parents to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c2, c3])
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c1, c3])

    def test_topo_reorder_multiple_children(self):
        c1, c2, c3 = self.make_commits([[1], [2, 1], [3, 1]])

        # c2 and c3 are FIFO but c1 moves to the end.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c1, c2])
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c3, c2])

        self.assertTopoOrderEqual([c2, c3, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c2, c3, c1], [c2, c1, c3])
        self.assertTopoOrderEqual([c2, c3, c1], [c1, c2, c3])

    def test_out_of_order_children(self):
        c1, c2, c3, c4, c5 = self.make_commits(
          [[1], [2, 1], [3, 2], [4, 1], [5, 3, 4]],
          times=[2, 1, 3, 4, 5])
        self.assertWalkYields([c5, c4, c3, c1, c2], [c5.id])
        self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id], order=ORDER_TOPO)

    def test_out_of_order_with_exclude(self):
        # Create the following graph:
        # c1-------x2---m6
        #   \          /
        #    \-y3--y4-/--y5
        # Due to skew, y5 is the oldest commit.
        c1, x2, y3, y4, y5, m6 = self.make_commits(
          [[1], [2, 1], [3, 1], [4, 3], [5, 4], [6, 2, 4]],
          times=[2, 3, 4, 5, 1, 6])
        self.assertWalkYields([m6, y4, y3, x2, c1], [m6.id])
        # Ensure that c1..y4 get excluded even though they're popped from the
        # priority queue long before y5.
        self.assertWalkYields([m6, x2], [m6.id], exclude=[y5.id])

    def test_empty_walk(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], exclude=[c3.id])
예제 #34
0
class FindShallowTests(TestCase):

    def setUp(self):
        super(FindShallowTests, self).setUp()
        self._store = MemoryObjectStore()

    def make_commit(self, **attrs):
        commit = make_commit(**attrs)
        self._store.add_object(commit)
        return commit

    def make_linear_commits(self, n, message=b''):
        commits = []
        parents = []
        for _ in range(n):
            commits.append(self.make_commit(parents=parents, message=message))
            parents = [commits[-1].id]
        return commits

    def assertSameElements(self, expected, actual):
        self.assertEqual(set(expected), set(actual))

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)

        self.assertEqual((set([c3.id]), set([])),
                         _find_shallow(self._store, [c3.id], 1))
        self.assertEqual((set([c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 2))
        self.assertEqual((set([c1.id]), set([c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 3))
        self.assertEqual((set([]), set([c1.id, c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 4))

    def test_multiple_independent(self):
        a = self.make_linear_commits(2, message=b'a')
        b = self.make_linear_commits(2, message=b'b')
        c = self.make_linear_commits(2, message=b'c')
        heads = [a[1].id, b[1].id, c[1].id]

        self.assertEqual((set([a[0].id, b[0].id, c[0].id]), set(heads)),
                         _find_shallow(self._store, heads, 2))

    def test_multiple_overlapping(self):
        # Create the following commit tree:
        # 1--2
        #  \
        #   3--4
        c1, c2 = self.make_linear_commits(2)
        c3 = self.make_commit(parents=[c1.id])
        c4 = self.make_commit(parents=[c3.id])

        # 1 is shallow along the path from 4, but not along the path from 2.
        self.assertEqual((set([c1.id]), set([c1.id, c2.id, c3.id, c4.id])),
                         _find_shallow(self._store, [c2.id, c4.id], 3))

    def test_merge(self):
        c1 = self.make_commit()
        c2 = self.make_commit()
        c3 = self.make_commit(parents=[c1.id, c2.id])

        self.assertEqual((set([c1.id, c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 2))

    def test_tag(self):
        c1, c2 = self.make_linear_commits(2)
        tag = make_tag(c2, name=b'tag')
        self._store.add_object(tag)

        self.assertEqual((set([c1.id]), set([c2.id])),
                         _find_shallow(self._store, [tag.id], 2))
예제 #35
0
class TestThinPack(PackTests):

    def setUp(self):
        super(TestThinPack, self).setUp()
        self.store = MemoryObjectStore()
        self.blobs = {}
        for blob in (b'foo', b'bar', b'foo1234', b'bar2468'):
            self.blobs[blob] = make_object(Blob, data=blob)
        self.store.add_object(self.blobs[b'foo'])
        self.store.add_object(self.blobs[b'bar'])

        # Build a thin pack. 'foo' is as an external reference, 'bar' an
        # internal reference.
        self.pack_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.pack_dir)
        self.pack_prefix = os.path.join(self.pack_dir, 'pack')

        with open(self.pack_prefix + '.pack', 'wb') as f:
            build_pack(f, [
                (REF_DELTA, (self.blobs[b'foo'].id, b'foo1234')),
                (Blob.type_num, b'bar'),
                (REF_DELTA, (self.blobs[b'bar'].id, b'bar2468'))],
                store=self.store)

        # Index the new pack.
        with self.make_pack(True) as pack:
            with PackData(pack._data_path) as data:
                data.pack = pack
                data.create_index(self.pack_prefix + '.idx')

        del self.store[self.blobs[b'bar'].id]

    def make_pack(self, resolve_ext_ref):
        return Pack(
            self.pack_prefix,
            resolve_ext_ref=self.store.get_raw if resolve_ext_ref else None)

    def test_get_raw(self):
        with self.make_pack(False) as p:
            self.assertRaises(
                KeyError, p.get_raw, self.blobs[b'foo1234'].id)
        with self.make_pack(True) as p:
            self.assertEqual(
                (3, b'foo1234'),
                p.get_raw(self.blobs[b'foo1234'].id))

    def test_get_raw_unresolved(self):
        with self.make_pack(False) as p:
            self.assertEqual(
                (7, '\x19\x10(\x15f=#\xf8\xb7ZG\xe7\xa0\x19e\xdc\xdc\x96F\x8c',
                    ['x\x9ccf\x9f\xc0\xccbhdl\x02\x00\x06f\x01l']),
                p.get_raw_unresolved(self.blobs[b'foo1234'].id))
        with self.make_pack(True) as p:
            self.assertEqual(
                (7, '\x19\x10(\x15f=#\xf8\xb7ZG\xe7\xa0\x19e\xdc\xdc\x96F\x8c',
                    ['x\x9ccf\x9f\xc0\xccbhdl\x02\x00\x06f\x01l']),
                p.get_raw_unresolved(self.blobs[b'foo1234'].id))

    def test_iterobjects(self):
        with self.make_pack(False) as p:
            self.assertRaises(KeyError, list, p.iterobjects())
        with self.make_pack(True) as p:
            self.assertEqual(
                sorted([self.blobs[b'foo1234'].id, self.blobs[b'bar'].id,
                        self.blobs[b'bar2468'].id]),
                sorted(o.id for o in p.iterobjects()))
예제 #36
0
class WalkerTest(TestCase):

    def setUp(self):
        super(WalkerTest, self).setUp()
        self.store = MemoryObjectStore()

    def make_commits(self, commit_spec, **kwargs):
        times = kwargs.pop('times', [])
        attrs = kwargs.pop('attrs', {})
        for i, t in enumerate(times):
            attrs.setdefault(i + 1, {})['commit_time'] = t
        return build_commit_graph(self.store, commit_spec, attrs=attrs,
                                  **kwargs)

    def make_linear_commits(self, num_commits, **kwargs):
        commit_spec = []
        for i in range(1, num_commits + 1):
            c = [i]
            if i > 1:
                c.append(i - 1)
            commit_spec.append(c)
        return self.make_commits(commit_spec, **kwargs)

    def assertWalkYields(self, expected, *args, **kwargs):
        walker = Walker(self.store, *args, **kwargs)
        expected = list(expected)
        for i, entry in enumerate(expected):
            if isinstance(entry, Commit):
                expected[i] = TestWalkEntry(entry, None)
        actual = list(walker)
        self.assertEqual(expected, actual)

    def test_tag(self):
        c1, c2, c3 = self.make_linear_commits(3)
        t2 = make_tag(target=c2)
        self.store.add_object(t2)
        self.assertWalkYields([c2, c1], [t2.id])

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1], [c1.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c2, c1], [c3.id, c1.id])
        self.assertWalkYields([c3, c2], [c3.id], exclude=[c1.id])
        self.assertWalkYields([c3, c2], [c3.id, c1.id], exclude=[c1.id])
        self.assertWalkYields([c3], [c3.id, c1.id], exclude=[c2.id])

    def test_missing(self):
        cs = list(reversed(self.make_linear_commits(20)))
        self.assertWalkYields(cs, [cs[0].id])

        # Exactly how close we can get to a missing commit depends on our
        # implementation (in particular the choice of _MAX_EXTRA_COMMITS), but
        # we should at least be able to walk some history in a broken repo.
        del self.store[cs[-1].id]
        for i in range(1, 11):
            self.assertWalkYields(cs[:i], [cs[0].id], max_entries=i)
        self.assertRaises(MissingCommitError, Walker, self.store, [cs[-1].id])

    def test_branch(self):
        c1, x2, x3, y4 = self.make_commits([[1], [2, 1], [3, 2], [4, 1]])
        self.assertWalkYields([x3, x2, c1], [x3.id])
        self.assertWalkYields([y4, c1], [y4.id])
        self.assertWalkYields([y4, x2, c1], [y4.id, x2.id])
        self.assertWalkYields([y4, x2], [y4.id, x2.id], exclude=[c1.id])
        self.assertWalkYields([y4, x3], [y4.id, x3.id], exclude=[x2.id])
        self.assertWalkYields([y4], [y4.id], exclude=[x3.id])
        self.assertWalkYields([x3, x2], [x3.id], exclude=[y4.id])

    def test_merge(self):
        c1, c2, c3, c4 = self.make_commits([[1], [2, 1], [3, 1], [4, 2, 3]])
        self.assertWalkYields([c4, c3, c2, c1], [c4.id])
        self.assertWalkYields([c3, c1], [c3.id])
        self.assertWalkYields([c2, c1], [c2.id])
        self.assertWalkYields([c4, c3], [c4.id], exclude=[c2.id])
        self.assertWalkYields([c4, c2], [c4.id], exclude=[c3.id])

    def test_reverse(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id], reverse=True)

    def test_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], max_entries=3)
        self.assertWalkYields([c3, c2], [c3.id], max_entries=2)
        self.assertWalkYields([c3], [c3.id], max_entries=1)

    def test_reverse_after_max_entries(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c1, c2, c3], [c3.id], max_entries=3,
                              reverse=True)
        self.assertWalkYields([c2, c3], [c3.id], max_entries=2, reverse=True)
        self.assertWalkYields([c3], [c3.id], max_entries=1, reverse=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_changes_multiple_parents(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        c1, c2, c3 = self.make_commits(
            [[1], [2], [3, 1, 2]],
            trees={1: [(b'a', blob_a1)], 2: [(b'b', blob_b2)],
                   3: [(b'a', blob_a3), (b'b', blob_b2)]})
        # a is a modify/add conflict and b is not conflicted.
        changes = [[
                TreeChange(CHANGE_MODIFY,
                           (b'a', F, blob_a1.id), (b'a', F, blob_a3.id)),
                TreeChange.add((b'a', F, blob_a3.id)),
        ]]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              exclude=[c1.id, c2.id])

    def test_path_matches(self):
        walker = Walker(None, [], paths=[b'foo', b'bar', b'baz/quux'])
        self.assertTrue(walker._path_matches(b'foo'))
        self.assertTrue(walker._path_matches(b'foo/a'))
        self.assertTrue(walker._path_matches(b'foo/a/b'))
        self.assertTrue(walker._path_matches(b'bar'))
        self.assertTrue(walker._path_matches(b'baz/quux'))
        self.assertTrue(walker._path_matches(b'baz/quux/a'))

        self.assertFalse(walker._path_matches(None))
        self.assertFalse(walker._path_matches(b'oops'))
        self.assertFalse(walker._path_matches(b'fool'))
        self.assertFalse(walker._path_matches(b'baz'))
        self.assertFalse(walker._path_matches(b'baz/quu'))

    def test_paths(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_b2 = make_object(Blob, data=b'b2')
        blob_a3 = make_object(Blob, data=b'a3')
        blob_b3 = make_object(Blob, data=b'b3')
        c1, c2, c3 = self.make_linear_commits(
            3, trees={1: [(b'a', blob_a1)],
                      2: [(b'a', blob_a1), (b'x/b', blob_b2)],
                      3: [(b'a', blob_a3), (b'x/b', blob_b3)]})

        self.assertWalkYields([c3, c2, c1], [c3.id])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'a'])
        self.assertWalkYields([c3, c2], [c3.id], paths=[b'x/b'])

        # All changes are included, not just for requested paths.
        changes = [
            TreeChange(CHANGE_MODIFY, (b'a', F, blob_a1.id),
                       (b'a', F, blob_a3.id)),
            TreeChange(CHANGE_MODIFY, (b'x/b', F, blob_b2.id),
                       (b'x/b', F, blob_b3.id)),
        ]
        self.assertWalkYields([TestWalkEntry(c3, changes)], [c3.id],
                              max_entries=1, paths=[b'a'])

    def test_paths_subtree(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2, c3 = self.make_linear_commits(
            3, trees={1: [(b'x/a', blob_a)],
                      2: [(b'b', blob_b), (b'x/a', blob_a)],
                      3: [(b'b', blob_b), (b'x/a', blob_a), (b'x/b', blob_b)]})
        self.assertWalkYields([c2], [c3.id], paths=[b'b'])
        self.assertWalkYields([c3, c1], [c3.id], paths=[b'x'])

    def test_paths_max_entries(self):
        blob_a = make_object(Blob, data=b'a')
        blob_b = make_object(Blob, data=b'b')
        c1, c2 = self.make_linear_commits(
            2, trees={1: [(b'a', blob_a)],
                      2: [(b'a', blob_a), (b'b', blob_b)]})
        self.assertWalkYields([c2], [c2.id], paths=[b'b'], max_entries=1)
        self.assertWalkYields([c1], [c1.id], paths=[b'a'], max_entries=1)

    def test_paths_merge(self):
        blob_a1 = make_object(Blob, data=b'a1')
        blob_a2 = make_object(Blob, data=b'a2')
        blob_a3 = make_object(Blob, data=b'a3')
        x1, y2, m3, m4 = self.make_commits(
            [[1], [2], [3, 1, 2], [4, 1, 2]],
            trees={1: [(b'a', blob_a1)],
                   2: [(b'a', blob_a2)],
                   3: [(b'a', blob_a3)],
                   4: [(b'a', blob_a1)]})  # Non-conflicting
        self.assertWalkYields([m3, y2, x1], [m3.id], paths=[b'a'])
        self.assertWalkYields([y2, x1], [m4.id], paths=[b'a'])

    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)

    def test_follow_rename(self):
        blob = make_object(Blob, data=b'blob')
        names = [b'a', b'a', b'b', b'b', b'c', b'c']

        trees = dict((i + 1, [(n, blob, F)]) for i, n in enumerate(names))
        c1, c2, c3, c4, c5, c6 = self.make_linear_commits(6, trees=trees)
        self.assertWalkYields([c5], [c6.id], paths=[b'c'])

        def e(n):
            return (n, F, blob.id)
        self.assertWalkYields(
            [TestWalkEntry(c5, [TreeChange(CHANGE_RENAME, e(b'b'), e(b'c'))]),
             TestWalkEntry(c3, [TreeChange(CHANGE_RENAME, e(b'a'), e(b'b'))]),
             TestWalkEntry(c1, [TreeChange.add(e(b'a'))])],
            [c6.id], paths=[b'c'], follow=True)

    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_since(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=0)
        self.assertWalkYields([c3, c2], [c3.id], since=1)
        self.assertWalkYields([c3, c2], [c3.id], since=99)
        self.assertWalkYields([c3, c2], [c3.id], since=100)
        self.assertWalkYields([c3], [c3.id], since=101)
        self.assertWalkYields([c3], [c3.id], since=199)
        self.assertWalkYields([c3], [c3.id], since=200)
        self.assertWalkYields([], [c3.id], since=201)
        self.assertWalkYields([], [c3.id], since=300)

    def test_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], until=-1)
        self.assertWalkYields([c1], [c3.id], until=0)
        self.assertWalkYields([c1], [c3.id], until=1)
        self.assertWalkYields([c1], [c3.id], until=99)
        self.assertWalkYields([c2, c1], [c3.id], until=100)
        self.assertWalkYields([c2, c1], [c3.id], until=101)
        self.assertWalkYields([c2, c1], [c3.id], until=199)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=200)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=201)
        self.assertWalkYields([c3, c2, c1], [c3.id], until=300)

    def test_since_until(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], since=100, until=99)
        self.assertWalkYields([c3, c2, c1], [c3.id], since=-1, until=201)
        self.assertWalkYields([c2], [c3.id], since=100, until=100)
        self.assertWalkYields([c2], [c3.id], since=50, until=150)

    def test_since_over_scan(self):
        commits = self.make_linear_commits(
          11, times=[9, 0, 1, 2, 3, 4, 5, 8, 6, 7, 9])
        c8, _, c10, c11 = commits[-4:]
        del self.store[commits[0].id]
        # c9 is older than we want to walk, but is out of order with its
        # parent, so we need to walk past it to get to c8.
        # c1 would also match, but we've deleted it, and it should get pruned
        # even with over-scanning.
        self.assertWalkYields([c11, c10, c8], [c11.id], since=7)

    def assertTopoOrderEqual(self, expected_commits, commits):
        entries = [TestWalkEntry(c, None) for c in commits]
        actual_ids = [e.commit.id for e in list(_topo_reorder(entries))]
        self.assertEqual([c.id for c in expected_commits], actual_ids)

    def test_topo_reorder_linear(self):
        commits = self.make_linear_commits(5)
        commits.reverse()
        for perm in permutations(commits):
            self.assertTopoOrderEqual(commits, perm)

    def test_topo_reorder_multiple_parents(self):
        c1, c2, c3 = self.make_commits([[1], [2], [3, 1, 2]])
        # Already sorted, so totally FIFO.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c3, c1, c2])

        # c3 causes one parent to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c3, c1, c2], [c1, c3, c2])

        # c3 causes both parents to be yielded.
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c2, c3])
        self.assertTopoOrderEqual([c3, c2, c1], [c2, c1, c3])

    def test_topo_reorder_multiple_children(self):
        c1, c2, c3 = self.make_commits([[1], [2, 1], [3, 1]])

        # c2 and c3 are FIFO but c1 moves to the end.
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c2, c1])
        self.assertTopoOrderEqual([c3, c2, c1], [c3, c1, c2])
        self.assertTopoOrderEqual([c3, c2, c1], [c1, c3, c2])

        self.assertTopoOrderEqual([c2, c3, c1], [c2, c3, c1])
        self.assertTopoOrderEqual([c2, c3, c1], [c2, c1, c3])
        self.assertTopoOrderEqual([c2, c3, c1], [c1, c2, c3])

    def test_out_of_order_children(self):
        c1, c2, c3, c4, c5 = self.make_commits(
          [[1], [2, 1], [3, 2], [4, 1], [5, 3, 4]],
          times=[2, 1, 3, 4, 5])
        self.assertWalkYields([c5, c4, c3, c1, c2], [c5.id])
        self.assertWalkYields([c5, c4, c3, c2, c1], [c5.id], order=ORDER_TOPO)

    def test_out_of_order_with_exclude(self):
        # Create the following graph:
        # c1-------x2---m6
        #   \          /
        #    \-y3--y4-/--y5
        # Due to skew, y5 is the oldest commit.
        c1, x2, y3, y4, y5, m6 = self.make_commits(
          [[1], [2, 1], [3, 1], [4, 3], [5, 4], [6, 2, 4]],
          times=[2, 3, 4, 5, 1, 6])
        self.assertWalkYields([m6, y4, y3, x2, c1], [m6.id])
        # Ensure that c1..y4 get excluded even though they're popped from the
        # priority queue long before y5.
        self.assertWalkYields([m6, x2], [m6.id], exclude=[y5.id])

    def test_empty_walk(self):
        c1, c2, c3 = self.make_linear_commits(3)
        self.assertWalkYields([], [c3.id], exclude=[c3.id])
예제 #37
0
class CommitTreeChangesTests(TestCase):
    def setUp(self):
        super(CommitTreeChangesTests, self).setUp()
        self.store = MemoryObjectStore()
        self.blob_a = make_object(Blob, data=b"a")
        self.blob_b = make_object(Blob, data=b"b")
        self.blob_c = make_object(Blob, data=b"c")
        for blob in [self.blob_a, self.blob_b, self.blob_c]:
            self.store.add_object(blob)

        blobs = [
            (b"a", self.blob_a.id, 0o100644),
            (b"ad/b", self.blob_b.id, 0o100644),
            (b"ad/bd/c", self.blob_c.id, 0o100755),
            (b"ad/c", self.blob_c.id, 0o100644),
            (b"c", self.blob_c.id, 0o100644),
        ]
        self.tree_id = commit_tree(self.store, blobs)

    def test_no_changes(self):
        self.assertEqual(
            self.store[self.tree_id],
            commit_tree_changes(self.store, self.store[self.tree_id], []),
        )

    def test_add_blob(self):
        blob_d = make_object(Blob, data=b"d")
        new_tree = commit_tree_changes(self.store, self.store[self.tree_id],
                                       [(b"d", 0o100644, blob_d.id)])
        self.assertEqual(
            new_tree[b"d"],
            (33188, b"c59d9b6344f1af00e504ba698129f07a34bbed8d"),
        )

    def test_add_blob_in_dir(self):
        blob_d = make_object(Blob, data=b"d")
        new_tree = commit_tree_changes(
            self.store,
            self.store[self.tree_id],
            [(b"e/f/d", 0o100644, blob_d.id)],
        )
        self.assertEqual(
            new_tree.items(),
            [
                TreeEntry(path=b"a",
                          mode=stat.S_IFREG | 0o100644,
                          sha=self.blob_a.id),
                TreeEntry(
                    path=b"ad",
                    mode=stat.S_IFDIR,
                    sha=b"0e2ce2cd7725ff4817791be31ccd6e627e801f4a",
                ),
                TreeEntry(path=b"c",
                          mode=stat.S_IFREG | 0o100644,
                          sha=self.blob_c.id),
                TreeEntry(
                    path=b"e",
                    mode=stat.S_IFDIR,
                    sha=b"6ab344e288724ac2fb38704728b8896e367ed108",
                ),
            ],
        )
        e_tree = self.store[new_tree[b"e"][1]]
        self.assertEqual(
            e_tree.items(),
            [
                TreeEntry(
                    path=b"f",
                    mode=stat.S_IFDIR,
                    sha=b"24d2c94d8af232b15a0978c006bf61ef4479a0a5",
                )
            ],
        )
        f_tree = self.store[e_tree[b"f"][1]]
        self.assertEqual(
            f_tree.items(),
            [
                TreeEntry(
                    path=b"d", mode=stat.S_IFREG | 0o100644, sha=blob_d.id)
            ],
        )

    def test_delete_blob(self):
        new_tree = commit_tree_changes(self.store, self.store[self.tree_id],
                                       [(b"ad/bd/c", None, None)])
        self.assertEqual(set(new_tree), {b"a", b"ad", b"c"})
        ad_tree = self.store[new_tree[b"ad"][1]]
        self.assertEqual(set(ad_tree), {b"b", b"c"})
예제 #38
0
class CommitTreeChangesTests(TestCase):
    def setUp(self):
        super(CommitTreeChangesTests, self).setUp()
        self.store = MemoryObjectStore()
        self.blob_a = make_object(Blob, data=b'a')
        self.blob_b = make_object(Blob, data=b'b')
        self.blob_c = make_object(Blob, data=b'c')
        for blob in [self.blob_a, self.blob_b, self.blob_c]:
            self.store.add_object(blob)

        blobs = [
            (b'a', self.blob_a.id, 0o100644),
            (b'ad/b', self.blob_b.id, 0o100644),
            (b'ad/bd/c', self.blob_c.id, 0o100755),
            (b'ad/c', self.blob_c.id, 0o100644),
            (b'c', self.blob_c.id, 0o100644),
        ]
        self.tree_id = commit_tree(self.store, blobs)

    def test_no_changes(self):
        self.assertEqual(
            self.store[self.tree_id],
            commit_tree_changes(self.store, self.store[self.tree_id], []))

    def test_add_blob(self):
        blob_d = make_object(Blob, data=b'd')
        new_tree = commit_tree_changes(self.store, self.store[self.tree_id],
                                       [(b'd', 0o100644, blob_d.id)])
        self.assertEqual(new_tree[b'd'],
                         (33188, b'c59d9b6344f1af00e504ba698129f07a34bbed8d'))

    def test_add_blob_in_dir(self):
        blob_d = make_object(Blob, data=b'd')
        new_tree = commit_tree_changes(self.store, self.store[self.tree_id],
                                       [(b'e/f/d', 0o100644, blob_d.id)])
        self.assertEqual(new_tree.items(), [
            TreeEntry(
                path=b'a', mode=stat.S_IFREG | 0o100644, sha=self.blob_a.id),
            TreeEntry(path=b'ad',
                      mode=stat.S_IFDIR,
                      sha=b'0e2ce2cd7725ff4817791be31ccd6e627e801f4a'),
            TreeEntry(
                path=b'c', mode=stat.S_IFREG | 0o100644, sha=self.blob_c.id),
            TreeEntry(path=b'e',
                      mode=stat.S_IFDIR,
                      sha=b'6ab344e288724ac2fb38704728b8896e367ed108')
        ])
        e_tree = self.store[new_tree[b'e'][1]]
        self.assertEqual(e_tree.items(), [
            TreeEntry(path=b'f',
                      mode=stat.S_IFDIR,
                      sha=b'24d2c94d8af232b15a0978c006bf61ef4479a0a5')
        ])
        f_tree = self.store[e_tree[b'f'][1]]
        self.assertEqual(f_tree.items(), [
            TreeEntry(path=b'd', mode=stat.S_IFREG | 0o100644, sha=blob_d.id)
        ])

    def test_delete_blob(self):
        new_tree = commit_tree_changes(self.store, self.store[self.tree_id],
                                       [(b'ad/bd/c', None, None)])
        self.assertEqual(set(new_tree), {b'a', b'ad', b'c'})
        ad_tree = self.store[new_tree[b'ad'][1]]
        self.assertEqual(set(ad_tree), {b'b', b'c'})
예제 #39
0
class FindShallowTests(TestCase):
    def setUp(self):
        self._store = MemoryObjectStore()

    def make_commit(self, **attrs):
        commit = make_commit(**attrs)
        self._store.add_object(commit)
        return commit

    def make_linear_commits(self, n, message=""):
        commits = []
        parents = []
        for _ in range(n):
            commits.append(self.make_commit(parents=parents, message=message))
            parents = [commits[-1].id]
        return commits

    def assertSameElements(self, expected, actual):
        self.assertEqual(set(expected), set(actual))

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)

        self.assertEqual((set([c3.id]), set([])), _find_shallow(self._store, [c3.id], 0))
        self.assertEqual((set([c2.id]), set([c3.id])), _find_shallow(self._store, [c3.id], 1))
        self.assertEqual((set([c1.id]), set([c2.id, c3.id])), _find_shallow(self._store, [c3.id], 2))
        self.assertEqual((set([]), set([c1.id, c2.id, c3.id])), _find_shallow(self._store, [c3.id], 3))

    def test_multiple_independent(self):
        a = self.make_linear_commits(2, message="a")
        b = self.make_linear_commits(2, message="b")
        c = self.make_linear_commits(2, message="c")
        heads = [a[1].id, b[1].id, c[1].id]

        self.assertEqual((set([a[0].id, b[0].id, c[0].id]), set(heads)), _find_shallow(self._store, heads, 1))

    def test_multiple_overlapping(self):
        # Create the following commit tree:
        # 1--2
        #  \
        #   3--4
        c1, c2 = self.make_linear_commits(2)
        c3 = self.make_commit(parents=[c1.id])
        c4 = self.make_commit(parents=[c3.id])

        # 1 is shallow along the path from 4, but not along the path from 2.
        self.assertEqual(
            (set([c1.id]), set([c1.id, c2.id, c3.id, c4.id])), _find_shallow(self._store, [c2.id, c4.id], 2)
        )

    def test_merge(self):
        c1 = self.make_commit()
        c2 = self.make_commit()
        c3 = self.make_commit(parents=[c1.id, c2.id])

        self.assertEqual((set([c1.id, c2.id]), set([c3.id])), _find_shallow(self._store, [c3.id], 1))

    def test_tag(self):
        c1, c2 = self.make_linear_commits(2)
        tag = make_object(
            Tag,
            name="tag",
            message="",
            tagger="Tagger <*****@*****.**>",
            tag_time=12345,
            tag_timezone=0,
            object=(Commit, c2.id),
        )
        self._store.add_object(tag)

        self.assertEqual((set([c1.id]), set([c2.id])), _find_shallow(self._store, [tag.id], 1))
예제 #40
0
class TestThinPack(PackTests):

    def setUp(self):
        super(TestThinPack, self).setUp()
        self.store = MemoryObjectStore()
        self.blobs = {}
        for blob in (b'foo', b'bar', b'foo1234', b'bar2468'):
            self.blobs[blob] = make_object(Blob, data=blob)
        self.store.add_object(self.blobs[b'foo'])
        self.store.add_object(self.blobs[b'bar'])

        # Build a thin pack. 'foo' is as an external reference, 'bar' an
        # internal reference.
        self.pack_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, self.pack_dir)
        self.pack_prefix = os.path.join(self.pack_dir, 'pack')

        with open(self.pack_prefix + '.pack', 'wb') as f:
            build_pack(f, [
                (REF_DELTA, (self.blobs[b'foo'].id, b'foo1234')),
                (Blob.type_num, b'bar'),
                (REF_DELTA, (self.blobs[b'bar'].id, b'bar2468'))],
                store=self.store)

        # Index the new pack.
        with self.make_pack(True) as pack:
            with PackData(pack._data_path) as data:
                data.pack = pack
                data.create_index(self.pack_prefix + '.idx')

        del self.store[self.blobs[b'bar'].id]

    def make_pack(self, resolve_ext_ref):
        return Pack(
            self.pack_prefix,
            resolve_ext_ref=self.store.get_raw if resolve_ext_ref else None)

    def test_get_raw(self):
        with self.make_pack(False) as p:
            self.assertRaises(
                KeyError, p.get_raw, self.blobs[b'foo1234'].id)
        with self.make_pack(True) as p:
            self.assertEqual(
                (3, b'foo1234'),
                p.get_raw(self.blobs[b'foo1234'].id))

    def test_get_raw_unresolved(self):
        with self.make_pack(False) as p:
            self.assertEqual(
                (7,
                 b'\x19\x10(\x15f=#\xf8\xb7ZG\xe7\xa0\x19e\xdc\xdc\x96F\x8c',
                 [b'x\x9ccf\x9f\xc0\xccbhdl\x02\x00\x06f\x01l']),
                p.get_raw_unresolved(self.blobs[b'foo1234'].id))
        with self.make_pack(True) as p:
            self.assertEqual(
                (7,
                 b'\x19\x10(\x15f=#\xf8\xb7ZG\xe7\xa0\x19e\xdc\xdc\x96F\x8c',
                 [b'x\x9ccf\x9f\xc0\xccbhdl\x02\x00\x06f\x01l']),
                p.get_raw_unresolved(self.blobs[b'foo1234'].id))

    def test_iterobjects(self):
        with self.make_pack(False) as p:
            self.assertRaises(KeyError, list, p.iterobjects())
        with self.make_pack(True) as p:
            self.assertEqual(
                sorted([self.blobs[b'foo1234'].id, self.blobs[b'bar'].id,
                        self.blobs[b'bar2468'].id]),
                sorted(o.id for o in p.iterobjects()))
예제 #41
0
파일: test_pack.py 프로젝트: sid0/dulwich
class DeltaChainIteratorTests(TestCase):

    def setUp(self):
        super(DeltaChainIteratorTests, self).setUp()
        self.store = MemoryObjectStore()
        self.fetched = set()

    def store_blobs(self, blobs_data):
        blobs = []
        for data in blobs_data:
            blob = make_object(Blob, data=data)
            blobs.append(blob)
            self.store.add_object(blob)
        return blobs

    def get_raw_no_repeat(self, bin_sha):
        """Wrapper around store.get_raw that doesn't allow repeat lookups."""
        hex_sha = sha_to_hex(bin_sha)
        self.assertFalse(hex_sha in self.fetched,
                         'Attempted to re-fetch object %s' % hex_sha)
        self.fetched.add(hex_sha)
        return self.store.get_raw(hex_sha)

    def make_pack_iter(self, f, thin=None):
        if thin is None:
            thin = bool(list(self.store))
        resolve_ext_ref = thin and self.get_raw_no_repeat or None
        data = PackData('test.pack', file=f)
        return TestPackIterator.for_pack_data(
          data, resolve_ext_ref=resolve_ext_ref)

    def assertEntriesMatch(self, expected_indexes, entries, pack_iter):
        expected = [entries[i] for i in expected_indexes]
        self.assertEqual(expected, list(pack_iter._walk_all_chains()))

    def test_no_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Commit.type_num, 'commit'),
          (Blob.type_num, 'blob'),
          (Tree.type_num, 'tree'),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ofs_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (0, 'blob2')),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ofs_deltas_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ref_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob1')),
          (Blob.type_num, ('blob')),
          (REF_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 0, 2], entries, self.make_pack_iter(f))

    def test_ref_deltas_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (2, 'blob1')),
          (Blob.type_num, ('blob')),
          (REF_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f))

    def test_ofs_and_ref_deltas(self):
        # Deltas pending on this offset are popped before deltas depending on
        # this ref.
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob1')),
          (Blob.type_num, ('blob')),
          (OFS_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f))

    def test_mixed_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (REF_DELTA, (2, 'blob2')),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (1, 'blob3')),
          (OFS_DELTA, (0, 'bob')),
          ])
        self.assertEntriesMatch([0, 2, 1, 3, 4], entries,
                                self.make_pack_iter(f))

    def test_long_chain(self):
        n = 100
        objects_spec = [(Blob.type_num, 'blob')]
        for i in range(n):
            objects_spec.append((OFS_DELTA, (i, 'blob%i' % i)))
        f = BytesIO()
        entries = build_pack(f, objects_spec)
        self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f))

    def test_branchy_chain(self):
        n = 100
        objects_spec = [(Blob.type_num, 'blob')]
        for i in range(n):
            objects_spec.append((OFS_DELTA, (0, 'blob%i' % i)))
        f = BytesIO()
        entries = build_pack(f, objects_spec)
        self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f))

    def test_ext_ref(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))],
                             store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_ext_ref_chain(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob2')),
          (REF_DELTA, (blob.id, 'blob1')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([1, 0], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_ext_ref_multiple_times(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (blob.id, 'blob1')),
          (REF_DELTA, (blob.id, 'blob2')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0, 1], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_multiple_ext_refs(self):
        b1, b2 = self.store_blobs(['foo', 'bar'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (b1.id, 'foo1')),
          (REF_DELTA, (b2.id, 'bar2')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0, 1], entries, pack_iter)
        self.assertEqual([hex_to_sha(b1.id), hex_to_sha(b2.id)],
                         pack_iter.ext_refs())

    def test_bad_ext_ref_non_thin_pack(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))],
                             store=self.store)
        pack_iter = self.make_pack_iter(f, thin=False)
        try:
            list(pack_iter._walk_all_chains())
            self.fail()
        except KeyError as e:
            self.assertEqual(([blob.id],), e.args)

    def test_bad_ext_ref_thin_pack(self):
        b1, b2, b3 = self.store_blobs(['foo', 'bar', 'baz'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'foo99')),
          (REF_DELTA, (b1.id, 'foo1')),
          (REF_DELTA, (b2.id, 'bar2')),
          (REF_DELTA, (b3.id, 'baz3')),
          ], store=self.store)
        del self.store[b2.id]
        del self.store[b3.id]
        pack_iter = self.make_pack_iter(f)
        try:
            list(pack_iter._walk_all_chains())
            self.fail()
        except KeyError as e:
            self.assertEqual((sorted([b2.id, b3.id]),), e.args)
예제 #42
0
class DeltaChainIteratorTests(TestCase):

    def setUp(self):
        super(DeltaChainIteratorTests, self).setUp()
        self.store = MemoryObjectStore()
        self.fetched = set()

    def store_blobs(self, blobs_data):
        blobs = []
        for data in blobs_data:
            blob = make_object(Blob, data=data)
            blobs.append(blob)
            self.store.add_object(blob)
        return blobs

    def get_raw_no_repeat(self, bin_sha):
        """Wrapper around store.get_raw that doesn't allow repeat lookups."""
        hex_sha = sha_to_hex(bin_sha)
        self.assertFalse(hex_sha in self.fetched,
                         'Attempted to re-fetch object %s' % hex_sha)
        self.fetched.add(hex_sha)
        return self.store.get_raw(hex_sha)

    def make_pack_iter(self, f, thin=None):
        if thin is None:
            thin = bool(list(self.store))
        resolve_ext_ref = thin and self.get_raw_no_repeat or None
        data = PackData('test.pack', file=f)
        return TestPackIterator.for_pack_data(
          data, resolve_ext_ref=resolve_ext_ref)

    def assertEntriesMatch(self, expected_indexes, entries, pack_iter):
        expected = [entries[i] for i in expected_indexes]
        self.assertEqual(expected, list(pack_iter._walk_all_chains()))

    def test_no_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Commit.type_num, 'commit'),
          (Blob.type_num, 'blob'),
          (Tree.type_num, 'tree'),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ofs_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (0, 'blob2')),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ofs_deltas_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([0, 1, 2], entries, self.make_pack_iter(f))

    def test_ref_deltas(self):
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob1')),
          (Blob.type_num, ('blob')),
          (REF_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 0, 2], entries, self.make_pack_iter(f))

    def test_ref_deltas_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (2, 'blob1')),
          (Blob.type_num, ('blob')),
          (REF_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f))

    def test_ofs_and_ref_deltas(self):
        # Deltas pending on this offset are popped before deltas depending on
        # this ref.
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob1')),
          (Blob.type_num, ('blob')),
          (OFS_DELTA, (1, 'blob2')),
          ])
        self.assertEntriesMatch([1, 2, 0], entries, self.make_pack_iter(f))

    def test_mixed_chain(self):
        f = BytesIO()
        entries = build_pack(f, [
          (Blob.type_num, 'blob'),
          (REF_DELTA, (2, 'blob2')),
          (OFS_DELTA, (0, 'blob1')),
          (OFS_DELTA, (1, 'blob3')),
          (OFS_DELTA, (0, 'bob')),
          ])
        self.assertEntriesMatch([0, 2, 1, 3, 4], entries,
                                self.make_pack_iter(f))

    def test_long_chain(self):
        n = 100
        objects_spec = [(Blob.type_num, 'blob')]
        for i in range(n):
            objects_spec.append((OFS_DELTA, (i, 'blob%i' % i)))
        f = BytesIO()
        entries = build_pack(f, objects_spec)
        self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f))

    def test_branchy_chain(self):
        n = 100
        objects_spec = [(Blob.type_num, 'blob')]
        for i in range(n):
            objects_spec.append((OFS_DELTA, (0, 'blob%i' % i)))
        f = BytesIO()
        entries = build_pack(f, objects_spec)
        self.assertEntriesMatch(range(n + 1), entries, self.make_pack_iter(f))

    def test_ext_ref(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))],
                             store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_ext_ref_chain(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (1, 'blob2')),
          (REF_DELTA, (blob.id, 'blob1')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([1, 0], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_ext_ref_chain_degenerate(self):
        # Test a degenerate case where the sender is sending a REF_DELTA
        # object that expands to an object already in the repository.
        blob, = self.store_blobs(['blob'])
        blob2, = self.store_blobs(['blob2'])
        assert blob.id < blob2.id

        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (blob.id, 'blob2')),
          (REF_DELTA, (0, 'blob3')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0, 1], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_ext_ref_multiple_times(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (blob.id, 'blob1')),
          (REF_DELTA, (blob.id, 'blob2')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0, 1], entries, pack_iter)
        self.assertEqual([hex_to_sha(blob.id)], pack_iter.ext_refs())

    def test_multiple_ext_refs(self):
        b1, b2 = self.store_blobs(['foo', 'bar'])
        f = BytesIO()
        entries = build_pack(f, [
          (REF_DELTA, (b1.id, 'foo1')),
          (REF_DELTA, (b2.id, 'bar2')),
          ], store=self.store)
        pack_iter = self.make_pack_iter(f)
        self.assertEntriesMatch([0, 1], entries, pack_iter)
        self.assertEqual([hex_to_sha(b1.id), hex_to_sha(b2.id)],
                         pack_iter.ext_refs())

    def test_bad_ext_ref_non_thin_pack(self):
        blob, = self.store_blobs(['blob'])
        f = BytesIO()
        build_pack(f, [(REF_DELTA, (blob.id, 'blob1'))],
                             store=self.store)
        pack_iter = self.make_pack_iter(f, thin=False)
        try:
            list(pack_iter._walk_all_chains())
            self.fail()
        except KeyError as e:
            self.assertEqual(([blob.id],), e.args)

    def test_bad_ext_ref_thin_pack(self):
        b1, b2, b3 = self.store_blobs(['foo', 'bar', 'baz'])
        f = BytesIO()
        build_pack(f, [
          (REF_DELTA, (1, 'foo99')),
          (REF_DELTA, (b1.id, 'foo1')),
          (REF_DELTA, (b2.id, 'bar2')),
          (REF_DELTA, (b3.id, 'baz3')),
          ], store=self.store)
        del self.store[b2.id]
        del self.store[b3.id]
        pack_iter = self.make_pack_iter(f)
        try:
            list(pack_iter._walk_all_chains())
            self.fail()
        except KeyError as e:
            self.assertEqual((sorted([b2.id, b3.id]),), (sorted(e.args[0]),))
예제 #43
0
class FindShallowTests(TestCase):

    def setUp(self):
        super(FindShallowTests, self).setUp()
        self._store = MemoryObjectStore()

    def make_commit(self, **attrs):
        commit = make_commit(**attrs)
        self._store.add_object(commit)
        return commit

    def make_linear_commits(self, n, message=b''):
        commits = []
        parents = []
        for _ in range(n):
            commits.append(self.make_commit(parents=parents, message=message))
            parents = [commits[-1].id]
        return commits

    def assertSameElements(self, expected, actual):
        self.assertEqual(set(expected), set(actual))

    def test_linear(self):
        c1, c2, c3 = self.make_linear_commits(3)

        self.assertEqual((set([c3.id]), set([])),
                         _find_shallow(self._store, [c3.id], 0))
        self.assertEqual((set([c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 1))
        self.assertEqual((set([c1.id]), set([c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 2))
        self.assertEqual((set([]), set([c1.id, c2.id, c3.id])),
                         _find_shallow(self._store, [c3.id], 3))

    def test_multiple_independent(self):
        a = self.make_linear_commits(2, message=b'a')
        b = self.make_linear_commits(2, message=b'b')
        c = self.make_linear_commits(2, message=b'c')
        heads = [a[1].id, b[1].id, c[1].id]

        self.assertEqual((set([a[0].id, b[0].id, c[0].id]), set(heads)),
                         _find_shallow(self._store, heads, 1))

    def test_multiple_overlapping(self):
        # Create the following commit tree:
        # 1--2
        #  \
        #   3--4
        c1, c2 = self.make_linear_commits(2)
        c3 = self.make_commit(parents=[c1.id])
        c4 = self.make_commit(parents=[c3.id])

        # 1 is shallow along the path from 4, but not along the path from 2.
        self.assertEqual((set([c1.id]), set([c1.id, c2.id, c3.id, c4.id])),
                         _find_shallow(self._store, [c2.id, c4.id], 2))

    def test_merge(self):
        c1 = self.make_commit()
        c2 = self.make_commit()
        c3 = self.make_commit(parents=[c1.id, c2.id])

        self.assertEqual((set([c1.id, c2.id]), set([c3.id])),
                         _find_shallow(self._store, [c3.id], 1))

    def test_tag(self):
        c1, c2 = self.make_linear_commits(2)
        tag = make_tag(c2, name=b'tag')
        self._store.add_object(tag)

        self.assertEqual((set([c1.id]), set([c2.id])),
                         _find_shallow(self._store, [tag.id], 1))