Browse Source

Re-add dulwich.tests.utils and dulwich.tests.test_object_store for use with e.g. breezy

Jelmer Vernooij 11 months ago
parent
commit
cc93029c25

+ 21 - 0
dulwich/tests/__init__.py

@@ -0,0 +1,21 @@
+# __init__.py -- The tests for dulwich
+# Copyright (C) 2024 Jelmer Vernooij <jelmer@jelmer.uk>
+#
+# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
+# General Public License as public by the Free Software Foundation; version 2.0
+# or (at your option) any later version. You can redistribute it and/or
+# modify it under the terms of either of these two licenses.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the licenses; if not, see
+# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
+# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
+# License, Version 2.0.
+#
+
+"""Tests for Dulwich."""

+ 299 - 0
dulwich/tests/test_object_store.py

@@ -0,0 +1,299 @@
+# test_object_store.py -- tests for object_store.py
+# Copyright (C) 2008 Jelmer Vernooij <jelmer@jelmer.uk>
+#
+# Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
+# General Public License as public by the Free Software Foundation; version 2.0
+# or (at your option) any later version. You can redistribute it and/or
+# modify it under the terms of either of these two licenses.
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# You should have received a copy of the licenses; if not, see
+# <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
+# and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
+# License, Version 2.0.
+#
+
+"""Tests for the object store interface."""
+
+from unittest import skipUnless
+
+from dulwich.index import commit_tree
+from dulwich.object_store import (
+    iter_tree_contents,
+    peel_sha,
+)
+from dulwich.objects import (
+    Blob,
+    TreeEntry,
+)
+from dulwich.protocol import DEPTH_INFINITE
+
+from .utils import make_object, make_tag
+
+try:
+    from unittest.mock import patch
+except ImportError:
+    patch = None  # type: ignore
+
+
+testobject = make_object(Blob, data=b"yummy data")
+
+
+class ObjectStoreTests:
+    def test_determine_wants_all(self):
+        self.assertEqual(
+            [b"1" * 40],
+            self.store.determine_wants_all({b"refs/heads/foo": b"1" * 40}),
+        )
+
+    def test_determine_wants_all_zero(self):
+        self.assertEqual(
+            [], self.store.determine_wants_all({b"refs/heads/foo": b"0" * 40})
+        )
+
+    @skipUnless(patch, "Required mock.patch")
+    def test_determine_wants_all_depth(self):
+        self.store.add_object(testobject)
+        refs = {b"refs/heads/foo": testobject.id}
+        with patch.object(self.store, "_get_depth", return_value=1) as m:
+            self.assertEqual([], self.store.determine_wants_all(refs, depth=0))
+            self.assertEqual(
+                [testobject.id],
+                self.store.determine_wants_all(refs, depth=DEPTH_INFINITE),
+            )
+            m.assert_not_called()
+
+            self.assertEqual([], self.store.determine_wants_all(refs, depth=1))
+            m.assert_called_with(testobject.id)
+            self.assertEqual(
+                [testobject.id], self.store.determine_wants_all(refs, depth=2)
+            )
+
+    def test_get_depth(self):
+        self.assertEqual(0, self.store._get_depth(testobject.id))
+
+        self.store.add_object(testobject)
+        self.assertEqual(
+            1, self.store._get_depth(testobject.id, get_parents=lambda x: [])
+        )
+
+        parent = make_object(Blob, data=b"parent data")
+        self.store.add_object(parent)
+        self.assertEqual(
+            2,
+            self.store._get_depth(
+                testobject.id,
+                get_parents=lambda x: [parent.id] if x == testobject else [],
+            ),
+        )
+
+    def test_iter(self):
+        self.assertEqual([], list(self.store))
+
+    def test_get_nonexistant(self):
+        self.assertRaises(KeyError, lambda: self.store[b"a" * 40])
+
+    def test_contains_nonexistant(self):
+        self.assertNotIn(b"a" * 40, self.store)
+
+    def test_add_objects_empty(self):
+        self.store.add_objects([])
+
+    def test_add_commit(self):
+        # TODO: Argh, no way to construct Git commit objects without
+        # access to a serialized form.
+        self.store.add_objects([])
+
+    def test_store_resilience(self):
+        """Test if updating an existing stored object doesn't erase the
+        object from the store.
+        """
+        test_object = make_object(Blob, data=b"data")
+
+        self.store.add_object(test_object)
+        test_object_id = test_object.id
+        test_object.data = test_object.data + b"update"
+        stored_test_object = self.store[test_object_id]
+
+        self.assertNotEqual(test_object.id, stored_test_object.id)
+        self.assertEqual(stored_test_object.id, test_object_id)
+
+    def test_add_object(self):
+        self.store.add_object(testobject)
+        self.assertEqual({testobject.id}, set(self.store))
+        self.assertIn(testobject.id, self.store)
+        r = self.store[testobject.id]
+        self.assertEqual(r, testobject)
+
+    def test_add_objects(self):
+        data = [(testobject, "mypath")]
+        self.store.add_objects(data)
+        self.assertEqual({testobject.id}, set(self.store))
+        self.assertIn(testobject.id, self.store)
+        r = self.store[testobject.id]
+        self.assertEqual(r, testobject)
+
+    def test_tree_changes(self):
+        blob_a1 = make_object(Blob, data=b"a1")
+        blob_a2 = make_object(Blob, data=b"a2")
+        blob_b = make_object(Blob, data=b"b")
+        for blob in [blob_a1, blob_a2, blob_b]:
+            self.store.add_object(blob)
+
+        blobs_1 = [(b"a", blob_a1.id, 0o100644), (b"b", blob_b.id, 0o100644)]
+        tree1_id = commit_tree(self.store, blobs_1)
+        blobs_2 = [(b"a", blob_a2.id, 0o100644), (b"b", blob_b.id, 0o100644)]
+        tree2_id = commit_tree(self.store, blobs_2)
+        change_a = (
+            (b"a", b"a"),
+            (0o100644, 0o100644),
+            (blob_a1.id, blob_a2.id),
+        )
+        self.assertEqual([change_a], list(self.store.tree_changes(tree1_id, tree2_id)))
+        self.assertEqual(
+            [
+                change_a,
+                ((b"b", b"b"), (0o100644, 0o100644), (blob_b.id, blob_b.id)),
+            ],
+            list(self.store.tree_changes(tree1_id, tree2_id, want_unchanged=True)),
+        )
+
+    def test_iter_tree_contents(self):
+        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),
+        ]
+        tree_id = commit_tree(self.store, blobs)
+        self.assertEqual(
+            [TreeEntry(p, m, h) for (p, h, m) in blobs],
+            list(iter_tree_contents(self.store, tree_id)),
+        )
+        self.assertEqual([], list(iter_tree_contents(self.store, None)))
+
+    def test_iter_tree_contents_include_trees(self):
+        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),
+        ]
+        tree_id = commit_tree(self.store, blobs)
+        tree = self.store[tree_id]
+        tree_ad = self.store[tree[b"ad"][1]]
+        tree_bd = self.store[tree_ad[b"bd"][1]]
+
+        expected = [
+            TreeEntry(b"", 0o040000, tree_id),
+            TreeEntry(b"a", 0o100644, blob_a.id),
+            TreeEntry(b"ad", 0o040000, tree_ad.id),
+            TreeEntry(b"ad/b", 0o100644, blob_b.id),
+            TreeEntry(b"ad/bd", 0o040000, tree_bd.id),
+            TreeEntry(b"ad/bd/c", 0o100755, blob_c.id),
+        ]
+        actual = iter_tree_contents(self.store, tree_id, include_trees=True)
+        self.assertEqual(expected, list(actual))
+
+    def make_tag(self, name, obj):
+        tag = make_tag(obj, name=name)
+        self.store.add_object(tag)
+        return tag
+
+    def test_peel_sha(self):
+        self.store.add_object(testobject)
+        tag1 = self.make_tag(b"1", testobject)
+        tag2 = self.make_tag(b"2", testobject)
+        tag3 = self.make_tag(b"3", testobject)
+        for obj in [testobject, tag1, tag2, tag3]:
+            self.assertEqual((obj, testobject), peel_sha(self.store, obj.id))
+
+    def test_get_raw(self):
+        self.store.add_object(testobject)
+        self.assertEqual(
+            (Blob.type_num, b"yummy data"), self.store.get_raw(testobject.id)
+        )
+
+    def test_close(self):
+        # For now, just check that close doesn't barf.
+        self.store.add_object(testobject)
+        self.store.close()
+
+
+class PackBasedObjectStoreTests(ObjectStoreTests):
+    def tearDown(self):
+        for pack in self.store.packs:
+            pack.close()
+
+    def test_empty_packs(self):
+        self.assertEqual([], list(self.store.packs))
+
+    def test_pack_loose_objects(self):
+        b1 = make_object(Blob, data=b"yummy data")
+        self.store.add_object(b1)
+        b2 = make_object(Blob, data=b"more yummy data")
+        self.store.add_object(b2)
+        b3 = make_object(Blob, data=b"even more yummy data")
+        b4 = make_object(Blob, data=b"and more yummy data")
+        self.store.add_objects([(b3, None), (b4, None)])
+        self.assertEqual({b1.id, b2.id, b3.id, b4.id}, set(self.store))
+        self.assertEqual(1, len(self.store.packs))
+        self.assertEqual(2, self.store.pack_loose_objects())
+        self.assertNotEqual([], list(self.store.packs))
+        self.assertEqual(0, self.store.pack_loose_objects())
+
+    def test_repack(self):
+        b1 = make_object(Blob, data=b"yummy data")
+        self.store.add_object(b1)
+        b2 = make_object(Blob, data=b"more yummy data")
+        self.store.add_object(b2)
+        b3 = make_object(Blob, data=b"even more yummy data")
+        b4 = make_object(Blob, data=b"and more yummy data")
+        self.store.add_objects([(b3, None), (b4, None)])
+        b5 = make_object(Blob, data=b"and more data")
+        b6 = make_object(Blob, data=b"and some more data")
+        self.store.add_objects([(b5, None), (b6, None)])
+        self.assertEqual({b1.id, b2.id, b3.id, b4.id, b5.id, b6.id}, set(self.store))
+        self.assertEqual(2, len(self.store.packs))
+        self.assertEqual(6, self.store.repack())
+        self.assertEqual(1, len(self.store.packs))
+        self.assertEqual(0, self.store.pack_loose_objects())
+
+    def test_repack_existing(self):
+        b1 = make_object(Blob, data=b"yummy data")
+        self.store.add_object(b1)
+        b2 = make_object(Blob, data=b"more yummy data")
+        self.store.add_object(b2)
+        self.store.add_objects([(b1, None), (b2, None)])
+        self.store.add_objects([(b2, None)])
+        self.assertEqual({b1.id, b2.id}, set(self.store))
+        self.assertEqual(2, len(self.store.packs))
+        self.assertEqual(2, self.store.repack())
+        self.assertEqual(1, len(self.store.packs))
+        self.assertEqual(0, self.store.pack_loose_objects())
+
+        self.assertEqual({b1.id, b2.id}, set(self.store))
+        self.assertEqual(1, len(self.store.packs))
+        self.assertEqual(2, self.store.repack())
+        self.assertEqual(1, len(self.store.packs))
+        self.assertEqual(0, self.store.pack_loose_objects())
+
+
+

