From beb76aba0c835669629d95c905551f58cc927299 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 12 Oct 2009 17:41:00 +0200 Subject: repo.active_branch now returns a Head object, not a string --- test/git/test_repo.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 3e2fb3dc..e999ffe8 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -91,13 +91,12 @@ class TestRepo(object): def test_tree(self, git): git.return_value = fixture('ls_tree_a') - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo, 'master')) assert_equal(4, len([c for c in tree.values() if isinstance(c, Blob)])) assert_equal(3, len([c for c in tree.values() if isinstance(c, Tree)])) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Git, '_call_process') def test_blob(self, git): @@ -255,7 +254,7 @@ class TestRepo(object): @patch_object(Git, '_call_process') def test_active_branch(self, git): git.return_value = 'refs/heads/major-refactoring' - assert_equal(self.repo.active_branch, 'major-refactoring') + assert_equal(self.repo.active_branch.name, 'major-refactoring') assert_equal(git.call_args, (('symbolic_ref', 'HEAD'), {})) @patch_object(Git, '_call_process') -- cgit v1.2.1 From ff3d142387e1f38b0ed390333ea99e2e23d96e35 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 12 Oct 2009 18:02:07 +0200 Subject: test_base: Improved basic object creation as well as set hash tests --- test/git/test_base.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/git/test_base.py b/test/git/test_base.py index a153eb83..aff0947d 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -24,14 +24,14 @@ class TestBase(object): def test_base_object(self): # test interface of base object classes - fcreators = (self.repo.blob, self.repo.tree, self.repo.commit, lambda id: TagObject(self.repo,id) ) - assert len(fcreators) == len(self.type_tuples) + types = (Blob, Tree, Commit, TagObject) + assert len(types) == len(self.type_tuples) s = set() num_objs = 0 num_index_objs = 0 - for fcreator, (typename, hexsha) in zip(fcreators, self.type_tuples): - item = fcreator(hexsha) + for obj_type, (typename, hexsha) in zip(types, self.type_tuples): + item = obj_type(self.repo,hexsha) num_objs += 1 assert item.id == hexsha assert item.type == typename @@ -53,6 +53,7 @@ class TestBase(object): # each has a unique sha assert len(s) == num_objs + assert len(s|s) == num_objs assert num_index_objs == 2 @@ -70,6 +71,7 @@ class TestBase(object): s.add(ref) # END for each ref assert len(s) == ref_count + assert len(s|s) == ref_count def test_get_object_type_by_name(self): for tname in base.Object.TYPES: -- cgit v1.2.1 From a58a60ac5f322eb4bfd38741469ff21b5a33d2d5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 12 Oct 2009 23:18:43 +0200 Subject: tree: now behaves like a list with string indexing functionality - using a dict as cache is a problem as the tree is ordered, added blobs, trees and traverse method repo: remove blob function as blobs are created directly or iterated - primitve types should not clutter the repo interface --- test/git/test_repo.py | 6 ++--- test/git/test_tree.py | 68 +++++++++++++++++++++++++++++++----------------- test/testlib/__init__.py | 1 + 3 files changed, 48 insertions(+), 27 deletions(-) (limited to 'test') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index e999ffe8..7f87f78b 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -93,8 +93,8 @@ class TestRepo(object): tree = self.repo.tree(Head(self.repo, 'master')) - assert_equal(4, len([c for c in tree.values() if isinstance(c, Blob)])) - assert_equal(3, len([c for c in tree.values() if isinstance(c, Tree)])) + assert_equal(4, len([c for c in tree if isinstance(c, Blob)])) + assert_equal(3, len([c for c in tree if isinstance(c, Tree)])) assert_true(git.called) @@ -102,7 +102,7 @@ class TestRepo(object): def test_blob(self, git): git.return_value = fixture('cat_file_blob') - blob = self.repo.blob("abc") + blob = Blob(self.repo,"abc") assert_equal("Hello world", blob.data) assert_true(git.called) diff --git a/test/git/test_tree.py b/test/git/test_tree.py index cb8ebb04..e0429db1 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -7,19 +7,20 @@ from test.testlib import * from git import * -class TestTree(object): - def setup(self): +class TestTree(TestCase): + + def setUp(self): self.repo = Repo(GIT_REPO) @patch_object(Git, '_call_process') def test_contents_should_cache(self, git): git.return_value = fixture('ls_tree_a') + fixture('ls_tree_b') - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) child = tree['grit'] - child.items() - child.items() + len(child) + len(child) assert_true(git.called) assert_equal(2, git.call_count) @@ -27,7 +28,7 @@ class TestTree(object): def test_content_from_string_tree_should_return_tree(self): text = fixture('ls_tree_a').splitlines()[-1] - tree = Tree.content__from_string(None, text) + tree = Tree.content_from_string(None, text) assert_equal(Tree, tree.__class__) assert_equal("650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44", tree.id) @@ -37,7 +38,7 @@ class TestTree(object): def test_content_from_string_tree_should_return_blob(self): text = fixture('ls_tree_b').split("\n")[0] - tree = Tree.content__from_string(None, text) + tree = Tree.content_from_string(None, text) assert_equal(Blob, tree.__class__) assert_equal("aa94e396335d2957ca92606f909e53e7beaf3fbb", tree.id) @@ -47,12 +48,12 @@ class TestTree(object): def test_content_from_string_tree_should_return_commit(self): text = fixture('ls_tree_commit').split("\n")[1] - tree = Tree.content__from_string(None, text) + tree = Tree.content_from_string(None, text) assert_none(tree) @raises(TypeError) def test_content_from_string_invalid_type_should_raise(self): - Tree.content__from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") + Tree.content_from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") @patch_object(Blob, 'size') @patch_object(Git, '_call_process') @@ -60,13 +61,37 @@ class TestTree(object): git.return_value = fixture('ls_tree_a') blob.return_value = 1 - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', (tree/'lib').id) assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + + def test_traverse(self): + root = self.repo.tree() + num_recursive = 0 + all_items = list() + for obj in root.traverse(): + if "/" in obj.path: + num_recursive += 1 + + assert isinstance(obj, (Blob, Tree)) + all_items.append(obj) + # END for each object + # limit recursion level to 0 - should be same as default iteration + assert all_items + assert 'CHANGES' in root + assert len(list(root)) == len(list(root.traverse(max_depth=0))) + + # only choose trees + trees_only = lambda i: i.type == "tree" + trees = list(root.traverse(predicate = trees_only)) + assert len(trees) == len(list( i for i in root.traverse() if trees_only(i) )) + + # trees and blobs + assert len(set(trees)|set(root.trees)) == len(trees) + assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len( root.blobs ) @patch_object(Blob, 'size') @patch_object(Git, '_call_process') @@ -74,26 +99,24 @@ class TestTree(object): git.return_value = fixture('ls_tree_a') blob.return_value = 0 - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) assert_not_none(tree/'README.txt') assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Git, '_call_process') def test_slash_with_commits(self, git): git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) - assert_none(tree/'bar') + self.failUnlessRaises(KeyError, tree.__div__, 'bar') assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', (tree/'foo').id) assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', (tree/'baz').id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Blob, 'size') @patch_object(Git, '_call_process') @@ -101,13 +124,12 @@ class TestTree(object): git.return_value = fixture('ls_tree_a') blob.return_value = 1 - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', tree['lib'].id) assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Blob, 'size') @patch_object(Git, '_call_process') @@ -115,33 +137,31 @@ class TestTree(object): git.return_value = fixture('ls_tree_a') blob.return_value = 0 - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) assert_not_none(tree['README.txt']) assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Git, '_call_process') def test_dict_with_commits(self, git): git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) - assert_none(tree.get('bar')) + self.failUnlessRaises(KeyError, tree.__getitem__, 'bar') assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', tree['foo'].id) assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', tree['baz'].id) assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) @patch_object(Git, '_call_process') @raises(KeyError) def test_dict_with_non_existant_file(self, git): git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') + tree = self.repo.tree(Head(self.repo,'master')) tree['bar'] def test_repr(self): diff --git a/test/testlib/__init__.py b/test/testlib/__init__.py index 2133eb8c..f364171b 100644 --- a/test/testlib/__init__.py +++ b/test/testlib/__init__.py @@ -8,6 +8,7 @@ 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)) ] -- cgit v1.2.1 From 86fa577e135713e56b287169d69d976cde27ac97 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 13 Oct 2009 17:36:27 +0200 Subject: tree: renamed content_from_string to _from_string to make it private. Removed tests that were testing that method --- test/git/test_tree.py | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) (limited to 'test') diff --git a/test/git/test_tree.py b/test/git/test_tree.py index e0429db1..0104a16b 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -25,35 +25,10 @@ class TestTree(TestCase): assert_true(git.called) assert_equal(2, git.call_count) assert_equal(git.call_args, (('ls_tree', '34868e6e7384cb5ee51c543a8187fdff2675b5a7'), {})) - - def test_content_from_string_tree_should_return_tree(self): - text = fixture('ls_tree_a').splitlines()[-1] - tree = Tree.content_from_string(None, text) - - assert_equal(Tree, tree.__class__) - assert_equal("650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44", tree.id) - assert_equal(0,tree.mode) # git tree objects always use this mode - assert_equal("test", tree.path) - - def test_content_from_string_tree_should_return_blob(self): - text = fixture('ls_tree_b').split("\n")[0] - - tree = Tree.content_from_string(None, text) - - assert_equal(Blob, tree.__class__) - assert_equal("aa94e396335d2957ca92606f909e53e7beaf3fbb", tree.id) - assert_mode_644(tree.mode) - assert_equal("grit.rb", tree.path) - - def test_content_from_string_tree_should_return_commit(self): - text = fixture('ls_tree_commit').split("\n")[1] - - tree = Tree.content_from_string(None, text) - assert_none(tree) @raises(TypeError) - def test_content_from_string_invalid_type_should_raise(self): - Tree.content_from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") + def test__from_string_invalid_type_should_raise(self): + Tree._from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") @patch_object(Blob, 'size') @patch_object(Git, '_call_process') -- cgit v1.2.1 From 5eb0f2c241718bc7462be44e5e8e1e36e35f9b15 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 13 Oct 2009 17:50:26 +0200 Subject: unified name of utils module, recently it was named util and utils in different packages --- test/git/test_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/git/test_base.py b/test/git/test_base.py index aff0947d..97dfc255 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -10,7 +10,7 @@ from git import * import git.objects.base as base import git.refs as refs from itertools import chain -from git.objects.util import get_object_type_by_name +from git.objects.utils import get_object_type_by_name class TestBase(object): -- cgit v1.2.1 From 6acec357c7609fdd2cb0f5fdb1d2756726c7fe98 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 13 Oct 2009 21:26:19 +0200 Subject: renamed find_all to list_all, changed commit to use iterable interface in preparation for command changes --- test/git/test_commit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index fa49821d..0fb4bceb 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -216,7 +216,7 @@ class TestCommit(object): bisect_all=True) assert_true(git.called) - commits = Commit._list_from_string(self.repo, revs) + commits = Commit._iter_from_stream(self.repo, iter(revs.splitlines(False))) expected_ids = ( 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', '33ebe7acec14b25c5f84f35a664803fcab2f7781', -- cgit v1.2.1 From ead94f267065bb55303f79a0a6df477810b3c68d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 14:33:51 +0200 Subject: cmd: added option to return the process directly, allowing to read the output directly from the output stream commit: now reads commit information directly from the output stream of the process by implementing its iterator method repo: removed log method as it was redundant ( equal to the commits method ) --- test/git/test_commit.py | 28 ++++++++-------------------- test/git/test_repo.py | 22 ++-------------------- test/testlib/helper.py | 11 +++++++++++ 3 files changed, 21 insertions(+), 40 deletions(-) (limited to 'test') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 0fb4bceb..00af6b52 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -11,18 +11,13 @@ class TestCommit(object): def setup(self): self.repo = Repo(GIT_REPO) - @patch_object(Git, '_call_process') - def test_bake(self, git): - git.return_value = fixture('rev_list_single') + def test_bake(self): - commit = Commit(self.repo, **{'id': '4c8124ffcf4039d292442eeccabdeca5af5c5017'}) + commit = Commit(self.repo, **{'id': '2454ae89983a4496a445ce347d7a41c0bb0ea7ae'}) commit.author # bake - assert_equal("Tom Preston-Werner", commit.author.name) - assert_equal("tom@mojombo.com", commit.author.email) - - assert_true(git.called) - assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) + assert_equal("Sebastian Thiel", commit.author.name) + assert_equal("byronimo@gmail.com", commit.author.email) @patch_object(Git, '_call_process') @@ -159,17 +154,10 @@ class TestCommit(object): assert diff.deleted_file and isinstance(diff.deleted_file, bool) # END for each diff in initial import commit - @patch_object(Git, '_call_process') - def test_diffs_on_initial_import_with_empty_commit(self, git): - git.return_value = fixture('show_empty_commit') - - commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') + def test_diffs_on_initial_import_without_parents(self): + commit = Commit(self.repo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') diffs = commit.diffs - - assert_equal([], diffs) - - assert_true(git.called) - assert_equal(git.call_args, (('show', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '-M'), {'full_index': True, 'pretty': 'raw'})) + assert diffs def test_diffs_with_mode_only_change(self): commit = Commit(self.repo, id='ccde80b7a3037a004a7807a6b79916ce2a1e9729') @@ -216,7 +204,7 @@ class TestCommit(object): bisect_all=True) assert_true(git.called) - commits = Commit._iter_from_stream(self.repo, iter(revs.splitlines(False))) + commits = Commit._iter_from_process(self.repo, ListProcessAdapter(revs)) expected_ids = ( 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', '33ebe7acec14b25c5f84f35a664803fcab2f7781', diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 7f87f78b..f0687050 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -41,7 +41,7 @@ class TestRepo(object): @patch_object(Git, '_call_process') def test_commits(self, git): - git.return_value = fixture('rev_list') + git.return_value = ListProcessAdapter(fixture('rev_list')) commits = self.repo.commits('master', max_count=10) @@ -65,7 +65,6 @@ class TestRepo(object): assert_equal("Merge branch 'site'", c.summary) assert_true(git.called) - assert_equal(git.call_args, (('rev_list', 'master', '--', ''), {'skip': 0, 'pretty': 'raw', 'max_count': 10})) @patch_object(Git, '_call_process') def test_commit_count(self, git): @@ -78,14 +77,13 @@ class TestRepo(object): @patch_object(Git, '_call_process') def test_commit(self, git): - git.return_value = fixture('rev_list_single') + git.return_value = ListProcessAdapter(fixture('rev_list_single')) commit = self.repo.commit('4c8124ffcf4039d292442eeccabdeca5af5c5017') assert_equal("4c8124ffcf4039d292442eeccabdeca5af5c5017", commit.id) assert_true(git.called) - assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) @patch_object(Git, '_call_process') def test_tree(self, git): @@ -217,22 +215,6 @@ class TestRepo(object): path = os.path.join(os.path.abspath(GIT_REPO), '.git') assert_equal('' % path, repr(self.repo)) - @patch_object(Git, '_call_process') - def test_log(self, git): - git.return_value = fixture('rev_list') - assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', self.repo.log()[0].id) - assert_equal('ab25fd8483882c3bda8a458ad2965d2248654335', self.repo.log()[-1].id) - assert_true(git.called) - assert_equal(git.call_count, 2) - assert_equal(git.call_args, (('log', 'master', '--'), {'pretty': 'raw'})) - - @patch_object(Git, '_call_process') - def test_log_with_path_and_options(self, git): - git.return_value = fixture('rev_list') - self.repo.log('master', 'file.rb', **{'max_count': 1}) - assert_true(git.called) - assert_equal(git.call_args, (('log', 'master', '--', 'file.rb'), {'pretty': 'raw', 'max_count': 1})) - def test_is_dirty_with_bare_repository(self): self.repo.bare = True assert_false(self.repo.is_dirty) diff --git a/test/testlib/helper.py b/test/testlib/helper.py index 74f48447..b66d3eaa 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -17,3 +17,14 @@ def fixture(name): def absolute_project_path(): return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + + +class ListProcessAdapter(object): + """Allows to use lists as Process object as returned by SubProcess.Popen. + Its tailored to work with the test system only""" + + def __init__(self, input_list_or_string): + l = input_list_or_string + if isinstance(l,basestring): + l = l.splitlines() + self.stdout = iter(l) -- cgit v1.2.1 From 6eeae8b24135b4de05f6d725b009c287577f053d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 17:24:15 +0200 Subject: test: Added time-consuming test which could also be a benchmark in fact - currently it cause hundreds of command invocations which is slow Fixed issue with trees not properly initialized with their default mode _set_cache_: some objects checked whether the attribute was within their __slots__ although it should have been accessed through its class --- test/git/test_commit.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 00af6b52..fd8fc51e 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -229,3 +229,18 @@ class TestCommit(object): commit3 = Commit(self.repo, id='zyx') assert_equal(commit1, commit2) assert_not_equal(commit2, commit3) + + def test_iteration(self): + root = self.repo.tree() + head = self.repo.active_branch + num_objs = 0 + + # find the first commit containing the given path - always do a full + # iteration ( restricted to the path in question ), but in fact it should + # return quite a lot of commits, we just take one and hence abort the operation + for obj in root.traverse(): + num_objs += 1 + commit = Commit.iter_items( self.repo, head, obj.path ).next() + assert obj in commit.tree.traverse() + # END for each object + -- cgit v1.2.1 From a28d3d18f9237af5101eb22e506a9ddda6d44025 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 18:50:55 +0200 Subject: Implemented git command facility to keep persistent commands for fast object information retrieval --- test/git/test_git.py | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/git/test_git.py b/test/git/test_git.py index c9f399cc..591d5939 100644 --- a/test/git/test_git.py +++ b/test/git/test_git.py @@ -10,8 +10,7 @@ from git import Git, GitCommandError class TestGit(object): def setup(self): - base = os.path.join(os.path.dirname(__file__), "../..") - self.git = Git(base) + self.git = Git(GIT_REPO) @patch_object(Git, 'execute') def test_call_process_calls_execute(self, git): @@ -56,3 +55,35 @@ class TestGit(object): # this_should_not_be_ignored=False implies it *should* be ignored output = self.git.version(pass_this_kwarg=False) assert_true("pass_this_kwarg" not in git.call_args[1]) + + def test_persistent_cat_file_command(self): + # read header only + import subprocess as sp + hexsha = "b2339455342180c7cc1e9bba3e9f181f7baa5167" + g = self.git.cat_file(batch_check=True, istream=sp.PIPE,as_process=True) + g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") + g.stdin.flush() + obj_info = g.stdout.readline() + + # read header + data + g = self.git.cat_file(batch=True, istream=sp.PIPE,as_process=True) + g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") + g.stdin.flush() + obj_info_two = g.stdout.readline() + assert obj_info == obj_info_two + + # read data - have to read it in one large chunk + size = int(obj_info.split()[2]) + data = g.stdout.read(size) + terminating_newline = g.stdout.read(1) + + # now we should be able to read a new object + g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") + g.stdin.flush() + assert g.stdout.readline() == obj_info + + + # same can be achived using the respective command functions + typename, size = self.git.get_object_header(hexsha) + typename_two, size_two, data = self.git.get_object_data(hexsha) + assert typename == typename_two and size == size_two -- cgit v1.2.1 From 6745f4542cfb74bbf3b933dba7a59ef2f54a4380 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 19:34:45 +0200 Subject: test_blob: removed many redundant tests that would fail now as the mock cannot handle the complexity of the command backend All objects but Tree now use the persistent command to read their object information - Trees get binary data and would need their own pretty-printing or they need to parse the data themselves which is my favorite --- test/git/test_base.py | 10 ++++++++++ test/git/test_blob.py | 49 ++++++------------------------------------------- test/git/test_commit.py | 2 +- test/git/test_repo.py | 10 ---------- 4 files changed, 17 insertions(+), 54 deletions(-) (limited to 'test') diff --git a/test/git/test_base.py b/test/git/test_base.py index 97dfc255..6e3aad7f 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -73,6 +73,16 @@ class TestBase(object): assert len(s) == ref_count assert len(s|s) == ref_count + def test_heads(self): + # see how it dynmically updates its object + for head in self.repo.heads: + head.name + head.path + cur_obj = head.object + del( head.object ) + assert cur_obj == head.object + # END for each head + def test_get_object_type_by_name(self): for tname in base.Object.TYPES: assert base.Object in get_object_type_by_name(tname).mro() diff --git a/test/git/test_blob.py b/test/git/test_blob.py index ebb53d0c..266f3a23 100644 --- a/test/git/test_blob.py +++ b/test/git/test_blob.py @@ -12,51 +12,14 @@ class TestBlob(object): def setup(self): self.repo = Repo(GIT_REPO) - @patch_object(Git, '_call_process') - def test_should_return_blob_contents(self, git): - git.return_value = fixture('cat_file_blob') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal("Hello world", blob.data) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - - @patch_object(Git, '_call_process') - def test_should_return_blob_contents_with_newline(self, git): - git.return_value = fixture('cat_file_blob_nl') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal("Hello world\n", blob.data) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - - @patch_object(Git, '_call_process') - def test_should_cache_data(self, git): - git.return_value = fixture('cat_file_blob') - bid = '787b92b63f629398f3d2ceb20f7f0c2578259e84' + def test_should_cache_data(self): + bid = 'a802c139d4767c89dcad79d836d05f7004d39aac' blob = Blob(self.repo, bid) blob.data - blob.data - assert_true(git.called) - assert_equal(git.call_count, 1) - assert_equal(git.call_args, (('cat_file', bid), {'p': True, 'with_raw_output': True})) - - @patch_object(Git, '_call_process') - def test_should_return_file_size(self, git): - git.return_value = fixture('cat_file_blob_size') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal(11, blob.size) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) - - @patch_object(Git, '_call_process') - def test_should_cache_file_size(self, git): - git.return_value = fixture('cat_file_blob_size') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal(11, blob.size) - assert_equal(11, blob.size) - assert_true(git.called) - assert_equal(git.call_count, 1) - assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) - + 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'}) assert_equal("image/png", blob.mime_type) diff --git a/test/git/test_commit.py b/test/git/test_commit.py index fd8fc51e..c050fd11 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -204,7 +204,7 @@ class TestCommit(object): bisect_all=True) assert_true(git.called) - commits = Commit._iter_from_process(self.repo, ListProcessAdapter(revs)) + commits = Commit._iter_from_process_or_stream(self.repo, ListProcessAdapter(revs)) expected_ids = ( 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', '33ebe7acec14b25c5f84f35a664803fcab2f7781', diff --git a/test/git/test_repo.py b/test/git/test_repo.py index f0687050..b882752d 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -96,16 +96,6 @@ class TestRepo(object): assert_true(git.called) - @patch_object(Git, '_call_process') - def test_blob(self, git): - git.return_value = fixture('cat_file_blob') - - blob = Blob(self.repo,"abc") - assert_equal("Hello world", blob.data) - - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - @patch_object(Repo, '__init__') @patch_object(Git, '_call_process') def test_init_bare(self, git, repo): -- cgit v1.2.1 From c5df44408218003eb49e3b8fc94329c5e8b46c7d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 19:41:27 +0200 Subject: persistent command signature changed to also return the hexsha from a possible input ref - the objects pointed to by refs are now baked on demand - perhaps it should change to always be re-retrieved using a property as it is relatively fast - this way refs can always be cached --- test/git/test_git.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/git/test_git.py b/test/git/test_git.py index 591d5939..1f44aebc 100644 --- a/test/git/test_git.py +++ b/test/git/test_git.py @@ -84,6 +84,6 @@ class TestGit(object): # same can be achived using the respective command functions - typename, size = self.git.get_object_header(hexsha) - typename_two, size_two, data = self.git.get_object_data(hexsha) + hexsha, typename, size = self.git.get_object_header(hexsha) + hexsha, typename_two, size_two, data = self.git.get_object_data(hexsha) assert typename == typename_two and size == size_two -- cgit v1.2.1 From 832b56394b079c9f6e4c777934447a9e224facfe Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 19:46:24 +0200 Subject: Refs are now truly dynamic - this costs a little bit of (persistent command) work, but assures refs behave as expected --- test/git/test_base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/git/test_base.py b/test/git/test_base.py index 6e3aad7f..402cdba3 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -78,9 +78,10 @@ class TestBase(object): for head in self.repo.heads: head.name head.path - cur_obj = head.object - del( head.object ) - assert cur_obj == head.object + prev_object = head.object + cur_object = head.object + assert prev_object == cur_object # represent the same git object + assert prev_object is not cur_object # but are different instances # END for each head def test_get_object_type_by_name(self): -- cgit v1.2.1 From 2e6d110fbfa1f2e6a96bc8329e936d0cf1192844 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 23:37:45 +0200 Subject: tree: now reads tress directly by parsing the binary data, allowing it to safe possibly hundreds of command calls --- test/git/test_repo.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'test') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index b882752d..e998ac6d 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -84,18 +84,7 @@ class TestRepo(object): assert_equal("4c8124ffcf4039d292442eeccabdeca5af5c5017", commit.id) assert_true(git.called) - - @patch_object(Git, '_call_process') - def test_tree(self, git): - git.return_value = fixture('ls_tree_a') - - tree = self.repo.tree(Head(self.repo, 'master')) - - assert_equal(4, len([c for c in tree if isinstance(c, Blob)])) - assert_equal(3, len([c for c in tree if isinstance(c, Tree)])) - - assert_true(git.called) - + @patch_object(Repo, '__init__') @patch_object(Git, '_call_process') def test_init_bare(self, git, repo): -- cgit v1.2.1 From 7cdfaceebe916c91acdf8de3f9506989bc70ad65 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 14 Oct 2009 23:41:48 +0200 Subject: Removed plenty of mocked tree tests as they cannot work anymore with persistent commands that require stdin AND binary data - not even an adapter would help here. These tests will have to be replaced. test_commit: Improved efficiency of traversal test --- test/git/test_commit.py | 6 ++- test/git/test_tree.py | 100 ------------------------------------------------ 2 files changed, 4 insertions(+), 102 deletions(-) (limited to 'test') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index c050fd11..1966d198 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -233,14 +233,16 @@ class TestCommit(object): def test_iteration(self): root = self.repo.tree() head = self.repo.active_branch + head_commit = self.repo.active_branch.object num_objs = 0 # find the first commit containing the given path - always do a full # iteration ( restricted to the path in question ), but in fact it should # return quite a lot of commits, we just take one and hence abort the operation + for obj in root.traverse(): num_objs += 1 - commit = Commit.iter_items( self.repo, head, obj.path ).next() - assert obj in commit.tree.traverse() + del( head_commit.tree ) # force it to clear the cache, just to make it harder + assert obj in head_commit.tree.traverse() # END for each object diff --git a/test/git/test_tree.py b/test/git/test_tree.py index 0104a16b..dafb6f3f 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -12,36 +12,7 @@ class TestTree(TestCase): def setUp(self): self.repo = Repo(GIT_REPO) - @patch_object(Git, '_call_process') - def test_contents_should_cache(self, git): - git.return_value = fixture('ls_tree_a') + fixture('ls_tree_b') - tree = self.repo.tree(Head(self.repo,'master')) - - child = tree['grit'] - len(child) - len(child) - - assert_true(git.called) - assert_equal(2, git.call_count) - assert_equal(git.call_args, (('ls_tree', '34868e6e7384cb5ee51c543a8187fdff2675b5a7'), {})) - - @raises(TypeError) - def test__from_string_invalid_type_should_raise(self): - Tree._from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") - - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_slash(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 1 - - tree = self.repo.tree(Head(self.repo,'master')) - - assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', (tree/'lib').id) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) - - assert_true(git.called) def test_traverse(self): root = self.repo.tree() @@ -68,77 +39,6 @@ class TestTree(TestCase): assert len(set(trees)|set(root.trees)) == len(trees) assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len( root.blobs ) - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_slash_with_zero_length_file(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 0 - - tree = self.repo.tree(Head(self.repo,'master')) - - assert_not_none(tree/'README.txt') - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) - - assert_true(git.called) - - @patch_object(Git, '_call_process') - def test_slash_with_commits(self, git): - git.return_value = fixture('ls_tree_commit') - - tree = self.repo.tree(Head(self.repo,'master')) - - self.failUnlessRaises(KeyError, tree.__div__, 'bar') - assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', (tree/'foo').id) - assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', (tree/'baz').id) - - assert_true(git.called) - - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_dict(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 1 - - tree = self.repo.tree(Head(self.repo,'master')) - - assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', tree['lib'].id) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) - - assert_true(git.called) - - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_dict_with_zero_length_file(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 0 - - tree = self.repo.tree(Head(self.repo,'master')) - - assert_not_none(tree['README.txt']) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) - - assert_true(git.called) - - @patch_object(Git, '_call_process') - def test_dict_with_commits(self, git): - git.return_value = fixture('ls_tree_commit') - - tree = self.repo.tree(Head(self.repo,'master')) - - self.failUnlessRaises(KeyError, tree.__getitem__, 'bar') - assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', tree['foo'].id) - assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', tree['baz'].id) - - assert_true(git.called) - - @patch_object(Git, '_call_process') - @raises(KeyError) - def test_dict_with_non_existant_file(self, git): - git.return_value = fixture('ls_tree_commit') - - tree = self.repo.tree(Head(self.repo,'master')) - tree['bar'] - def test_repr(self): tree = Tree(self.repo, id='abc') assert_equal('', repr(tree)) -- cgit v1.2.1 From 1a4bfd979e5d4ea0d0457e552202eb2effc36cac Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 15 Oct 2009 00:06:08 +0200 Subject: test_performance: module containing benchmarks to get an idea of the achieved throughput repo.commits: max_count is None by default moved benchmark-like test from test_commit to test_performance --- test/git/test_commit.py | 16 ---------------- test/git/test_performance.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 test/git/test_performance.py (limited to 'test') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 1966d198..a95fb675 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -230,19 +230,3 @@ class TestCommit(object): assert_equal(commit1, commit2) assert_not_equal(commit2, commit3) - def test_iteration(self): - root = self.repo.tree() - head = self.repo.active_branch - head_commit = self.repo.active_branch.object - num_objs = 0 - - # find the first commit containing the given path - always do a full - # iteration ( restricted to the path in question ), but in fact it should - # return quite a lot of commits, we just take one and hence abort the operation - - for obj in root.traverse(): - num_objs += 1 - del( head_commit.tree ) # force it to clear the cache, just to make it harder - assert obj in head_commit.tree.traverse() - # END for each object - diff --git a/test/git/test_performance.py b/test/git/test_performance.py new file mode 100644 index 00000000..96f13a2e --- /dev/null +++ b/test/git/test_performance.py @@ -0,0 +1,38 @@ +# test_performance.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php + +from test.testlib import * +from git import * +from time import time + +class TestPerformance(object): + def setup(self): + self.repo = Repo(GIT_REPO) + + def test_iteration(self): + num_objs = 0 + num_commits = 0 + + # find the first commit containing the given path - always do a full + # iteration ( restricted to the path in question ), but in fact it should + # return quite a lot of commits, we just take one and hence abort the operation + + st = time() + for c in self.repo.commits(): + num_commits += 1 + c.author + c.authored_date + c.committer + c.committed_date + c.message + for obj in c.tree.traverse(): + obj.size + num_objs += 1 + # END for each object + # END for each commit + elapsed_time = time() - st + print "Traversed %i Trees and a total of %i unchached objects in %s [s] ( %f objs/s )" % (num_commits, num_objs, elapsed_time, num_objs/elapsed_time) + -- cgit v1.2.1