diff options
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | test/git/test_base.py | 29 | ||||
-rw-r--r-- | test/git/test_blob.py | 12 | ||||
-rw-r--r-- | test/git/test_commit.py | 28 | ||||
-rw-r--r-- | test/git/test_config.py | 4 | ||||
-rw-r--r-- | test/git/test_diff.py | 14 | ||||
-rw-r--r-- | test/git/test_git.py | 8 | ||||
-rw-r--r-- | test/git/test_head.py | 8 | ||||
-rw-r--r-- | test/git/test_index.py | 18 | ||||
-rw-r--r-- | test/git/test_performance.py | 6 | ||||
-rw-r--r-- | test/git/test_remote.py | 27 | ||||
-rw-r--r-- | test/git/test_repo.py | 88 | ||||
-rw-r--r-- | test/git/test_stats.py | 6 | ||||
-rw-r--r-- | test/git/test_tag.py | 8 | ||||
-rw-r--r-- | test/testlib/__init__.py | 1 | ||||
-rw-r--r-- | test/testlib/helper.py | 118 |
16 files changed, 246 insertions, 135 deletions
@@ -138,6 +138,12 @@ Remote * Repo.remotes lists all remotes * Repo.remote returns a remote of the specified name if it exists +Test Framework +-------------- +* Added support for common TestCase base class that provides additional functionality + to receive repositories tests can also write to. This way, more aspects can be + tested under real-world ( un-mocked ) conditions. + Tree ---- * former 'name' member renamed to path as it suits the actual data better diff --git a/test/git/test_base.py b/test/git/test_base.py index b93e61c1..a7ef9374 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -14,16 +14,13 @@ from itertools import chain from git.objects.utils import get_object_type_by_name import tempfile -class TestBase(object): +class TestBase(TestBase): type_tuples = ( ("blob", "8741fc1d09d61f02ffd8cded15ff603eff1ec070"), ("tree", "3a6a5e3eeed3723c09f1ef0399f81ed6b8d82e79"), ("commit", "4251bd59fb8e11e40c40548cba38180a9536118c"), ("tag", "e56a60e8e9cd333cfba0140a77cd12b0d9398f10") ) - def setup(self): - self.repo = Repo(GIT_REPO) - def test_base_object(self): # test interface of base object classes types = (Blob, Tree, Commit, TagObject) @@ -33,7 +30,7 @@ class TestBase(object): num_objs = 0 num_index_objs = 0 for obj_type, (typename, hexsha) in zip(types, self.type_tuples): - item = obj_type(self.repo,hexsha) + item = obj_type(self.rorepo,hexsha) num_objs += 1 assert item.id == hexsha assert item.type == typename @@ -74,7 +71,7 @@ class TestBase(object): # tag refs can point to tag objects or to commits s = set() ref_count = 0 - for ref in chain(self.repo.tags, self.repo.heads): + for ref in chain(self.rorepo.tags, self.rorepo.heads): ref_count += 1 assert isinstance(ref, refs.Reference) assert str(ref) == ref.name @@ -88,7 +85,7 @@ class TestBase(object): def test_heads(self): # see how it dynmically updates its object - for head in self.repo.heads: + for head in self.rorepo.heads: head.name head.path prev_object = head.object @@ -106,4 +103,20 @@ class TestBase(object): def test_object_resolution(self): # objects must be resolved to shas so they compare equal - assert self.repo.head.object == self.repo.active_branch.object + assert self.rorepo.head.object == self.rorepo.active_branch.object + + @with_bare_rw_repo + def test_with_bare_rw_repo(self, bare_rw_repo): + assert bare_rw_repo.config_reader("repository").getboolean("core", "bare") + assert os.path.isfile(os.path.join(bare_rw_repo.path,'HEAD')) + + @with_rw_repo('0.1.6') + def test_with_rw_repo(self, rw_repo): + assert not rw_repo.config_reader("repository").getboolean("core", "bare") + assert os.path.isdir(os.path.join(rw_repo.git.git_dir,'lib')) + + @with_rw_and_rw_remote_repo('0.1.6') + def test_with_rw_remote_and_rw_repo(self, rw_repo, rw_remote_repo): + assert not rw_repo.config_reader("repository").getboolean("core", "bare") + assert rw_remote_repo.config_reader("repository").getboolean("core", "bare") + assert os.path.isdir(os.path.join(rw_repo.git.git_dir,'lib')) diff --git a/test/git/test_blob.py b/test/git/test_blob.py index e151b3c8..1b3b68f8 100644 --- a/test/git/test_blob.py +++ b/test/git/test_blob.py @@ -7,26 +7,24 @@ from test.testlib import * from git import * -class TestBlob(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestBlob(TestBase): def test_should_cache_data(self): bid = 'a802c139d4767c89dcad79d836d05f7004d39aac' - blob = Blob(self.repo, bid) + blob = Blob(self.rorepo, bid) blob.data assert blob.data blob.size blob.size def test_mime_type_should_return_mime_type_for_known_types(self): - blob = Blob(self.repo, **{'id': 'abc', 'path': 'foo.png'}) + blob = Blob(self.rorepo, **{'id': 'abc', 'path': 'foo.png'}) assert_equal("image/png", blob.mime_type) def test_mime_type_should_return_text_plain_for_unknown_types(self): - blob = Blob(self.repo, **{'id': 'abc','path': 'something'}) + blob = Blob(self.rorepo, **{'id': 'abc','path': 'something'}) assert_equal("text/plain", blob.mime_type) def test_should_return_appropriate_representation(self): - blob = Blob(self.repo, **{'id': 'abc'}) + blob = Blob(self.rorepo, **{'id': 'abc'}) assert_equal('<git.Blob "abc">', repr(blob)) diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 3d7feb6d..1a74593d 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -7,13 +7,11 @@ from test.testlib import * from git import * -class TestCommit(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestCommit(TestBase): def test_bake(self): - commit = Commit(self.repo, **{'id': '2454ae89983a4496a445ce347d7a41c0bb0ea7ae'}) + commit = Commit(self.rorepo, **{'id': '2454ae89983a4496a445ce347d7a41c0bb0ea7ae'}) commit.author # bake assert_equal("Sebastian Thiel", commit.author.name) @@ -21,7 +19,7 @@ class TestCommit(object): def test_stats(self): - commit = Commit(self.repo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') + commit = Commit(self.rorepo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') stats = commit.stats def check_entries(d): @@ -48,13 +46,13 @@ class TestCommit(object): git.return_value = fixture('rev_list_bisect_all') - revs = self.repo.git.rev_list('HEAD', + revs = self.rorepo.git.rev_list('HEAD', pretty='raw', first_parent=True, bisect_all=True) assert_true(git.called) - commits = Commit._iter_from_process_or_stream(self.repo, ListProcessAdapter(revs)) + commits = Commit._iter_from_process_or_stream(self.rorepo, ListProcessAdapter(revs)) expected_ids = ( 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', '33ebe7acec14b25c5f84f35a664803fcab2f7781', @@ -66,29 +64,29 @@ class TestCommit(object): assert_equal(sha1, commit.id) def test_count(self): - assert self.repo.tag('0.1.5').commit.count( ) == 141 + assert self.rorepo.tag('0.1.5').commit.count( ) == 141 def test_list(self): - assert isinstance(Commit.list_items(self.repo, '0.1.5', max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) + assert isinstance(Commit.list_items(self.rorepo, '0.1.5', max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) def test_str(self): - commit = Commit(self.repo, id='abc') + commit = Commit(self.rorepo, id='abc') assert_equal ("abc", str(commit)) def test_repr(self): - commit = Commit(self.repo, id='abc') + commit = Commit(self.rorepo, id='abc') assert_equal('<git.Commit "abc">', repr(commit)) def test_equality(self): - commit1 = Commit(self.repo, id='abc') - commit2 = Commit(self.repo, id='abc') - commit3 = Commit(self.repo, id='zyx') + commit1 = Commit(self.rorepo, id='abc') + commit2 = Commit(self.rorepo, id='abc') + commit3 = Commit(self.rorepo, id='zyx') assert_equal(commit1, commit2) assert_not_equal(commit2, commit3) def test_iter_parents(self): # should return all but ourselves, even if skip is defined - c = self.repo.commit('0.1.5') + c = self.rorepo.commit('0.1.5') for skip in (0, 1): piter = c.iter_parents(skip=skip) first_parent = piter.next() diff --git a/test/git/test_config.py b/test/git/test_config.py index 843da723..c2909b8f 100644 --- a/test/git/test_config.py +++ b/test/git/test_config.py @@ -11,10 +11,6 @@ from copy import copy class TestBase(TestCase): - @classmethod - def setUpAll(cls): - cls.repo = Repo(GIT_REPO) - def _to_memcache(self, file_path): fp = open(file_path, "r") sio = StringIO.StringIO() diff --git a/test/git/test_diff.py b/test/git/test_diff.py index 501d937d..d7505987 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -7,19 +7,17 @@ from test.testlib import * from git import * -class TestDiff(TestCase): - def setUp(self): - self.repo = Repo(GIT_REPO) - +class TestDiff(TestBase): + def test_list_from_string_new_mode(self): output = ListProcessAdapter(fixture('diff_new_mode')) - diffs = Diff._index_from_patch_format(self.repo, output.stdout) + diffs = Diff._index_from_patch_format(self.rorepo, output.stdout) assert_equal(1, len(diffs)) assert_equal(10, len(diffs[0].diff.splitlines())) def test_diff_with_rename(self): output = ListProcessAdapter(fixture('diff_rename')) - diffs = Diff._index_from_patch_format(self.repo, output.stdout) + diffs = Diff._index_from_patch_format(self.rorepo, output.stdout) assert_equal(1, len(diffs)) @@ -37,13 +35,13 @@ class TestDiff(TestCase): for fixture_name in fixtures: diff_proc = ListProcessAdapter(fixture(fixture_name)) - diffs = Diff._index_from_patch_format(self.repo, diff_proc.stdout) + diffs = Diff._index_from_patch_format(self.rorepo, diff_proc.stdout) # END for each fixture def test_diff_interface(self): # test a few variations of the main diff routine assertion_map = dict() - for i, commit in enumerate(self.repo.iter_commits('0.1.6', max_count=10)): + for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=10)): diff_item = commit if i%2 == 0: diff_item = commit.tree diff --git a/test/git/test_git.py b/test/git/test_git.py index 1f44aebc..c4a39e85 100644 --- a/test/git/test_git.py +++ b/test/git/test_git.py @@ -8,9 +8,11 @@ import os, sys from test.testlib import * from git import Git, GitCommandError -class TestGit(object): - def setup(self): - self.git = Git(GIT_REPO) +class TestGit(TestCase): + + @classmethod + def setUpAll(cls): + cls.git = Git(GIT_REPO) @patch_object(Git, 'execute') def test_call_process_calls_execute(self, git): diff --git a/test/git/test_head.py b/test/git/test_head.py index b8380838..9b18ad7c 100644 --- a/test/git/test_head.py +++ b/test/git/test_head.py @@ -7,12 +7,10 @@ from test.testlib import * from git import * -class TestHead(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestHead(TestBase): def test_base(self): - for head in self.repo.heads: + for head in self.rorepo.heads: assert head.name assert "refs/heads" in head.path # END for each head @@ -20,7 +18,7 @@ class TestHead(object): @patch_object(Git, '_call_process') def test_ref_with_path_component(self, git): git.return_value = fixture('for_each_ref_with_path_component') - head = self.repo.heads[0] + head = self.rorepo.heads[0] assert_equal('refactoring/feature1', head.name) assert_true(git.called) diff --git a/test/git/test_index.py b/test/git/test_index.py index 4c17f5e5..10ffb79d 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -10,15 +10,11 @@ import inspect import os import tempfile -class TestTree(TestCase): +class TestTree(TestBase): - @classmethod - def setUpAll(cls): - cls.repo = Repo(GIT_REPO) - def test_base(self): # read from file - index = Index.from_file(self.repo, fixture_path("index")) + index = Index.from_file(self.rorepo, fixture_path("index")) assert index.entries assert index.version > 0 @@ -31,7 +27,7 @@ class TestTree(TestCase): # END for each method # test stage - index_merge = Index.from_file(self.repo, fixture_path("index_merge")) + index_merge = Index.from_file(self.rorepo, fixture_path("index_merge")) assert len(index_merge.entries) == 106 assert len(list(e for e in index_merge.entries.itervalues() if e.stage != 0 )) @@ -50,7 +46,7 @@ class TestTree(TestCase): def _cmp_tree_index(self, tree, index): # fail unless both objects contain the same paths and blobs if isinstance(tree, str): - tree = self.repo.commit(tree).tree + tree = self.rorepo.commit(tree).tree num_blobs = 0 for blob in tree.traverse(predicate = lambda e: e.type == "blob"): @@ -65,17 +61,17 @@ class TestTree(TestCase): other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" # simple index from tree - base_index = Index.from_tree(self.repo, common_ancestor_sha) + base_index = Index.from_tree(self.rorepo, common_ancestor_sha) assert base_index.entries self._cmp_tree_index(common_ancestor_sha, base_index) # merge two trees - its like a fast-forward - two_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha) + two_way_index = Index.from_tree(self.rorepo, common_ancestor_sha, cur_sha) assert two_way_index.entries self._cmp_tree_index(cur_sha, two_way_index) # merge three trees - here we have a merge conflict - three_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) + three_way_index = Index.from_tree(self.rorepo, common_ancestor_sha, cur_sha, other_sha) assert len(list(e for e in three_way_index.entries.values() if e.stage != 0)) diff --git a/test/git/test_performance.py b/test/git/test_performance.py index 77567515..83d4a91e 100644 --- a/test/git/test_performance.py +++ b/test/git/test_performance.py @@ -8,9 +8,7 @@ from test.testlib import * from git import * from time import time -class TestPerformance(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestPerformance(TestBase): def test_iteration(self): num_objs = 0 @@ -21,7 +19,7 @@ class TestPerformance(object): # return quite a lot of commits, we just take one and hence abort the operation st = time() - for c in self.repo.iter_commits('0.1.6'): + for c in self.rorepo.iter_commits('0.1.6'): num_commits += 1 c.author c.authored_date diff --git a/test/git/test_remote.py b/test/git/test_remote.py index aeb6b4af..ef00056d 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -7,16 +7,13 @@ from test.testlib import * from git import * -class TestRemote(TestCase): +class TestRemote(TestBase): - @classmethod - def setUpAll(cls): - cls.repo = Repo(GIT_REPO) - - def test_base(self): + @with_rw_and_rw_remote_repo('0.1.6') + def test_base(self, rw_repo, remote_repo): num_remotes = 0 remote_set = set() - for remote in self.repo.remotes: + for remote in rw_repo.remotes: num_remotes += 1 assert remote == remote assert str(remote) != repr(remote) @@ -64,27 +61,29 @@ class TestRemote(TestCase): remote.fetch() self.failUnlessRaises(GitCommandError, remote.pull) + remote.pull('master') remote.update() self.fail("test push once there is a test-repo") # END for each remote assert num_remotes assert num_remotes == len(remote_set) - origin = self.repo.remote('origin') - assert origin == self.repo.remotes.origin + origin = rw_repo.remote('origin') + assert origin == rw_repo.remotes.origin - def test_creation_and_removal(self): + @with_bare_rw_repo + def test_creation_and_removal(self, bare_rw_repo): new_name = "test_new_one" arg_list = (new_name, "git@server:hello.git") - remote = Remote.create(self.repo, *arg_list ) + remote = Remote.create(bare_rw_repo, *arg_list ) assert remote.name == "test_new_one" # create same one again - self.failUnlessRaises(GitCommandError, Remote.create, self.repo, *arg_list) + self.failUnlessRaises(GitCommandError, Remote.create, bare_rw_repo, *arg_list) - Remote.remove(self.repo, new_name) + Remote.remove(bare_rw_repo, new_name) - for remote in self.repo.remotes: + for remote in bare_rw_repo.remotes: if remote.name == new_name: raise AssertionError("Remote removal failed") # END if deleted remote matches existing remote's name diff --git a/test/git/test_repo.py b/test/git/test_repo.py index ff10f6a6..02eea7de 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -8,11 +8,7 @@ import os, sys from test.testlib import * from git import * -class TestRepo(TestCase): - - @classmethod - def setUpAll(cls): - cls.repo = Repo(GIT_REPO) +class TestRepo(TestBase): @raises(InvalidGitRepositoryError) def test_new_should_raise_on_invalid_repo_location(self): @@ -27,27 +23,27 @@ class TestRepo(TestCase): def test_description(self): txt = "Test repository" - self.repo.description = txt - assert_equal(self.repo.description, txt) + self.rorepo.description = txt + assert_equal(self.rorepo.description, txt) def test_heads_should_return_array_of_head_objects(self): - for head in self.repo.heads: + for head in self.rorepo.heads: assert_equal(Head, head.__class__) def test_heads_should_populate_head_data(self): - for head in self.repo.heads: + for head in self.rorepo.heads: assert head.name assert isinstance(head.commit,Commit) # END for each head - assert isinstance(self.repo.heads.master, Head) - assert isinstance(self.repo.heads['master'], Head) + assert isinstance(self.rorepo.heads.master, Head) + assert isinstance(self.rorepo.heads['master'], Head) @patch_object(Git, '_call_process') def test_commits(self, git): git.return_value = ListProcessAdapter(fixture('rev_list')) - commits = list( self.repo.iter_commits('master', max_count=10) ) + commits = list( self.rorepo.iter_commits('master', max_count=10) ) c = commits[0] assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id) @@ -73,7 +69,7 @@ class TestRepo(TestCase): def test_trees(self): mc = 30 num_trees = 0 - for tree in self.repo.iter_trees('0.1.5', max_count=mc): + for tree in self.rorepo.iter_trees('0.1.5', max_count=mc): num_trees += 1 assert isinstance(tree, Tree) # END for each tree @@ -93,7 +89,7 @@ class TestRepo(TestCase): assert_true(repo.called) def test_bare_property(self): - self.repo.bare + self.rorepo.bare @patch_object(Repo, '__init__') @patch_object(Git, '_call_process') @@ -113,7 +109,7 @@ class TestRepo(TestCase): git.return_value = None repo.return_value = None - self.repo.clone("repos/foo/bar.git") + self.rorepo.clone("repos/foo/bar.git") assert_true(git.called) path = os.path.join(absolute_project_path(), '.git') @@ -126,7 +122,7 @@ class TestRepo(TestCase): git.return_value = None repo.return_value = None - self.repo.clone("repos/foo/bar.git", **{'template': '/awesome'}) + self.rorepo.clone("repos/foo/bar.git", **{'template': '/awesome'}) assert_true(git.called) path = os.path.join(absolute_project_path(), '.git') @@ -136,63 +132,63 @@ class TestRepo(TestCase): def test_daemon_export(self): - orig_val = self.repo.daemon_export - self.repo.daemon_export = not orig_val - assert self.repo.daemon_export == ( not orig_val ) - self.repo.daemon_export = orig_val - assert self.repo.daemon_export == orig_val + orig_val = self.rorepo.daemon_export + self.rorepo.daemon_export = not orig_val + assert self.rorepo.daemon_export == ( not orig_val ) + self.rorepo.daemon_export = orig_val + assert self.rorepo.daemon_export == orig_val def test_alternates(self): - cur_alternates = self.repo.alternates + cur_alternates = self.rorepo.alternates # empty alternates - self.repo.alternates = [] - assert self.repo.alternates == [] + self.rorepo.alternates = [] + assert self.rorepo.alternates == [] alts = [ "other/location", "this/location" ] - self.repo.alternates = alts - assert alts == self.repo.alternates - self.repo.alternates = cur_alternates + self.rorepo.alternates = alts + assert alts == self.rorepo.alternates + self.rorepo.alternates = cur_alternates def test_repr(self): path = os.path.join(os.path.abspath(GIT_REPO), '.git') - assert_equal('<git.Repo "%s">' % path, repr(self.repo)) + assert_equal('<git.Repo "%s">' % path, repr(self.rorepo)) def test_is_dirty_with_bare_repository(self): - self.repo._bare = True - assert_false(self.repo.is_dirty) + self.rorepo._bare = True + assert_false(self.rorepo.is_dirty) def test_is_dirty(self): - self.repo._bare = False + self.rorepo._bare = False for index in (0,1): for working_tree in (0,1): for untracked_files in (0,1): - assert self.repo.is_dirty in (True, False) + assert self.rorepo.is_dirty in (True, False) # END untracked files # END working tree # END index - self.repo._bare = True - assert self.repo.is_dirty == False + self.rorepo._bare = True + assert self.rorepo.is_dirty == False @patch_object(Git, '_call_process') def test_active_branch(self, git): git.return_value = 'refs/heads/major-refactoring' - assert_equal(self.repo.active_branch.name, 'major-refactoring') + assert_equal(self.rorepo.active_branch.name, 'major-refactoring') assert_equal(git.call_args, (('symbolic_ref', 'HEAD'), {})) def test_head(self): - assert self.repo.head.object == self.repo.active_branch.object + assert self.rorepo.head.object == self.rorepo.active_branch.object def test_tag(self): - assert self.repo.tag('0.1.5').commit + assert self.rorepo.tag('0.1.5').commit def test_archive(self): tmpfile = os.tmpfile() - self.repo.archive(tmpfile, '0.1.5') + self.rorepo.archive(tmpfile, '0.1.5') assert tmpfile.tell() @patch_object(Git, '_call_process') def test_should_display_blame_information(self, git): git.return_value = fixture('blame') - b = self.repo.blame( 'master', 'lib/git.py') + b = self.rorepo.blame( 'master', 'lib/git.py') assert_equal(13, len(b)) assert_equal( 2, len(b[0]) ) # assert_equal(25, reduce(lambda acc, x: acc + len(x[-1]), b)) @@ -217,7 +213,7 @@ class TestRepo(TestCase): assert_true( len( tlist ) < sum( len(t) for t in tlist ) ) # test for single-char bug def test_untracked_files(self): - base = self.repo.git.git_dir + base = self.rorepo.git.git_dir files = (base+"/__test_myfile", base+"/__test_other_file") num_recently_untracked = 0 try: @@ -225,7 +221,7 @@ class TestRepo(TestCase): fd = open(fpath,"wb") fd.close() # END for each filename - untracked_files = self.repo.untracked_files + untracked_files = self.rorepo.untracked_files num_recently_untracked = len(untracked_files) # assure we have all names - they are relative to the git-dir @@ -239,18 +235,18 @@ class TestRepo(TestCase): os.remove(fpath) # END handle files - assert len(self.repo.untracked_files) == (num_recently_untracked - len(files)) + assert len(self.rorepo.untracked_files) == (num_recently_untracked - len(files)) def test_config_reader(self): - reader = self.repo.config_reader() # all config files + reader = self.rorepo.config_reader() # all config files assert reader.read_only - reader = self.repo.config_reader("repository") # single config file + reader = self.rorepo.config_reader("repository") # single config file assert reader.read_only def test_config_writer(self): - for config_level in self.repo.config_level: + for config_level in self.rorepo.config_level: try: - writer = self.repo.config_writer(config_level) + writer = self.rorepo.config_writer(config_level) assert not writer.read_only except IOError: # its okay not to get a writer for some configuration files if we diff --git a/test/git/test_stats.py b/test/git/test_stats.py index 706f29a4..7392a96e 100644 --- a/test/git/test_stats.py +++ b/test/git/test_stats.py @@ -7,13 +7,11 @@ from test.testlib import * from git import * -class TestStats(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestStats(TestBase): def test__list_from_string(self): output = fixture('diff_numstat') - stats = Stats._list_from_string(self.repo, output) + stats = Stats._list_from_string(self.rorepo, output) assert_equal(2, stats.total['files']) assert_equal(52, stats.total['lines']) diff --git a/test/git/test_tag.py b/test/git/test_tag.py index 9641e0ac..97e0acd1 100644 --- a/test/git/test_tag.py +++ b/test/git/test_tag.py @@ -9,13 +9,11 @@ from test.testlib import * from git import * from git.objects.tag import TagObject -class TestTag(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestTag(TestBase): def test_tag_base(self): tag_object_refs = list() - for tag in self.repo.tags: + for tag in self.rorepo.tags: assert "refs/tags" in tag.path assert tag.name assert isinstance( tag.commit, Commit ) @@ -30,6 +28,6 @@ class TestTag(object): # END if we have a tag object # END for tag in repo-tags assert tag_object_refs - assert isinstance(self.repo.tags['0.1.5'], TagReference) + assert isinstance(self.rorepo.tags['0.1.5'], TagReference) diff --git a/test/testlib/__init__.py b/test/testlib/__init__.py index f364171b..2133eb8c 100644 --- a/test/testlib/__init__.py +++ b/test/testlib/__init__.py @@ -8,7 +8,6 @@ import inspect from mock import * from asserts import * from helper import * -from unittest import TestCase __all__ = [ name for name, obj in locals().items() if not (name.startswith('_') or inspect.ismodule(obj)) ] diff --git a/test/testlib/helper.py b/test/testlib/helper.py index b34c9303..eef7876f 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -5,6 +5,10 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os +from git import Repo +from unittest import TestCase +import tempfile +import shutil GIT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -58,3 +62,117 @@ class ListProcessAdapter(object): return 0 poll = wait + + +def with_bare_rw_repo(func): + """ + Decorator providing a specially made read-write repository to the test case + decorated with it. The test case requires the following signature:: + def case(self, rw_repo) + + The rwrepo will be a bare clone or the types rorepo. Once the method finishes, + it will be removed completely. + + Use this if you want to make purely index based adjustments, change refs, create + heads, generally operations that do not need a working tree. + """ + def bare_repo_creator(self): + repo_dir = tempfile.mktemp("bare_repo") + rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=True) + try: + return func(self, rw_repo) + finally: + shutil.rmtree(repo_dir) + # END cleanup + # END bare repo creator + bare_repo_creator.__name__ = func.__name__ + return bare_repo_creator + +def with_rw_repo(working_tree_ref): + """ + Same as with_bare_repo, but clones the rorepo as non-bare repository, checking + out the working tree at the given working_tree_ref. + + This repository type is more costly due to the working copy checkout. + """ + assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" + def argument_passer(func): + def repo_creator(self): + repo_dir = tempfile.mktemp("non_bare_repo") + rw_repo = self.rorepo.clone(repo_dir, shared=True, bare=False, n=True) + rw_repo.git.checkout(working_tree_ref) + try: + return func(self, rw_repo) + finally: + shutil.rmtree(repo_dir) + # END cleanup + # END rw repo creator + repo_creator.__name__ = func.__name__ + return repo_creator + # END argument passer + return argument_passer + +def with_rw_and_rw_remote_repo(working_tree_ref): + """ + Same as with_rw_repo, but also provides a writable remote repository from which the + rw_repo has been forked. The remote repository was cloned as bare repository from + the rorepo, wheras the rw repo has a working tree and was cloned from the remote repository. + + The following scetch demonstrates this:: + rorepo ---<bare clone>---> rw_remote_repo ---<clone>---> rw_repo + + The test case needs to support the following signature:: + def case(self, rw_repo, rw_remote_repo) + + This setup allows you to test push and pull scenarios and hooks nicely. + """ + assert isinstance(working_tree_ref, basestring), "Decorator requires ref name for working tree checkout" + def argument_passer(func): + def remote_repo_creator(self): + remote_repo_dir = tempfile.mktemp("remote_repo") + repo_dir = tempfile.mktemp("remote_clone_non_bare_repo") + + rw_remote_repo = self.rorepo.clone(remote_repo_dir, shared=True, bare=True) + rw_repo = rw_remote_repo.clone(repo_dir, shared=True, bare=False, n=True) # recursive alternates info ? + rw_repo.git.checkout(working_tree_ref) + try: + return func(self, rw_repo, rw_remote_repo) + finally: + shutil.rmtree(repo_dir) + shutil.rmtree(remote_repo_dir) + # END cleanup + # END bare repo creator + remote_repo_creator.__name__ = func.__name__ + return remote_repo_creator + # END remote repo creator + # END argument parsser + + return argument_passer + + +class TestBase(TestCase): + """ + Base Class providing default functionality to all tests such as: + + - Utility functions provided by the TestCase base of the unittest method such as:: + self.fail("todo") + self.failUnlessRaises(...) + + - Class level repository which is considered read-only as it is shared among + all test cases in your type. + Access it using:: + self.rorepo # 'ro' stands for read-only + + The rorepo is in fact your current project's git repo. If you refer to specific + shas for your objects, be sure you choose some that are part of the immutable portion + of the project history ( to assure tests don't fail for others ). + """ + + @classmethod + def setUpAll(cls): + """ + Dynamically add a read-only repository to our actual type. This way + each test type has its own repository + """ + cls.rorepo = Repo(GIT_REPO) + |