diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2009-10-22 16:20:35 +0200 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2009-10-22 16:20:35 +0200 |
commit | 3c658c16f3437ed7e78f6072b6996cb423a8f504 (patch) | |
tree | 4dcb21b565410c48878be31deebbb441201d542b /test | |
parent | 59e26435a8d2008073fc315bafe9f329d0ef689a (diff) | |
parent | b197b2dbb527de9856e6e808339ab0ceaf0a512d (diff) | |
download | gitpython-3c658c16f3437ed7e78f6072b6996cb423a8f504.tar.gz |
Merge branch 'testsystem' into improvements
* testsystem:
Adjusted all remaining test suites to use the new TestBase class where appropriate
Fixed decorator issue that would cause a function to be passed even though there is a default argument. This feels inconsistent as the 'argument passer' wrapper function can be called with a function or a string as first argument depending on whether the client code was explicitly passing an argument or not. That ... sucks. Now test for that case specifically and fail with a proper assertion error. I don't like it, but what can I do ... .
Implemented decorators, tests pass at least
Added frame for new Repo handling and some neat decorators, including tests that test whether the testing framework does what it should
Diffstat (limited to 'test')
-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 |
15 files changed, 240 insertions, 135 deletions
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) + |