+ 2 - 3
tests/utils.py → dulwich/tests/utils.py

@@ -27,6 +27,7 @@ import tempfile
 import time
 import types
 import warnings
+from unittest import SkipTest
 
 from dulwich.index import commit_tree
 from dulwich.objects import Commit, FixedSha, Tag, object_class
@@ -42,8 +43,6 @@ from dulwich.pack import (
 )
 from dulwich.repo import Repo
 
-from . import SkipTest
-
 # Plain files are very frequently used in tests, so let the mode be very short.
 F = 0o100644  # Shorthand mode for Files.
 
@@ -65,7 +64,7 @@ def open_repo(name, temp_dir=None):
     if temp_dir is None:
         temp_dir = tempfile.mkdtemp()
     repo_dir = os.path.join(
-        os.path.dirname(__file__), "..", "testdata", "repos", name
+        os.path.dirname(__file__), "..", "..", "testdata", "repos", name
     )
     temp_repo_dir = os.path.join(temp_dir, name)
     shutil.copytree(repo_dir, temp_repo_dir, symlinks=True)

+ 1 - 1
tests/compat/server_utils.py

@@ -30,8 +30,8 @@ from dulwich.objects import hex_to_sha
 from dulwich.protocol import CAPABILITY_SIDE_BAND_64K
 from dulwich.repo import Repo
 from dulwich.server import ReceivePackHandler
