summaryrefslogtreecommitdiff
path: root/test/testlib/helper.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-10-22 16:20:35 +0200
committerSebastian Thiel <byronimo@gmail.com>2009-10-22 16:20:35 +0200
commit3c658c16f3437ed7e78f6072b6996cb423a8f504 (patch)
tree4dcb21b565410c48878be31deebbb441201d542b /test/testlib/helper.py
parent59e26435a8d2008073fc315bafe9f329d0ef689a (diff)
parentb197b2dbb527de9856e6e808339ab0ceaf0a512d (diff)
downloadgitpython-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/testlib/helper.py')
-rw-r--r--test/testlib/helper.py118
1 files changed, 118 insertions, 0 deletions
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)
+