summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--test/git/test_base.py26
-rw-r--r--test/testlib/__init__.py1
-rw-r--r--test/testlib/helper.py98
4 files changed, 122 insertions, 9 deletions
diff --git a/CHANGES b/CHANGES
index 377d7e07..3b42095e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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..9f4cfa05 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,17 @@ 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")
+
+ @with_rw_repo
+ def test_with_rw_repo(self, rw_repo):
+ assert not rw_repo.config_reader("repository").getboolean("core", "bare")
+
+ @with_rw_and_rw_remote_repo
+ 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")
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..bc314cb2 100644
--- a/test/testlib/helper.py
+++ b/test/testlib/helper.py
@@ -5,6 +5,8 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
import os
+from git import Repo
+from unittest import TestCase
GIT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
@@ -58,3 +60,99 @@ 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):
+ rw_repo = None
+ try:
+ return func(self, rw_repo)
+ finally:
+ pass
+ # END cleanup
+ # END bare repo creator
+ bare_repo_creator.__name__ = func.__name__
+ return bare_repo_creator
+
+def with_rw_repo(func, working_tree_ref='0.1.6'):
+ """
+ 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.
+ """
+ def repo_creator(self):
+ rw_repo = None
+ try:
+ return func(self, rw_repo)
+ finally:
+ pass
+ # END cleanup
+ # END bare repo creator
+ repo_creator.__name__ = func.__name__
+ return repo_creator
+
+def with_rw_and_rw_remote_repo(func):
+ """
+ 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.
+ """
+ def remote_repo_creator(self):
+ rw_repo = None
+ rw_remote_repo = None
+ try:
+ return func(self, rw_repo, rw_remote_repo)
+ finally:
+ pass
+ # END cleanup
+ # END bare repo creator
+ remote_repo_creator.__name__ = func.__name__
+ return remote_repo_creator
+
+
+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)
+