+from dulwich.tests.utils import tear_down_repo
 
-from ..utils import tear_down_repo
 from .utils import require_git_version, run_git_or_fail
 
 

+ 1 - 1
tests/compat/test_porcelain.py

@@ -26,9 +26,9 @@ import sys
 from unittest import skipIf
 
 from dulwich import porcelain
+from dulwich.tests.utils import build_commit_graph
 
 from ..test_porcelain import PorcelainGpgTestCase
-from ..utils import build_commit_graph
 from .utils import CompatTestCase, run_git_or_fail
 
 

+ 1 - 2
tests/contrib/test_release_robot.py

@@ -30,8 +30,7 @@ from typing import ClassVar, Dict, List, Optional, Tuple
 
 from dulwich.contrib import release_robot
 from dulwich.repo import Repo
-
-from ..utils import make_commit, make_tag
+from dulwich.tests.utils import make_commit, make_tag
 
 BASEDIR = os.path.abspath(os.path.dirname(__file__))  # this directory
 

+ 1 - 1
tests/test_archive.py

@@ -28,9 +28,9 @@ from unittest import skipUnless
 from dulwich.archive import tar_stream
 from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import Blob, Tree
+from dulwich.tests.utils import build_commit_graph
 
 from . import TestCase
-from .utils import build_commit_graph
 
 try:
     from unittest.mock import patch

+ 1 - 1
tests/test_client.py

@@ -60,9 +60,9 @@ from dulwich.objects import Commit, Tree
 from dulwich.pack import pack_objects_to_data, write_pack_data, write_pack_objects
 from dulwich.protocol import TCP_GIT_PORT, Protocol
 from dulwich.repo import MemoryRepo, Repo
+from dulwich.tests.utils import open_repo, setup_warning_catcher, tear_down_repo
 
 from . import TestCase, skipIf
-from .utils import open_repo, setup_warning_catcher, tear_down_repo
 
 
 class DummyClient(TraditionalGitClient):

+ 2 - 2
tests/test_config.py

@@ -312,7 +312,7 @@ class StackedConfigTests(TestCase):
 
     @skipIf(sys.platform != "win32", "Windows specific config location.")
     def test_windows_config_from_path(self):
-        from ..config import get_win_system_paths
+        from dulwich.config import get_win_system_paths
 
         install_dir = os.path.join("C:", "foo", "Git")
         self.overrideEnv("PATH", os.path.join(install_dir, "cmd"))
@@ -330,7 +330,7 @@ class StackedConfigTests(TestCase):
     def test_windows_config_from_reg(self):
         import winreg
 
-        from ..config import get_win_system_paths
+        from dulwich.config import get_win_system_paths
 
         self.overrideEnv("PATH", None)
         install_dir = os.path.join("C:", "foo", "Git")

+ 1 - 1
tests/test_diff_tree.py

@@ -43,9 +43,9 @@ from dulwich.diff_tree import (
 from dulwich.index import commit_tree
 from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import Blob, ShaFile, Tree, TreeEntry
+from dulwich.tests.utils import F, ext_functest_builder, functest_builder, make_object
 
 from . import TestCase
-from .utils import F, ext_functest_builder, functest_builder, make_object
 
 
 class DiffTestCase(TestCase):

+ 1 - 1
tests/test_fastexport.py

@@ -24,9 +24,9 @@ from io import BytesIO
 from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import ZERO_SHA, Blob, Commit, Tree
 from dulwich.repo import MemoryRepo
+from dulwich.tests.utils import build_commit_graph
 
 from . import SkipTest, TestCase
-from .utils import build_commit_graph
 
 
 class GitFastExporterTests(TestCase):

+ 1 - 1
tests/test_graph.py

@@ -21,9 +21,9 @@
 
 from dulwich.graph import WorkList, _find_lcas, can_fast_forward
 from dulwich.repo import MemoryRepo
+from dulwich.tests.utils import make_commit
 
 from . import TestCase
-from .utils import make_commit
 
 
 class FindMergeBaseTests(TestCase):

+ 1 - 1
tests/test_missing_obj_finder.py

@@ -20,9 +20,9 @@
 
 from dulwich.object_store import MemoryObjectStore, MissingObjectFinder
 from dulwich.objects import Blob
+from dulwich.tests.utils import build_commit_graph, make_object, make_tag
 
 from . import TestCase
-from .utils import build_commit_graph, make_object, make_tag
 
 
 class MissingObjectFinderTest(TestCase):

+ 2 - 263
tests/test_object_store.py

@@ -27,7 +27,6 @@ import sys
 import tempfile
 from contextlib import closing
 from io import BytesIO
-from unittest import skipUnless
 
 from dulwich.errors import NotTreeError
 from dulwich.index import commit_tree
@@ -37,8 +36,6 @@ from dulwich.object_store import (
     ObjectStoreGraphWalker,
     OverlayObjectStore,
     commit_tree_changes,
-    iter_tree_contents,
-    peel_sha,
     read_packs_file,
     tree_lookup_path,
 )
@@ -52,213 +49,14 @@ from dulwich.objects import (
     sha_to_hex,
 )
 from dulwich.pack import REF_DELTA, write_pack_objects
-from dulwich.protocol import DEPTH_INFINITE
+from dulwich.tests.test_object_store import ObjectStoreTests, PackBasedObjectStoreTests
+from dulwich.tests.utils import build_pack, make_object
 
 from . import TestCase
-from .utils import build_pack, make_object, make_tag
-
-try:
-    from unittest.mock import patch
-except ImportError:
-    patch = None  # type: ignore
-
 
 testobject = make_object(Blob, data=b"yummy data")
 
 
-class ObjectStoreTests:
-    def test_determine_wants_all(self):
-        self.assertEqual(
-            [b"1" * 40],
-            self.store.determine_wants_all({b"refs/heads/foo": b"1" * 40}),
-        )
-
-    def test_determine_wants_all_zero(self):
-        self.assertEqual(
-            [], self.store.determine_wants_all({b"refs/heads/foo": b"0" * 40})
-        )
-
-    @skipUnless(patch, "Required mock.patch")
-    def test_determine_wants_all_depth(self):
-        self.store.add_object(testobject)
-        refs = {b"refs/heads/foo": testobject.id}
-        with patch.object(self.store, "_get_depth", return_value=1) as m:
-            self.assertEqual([], self.store.determine_wants_all(refs, depth=0))
-            self.assertEqual(
-                [testobject.id],
-                self.store.determine_wants_all(refs, depth=DEPTH_INFINITE),
-            )
-            m.assert_not_called()
-
-            self.assertEqual([], self.store.determine_wants_all(refs, depth=1))
-            m.assert_called_with(testobject.id)
-            self.assertEqual(
-                [testobject.id], self.store.determine_wants_all(refs, depth=2)
-            )
-
-    def test_get_depth(self):
-        self.assertEqual(0, self.store._get_depth(testobject.id))
-
-        self.store.add_object(testobject)
-        self.assertEqual(
-            1, self.store._get_depth(testobject.id, get_parents=lambda x: [])
-        )
-
-        parent = make_object(Blob, data=b"parent data")
-        self.store.add_object(parent)
-        self.assertEqual(
-            2,
-            self.store._get_depth(
-                testobject.id,
-                get_parents=lambda x: [parent.id] if x == testobject else [],
-            ),
-        )
-
-    def test_iter(self):
-        self.assertEqual([], list(self.store))
-
-    def test_get_nonexistant(self):
-        self.assertRaises(KeyError, lambda: self.store[b"a" * 40])
-
-    def test_contains_nonexistant(self):
-        self.assertNotIn(b"a" * 40, self.store)
-
-    def test_add_objects_empty(self):
-        self.store.add_objects([])
-
-    def test_add_commit(self):
-        # TODO: Argh, no way to construct Git commit objects without
-        # access to a serialized form.
-        self.store.add_objects([])
-
-    def test_store_resilience(self):
-        """Test if updating an existing stored object doesn't erase the
-        object from the store.
-        """
-        test_object = make_object(Blob, data=b"data")
-
-        self.store.add_object(test_object)
-        test_object_id = test_object.id
-        test_object.data = test_object.data + b"update"
-        stored_test_object = self.store[test_object_id]
-
-        self.assertNotEqual(test_object.id, stored_test_object.id)
-        self.assertEqual(stored_test_object.id, test_object_id)
-
-    def test_add_object(self):
-        self.store.add_object(testobject)
-        self.assertEqual({testobject.id}, set(self.store))
-        self.assertIn(testobject.id, self.store)
-        r = self.store[testobject.id]
-        self.assertEqual(r, testobject)
-
-    def test_add_objects(self):
-        data = [(testobject, "mypath")]
-        self.store.add_objects(data)
-        self.assertEqual({testobject.id}, set(self.store))
-        self.assertIn(testobject.id, self.store)
-        r = self.store[testobject.id]
-        self.assertEqual(r, testobject)
-
-    def test_tree_changes(self):
-        blob_a1 = make_object(Blob, data=b"a1")
-        blob_a2 = make_object(Blob, data=b"a2")
-        blob_b = make_object(Blob, data=b"b")
-        for blob in [blob_a1, blob_a2, blob_b]:
-            self.store.add_object(blob)
-
-        blobs_1 = [(b"a", blob_a1.id, 0o100644), (b"b", blob_b.id, 0o100644)]
-        tree1_id = commit_tree(self.store, blobs_1)
-        blobs_2 = [(b"a", blob_a2.id, 0o100644), (b"b", blob_b.id, 0o100644)]
-        tree2_id = commit_tree(self.store, blobs_2)
-        change_a = (
-            (b"a", b"a"),
-            (0o100644, 0o100644),
-            (blob_a1.id, blob_a2.id),
-        )
-        self.assertEqual([change_a], list(self.store.tree_changes(tree1_id, tree2_id)))
-        self.assertEqual(
-            [
-                change_a,
-                ((b"b", b"b"), (0o100644, 0o100644), (blob_b.id, blob_b.id)),
-            ],
-            list(self.store.tree_changes(tree1_id, tree2_id, want_unchanged=True)),
-        )
-
-    def test_iter_tree_contents(self):
-        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),
-        ]
-        tree_id = commit_tree(self.store, blobs)
-        self.assertEqual(
-            [TreeEntry(p, m, h) for (p, h, m) in blobs],
-            list(iter_tree_contents(self.store, tree_id)),
-        )
-        self.assertEqual([], list(iter_tree_contents(self.store, None)))
-
-    def test_iter_tree_contents_include_trees(self):
-        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),
-        ]
-        tree_id = commit_tree(self.store, blobs)
-        tree = self.store[tree_id]
-        tree_ad = self.store[tree[b"ad"][1]]
-        tree_bd = self.store[tree_ad[b"bd"][1]]
-
-        expected = [
-            TreeEntry(b"", 0o040000, tree_id),
-            TreeEntry(b"a", 0o100644, blob_a.id),
-            TreeEntry(b"ad", 0o040000, tree_ad.id),
-            TreeEntry(b"ad/b", 0o100644, blob_b.id),
-            TreeEntry(b"ad/bd", 0o040000, tree_bd.id),
-            TreeEntry(b"ad/bd/c", 0o100755, blob_c.id),
-        ]
-        actual = iter_tree_contents(self.store, tree_id, include_trees=True)
-        self.assertEqual(expected, list(actual))
-
-    def make_tag(self, name, obj):
-        tag = make_tag(obj, name=name)
-        self.store.add_object(tag)
-        return tag
-
-    def test_peel_sha(self):
-        self.store.add_object(testobject)
-        tag1 = self.make_tag(b"1", testobject)
-        tag2 = self.make_tag(b"2", testobject)
-        tag3 = self.make_tag(b"3", testobject)
-        for obj in [testobject, tag1, tag2, tag3]:
-            self.assertEqual((obj, testobject), peel_sha(self.store, obj.id))
-
-    def test_get_raw(self):
-        self.store.add_object(testobject)
-        self.assertEqual(
-            (Blob.type_num, b"yummy data"), self.store.get_raw(testobject.id)
-        )
-
-    def test_close(self):
-        # For now, just check that close doesn't barf.
-        self.store.add_object(testobject)
-        self.store.close()
-
-
 class OverlayObjectStoreTests(ObjectStoreTests, TestCase):
     def setUp(self):
         TestCase.setUp(self)
@@ -316,65 +114,6 @@ class MemoryObjectStoreTests(ObjectStoreTests, TestCase):
         o.add_thin_pack(f.read, None)
 
 
-class PackBasedObjectStoreTests(ObjectStoreTests):
-    def tearDown(self):
-        for pack in self.store.packs:
-            pack.close()
-
-    def test_empty_packs(self):
-        self.assertEqual([], list(self.store.packs))
-
-    def test_pack_loose_objects(self):
-        b1 = make_object(Blob, data=b"yummy data")
-        self.store.add_object(b1)
-        b2 = make_object(Blob, data=b"more yummy data")
-        self.store.add_object(b2)
-        b3 = make_object(Blob, data=b"even more yummy data")
-        b4 = make_object(Blob, data=b"and more yummy data")
-        self.store.add_objects([(b3, None), (b4, None)])
-        self.assertEqual({b1.id, b2.id, b3.id, b4.id}, set(self.store))
-        self.assertEqual(1, len(self.store.packs))
-        self.assertEqual(2, self.store.pack_loose_objects())
-        self.assertNotEqual([], list(self.store.packs))
-        self.assertEqual(0, self.store.pack_loose_objects())
-
-    def test_repack(self):
-        b1 = make_object(Blob, data=b"yummy data")
-        self.store.add_object(b1)
-        b2 = make_object(Blob, data=b"more yummy data")
-        self.store.add_object(b2)
-        b3 = make_object(Blob, data=b"even more yummy data")
-        b4 = make_object(Blob, data=b"and more yummy data")
-        self.store.add_objects([(b3, None), (b4, None)])
-        b5 = make_object(Blob, data=b"and more data")
-        b6 = make_object(Blob, data=b"and some more data")
-        self.store.add_objects([(b5, None), (b6, None)])
-        self.assertEqual({b1.id, b2.id, b3.id, b4.id, b5.id, b6.id}, set(self.store))
-        self.assertEqual(2, len(self.store.packs))
-        self.assertEqual(6, self.store.repack())
-        self.assertEqual(1, len(self.store.packs))
-        self.assertEqual(0, self.store.pack_loose_objects())
-
-    def test_repack_existing(self):
-        b1 = make_object(Blob, data=b"yummy data")
-        self.store.add_object(b1)
-        b2 = make_object(Blob, data=b"more yummy data")
-        self.store.add_object(b2)
-        self.store.add_objects([(b1, None), (b2, None)])
-        self.store.add_objects([(b2, None)])
-        self.assertEqual({b1.id, b2.id}, set(self.store))
-        self.assertEqual(2, len(self.store.packs))
-        self.assertEqual(2, self.store.repack())
-        self.assertEqual(1, len(self.store.packs))
-        self.assertEqual(0, self.store.pack_loose_objects())
-
-        self.assertEqual({b1.id, b2.id}, set(self.store))
-        self.assertEqual(1, len(self.store.packs))
-        self.assertEqual(2, self.store.repack())
-        self.assertEqual(1, len(self.store.packs))
-        self.assertEqual(0, self.store.pack_loose_objects())
-
-
 class DiskObjectStoreTests(PackBasedObjectStoreTests, TestCase):
     def setUp(self):
         TestCase.setUp(self)

+ 6 - 1
tests/test_objects.py

@@ -52,9 +52,14 @@ from dulwich.objects import (
     sha_to_hex,
     sorted_tree_items,
 )
+from dulwich.tests.utils import (
+    ext_functest_builder,
+    functest_builder,
+    make_commit,
+    make_object,
+)
 
 from . import TestCase
-from .utils import ext_functest_builder, functest_builder, make_commit, make_object
 
 a_sha = b"6f670c0fb53f9463760b7295fbb814e965fb20c8"
 b_sha = b"2969be3e8ee1c0222396a5611407e4769f14e54b"

+ 1 - 1
tests/test_objectspec.py

@@ -34,9 +34,9 @@ from dulwich.objectspec import (
     parse_tree,
 )
 from dulwich.repo import MemoryRepo
+from dulwich.tests.utils import build_commit_graph
 
 from . import TestCase
-from .utils import build_commit_graph
 
 
 class ParseObjectTests(TestCase):

+ 1 - 1
tests/test_pack.py

@@ -59,9 +59,9 @@ from dulwich.pack import (
     write_pack_index_v2,
     write_pack_object,
 )
+from dulwich.tests.utils import build_pack, make_object
 
 from . import TestCase
-from .utils import build_pack, make_object
 
 pack1_sha = b"bc63ddad95e7321ee734ea11a7a62d314e0d7481"
 

+ 1 - 1
tests/test_porcelain.py

@@ -42,10 +42,10 @@ from dulwich.objects import ZERO_SHA, Blob, Tag, Tree
 from dulwich.porcelain import CheckoutError
 from dulwich.repo import NoIndexPresent, Repo
 from dulwich.server import DictBackend
+from dulwich.tests.utils import build_commit_graph, make_commit, make_object
 from dulwich.web import make_server, make_wsgi_chain
 
 from . import TestCase
-from .utils import build_commit_graph, make_commit, make_object
 
 try:
     import gpg

+ 1 - 1
tests/test_refs.py

@@ -42,9 +42,9 @@ from dulwich.refs import (
     write_packed_refs,
 )
 from dulwich.repo import Repo
+from dulwich.tests.utils import open_repo, tear_down_repo
 
 from . import SkipTest, TestCase
-from .utils import open_repo, tear_down_repo
 
 
 class CheckRefFormatTests(TestCase):

+ 1 - 1
tests/test_repository.py

@@ -41,9 +41,9 @@ from dulwich.repo import (
     UnsupportedVersion,
     check_user_identity,
 )
+from dulwich.tests.utils import open_repo, setup_warning_catcher, tear_down_repo
 
 from . import TestCase, skipIf
-from .utils import open_repo, setup_warning_catcher, tear_down_repo
 
 missing_sha = b"b91fa4d900e17e99b433218e988c4eb4a3e9a097"
 

+ 1 - 1
tests/test_server.py

@@ -53,9 +53,9 @@ from dulwich.server import (
     serve_command,
     update_server_info,
 )
+from dulwich.tests.utils import make_commit, make_tag
 
 from . import TestCase
-from .utils import make_commit, make_tag
 
 ONE = b"1" * 40
 TWO = b"2" * 40

+ 1 - 1
tests/test_utils.py

@@ -22,9 +22,9 @@
 
 from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import Blob
+from dulwich.tests.utils import build_commit_graph, make_object
 
 from . import TestCase
-from .utils import build_commit_graph, make_object
 
 
 class BuildCommitGraphTest(TestCase):

+ 1 - 1
tests/test_walk.py

@@ -27,10 +27,10 @@ from dulwich.diff_tree import CHANGE_MODIFY, CHANGE_RENAME, RenameDetector, Tree
 from dulwich.errors import MissingCommitError
 from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import Blob, Commit
+from dulwich.tests.utils import F, build_commit_graph, make_object, make_tag
 from dulwich.walk import ORDER_TOPO, WalkEntry, Walker, _topo_reorder
 
 from . import TestCase
-from .utils import F, build_commit_graph, make_object, make_tag
 
 
 class TestWalkEntry:

+ 1 - 1
tests/test_web.py

@@ -30,6 +30,7 @@ from dulwich.object_store import MemoryObjectStore
 from dulwich.objects import Blob
 from dulwich.repo import BaseRepo, MemoryRepo
 from dulwich.server import DictBackend
+from dulwich.tests.utils import make_object, make_tag
 from dulwich.web import (
     HTTP_ERROR,
     HTTP_FORBIDDEN,
@@ -50,7 +51,6 @@ from dulwich.web import (
 )
 
 from . import TestCase
-from .utils import make_object, make_tag
 
 
 class MinimalistWSGIInputStream: