From 919164df96d9f956c8be712f33a9a037b097745b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 16 Oct 2009 13:05:01 +0200 Subject: repo.untracked_files added including test --- test/git/test_repo.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 96d08b91..250974a5 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -225,3 +225,28 @@ class TestRepo(object): assert_true( tlist ) assert_true( isinstance( tlist[0], basestring ) ) 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 + files = (base+"/__test_myfile", base+"/__test_other_file") + num_recently_untracked = 0 + try: + for fpath in files: + fd = open(fpath,"wb") + fd.close() + # END for each filename + untracked_files = self.repo.untracked_files + num_recently_untracked = len(untracked_files) + + # assure we have all names - they are relative to the git-dir + num_test_untracked = 0 + for utfile in untracked_files: + num_test_untracked += os.path.join(base, utfile) in files + assert len(files) == num_test_untracked + finally: + for fpath in files: + if os.path.isfile(fpath): + os.remove(fpath) + # END handle files + + assert len(self.repo.untracked_files) == (num_recently_untracked - len(files)) -- cgit v1.2.3 From bb24f67e64b4ebe11c4d3ce7df021a6ad7ca98f2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 16 Oct 2009 16:09:07 +0200 Subject: Fixed object bug that would cause object ids not to be resolved to sha's as this was assumed - now there is a test for it as well repo: removed diff and commit_diff methods, added 'head' property returning the current head as Reference object --- test/git/test_base.py | 3 +++ test/git/test_repo.py | 3 +++ 2 files changed, 6 insertions(+) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 04222e2e..71576048 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -90,3 +90,6 @@ class TestBase(object): assert_raises( ValueError, get_object_type_by_name, "doesntexist" ) + 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 diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 250974a5..e0bda1c5 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -199,6 +199,9 @@ class TestRepo(object): assert_equal(self.repo.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 + @patch_object(Git, '_call_process') def test_should_display_blame_information(self, git): git.return_value = fixture('blame') -- cgit v1.2.3 From a5cf1bc1d3e38ab32a20707d66b08f1bb0beae91 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 17 Oct 2009 20:13:02 +0200 Subject: Removed a few diff-related test cases that fail now as the respective method is missing - these tests have to be redone in test-diff module accordingly --- test/git/test_commit.py | 150 ------------------------------------------------ test/git/test_diff.py | 14 +++-- test/git/test_repo.py | 36 +----------- 3 files changed, 9 insertions(+), 191 deletions(-) (limited to 'test/git') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 4e698ed0..c8bca564 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -20,156 +20,6 @@ class TestCommit(object): assert_equal("byronimo@gmail.com", commit.author.email) - @patch_object(Git, '_call_process') - def test_diff(self, git): - git.return_value = fixture('diff_p') - - diffs = Commit.diff(self.repo, 'master') - - assert_equal(15, len(diffs)) - - diff = diffs[0] - assert_equal('.gitignore', diff.a_blob.path) - assert_equal('.gitignore', diff.b_blob.path) - assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diff.a_blob.id) - assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diff.b_blob.id) - - assert_mode_644(diff.b_blob.mode) - - assert_equal(False, diff.new_file) - assert_equal(False, diff.deleted_file) - assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diff.diff) - - diff = diffs[5] - assert_equal('lib/grit/actor.rb', diff.b_blob.path) - assert_equal(None, diff.a_blob) - assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diff.b_blob.id) - assert_equal( None, diff.a_mode ) - assert_equal(True, diff.new_file) - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', 'master'), {'full_index': True})) - - @patch_object(Git, '_call_process') - def test_diff_with_rename(self, git): - git.return_value = fixture('diff_rename') - - diffs = Commit.diff(self.repo, 'rename') - - assert_equal(1, len(diffs)) - - diff = diffs[0] - assert_true(diff.renamed) - assert_equal(diff.rename_from, 'AUTHORS') - assert_equal(diff.rename_to, 'CONTRIBUTORS') - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', 'rename'), {'full_index': True})) - - @patch_object(Git, '_call_process') - def test_diff_with_two_commits(self, git): - git.return_value = fixture('diff_2') - - diffs = Commit.diff(self.repo, '59ddc32', '13d27d5') - - assert_equal(3, len(diffs)) - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5'), {'full_index': True})) - - @patch_object(Git, '_call_process') - def test_diff_with_files(self, git): - git.return_value = fixture('diff_f') - - diffs = Commit.diff(self.repo, '59ddc32', ['lib']) - - assert_equal(1, len(diffs)) - assert_equal('lib/grit/diff.rb', diffs[0].a_blob.path) - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '--', 'lib'), {'full_index': True})) - - @patch_object(Git, '_call_process') - def test_diff_with_two_commits_and_files(self, git): - git.return_value = fixture('diff_2f') - - diffs = Commit.diff(self.repo, '59ddc32', '13d27d5', ['lib']) - - assert_equal(1, len(diffs)) - assert_equal('lib/grit/commit.rb', diffs[0].a_blob.path) - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5', '--', 'lib'), {'full_index': True})) - - @patch_object(Git, '_call_process') - def test_diffs(self, git): - git.return_value = fixture('diff_p') - - commit = Commit(self.repo, id='91169e1f5fa4de2eaea3f176461f5dc784796769', parents=['038af8c329ef7c1bae4568b98bd5c58510465493']) - diffs = commit.diffs - - assert_equal(15, len(diffs)) - - diff = diffs[0] - assert_equal('.gitignore', diff.a_blob.path) - assert_equal('.gitignore', diff.b_blob.path) - assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diff.a_blob.id) - assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diff.b_blob.id) - assert_mode_644(diff.b_blob.mode) - assert_equal(False, diff.new_file) - assert_equal(False, diff.deleted_file) - assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diff.diff) - - diff = diffs[5] - assert_equal('lib/grit/actor.rb', diff.b_blob.path) - assert_equal(None, diff.a_blob) - assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diff.b_blob.id) - assert_equal(True, diff.new_file) - - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', - '038af8c329ef7c1bae4568b98bd5c58510465493', - '91169e1f5fa4de2eaea3f176461f5dc784796769', - ), {'full_index': True})) - - def test_diffs_on_initial_import(self): - commit = Commit(self.repo, '33ebe7acec14b25c5f84f35a664803fcab2f7781') - - for diff in commit.diffs: - assert isinstance(diff, Diff) - assert isinstance(diff.a_blob, Blob) or isinstance(diff.b_blob, Blob) - - if diff.a_mode is not None: - assert isinstance(diff.a_mode, int) - if diff.b_mode is not None: - isinstance(diff.b_mode, int) - - assert diff.diff is not None # can be empty - - if diff.renamed: - assert diff.rename_from and diff.rename_to and diff.rename_from != diff.rename_to - if diff.a_blob is None: - assert diff.new_file and isinstance(diff.new_file, bool) - if diff.b_blob is None: - assert diff.deleted_file and isinstance(diff.deleted_file, bool) - # END for each diff in initial import commit - - def test_diffs_on_initial_import_without_parents(self): - commit = Commit(self.repo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') - diffs = commit.diffs - assert diffs - - def test_diffs_with_mode_only_change(self): - commit = Commit(self.repo, id='ccde80b7a3037a004a7807a6b79916ce2a1e9729') - diffs = commit.diffs - - # in case of mode-only changes, there is no blob - assert_equal(1, len(diffs)) - assert_equal(None, diffs[0].a_blob) - assert_equal(None, diffs[0].b_blob) - assert_mode_644(diffs[0].a_mode) - assert_mode_755(diffs[0].b_mode) - def test_stats(self): commit = Commit(self.repo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') stats = commit.stats diff --git a/test/git/test_diff.py b/test/git/test_diff.py index b2339455..ea83145d 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -7,19 +7,19 @@ from test.testlib import * from git import * -class TestDiff(object): - def setup(self): +class TestDiff(TestCase): + def setUp(self): self.repo = Repo(GIT_REPO) def test_list_from_string_new_mode(self): - output = fixture('diff_new_mode') - diffs = Diff._list_from_string(self.repo, output) + output = ListProcessAdapter(fixture('diff_new_mode')) + diffs = Diff._index_from_patch_format(self.repo, output.stdout) assert_equal(1, len(diffs)) assert_equal(10, len(diffs[0].diff.splitlines())) def test_diff_with_rename(self): - output = fixture('diff_rename') - diffs = Diff._list_from_string(self.repo, output) + output = ListProcessAdapter(fixture('diff_rename')) + diffs = Diff._index_from_patch_format(self.repo, output.stdout) assert_equal(1, len(diffs)) @@ -28,3 +28,5 @@ class TestDiff(object): assert_equal(diff.rename_from, 'AUTHORS') assert_equal(diff.rename_to, 'CONTRIBUTORS') + def test_diff_interface(self): + self.fail( "TODO: Test full diff interface on commits, trees, index, patch and non-patch" ) diff --git a/test/git/test_repo.py b/test/git/test_repo.py index e0bda1c5..87332067 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -43,7 +43,7 @@ class TestRepo(object): git.return_value = ListProcessAdapter(fixture('rev_list')) commits = list( self.repo.iter_commits('master', max_count=10) ) - + c = commits[0] assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id) assert_equal(["634396b2f541a9f2d58b00be1a07f0c358b999b3"], [p.id for p in c.parents]) @@ -116,40 +116,6 @@ class TestRepo(object): { 'template': '/awesome'})) assert_true(repo.called) - @patch_object(Git, '_call_process') - def test_diff(self, git): - self.repo.diff('master^', 'master') - - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--'), {})) - - self.repo.diff('master^', 'master', 'foo/bar') - - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar'), {})) - - self.repo.diff('master^', 'master', 'foo/bar', 'foo/baz') - - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar', 'foo/baz'), {})) - - @patch_object(Git, '_call_process') - def test_diff_with_parents(self, git): - git.return_value = fixture('diff_p') - - diffs = self.repo.commit_diff('master') - assert_equal(15, len(diffs)) - assert_true(git.called) - - def test_archive(self): - args = ( tuple(), (self.repo.heads[-1],),(None,"hello") ) - for arg_list in args: - ftmp = os.tmpfile() - self.repo.archive(ftmp, *arg_list) - ftmp.seek(0,2) - assert ftmp.tell() - # END for each arg-list - @patch('git.utils.touch') def test_enable_daemon_serve(self, touch): self.repo.daemon_serve = False -- cgit v1.2.3 From 9946e0ce07c8d93a43bd7b8900ddf5d913fe3b03 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 12:33:06 +0200 Subject: implemented diff tests, but will have to move the diff module as it needs to create objects, whose import would create a dependency cycle --- test/git/test_diff.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index ea83145d..166ce310 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -28,5 +28,35 @@ class TestDiff(TestCase): assert_equal(diff.rename_from, 'AUTHORS') assert_equal(diff.rename_to, 'CONTRIBUTORS') + def test_diff_patch_format(self): + # test all of the 'old' format diffs for completness - it should at least + # be able to deal with it + fixtures = ("diff_2", "diff_2f", "diff_f", "diff_i", "diff_mode_only", + "diff_new_mode", "diff_numstat", "diff_p", "diff_rename", + "diff_tree_numstat_root" ) + + for fixture_name in fixtures: + diff_proc = ListProcessAdapter(fixture(fixture_name)) + diffs = Diff._index_from_patch_format(self.repo, diff_proc.stdout) + # END for each fixture + def test_diff_interface(self): + # test a few variations of the main diff routine + for i, commit in enumerate(self.repo.iter_commits('0.1.6', max_count=10)): + diff_item = commit + if i%2 == 0: + diff_item = commit.tree + # END use tree every second item + + for other in (None, commit.parents[0]): + for paths in (None, "CHANGES", ("CHANGES", "lib")): + for create_patch in range(2): + diff_index = diff_item.diff(other, paths, create_patch) + assert diff_index + # END for each patch option + # END for each path option + # END for each other side + # END for each commit + + self.fail( "TODO: Test full diff interface on commits, trees, index, patch and non-patch" ) -- cgit v1.2.3 From e063d101face690b8cf4132fa419c5ce3857ef44 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 13:24:04 +0200 Subject: diff: implemented raw diff parsing which appears to be able to handle possible input types, DiffIndex still requires implementation though --- test/git/test_diff.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index 166ce310..c9604faf 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -52,11 +52,12 @@ class TestDiff(TestCase): for paths in (None, "CHANGES", ("CHANGES", "lib")): for create_patch in range(2): diff_index = diff_item.diff(other, paths, create_patch) - assert diff_index + assert isinstance(diff_index, DiffIndex) + + # TODO: test diff index # END for each patch option # END for each path option # END for each other side # END for each commit - self.fail( "TODO: Test full diff interface on commits, trees, index, patch and non-patch" ) -- cgit v1.2.3 From 9acc7806d6bdb306a929c460437d3d03e5e48dcd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 14:24:30 +0200 Subject: DiffIndex implemented including test --- test/git/test_diff.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index c9604faf..deae7cfc 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -42,22 +42,35 @@ class TestDiff(TestCase): 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)): diff_item = commit if i%2 == 0: diff_item = commit.tree # END use tree every second item - for other in (None, commit.parents[0]): + for other in (None, commit.Index, commit.parents[0]): for paths in (None, "CHANGES", ("CHANGES", "lib")): for create_patch in range(2): diff_index = diff_item.diff(other, paths, create_patch) assert isinstance(diff_index, DiffIndex) - # TODO: test diff index + if diff_index: + for ct in DiffIndex.change_type: + key = 'ct_%s'%ct + assertion_map.setdefault(key, 0) + assertion_map[key] = assertion_map[key]+len(list(diff_index.iter_change_type(ct))) + # END for each changetype + # END diff index checking # END for each patch option # END for each path option # END for each other side # END for each commit - self.fail( "TODO: Test full diff interface on commits, trees, index, patch and non-patch" ) + # assert we could always find at least one instance of the members we + # can iterate in the diff index - if not this indicates its not working correctly + # or our test does not span the whole range of possibilities + for key,value in assertion_map.items(): + assert value, "Did not find diff for %s" % key + # END for each iteration type + -- cgit v1.2.3 From 9513aa01fab73f53e4fe18644c7d5b530a66c6a1 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 23:15:55 +0200 Subject: Added frame for configuration reader involving a meta class, decorators and tests - most of which still has to be filled out --- test/git/test_config.py | 18 ++++++++++++++++++ test/git/test_repo.py | 18 +++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 test/git/test_config.py (limited to 'test/git') diff --git a/test/git/test_config.py b/test/git/test_config.py new file mode 100644 index 00000000..ab08544f --- /dev/null +++ b/test/git/test_config.py @@ -0,0 +1,18 @@ +# test_config.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 * + +class TestBase(TestCase): + + @classmethod + def setUpAll(cls): + cls.repo = Repo(GIT_REPO) + + def test_base(self): + path = fixture_path("git_config") + self.fail("TODO: Base config writer testing") diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 87332067..843a4b4e 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -8,9 +8,11 @@ import os, sys from test.testlib import * from git import * -class TestRepo(object): - def setup(self): - self.repo = Repo(GIT_REPO) +class TestRepo(TestCase): + + @classmethod + def setUpAll(cls): + cls.repo = Repo(GIT_REPO) @raises(InvalidGitRepositoryError) def test_new_should_raise_on_invalid_repo_location(self): @@ -219,3 +221,13 @@ class TestRepo(object): # END handle files assert len(self.repo.untracked_files) == (num_recently_untracked - len(files)) + + def test_config_reader(self): + reader = self.repo.config_reader + assert reader.read_only + + def test_config_writer(self): + for config_level in self.repo.config_level: + writer = self.repo.config_writer(config_level) + assert not writer.read_only + # END for each config level -- cgit v1.2.3 From 3fd37230e76a014cf5c45d55daf0be2caa6948b7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 14:27:10 +0200 Subject: implemented config class as far as necessary, one check is still failing Added odict module to get an OrderedDict to be used in the config parser, assuring the order of sections and options does not change --- test/git/test_config.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_config.py b/test/git/test_config.py index ab08544f..c3080fb0 100644 --- a/test/git/test_config.py +++ b/test/git/test_config.py @@ -6,6 +6,8 @@ from test.testlib import * from git import * +import StringIO +from copy import copy class TestBase(TestCase): @@ -13,6 +15,54 @@ class TestBase(TestCase): def setUpAll(cls): cls.repo = Repo(GIT_REPO) + def _to_memcache(self, file_path): + fp = open(file_path, "r") + sio = StringIO.StringIO() + sio.write(fp.read()) + sio.seek(0) + sio.name = file_path + return sio + + def _parsers_equal_or_raise(self, lhs, rhs): + pass + + def test_read_write(self): + # writer must create the exact same file as the one read before + for filename in ("git_config", "git_config_global"): + file_obj = self._to_memcache(fixture_path(filename)) + file_obj_orig = copy(file_obj) + w_config = GitConfigParser(file_obj, read_only = False) + w_config.read() # enforce reading + assert w_config._sections + w_config.write() # enforce writing + assert file_obj.getvalue() == file_obj_orig.getvalue() + # END for each filename + def test_base(self): - path = fixture_path("git_config") + path_repo = fixture_path("git_config") + path_global = fixture_path("git_config_global") + r_config = GitConfigParser([path_repo, path_global], read_only=True) + assert r_config.read_only + num_sections = 0 + num_options = 0 + + # test reader methods + assert r_config._is_initialized == False + for section in r_config.sections(): + num_sections += 1 + for option in r_config.options(section): + num_options += 1 + val = r_config.get(section, option) + assert val + + # writing must fail + self.failUnlessRaises(IOError, r_config.set, section, option, None) + self.failUnlessRaises(IOError, r_config.remove_option, section, option ) + # END for each option + self.failUnlessRaises(IOError, r_config.remove_section, section) + # END for each section + assert num_sections and num_options + assert r_config._is_initialized == True + + self.fail("TODO: Base config writer testing") -- cgit v1.2.3 From 26029c29765043376370a2877b7e635c17f5e76d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 15:03:44 +0200 Subject: added additional testing for the configuration, concurrent access and config reading, all tests work --- test/git/test_config.py | 25 +++++++++++++++++++++++-- test/git/test_repo.py | 9 +++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_config.py b/test/git/test_config.py index c3080fb0..c5a8dc2c 100644 --- a/test/git/test_config.py +++ b/test/git/test_config.py @@ -36,6 +36,29 @@ class TestBase(TestCase): assert w_config._sections w_config.write() # enforce writing assert file_obj.getvalue() == file_obj_orig.getvalue() + + # creating an additional config writer must fail due to exclusive access + self.failUnlessRaises(IOError, GitConfigParser, file_obj, read_only = False) + + # should still have a lock and be able to make changes + assert w_config._has_lock() + + # changes should be written right away + sname = "my_section" + oname = "mykey" + val = "myvalue" + w_config.add_section(sname) + assert w_config.has_section(sname) + w_config.set(sname, oname, val) + assert w_config.has_option(sname,oname) + assert w_config.get(sname, oname) == val + + file_obj.seek(0) + r_config = GitConfigParser(file_obj, read_only=True) + assert r_config.has_section(sname) + assert r_config.has_option(sname, oname) + assert r_config.get(sname, oname) == val + # END for each filename def test_base(self): @@ -64,5 +87,3 @@ class TestBase(TestCase): assert num_sections and num_options assert r_config._is_initialized == True - - self.fail("TODO: Base config writer testing") diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 843a4b4e..0d8a473d 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -228,6 +228,11 @@ class TestRepo(TestCase): def test_config_writer(self): for config_level in self.repo.config_level: - writer = self.repo.config_writer(config_level) - assert not writer.read_only + try: + writer = self.repo.config_writer(config_level) + assert not writer.read_only + except IOError: + # its okay not to get a writer for some configuration files if we + # have no permissions + pass # END for each config level -- cgit v1.2.3 From a8f8582274cd6a368a79e569e2995cee7d6ea9f9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 18:01:52 +0200 Subject: added initial frame for remote handling- remotes are somewhat related to either parsing the command output or to reading the repo configuration which would be faster --- test/git/test_repo.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 0d8a473d..b30f6889 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -34,6 +34,11 @@ class TestRepo(TestCase): for head in self.repo.heads: assert_equal(Head, head.__class__) + def test_renites_should_return_array_of_remote_objects(self): + for remote in self.repo.remotes: + assert_equal(Remote, remote.__class__) + + def test_heads_should_populate_head_data(self): for head in self.repo.heads: assert head.name -- cgit v1.2.3 From a07cdbae1d485fd715a5b6eca767f211770fea4d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 18:06:19 +0200 Subject: Added remote module and test cases - about to implement remote option handling --- test/git/test_remote.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ test/git/test_repo.py | 5 ----- 2 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 test/git/test_remote.py (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py new file mode 100644 index 00000000..6d6fcea6 --- /dev/null +++ b/test/git/test_remote.py @@ -0,0 +1,48 @@ +# test_remote.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 * + +class TestRemote(TestCase): + + @classmethod + def setUpAll(cls): + cls.repo = Repo(GIT_REPO) + + def test_base(self): + num_remotes = 0 + for remote in self.repo.remotes: + num_remotes += 1 + assert str(remote) != repr(remote) + + + refs = remote.refs + assert refs + for ref in refs: + assert ref.remote_name == remote.name + assert ref.remote_branch + # END for each ref + + # test rename + other_name = "totally_other_name" + prev_name = remote.name + assert remote.rename(other_name) == remote + assert prev_name != remote.name + # multiple times + for time in range(2): + assert remote.rename(prev_name).name == prev_name + # END for each rename ( back to prev_name ) + + remote.update() + + # END for each remote + assert num_remotes + + def test_creation_and_removal(self): + self.fail( "Test remote creation/removal" ) + + diff --git a/test/git/test_repo.py b/test/git/test_repo.py index b30f6889..0d8a473d 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -34,11 +34,6 @@ class TestRepo(TestCase): for head in self.repo.heads: assert_equal(Head, head.__class__) - def test_renites_should_return_array_of_remote_objects(self): - for remote in self.repo.remotes: - assert_equal(Remote, remote.__class__) - - def test_heads_should_populate_head_data(self): for head in self.repo.heads: assert head.name -- cgit v1.2.3 From 048acc4596dc1c6d7ed3220807b827056cb01032 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 18:53:55 +0200 Subject: Added configuration access including tests to remote config: fixed issue that would cause it to abort reading if the file did not exist - this is valid now Test does not work as the configuration parsing does not work as expected - this must be fixed first --- test/git/test_remote.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 6d6fcea6..24fba07c 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -19,7 +19,7 @@ class TestRemote(TestCase): num_remotes += 1 assert str(remote) != repr(remote) - + # REFS refs = remote.refs assert refs for ref in refs: @@ -27,7 +27,28 @@ class TestRemote(TestCase): assert ref.remote_branch # END for each ref - # test rename + # OPTIONS + for opt in ("url", "fetch"): + val = getattr(remote, opt) + reader = remote.config_reader + assert reader.get(opt) == val + + # unable to write with a reader + self.failUnlessRaises(IOError, reader.set, opt, "test") + + # change value + writer = remote.config_writer + new_val = "myval" + writer.set(opt, new_val) + assert writer.get(opt) == new_val + writer.set(opt, val) + assert writer.get(opt) == val + del(writer) + assert getattr(remote, opt) == val + # END + self.fail( "option testing, read/write" ) + + # RENAME other_name = "totally_other_name" prev_name = remote.name assert remote.rename(other_name) == remote -- cgit v1.2.3 From 345d6be7829c6dab359390ebc5e1a7ae0c6d48bb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 20:17:36 +0200 Subject: config: fixed serious issues that would cause it to see initial tabs as continuation lines - this leads to very incorrect results when parsing git config files. Now the complete reading is overridden to make it work as there was no other way --- test/git/test_config.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/git') diff --git a/test/git/test_config.py b/test/git/test_config.py index c5a8dc2c..843da723 100644 --- a/test/git/test_config.py +++ b/test/git/test_config.py @@ -77,6 +77,8 @@ class TestBase(TestCase): num_options += 1 val = r_config.get(section, option) assert val + assert "\n" not in option + assert "\n" not in val # writing must fail self.failUnlessRaises(IOError, r_config.set, section, option, None) -- cgit v1.2.3 From cbf957a36f5ed47c4387ee8069c56b16d1b4f558 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 20:23:47 +0200 Subject: remote: base tests succeed now --- test/git/test_remote.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 24fba07c..ac282908 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -15,9 +15,13 @@ class TestRemote(TestCase): def test_base(self): num_remotes = 0 + remote_set = set() for remote in self.repo.remotes: num_remotes += 1 + assert remote == remote assert str(remote) != repr(remote) + remote_set.add(remote) + remote_set.add(remote) # should already exist # REFS refs = remote.refs @@ -46,7 +50,6 @@ class TestRemote(TestCase): del(writer) assert getattr(remote, opt) == val # END - self.fail( "option testing, read/write" ) # RENAME other_name = "totally_other_name" @@ -62,6 +65,8 @@ class TestRemote(TestCase): # END for each remote assert num_remotes + assert num_remotes == len(remote_set) + def test_creation_and_removal(self): self.fail( "Test remote creation/removal" ) -- cgit v1.2.3 From 53d26977f1aff8289f13c02ee672349d78eeb2f0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 21:31:55 +0200 Subject: remote: added tests for creation and removal, finishing the remote interface --- test/git/test_remote.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index ac282908..2446710f 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -49,7 +49,7 @@ class TestRemote(TestCase): assert writer.get(opt) == val del(writer) assert getattr(remote, opt) == val - # END + # END for each default option key # RENAME other_name = "totally_other_name" @@ -69,6 +69,21 @@ class TestRemote(TestCase): def test_creation_and_removal(self): - self.fail( "Test remote creation/removal" ) + new_name = "test_new_one" + arg_list = (new_name, "git@server:hello.git") + remote = Remote.create(self.repo, *arg_list ) + assert remote.name == "test_new_one" + + # create same one again + self.failUnlessRaises(GitCommandError, Remote.create, self.repo, *arg_list) + + Remote.remove(self.repo, new_name) + + for remote in self.repo.remotes: + if remote.name == new_name: + raise AssertionError("Remote removal failed") + # END if deleted remote matches existing remote's name + # END for each remote + -- cgit v1.2.3 From 11b1f6edc164e2084e3ff034d3b65306c461a0be Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 22:08:23 +0200 Subject: repo.remote method added CHANGES updated to carry information about remotes and config --- test/git/test_remote.py | 1 + 1 file changed, 1 insertion(+) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 2446710f..8c0177fd 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -67,6 +67,7 @@ class TestRemote(TestCase): assert num_remotes assert num_remotes == len(remote_set) + origin = self.repo.remote('origin') def test_creation_and_removal(self): new_name = "test_new_one" -- cgit v1.2.3 From 0b3ecf2dcace76b65765ddf1901504b0b4861b08 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 22:49:52 +0200 Subject: commit.count: is an instance method now repo: added head , tag and iter_trees methods for completeness changes: headlines now sorted chronologically --- test/git/test_commit.py | 2 +- test/git/test_repo.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index c8bca564..abe16dfb 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -66,7 +66,7 @@ class TestCommit(object): assert_equal(sha1, commit.id) def test_count(self): - assert Commit.count( self.repo, '0.1.5' ) == 141 + assert self.repo.tag('0.1.5').commit.count( ) == 141 def test_str(self): commit = Commit(self.repo, id='abc') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 0d8a473d..197a29cb 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -67,6 +67,16 @@ class TestRepo(TestCase): assert_true(git.called) + def test_trees(self): + mc = 30 + num_trees = 0 + for tree in self.repo.iter_trees('0.1.5', max_count=mc): + num_trees += 1 + assert isinstance(tree, Tree) + # END for each tree + assert num_trees == mc + + @patch_object(Repo, '__init__') @patch_object(Git, '_call_process') def test_init(self, git, repo): @@ -170,6 +180,9 @@ class TestRepo(TestCase): def test_head(self): assert self.repo.head.object == self.repo.active_branch.object + def test_tag(self): + assert self.repo.tag('0.1.5').commit + @patch_object(Git, '_call_process') def test_should_display_blame_information(self, git): git.return_value = fixture('blame') -- cgit v1.2.3 From 989671780551b7587d57e1d7cb5eb1002ade75b4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 23:44:18 +0200 Subject: Implemneted IterableLists for refs, commits and remote objects including simple tests --- test/git/test_commit.py | 3 +++ test/git/test_remote.py | 1 + test/git/test_repo.py | 3 +++ test/git/test_tag.py | 1 + 4 files changed, 8 insertions(+) (limited to 'test/git') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index abe16dfb..3d7feb6d 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -67,6 +67,9 @@ class TestCommit(object): def test_count(self): assert self.repo.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) def test_str(self): commit = Commit(self.repo, id='abc') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 8c0177fd..4cbb0b7b 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -68,6 +68,7 @@ class TestRemote(TestCase): assert num_remotes == len(remote_set) origin = self.repo.remote('origin') + assert origin == self.repo.remotes.origin def test_creation_and_removal(self): new_name = "test_new_one" diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 197a29cb..f9d81c69 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -39,6 +39,9 @@ class TestRepo(TestCase): 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) @patch_object(Git, '_call_process') def test_commits(self, git): diff --git a/test/git/test_tag.py b/test/git/test_tag.py index 8f12bf11..9641e0ac 100644 --- a/test/git/test_tag.py +++ b/test/git/test_tag.py @@ -30,5 +30,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) -- cgit v1.2.3 From e64957d8e52d7542310535bad1e77a9bbd7b4857 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 00:04:10 +0200 Subject: Improved is_dirty including test --- test/git/test_repo.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index f9d81c69..7ad68414 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -160,19 +160,17 @@ class TestRepo(TestCase): self.repo.bare = True assert_false(self.repo.is_dirty) - @patch_object(Git, '_call_process') - def test_is_dirty_with_clean_working_dir(self, git): - self.repo.bare = False - git.return_value = '' - assert_false(self.repo.is_dirty) - assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) - - @patch_object(Git, '_call_process') - def test_is_dirty_with_dirty_working_dir(self, git): + def test_is_dirty(self): self.repo.bare = False - git.return_value = '''-aaa\n+bbb''' - assert_true(self.repo.is_dirty) - assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) + 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) + # END untracked files + # END working tree + # END index + self.repo.bare = True + assert self.repo.is_dirty == False @patch_object(Git, '_call_process') def test_active_branch(self, git): -- cgit v1.2.3 From aa5e366889103172a9829730de1ba26d3dcbc01b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 10:11:16 +0200 Subject: Moved specialized methods like dashify, touch and is_git_dir to module to the respective modules that use them fixed repo.daemon_export which did not work anymore due to incorrect touch implementation and wrong property names --- test/git/test_repo.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 7ad68414..b91244c9 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -131,14 +131,13 @@ class TestRepo(TestCase): { 'template': '/awesome'})) assert_true(repo.called) - @patch('git.utils.touch') - def test_enable_daemon_serve(self, touch): - self.repo.daemon_serve = False - assert_false(self.repo.daemon_serve) - - def test_disable_daemon_serve(self): - self.repo.daemon_serve = True - assert_true(self.repo.daemon_serve) + + 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 @patch_object(os.path, 'exists') def test_alternates_no_file(self, os): -- cgit v1.2.3 From dd76b9e72b21d2502a51e3605e5e6ab640e5f0bd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 10:45:40 +0200 Subject: Fixed bare repository handling - bare is now a property to prevent writing it --- test/git/test_repo.py | 13 +++++++++---- test/git/test_utils.py | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index b91244c9..c89bcde3 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -91,6 +91,9 @@ class TestRepo(TestCase): assert_true(git.called) assert_true(repo.called) + + def test_bare_property(self): + self.repo.bare @patch_object(Repo, '__init__') @patch_object(Git, '_call_process') @@ -156,11 +159,11 @@ class TestRepo(TestCase): assert_equal('' % path, repr(self.repo)) def test_is_dirty_with_bare_repository(self): - self.repo.bare = True + self.repo._bare = True assert_false(self.repo.is_dirty) def test_is_dirty(self): - self.repo.bare = False + self.repo._bare = False for index in (0,1): for working_tree in (0,1): for untracked_files in (0,1): @@ -168,7 +171,7 @@ class TestRepo(TestCase): # END untracked files # END working tree # END index - self.repo.bare = True + self.repo._bare = True assert self.repo.is_dirty == False @patch_object(Git, '_call_process') @@ -236,7 +239,9 @@ class TestRepo(TestCase): assert len(self.repo.untracked_files) == (num_recently_untracked - len(files)) def test_config_reader(self): - reader = self.repo.config_reader + reader = self.repo.config_reader() # all config files + assert reader.read_only + reader = self.repo.config_reader("repository") # single config file assert reader.read_only def test_config_writer(self): diff --git a/test/git/test_utils.py b/test/git/test_utils.py index 2983a14a..6852d0ad 100644 --- a/test/git/test_utils.py +++ b/test/git/test_utils.py @@ -7,6 +7,7 @@ import os from test.testlib import * from git import * +from git.cmd import dashify class TestUtils(object): def setup(self): -- cgit v1.2.3 From 35a09c0534e89b2d43ec4101a5fb54576b577905 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 11:17:39 +0200 Subject: repo.alternates test cheked for correctness and bugfixed - totally mocked tests bare the risk that things do not work properly outside of the sandbox. --- test/git/test_repo.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index c89bcde3..bc2c7094 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -142,17 +142,15 @@ class TestRepo(TestCase): self.repo.daemon_export = orig_val assert self.repo.daemon_export == orig_val - @patch_object(os.path, 'exists') - def test_alternates_no_file(self, os): - os.return_value = False - assert_equal([], self.repo.alternates) - - assert_true(os.called) - - @patch_object(os, 'remove') - def test_alternates_setter_empty(self, os): + def test_alternates(self): + cur_alternates = self.repo.alternates + # empty alternates self.repo.alternates = [] - assert_true(os.called) + assert self.repo.alternates == [] + alts = [ "other/location", "this/location" ] + self.repo.alternates = alts + assert alts == self.repo.alternates + self.repo.alternates = cur_alternates def test_repr(self): path = os.path.join(os.path.abspath(GIT_REPO), '.git') -- cgit v1.2.3 From 4a534eba97db3c2cfb2926368756fd633d25c056 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 12:24:47 +0200 Subject: Added frame for index implementation and testing --- test/git/test_index.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 test/git/test_index.py (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py new file mode 100644 index 00000000..f58405d2 --- /dev/null +++ b/test/git/test_index.py @@ -0,0 +1,17 @@ +# test_index.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 * + +class TestTree(TestCase): + + @classmethod + def setUpAll(cls): + cls.repo = Repo(GIT_REPO) + + def test_base(self): + self.fail("TODO") -- cgit v1.2.3 From 50a9920b1bd9e6e8cf452c774c499b0b9014ccef Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 17:04:23 +0200 Subject: Added initial version of the index reading from file - IndexEntry interface is to be improved though, writing needs to be implemented as well --- test/git/test_index.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index f58405d2..272e68b3 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -14,4 +14,6 @@ class TestTree(TestCase): cls.repo = Repo(GIT_REPO) def test_base(self): - self.fail("TODO") + index = Index.from_file(fixture_path("index")) + assert index.entries + assert index.version > 0 -- cgit v1.2.3 From 56823868efddd3bdbc0b624cdc79adc3a2e94a75 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 21:32:00 +0200 Subject: Improved tuple access of EntryIndex class including test, stage and type access still needs to be decoded though --- test/git/test_index.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 272e68b3..91ce22fd 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -6,6 +6,7 @@ from test.testlib import * from git import * +import inspect class TestTree(TestCase): @@ -14,6 +15,19 @@ class TestTree(TestCase): cls.repo = Repo(GIT_REPO) def test_base(self): + # read from file index = Index.from_file(fixture_path("index")) assert index.entries assert index.version > 0 + + # test entry + last_val = None + entry = index.entries.itervalues().next() + for name, method in inspect.getmembers(entry,inspect.ismethod): + val = method(entry) + assert val != last_val + last_val = val + # END for each method + + # write + self.fail("writing, object type and stage") -- cgit v1.2.3 From 152bab7eb64e249122fefab0d5531db1e065f539 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 22:05:51 +0200 Subject: improved IndexEntry type and added test for parsing of the stage --- test/git/test_index.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 91ce22fd..86bde655 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -23,11 +23,15 @@ class TestTree(TestCase): # test entry last_val = None entry = index.entries.itervalues().next() - for name, method in inspect.getmembers(entry,inspect.ismethod): - val = method(entry) - assert val != last_val - last_val = val + for attr in ("path","ctime","mtime","dev","inode","mode","uid", + "gid","size","sha","stage"): + val = getattr(entry, attr) # END for each method + # test stage + index_merge = Index.from_file(fixture_path("index_merge")) + assert len(list(e for e in index_merge.entries.itervalues() if e.stage != 0 )) + # write - self.fail("writing, object type and stage") + self.fail("writing, what is 'size' attribute for ?") + -- cgit v1.2.3 From b9d6494f1075e5370a20e406c3edb102fca12854 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 13:34:43 +0200 Subject: index writing added including simple test, improved docs of IndexEntry --- test/git/test_index.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 86bde655..7a0e21eb 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -7,6 +7,7 @@ from test.testlib import * from git import * import inspect +import os class TestTree(TestCase): @@ -30,8 +31,13 @@ class TestTree(TestCase): # test stage index_merge = Index.from_file(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 )) - # write - self.fail("writing, what is 'size' attribute for ?") + # write the data - it must match the original + index_output = os.tmpfile() + index_merge.write(index_output) + + index_output.seek(0) + assert index_output.read() == fixture("index_merge") -- cgit v1.2.3 From a4fb3091a75005b047fbea72f812c53d27b15412 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 17:04:24 +0200 Subject: diff: added test to be sure index-vs-working copy diffs are solved properly --- test/git/test_diff.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index deae7cfc..501d937d 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -74,3 +74,6 @@ class TestDiff(TestCase): assert value, "Did not find diff for %s" % key # END for each iteration type + def test_diff_index_working_tree(self): + self.fail("""Find a good way to diff an index against the working tree +which is not possible with the current interface""") -- cgit v1.2.3 From babf5765da3e328cc1060cb9b37fbdeb6fd58350 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 16:52:25 +0200 Subject: Initial version of merge including tests for one-way, two-way and tree-way merge --- test/git/test_index.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 7a0e21eb..ead231d1 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -41,3 +41,24 @@ class TestTree(TestCase): index_output.seek(0) assert index_output.read() == fixture("index_merge") + def test_merge(self): + common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" + cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" + other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" + + # simple index from tree + base_index = Index.from_tree(self.repo, common_ancestor_sha) + assert base_index.entries + + # merge two trees + two_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha) + assert two_way_index.entries + for e in two_way_index.entries.values(): + print "%i | %s" % ( e.stage, e.path ) + + # merge three trees - here we have a merge conflict + tree_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) + assert len(list(e for e in tree_way_index.entries.values() if e.stage != 0)) + + def test_custom_commit(self): + self.fail("Custom commit:write tree, make commit with custom parents") -- cgit v1.2.3 From d97afa24ad1ae453002357e5023f3a116f76fb17 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 18:40:35 +0200 Subject: Improved testing of index against trees, tests succeed with next commit --- test/git/test_index.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index ead231d1..d256e7c0 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -41,6 +41,18 @@ class TestTree(TestCase): index_output.seek(0) assert index_output.read() == fixture("index_merge") + 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 + + num_blobs = 0 + for blob in tree.traverse(predicate = lambda e: e.type == "blob"): + assert (blob.path,0) in index.entries + num_blobs += 1 + # END for each blob in tree + assert num_blobs == len(index.entries) + def test_merge(self): common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" @@ -49,12 +61,12 @@ class TestTree(TestCase): # simple index from tree base_index = Index.from_tree(self.repo, common_ancestor_sha) assert base_index.entries + self._cmp_tree_index(common_ancestor_sha, base_index) - # merge two trees + # merge two trees - its like a fast-forward two_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha) assert two_way_index.entries - for e in two_way_index.entries.values(): - print "%i | %s" % ( e.stage, e.path ) + self._cmp_tree_index(cur_sha, two_way_index) # merge three trees - here we have a merge conflict tree_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) -- cgit v1.2.3 From 2e68d907022c84392597e05afc22d9fe06bf0927 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 18:45:41 +0200 Subject: tree.traverse: Added prune functionality - previously the predciate did both, pruning and preventing to return items --- test/git/test_tree.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/git') diff --git a/test/git/test_tree.py b/test/git/test_tree.py index dafb6f3f..b359e2d2 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -35,6 +35,11 @@ class TestTree(TestCase): trees = list(root.traverse(predicate = trees_only)) assert len(trees) == len(list( i for i in root.traverse() if trees_only(i) )) + # test prune + lib_folder = lambda t: t.path == "lib" + pruned_trees = list(root.traverse(predicate = trees_only,prune = lib_folder)) + assert len(pruned_trees) < len(trees) + # 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 ) -- cgit v1.2.3 From 6662422ba52753f8b10bc053aba82bac3f2e1b9c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 21:25:52 +0200 Subject: index.iter_blobs method added including tests ( which have been improved generally for more coverage ) --- test/git/test_index.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index d256e7c0..524f0778 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -8,6 +8,7 @@ from test.testlib import * from git import * import inspect import os +import tempfile class TestTree(TestCase): @@ -17,7 +18,7 @@ class TestTree(TestCase): def test_base(self): # read from file - index = Index.from_file(fixture_path("index")) + index = Index.from_file(self.repo, fixture_path("index")) assert index.entries assert index.version > 0 @@ -30,7 +31,7 @@ class TestTree(TestCase): # END for each method # test stage - index_merge = Index.from_file(fixture_path("index_merge")) + index_merge = Index.from_file(self.repo, 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 )) @@ -40,6 +41,11 @@ class TestTree(TestCase): index_output.seek(0) assert index_output.read() == fixture("index_merge") + + tmpfile = tempfile.mktemp() + Index.to_file(index_merge, tmpfile) + assert os.path.isfile(tmpfile) + os.remove(tmpfile) def _cmp_tree_index(self, tree, index): # fail unless both objects contain the same paths and blobs @@ -53,7 +59,7 @@ class TestTree(TestCase): # END for each blob in tree assert num_blobs == len(index.entries) - def test_merge(self): + def test_from_tree(self): common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" @@ -70,7 +76,16 @@ class TestTree(TestCase): # merge three trees - here we have a merge conflict tree_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) - assert len(list(e for e in tree_way_index.entries.values() if e.stage != 0)) + assert len(list(e for e in tree_way_index.entries.values() if e.stage != 0)) + + + # ITERATE BLOBS + merge_required = lambda t: t[0] != 0 + merge_blobs = list(tree_way_index.iter_blobs(merge_required)) + assert merge_blobs + assert merge_blobs[0][0] in (1,2,3) + assert isinstance(merge_blobs[0][1], Blob) + def test_custom_commit(self): self.fail("Custom commit:write tree, make commit with custom parents") -- cgit v1.2.3 From 3c9f55dd8e6697ab2f9eaf384315abd4cbefad38 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 22:53:51 +0200 Subject: remote: Added fetch, pull, push methods to the interface to make these operations more convenient, like repo.remotes.origin.fetch --- test/git/test_remote.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 4cbb0b7b..aeb6b4af 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -32,7 +32,8 @@ class TestRemote(TestCase): # END for each ref # OPTIONS - for opt in ("url", "fetch"): + # cannot use 'fetch' key anymore as it is now a method + for opt in ("url", ): val = getattr(remote, opt) reader = remote.config_reader assert reader.get(opt) == val @@ -61,8 +62,10 @@ class TestRemote(TestCase): assert remote.rename(prev_name).name == prev_name # END for each rename ( back to prev_name ) + remote.fetch() + self.failUnlessRaises(GitCommandError, remote.pull) 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) -- cgit v1.2.3 From 7b50af0a20bcc7280940ce07593007d17c5acabd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 23:11:40 +0200 Subject: index: Added write_tree method including test --- test/git/test_index.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 524f0778..a4e01054 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -87,5 +87,12 @@ class TestTree(TestCase): assert isinstance(merge_blobs[0][1], Blob) + # writing a tree should fail with an unmerged index + self.failUnlessRaises(GitCommandError, tree_way_index.write_tree) + + # removed unmerged entries + self.fail("remove unmerged") + + def test_custom_commit(self): self.fail("Custom commit:write tree, make commit with custom parents") -- cgit v1.2.3 From aa921fee6014ef43bb2740240e9663e614e25662 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 00:32:16 +0200 Subject: Implemented merge/resolve handling , but realized that index writing is not yet working properly as it is sha1 checked as well. This explains what my 20 byte 'extension_data' actually is ;) --- test/git/test_index.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index a4e01054..6208a1d9 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -75,23 +75,28 @@ class TestTree(TestCase): self._cmp_tree_index(cur_sha, two_way_index) # merge three trees - here we have a merge conflict - tree_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) - assert len(list(e for e in tree_way_index.entries.values() if e.stage != 0)) + three_way_index = Index.from_tree(self.repo, common_ancestor_sha, cur_sha, other_sha) + assert len(list(e for e in three_way_index.entries.values() if e.stage != 0)) # ITERATE BLOBS merge_required = lambda t: t[0] != 0 - merge_blobs = list(tree_way_index.iter_blobs(merge_required)) + merge_blobs = list(three_way_index.iter_blobs(merge_required)) assert merge_blobs assert merge_blobs[0][0] in (1,2,3) assert isinstance(merge_blobs[0][1], Blob) # writing a tree should fail with an unmerged index - self.failUnlessRaises(GitCommandError, tree_way_index.write_tree) + self.failUnlessRaises(GitCommandError, three_way_index.write_tree) # removed unmerged entries - self.fail("remove unmerged") + unmerged_blob_map = three_way_index.unmerged_blobs() + assert unmerged_blob_map + + # pick the first blob at the first stage we find and use it as resolved version + three_way_index.resolve_blobs( l[0][1] for l in unmerged_blob_map.itervalues() ) + three_way_index.write_tree() def test_custom_commit(self): -- cgit v1.2.3 From 30d822a468dc909aac5c83d078a59bfc85fc27aa Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 10:15:47 +0200 Subject: index writing now creates a sha on the content making it possible to write valid indices after manually removing or altering entriesgst --- test/git/test_index.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 6208a1d9..c8f6f4e3 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -96,7 +96,14 @@ class TestTree(TestCase): # pick the first blob at the first stage we find and use it as resolved version three_way_index.resolve_blobs( l[0][1] for l in unmerged_blob_map.itervalues() ) - three_way_index.write_tree() + tree = three_way_index.write_tree() + assert isinstance(tree, Tree) + num_blobs = 0 + for blob in tree.traverse(predicate=lambda item: item.type == "blob"): + assert (blob.path,0) in three_way_index.entries + num_blobs += 1 + # END for each blob + assert num_blobs == len(three_way_index.entries) def test_custom_commit(self): -- cgit v1.2.3 From 33fa178eeb7bf519f5fff118ebc8e27e76098363 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 11:04:30 +0200 Subject: added Object.data_stream property allowing to stream object data directly.Considering the implementation of the git commnd which temporarily keeps it in a cache, it doesnt make a huge diffence as the data is kept in memory while streaming. Only good thing is that it is in a different process so python will never see it if done properly --- test/git/test_base.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 71576048..4ad98d7f 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -48,6 +48,11 @@ class TestBase(object): assert not item.path.startswith("/") # must be relative assert isinstance(item.mode, int) # END index object check + + # read from stream + data_stream = item.data_stream + data = data_stream.read() + assert data # END for each object type to create # each has a unique sha -- cgit v1.2.3 From f62c9b9c0c9bda792c3fa531b18190e97eb53509 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 12:24:36 +0200 Subject: Git.cmd: removed with_raw_output option repo.archive: made it work with new way of custom output streams added test for repo.archive which was missing for some reason --- test/git/test_repo.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index bc2c7094..ff10f6a6 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -184,6 +184,11 @@ class TestRepo(TestCase): def test_tag(self): assert self.repo.tag('0.1.5').commit + def test_archive(self): + tmpfile = os.tmpfile() + self.repo.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') -- cgit v1.2.3 From 4fe5cfa0e063a8d51a1eb6f014e2aaa994e5e7d4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 12:28:04 +0200 Subject: Stream_data streams data to a given output stream most efficiently with a low memory footprint. Still, the git-cat-file command keeps all data in an interal buffer instead of streaming it directly. This is a git design issue though, and will be hard to address without some proper git-hacking. Conflicts: lib/git/cmd.py --- test/git/test_base.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 4ad98d7f..b93e61c1 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -4,12 +4,15 @@ # 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 * import git.objects.base as base import git.refs as refs +import os + +from test.testlib import * +from git import * from itertools import chain from git.objects.utils import get_object_type_by_name +import tempfile class TestBase(object): @@ -53,6 +56,12 @@ class TestBase(object): data_stream = item.data_stream data = data_stream.read() assert data + + tmpfile = os.tmpfile() + assert item == item.stream_data(tmpfile) + tmpfile.seek(0) + assert tmpfile.read() == data + # END stream to file directly # END for each object type to create # each has a unique sha -- cgit v1.2.3 From 1f2b19de3301e76ab3a6187a49c9c93ff78bafbd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 13:40:56 +0200 Subject: Removed index test marker for custom commits as this boils down to a good way to add files to the index/remove them and make commits which are possibly customized with custom parents --- test/git/test_index.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index c8f6f4e3..4c17f5e5 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -104,7 +104,5 @@ class TestTree(TestCase): num_blobs += 1 # END for each blob assert num_blobs == len(three_way_index.entries) - - - def test_custom_commit(self): - self.fail("Custom commit:write tree, make commit with custom parents") + + -- cgit v1.2.3 From bb0ac304431e8aed686a8a817aaccd74b1ba4f24 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 15:04:29 +0200 Subject: Added frame for new Repo handling and some neat decorators, including tests that test whether the testing framework does what it should --- test/git/test_base.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'test/git') 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") -- cgit v1.2.3 From 9c3bbc43d097656b54c808290ce0c656d127ce47 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 15:36:41 +0200 Subject: Implemented decorators, tests pass at least --- test/git/test_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 9f4cfa05..c2e199b3 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -109,7 +109,7 @@ class TestBase(TestBase): def test_with_bare_rw_repo(self, bare_rw_repo): assert bare_rw_repo.config_reader("repository").getboolean("core", "bare") - @with_rw_repo + @with_rw_repo(working_tree_ref='0.1.6') def test_with_rw_repo(self, rw_repo): assert not rw_repo.config_reader("repository").getboolean("core", "bare") -- cgit v1.2.3 From 3c770f8e98a0079497d3eb5bc31e7260cc70cc63 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 16:06:10 +0200 Subject: 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 ... . Remote tests adjusted to use rw repositories instead. More tests to follow, and many api methods are to be implemented now these things can be tested properly. --- test/git/test_base.py | 7 +++++-- test/git/test_remote.py | 27 +++++++++++++-------------- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index c2e199b3..a7ef9374 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -108,12 +108,15 @@ class TestBase(TestBase): @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(working_tree_ref='0.1.6') + @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 + @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_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 -- cgit v1.2.3 From b197b2dbb527de9856e6e808339ab0ceaf0a512d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 16:20:24 +0200 Subject: Adjusted all remaining test suites to use the new TestBase class where appropriate --- test/git/test_blob.py | 12 +++--- test/git/test_commit.py | 28 +++++++------- test/git/test_config.py | 4 -- test/git/test_diff.py | 14 +++---- test/git/test_git.py | 8 ++-- test/git/test_head.py | 8 ++-- test/git/test_index.py | 18 ++++----- test/git/test_performance.py | 6 +-- test/git/test_repo.py | 88 +++++++++++++++++++++----------------------- test/git/test_stats.py | 6 +-- test/git/test_tag.py | 8 ++-- 11 files changed, 88 insertions(+), 112 deletions(-) (limited to 'test/git') 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('', 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('', 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_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('' % path, repr(self.repo)) + assert_equal('' % 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) -- cgit v1.2.3 From 20c34a929a8b2871edd4fd44a38688e8977a4be6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 17:40:04 +0200 Subject: =?UTF-8?q?Added=20reset=20method=20to=20Head=20-=20its=20a=20clas?= =?UTF-8?q?s=20method=20due=20to=20the=20very=20general=20nature=20of=20th?= =?UTF-8?q?e=20command.=20Yet=20I=20don't=20really=20like=20the=20way=20yo?= =?UTF-8?q?u=20have=20to=20call=20it=20as=20repo=20has=20to=20be=20?= =?UTF-8?q?=E1=B9=95assed=20as=20first=20arg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/git/test_base.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index a7ef9374..3472608e 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -94,6 +94,22 @@ class TestBase(TestBase): assert prev_object is not cur_object # but are different instances # END for each head + @with_rw_repo('0.1.6') + def test_head_reset(self, rw_repo): + cur_head = rw_repo.head + new_head_commit = cur_head.commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only + assert reset_head.commit == new_head_commit + + self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) + new_head_commit = new_head_commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt + assert reset_head.commit == new_head_commit + + # paths + Head.reset(rw_repo, new_head_commit, paths = "lib") + + 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() -- cgit v1.2.3 From 3d9e7f1121d3bdbb08291c7164ad622350544a21 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 18:01:52 +0200 Subject: Index now behaves more like the default index if no explicit stream is given. It will lazily read its data on first access --- test/git/test_index.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 10ffb79d..8baf408c 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -101,4 +101,7 @@ class TestTree(TestBase): # END for each blob assert num_blobs == len(three_way_index.entries) - + def test_from_index(self): + # default Index instance points to our index + index = Index(self.rorepo) + assert len(index.entries) -- cgit v1.2.3 From 36f838e7977e62284d2928f65cacf29771f1952f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 19:05:00 +0200 Subject: utils: Added LockFile including test GitConfigFile is now derived from LockFile using its capabilities Implemented ConcurrentWriteOperation, test is yet to be done --- test/git/test_utils.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_utils.py b/test/git/test_utils.py index 6852d0ad..61527758 100644 --- a/test/git/test_utils.py +++ b/test/git/test_utils.py @@ -5,11 +5,15 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os +import tempfile + from test.testlib import * +from git.utils import * from git import * from git.cmd import dashify -class TestUtils(object): + +class TestUtils(TestCase): def setup(self): self.testdict = { "string": "42", @@ -20,3 +24,34 @@ class TestUtils(object): def test_it_should_dashify(self): assert_equal('this-is-my-argument', dashify('this_is_my_argument')) assert_equal('foo', dashify('foo')) + + + def test_lock_file(self): + my_file = tempfile.mktemp() + lock_file = LockFile(my_file) + assert not lock_file._has_lock() + # release lock we don't have - fine + lock_file._release_lock() + + # get lock + lock_file._obtain_lock_or_raise() + assert lock_file._has_lock() + + # concurrent access + other_lock_file = LockFile(my_file) + assert not other_lock_file._has_lock() + self.failUnlessRaises(IOError, other_lock_file._obtain_lock_or_raise) + + lock_file._release_lock() + assert not lock_file._has_lock() + + other_lock_file._obtain_lock_or_raise() + self.failUnlessRaises(IOError, lock_file._obtain_lock_or_raise) + + # auto-release on destruction + del(other_lock_file) + lock_file._obtain_lock_or_raise() + lock_file._release_lock() + + def test_safe_operation(self): + self.fail("todo") -- cgit v1.2.3 From 7184340f9d826a52b9e72fce8a30b21a7c73d5be Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 19:23:21 +0200 Subject: Added test for ConcurrentWriteOperation --- test/git/test_utils.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_utils.py b/test/git/test_utils.py index 61527758..029d2054 100644 --- a/test/git/test_utils.py +++ b/test/git/test_utils.py @@ -53,5 +53,54 @@ class TestUtils(TestCase): lock_file._obtain_lock_or_raise() lock_file._release_lock() + def _cmp_contents(self, file_path, data): + # raise if data from file at file_path + # does not match data string + fp = open(file_path, "r") + try: + assert fp.read() == data + finally: + fp.close() + def test_safe_operation(self): - self.fail("todo") + my_file = tempfile.mktemp() + orig_data = "hello" + new_data = "world" + my_file_fp = open(my_file, "w") + my_file_fp.write(orig_data) + my_file_fp.close() + + try: + cwrite = ConcurrentWriteOperation(my_file) + + # didn't start writing, doesnt matter + cwrite._end_writing(False) + cwrite._end_writing(True) + assert not cwrite._is_writing() + + # write data and fail + stream = cwrite._begin_writing() + assert cwrite._is_writing() + stream.write(new_data) + cwrite._end_writing(successful=False) + self._cmp_contents(my_file, orig_data) + assert not os.path.exists(stream.name) + + # write data - concurrently + ocwrite = ConcurrentWriteOperation(my_file) + stream = cwrite._begin_writing() + self.failUnlessRaises(IOError, ocwrite._begin_writing) + + stream.write("world") + cwrite._end_writing(successful=True) + self._cmp_contents(my_file, new_data) + assert not os.path.exists(stream.name) + + # could test automatic _end_writing on destruction + finally: + os.remove(my_file) + # END final cleanup + + + + -- cgit v1.2.3 From 1496979cf7e9692ef869d2f99da6141756e08d25 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 19:43:01 +0200 Subject: default index writing now writes the index of the current repository in a fashion comparable to the native implementation --- test/git/test_index.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 8baf408c..5c643a67 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -101,7 +101,13 @@ class TestTree(TestBase): # END for each blob assert num_blobs == len(three_way_index.entries) - def test_from_index(self): + @with_rw_repo('0.1.6') + def test_from_index(self, rw_repo): # default Index instance points to our index - index = Index(self.rorepo) + index = Index(rw_repo) assert len(index.entries) + + # write the file back + index.write() + + # could sha it, or check stats -- cgit v1.2.3 From ea33fe8b21d2b02f902b131aba0d14389f2f8715 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 22:14:02 +0200 Subject: Index: Is now diffable and appears to properly implement diffing against other items as well as the working tree Diff.Diffable: added callback allowing superclasses to preprocess diff arguments Diff.Diff: added eq, ne and hash methods, string methods would be nice --- test/git/test_diff.py | 13 +++++++++---- test/git/test_index.py | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 5 deletions(-) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index d7505987..ead231e5 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -59,6 +59,14 @@ class TestDiff(TestBase): assertion_map.setdefault(key, 0) assertion_map[key] = assertion_map[key]+len(list(diff_index.iter_change_type(ct))) # END for each changetype + + # check entries + diff_set = set() + diff_set.add(diff_index[0]) + diff_set.add(diff_index[0]) + assert len(diff_set) == 1 + assert diff_index[0] == diff_index[0] + assert not (diff_index[0] != diff_index[0]) # END diff index checking # END for each patch option # END for each path option @@ -71,7 +79,4 @@ class TestDiff(TestBase): for key,value in assertion_map.items(): assert value, "Did not find diff for %s" % key # END for each iteration type - - def test_diff_index_working_tree(self): - self.fail("""Find a good way to diff an index against the working tree -which is not possible with the current interface""") + diff --git a/test/git/test_index.py b/test/git/test_index.py index 5c643a67..257acf10 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -102,12 +102,45 @@ class TestTree(TestBase): assert num_blobs == len(three_way_index.entries) @with_rw_repo('0.1.6') - def test_from_index(self, rw_repo): + def test_from_index_and_diff(self, rw_repo): # default Index instance points to our index index = Index(rw_repo) + assert index.path is not None assert len(index.entries) # write the file back index.write() # could sha it, or check stats + + # test diff + # resetting the head will leave the index in a different state, and the + # diff will yield a few changes + cur_head_commit = rw_repo.head.commit + ref = rw_repo.head.reset(rw_repo, 'HEAD~6', index=True, working_tree=False) + + # diff against same index is 0 + diff = index.diff() + assert len(diff) == 0 + + # against HEAD as string, must be the same as it matches index + diff = index.diff('HEAD') + assert len(diff) == 0 + + # against previous head, there must be a difference + diff = index.diff(cur_head_commit) + assert len(diff) + + # we reverse the result + adiff = index.diff(str(cur_head_commit), R=True) + odiff = index.diff(cur_head_commit, R=False) # now its not reversed anymore + assert adiff != odiff + assert odiff == diff # both unreversed diffs against HEAD + + # against working copy - its still at cur_commit + wdiff = index.diff(None) + assert wdiff != adiff + assert wdiff != odiff + + # against something unusual + self.failUnlessRaises(ValueError, index.diff, int) -- cgit v1.2.3 From 58e2157ad3aa9d75ef4abb90eb2d1f01fba0ba2b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 23:20:16 +0200 Subject: Added SymbolicReference and HEAD type to better represent these special types of references and allow special handling Head.reset now is an instance method of HEAD type Concatenated all reference specific tests into test_refs started to fix tests breaking now because of changed interface --- test/git/test_base.py | 46 +-------------------------- test/git/test_commit.py | 2 +- test/git/test_head.py | 24 -------------- test/git/test_refs.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ test/git/test_tag.py | 33 ------------------- 5 files changed, 86 insertions(+), 103 deletions(-) delete mode 100644 test/git/test_head.py create mode 100644 test/git/test_refs.py delete mode 100644 test/git/test_tag.py (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 3472608e..1b78786a 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -66,50 +66,6 @@ class TestBase(TestBase): assert len(s|s) == num_objs assert num_index_objs == 2 - - def test_tags(self): - # tag refs can point to tag objects or to commits - s = set() - ref_count = 0 - for ref in chain(self.rorepo.tags, self.rorepo.heads): - ref_count += 1 - assert isinstance(ref, refs.Reference) - assert str(ref) == ref.name - assert repr(ref) - assert ref == ref - assert not ref != ref - s.add(ref) - # END for each ref - 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.rorepo.heads: - head.name - head.path - 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 - - @with_rw_repo('0.1.6') - def test_head_reset(self, rw_repo): - cur_head = rw_repo.head - new_head_commit = cur_head.commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only - assert reset_head.commit == new_head_commit - - self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) - new_head_commit = new_head_commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt - assert reset_head.commit == new_head_commit - - # paths - Head.reset(rw_repo, new_head_commit, paths = "lib") - - 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() @@ -119,7 +75,7 @@ class TestBase(TestBase): def test_object_resolution(self): # objects must be resolved to shas so they compare equal - assert self.rorepo.head.object == self.rorepo.active_branch.object + assert self.rorepo.head.reference.object == self.rorepo.active_branch.object @with_bare_rw_repo def test_with_bare_rw_repo(self, bare_rw_repo): diff --git a/test/git/test_commit.py b/test/git/test_commit.py index 1a74593d..c4ed4b72 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -64,7 +64,7 @@ class TestCommit(TestBase): assert_equal(sha1, commit.id) def test_count(self): - assert self.rorepo.tag('0.1.5').commit.count( ) == 141 + assert self.rorepo.tag('refs/tags/0.1.5').commit.count( ) == 141 def test_list(self): assert isinstance(Commit.list_items(self.rorepo, '0.1.5', max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) diff --git a/test/git/test_head.py b/test/git/test_head.py deleted file mode 100644 index 9b18ad7c..00000000 --- a/test/git/test_head.py +++ /dev/null @@ -1,24 +0,0 @@ -# test_head.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 * - -class TestHead(TestBase): - - def test_base(self): - for head in self.rorepo.heads: - assert head.name - assert "refs/heads" in head.path - # END for each head - - @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.rorepo.heads[0] - - assert_equal('refactoring/feature1', head.name) - assert_true(git.called) diff --git a/test/git/test_refs.py b/test/git/test_refs.py new file mode 100644 index 00000000..ece6bf3e --- /dev/null +++ b/test/git/test_refs.py @@ -0,0 +1,84 @@ +# test_refs.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 mock import * +from test.testlib import * +from git import * +import git.refs as refs +from git.objects.tag import TagObject +from itertools import chain + +class TestRefs(TestBase): + + def test_tag_base(self): + tag_object_refs = list() + for tag in self.rorepo.tags: + assert "refs/tags" in tag.path + assert tag.name + assert isinstance( tag.commit, Commit ) + if tag.tag is not None: + tag_object_refs.append( tag ) + tagobj = tag.tag + assert isinstance( tagobj, TagObject ) + assert tagobj.tag == tag.name + assert isinstance( tagobj.tagger, Actor ) + assert isinstance( tagobj.tagged_date, int ) + assert tagobj.message + # END if we have a tag object + # END for tag in repo-tags + assert tag_object_refs + assert isinstance(self.rorepo.tags['0.1.5'], TagReference) + + @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.rorepo.heads[0] + + assert_equal('refactoring/feature1', head.name) + assert_true(git.called) + + + def test_tags(self): + # tag refs can point to tag objects or to commits + s = set() + ref_count = 0 + for ref in chain(self.rorepo.tags, self.rorepo.heads): + ref_count += 1 + assert isinstance(ref, refs.Reference) + assert str(ref) == ref.name + assert repr(ref) + assert ref == ref + assert not ref != ref + s.add(ref) + # END for each ref + assert len(s) == ref_count + assert len(s|s) == ref_count + + def test_heads(self): + for head in self.rorepo.heads: + assert head.name + assert head.path + assert "refs/heads" in head.path + 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 + + @with_rw_repo('0.1.6') + def test_head_reset(self, rw_repo): + cur_head = rw_repo.head + new_head_commit = cur_head.ref.commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only + assert reset_head.commit == new_head_commit + + self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) + new_head_commit = new_head_commit.parents[0] + reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt + assert reset_head.commit == new_head_commit + + # paths + Head.reset(rw_repo, new_head_commit, paths = "lib") diff --git a/test/git/test_tag.py b/test/git/test_tag.py deleted file mode 100644 index 97e0acd1..00000000 --- a/test/git/test_tag.py +++ /dev/null @@ -1,33 +0,0 @@ -# test_tag.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 mock import * -from test.testlib import * -from git import * -from git.objects.tag import TagObject - -class TestTag(TestBase): - - def test_tag_base(self): - tag_object_refs = list() - for tag in self.rorepo.tags: - assert "refs/tags" in tag.path - assert tag.name - assert isinstance( tag.commit, Commit ) - if tag.tag is not None: - tag_object_refs.append( tag ) - tagobj = tag.tag - assert isinstance( tagobj, TagObject ) - assert tagobj.tag == tag.name - assert isinstance( tagobj.tagger, Actor ) - assert isinstance( tagobj.tagged_date, int ) - assert tagobj.message - # END if we have a tag object - # END for tag in repo-tags - assert tag_object_refs - assert isinstance(self.rorepo.tags['0.1.5'], TagReference) - - -- cgit v1.2.3 From b7a5c05875a760c0bf83af6617c68061bda6cfc5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 23:31:26 +0200 Subject: Adjusted tests to deal with API changes --- test/git/test_index.py | 4 ++-- test/git/test_refs.py | 12 ++++++------ test/git/test_repo.py | 10 ++-------- 3 files changed, 10 insertions(+), 16 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 257acf10..7bc2ad7e 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -116,8 +116,8 @@ class TestTree(TestBase): # test diff # resetting the head will leave the index in a different state, and the # diff will yield a few changes - cur_head_commit = rw_repo.head.commit - ref = rw_repo.head.reset(rw_repo, 'HEAD~6', index=True, working_tree=False) + cur_head_commit = rw_repo.head.reference.commit + ref = rw_repo.head.reset('HEAD~6', index=True, working_tree=False) # diff against same index is 0 diff = index.diff() diff --git a/test/git/test_refs.py b/test/git/test_refs.py index ece6bf3e..0954d42d 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -72,13 +72,13 @@ class TestRefs(TestBase): def test_head_reset(self, rw_repo): cur_head = rw_repo.head new_head_commit = cur_head.ref.commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True) # index only - assert reset_head.commit == new_head_commit + cur_head.reset(new_head_commit, index=True) # index only + assert cur_head.reference.commit == new_head_commit - self.failUnlessRaises(ValueError, Head.reset, rw_repo, new_head_commit, index=False, working_tree=True) + self.failUnlessRaises(ValueError, cur_head.reset, new_head_commit, index=False, working_tree=True) new_head_commit = new_head_commit.parents[0] - reset_head = Head.reset(rw_repo, new_head_commit, index=True, working_tree=True) # index + wt - assert reset_head.commit == new_head_commit + cur_head.reset(new_head_commit, index=True, working_tree=True) # index + wt + assert cur_head.reference.commit == new_head_commit # paths - Head.reset(rw_repo, new_head_commit, paths = "lib") + cur_head.reset(new_head_commit, paths = "lib") diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 02eea7de..b02610f4 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -168,17 +168,11 @@ class TestRepo(TestBase): 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.rorepo.active_branch.name, 'major-refactoring') - assert_equal(git.call_args, (('symbolic_ref', 'HEAD'), {})) - def test_head(self): - assert self.rorepo.head.object == self.rorepo.active_branch.object + assert self.rorepo.head.reference.object == self.rorepo.active_branch.object def test_tag(self): - assert self.rorepo.tag('0.1.5').commit + assert self.rorepo.tag('refs/tags/0.1.5').commit def test_archive(self): tmpfile = os.tmpfile() -- cgit v1.2.3 From d1bd99c0a376dec63f0f050aeb0c40664260da16 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 00:13:09 +0200 Subject: SymbolicReferences can now change they references safely as I think and well controlled, including test. Added commit method which will return the commit for detached symbolic refs or for normal symbolic refs which is quite convenient --- test/git/test_refs.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 0954d42d..1562310a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -82,3 +82,29 @@ class TestRefs(TestBase): # paths cur_head.reset(new_head_commit, paths = "lib") + + + # now that we have a write write repo, change the HEAD reference - its + # like git-reset --soft + heads = rw_repo.heads + assert heads + for head in heads: + cur_head.reference = head + assert cur_head.reference == head + assert cur_head.commit == head.commit + assert not cur_head.is_detached + # END for each head + + # detach + cur_head.reference = heads[0].commit + assert cur_head.commit == heads[0].commit + assert cur_head.is_detached + self.failUnlessRaises(TypeError, getattr, cur_head, "reference") + + some_tag = rw_repo.tags[0] + cur_head.reference = some_tag + assert cur_head.is_detached + assert cur_head.commit == some_tag.commit + + # type check + self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") -- cgit v1.2.3 From a10aa36bc6a82bd50df6f3df7d6b7ce04a7070f1 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 10:42:26 +0200 Subject: Renamed Index to IndexFile, adjusted tests, it will only operate on physical files, not on streams, as Indices are not streamed by any git command ( at least not in raw format ) --- test/git/test_index.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 7bc2ad7e..6fd3133a 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -12,9 +12,9 @@ import tempfile class TestTree(TestBase): - def test_base(self): + def test_index_file_base(self): # read from file - index = Index.from_file(self.rorepo, fixture_path("index")) + index = IndexFile(self.rorepo, fixture_path("index")) assert index.entries assert index.version > 0 @@ -27,20 +27,16 @@ class TestTree(TestBase): # END for each method # test stage - index_merge = Index.from_file(self.rorepo, fixture_path("index_merge")) + index_merge = IndexFile(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 )) # write the data - it must match the original - index_output = os.tmpfile() - index_merge.write(index_output) - - index_output.seek(0) - assert index_output.read() == fixture("index_merge") - tmpfile = tempfile.mktemp() - Index.to_file(index_merge, tmpfile) - assert os.path.isfile(tmpfile) + index_merge.write(tmpfile) + fp = open(tmpfile, 'r') + assert fp.read() == fixture("index_merge") + fp.close() os.remove(tmpfile) def _cmp_tree_index(self, tree, index): @@ -55,23 +51,23 @@ class TestTree(TestBase): # END for each blob in tree assert num_blobs == len(index.entries) - def test_from_tree(self): + def test_index_file_from_tree(self): common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" # simple index from tree - base_index = Index.from_tree(self.rorepo, common_ancestor_sha) + base_index = IndexFile.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.rorepo, common_ancestor_sha, cur_sha) + two_way_index = IndexFile.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.rorepo, common_ancestor_sha, cur_sha, other_sha) + three_way_index = IndexFile.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)) @@ -102,9 +98,9 @@ class TestTree(TestBase): assert num_blobs == len(three_way_index.entries) @with_rw_repo('0.1.6') - def test_from_index_and_diff(self, rw_repo): + def test_index_file_diffing(self, rw_repo): # default Index instance points to our index - index = Index(rw_repo) + index = IndexFile(rw_repo) assert index.path is not None assert len(index.entries) -- cgit v1.2.3 From 3d3a24b22d340c62fafc0e75a349c0ffe34d99d7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 11:07:04 +0200 Subject: Added repo.index property including simple test, and additional ideas in the TODO list --- test/git/test_repo.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index b02610f4..4995d901 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -170,7 +170,11 @@ class TestRepo(TestBase): def test_head(self): assert self.rorepo.head.reference.object == self.rorepo.active_branch.object - + + def test_index(self): + index = self.rorepo.index + assert isinstance(index, IndexFile) + def test_tag(self): assert self.rorepo.tag('refs/tags/0.1.5').commit -- cgit v1.2.3 From a7a4388eeaa4b6b94192dce67257a34c4a6cbd26 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 12:14:22 +0200 Subject: Added frame for IndexFile add/remove/commit methods and respective test markers --- test/git/test_index.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 6fd3133a..36e57d5c 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -26,6 +26,11 @@ class TestTree(TestBase): val = getattr(entry, attr) # END for each method + # test update + entries = index.entries + assert isinstance(index.update(), IndexFile) + assert entries is not index.entries + # test stage index_merge = IndexFile(self.rorepo, fixture_path("index_merge")) assert len(index_merge.entries) == 106 @@ -140,3 +145,11 @@ class TestTree(TestBase): # against something unusual self.failUnlessRaises(ValueError, index.diff, int) + + self.fail( "Test IndexFile.reset" ) + + @with_rw_repo('0.1.6') + def test_index_mutation(self, rw_repo): + # add / remove / commit / Working Tree Handling + self.fail( "add, remove, commit, working tree handling" ) + -- cgit v1.2.3 From 2c23ca3cd9b9bbeaca1b79068dee1eae045be5b6 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 14:46:18 +0200 Subject: refs: added create, delete and rename methods where appropriate. Tests are marked, implementation is needed for most of them --- test/git/test_refs.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 1562310a..2665d93b 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -108,3 +108,11 @@ class TestRefs(TestBase): # type check self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") + + + self.fail("head creation") + self.fail("head renaming") + self.fail("head removal") + self.fail("tag creation") + self.fail("tag deletion") + self.fail("remote deletion") -- cgit v1.2.3 From ddc5496506f0484e4f1331261aa8782c7e606bf2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 15:22:07 +0200 Subject: Implemented head methods: create, delete, rename, including tests --- test/git/test_refs.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 2665d93b..ac213384 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -109,10 +109,39 @@ class TestRefs(TestBase): # type check self.failUnlessRaises(ValueError, setattr, cur_head, "reference", "that") + # head handling + commit = 'HEAD' + prev_head_commit = cur_head.commit + for count, new_name in enumerate(("my_new_head", "feature/feature1")): + actual_commit = commit+"^"*count + new_head = Head.create(rw_repo, new_name, actual_commit) + assert cur_head.commit == prev_head_commit + assert isinstance(new_head, Head) + # already exists + self.failUnlessRaises(GitCommandError, Head.create, rw_repo, new_name) + + # force it + new_head = Head.create(rw_repo, new_name, actual_commit, force=True) + old_path = new_head.path + old_name = new_head.name + + assert new_head.rename("hello").name == "hello" + assert new_head.rename("hello/world").name == "hello/world" + assert new_head.rename(old_name).name == old_name and new_head.path == old_path + + # rename with force + tmp_head = Head.create(rw_repo, "tmphead") + self.failUnlessRaises(GitCommandError, tmp_head.rename, new_head) + tmp_head.rename(new_head, force=True) + assert tmp_head == new_head and tmp_head.object == new_head.object + + Head.delete(rw_repo, tmp_head) + heads = rw_repo.heads + assert tmp_head not in heads and new_head not in heads + # force on deletion testing would be missing here, code looks okay though ;) + # END for each new head name + self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name") - self.fail("head creation") - self.fail("head renaming") - self.fail("head removal") self.fail("tag creation") self.fail("tag deletion") self.fail("remote deletion") -- cgit v1.2.3 From 1047b41e2e925617474e2e7c9927314f71ce7365 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 15:45:23 +0200 Subject: Added TagRefernce creation and deletion including tests Added RemoteReference deletion and test --- test/git/test_refs.py | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index ac213384..88e8a21a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -142,6 +142,43 @@ class TestRefs(TestBase): # END for each new head name self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name") - self.fail("tag creation") - self.fail("tag deletion") - self.fail("remote deletion") + # tag ref + tag_name = "1.0.2" + light_tag = TagReference.create(rw_repo, tag_name) + self.failUnlessRaises(GitCommandError, TagReference.create, rw_repo, tag_name) + light_tag = TagReference.create(rw_repo, tag_name, "HEAD~1", force = True) + assert isinstance(light_tag, TagReference) + assert light_tag.name == tag_name + assert light_tag.commit == cur_head.commit.parents[0] + assert light_tag.tag is None + + # tag with tag object + other_tag_name = "releases/1.0.2RC" + msg = "my mighty tag\nsecond line" + obj_tag = TagReference.create(rw_repo, other_tag_name, message=msg) + assert isinstance(obj_tag, TagReference) + assert obj_tag.name == other_tag_name + assert obj_tag.commit == cur_head.commit + assert obj_tag.tag is not None + + TagReference.delete(rw_repo, light_tag, obj_tag) + tags = rw_repo.tags + assert light_tag not in tags and obj_tag not in tags + + # remote deletion + remote_refs_so_far = 0 + remotes = rw_repo.remotes + assert remotes + for remote in remotes: + refs = remote.refs + RemoteReference.delete(rw_repo, *refs) + remote_refs_so_far += len(refs) + # END for each ref to delete + assert remote_refs_so_far + + for remote in remotes: + # remotes without references throw + self.failUnlessRaises(AssertionError, getattr, remote, 'refs') + # END for each remote + + self.fail("set commit using ref.commit = that") -- cgit v1.2.3 From 9b9776e88f7abb59cebac8733c04cccf6eee1c60 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 16:07:45 +0200 Subject: Refs can now set the reference they are pointing to in a controlled fashion by writing their ref file directly --- test/git/test_refs.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 88e8a21a..696b95c7 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -181,4 +181,20 @@ class TestRefs(TestBase): self.failUnlessRaises(AssertionError, getattr, remote, 'refs') # END for each remote - self.fail("set commit using ref.commit = that") + # change where the active head points to + if cur_head.is_detached: + cur_head.reference = rw_repo.heads[0] + + head = cur_head.reference + old_commit = head.commit + head.commit = old_commit.parents[0] + assert head.commit == old_commit.parents[0] + assert head.commit == cur_head.commit + head.commit = old_commit + + # setting a non-commit as commit fails, but succeeds as object + head_tree = head.commit.tree + self.failUnlessRaises(TypeError, setattr, head, 'commit', head_tree) + assert head.commit == old_commit # and the ref did not change + head.object = head_tree + assert head.object == head_tree -- cgit v1.2.3 From 1b89f39432cdb395f5fbb9553b56595d29e2b773 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 16:39:02 +0200 Subject: commit.name_rev property added for convenience --- test/git/test_commit.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/git') diff --git a/test/git/test_commit.py b/test/git/test_commit.py index c4ed4b72..251387bd 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -94,3 +94,7 @@ class TestCommit(TestBase): assert first_parent == c.parents[0] # END for each + def test_base(self): + name_rev = self.rorepo.head.commit.name_rev + assert isinstance(name_rev, basestring) + -- cgit v1.2.3 From 13a26d4f9c22695033040dfcd8c76fd94187035b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 17:55:33 +0200 Subject: Implemented index.reset method including test --- test/git/test_index.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 36e57d5c..7236aad9 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -146,7 +146,33 @@ class TestTree(TestBase): # against something unusual self.failUnlessRaises(ValueError, index.diff, int) - self.fail( "Test IndexFile.reset" ) + # adjust the index to match an old revision + cur_branch = rw_repo.active_branch + cur_commit = cur_branch.commit + rev_head_parent = 'HEAD~1' + assert index.reset(rev_head_parent) is index + + assert cur_branch == rw_repo.active_branch + assert cur_commit == rw_repo.head.commit + + # there must be differences towards the working tree which is in the 'future' + assert index.diff(None) + + # reset the working copy as well to current head,to pull 'back' as well + new_data = "will be reverted" + file_path = os.path.join(rw_repo.git.git_dir, "CHANGES") + fp = open(file_path, "w") + fp.write(new_data) + fp.close() + index.reset(rev_head_parent, working_tree=True) + assert not index.diff(None) + assert cur_branch == rw_repo.active_branch + assert cur_commit == rw_repo.head.commit + fp = open(file_path) + try: + assert fp.read() != new_data + finally: + fp.close() @with_rw_repo('0.1.6') def test_index_mutation(self, rw_repo): -- cgit v1.2.3 From 0cd09bd306486028f5442c56ef2e947355a06282 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 21:49:13 +0200 Subject: index.remove implemented including throrough test --- test/git/test_index.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 7236aad9..2f8fed32 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -9,6 +9,7 @@ from git import * import inspect import os import tempfile +import glob class TestTree(TestBase): @@ -174,8 +175,67 @@ class TestTree(TestBase): finally: fp.close() + + def _count_existing(self, repo, files): + existing = 0 + basedir = repo.git.git_dir + for f in files: + existing += os.path.isfile(os.path.join(basedir, f)) + # END for each deleted file + return existing + # END num existing helper + + + @with_rw_repo('0.1.6') def test_index_mutation(self, rw_repo): - # add / remove / commit / Working Tree Handling - self.fail( "add, remove, commit, working tree handling" ) + index = rw_repo.index + num_entries = len(index.entries) + # remove all of the files, provide a wild mix of paths, BaseIndexEntries, + # IndexEntries + def mixed_iterator(): + count = 0 + for entry in index.entries.itervalues(): + type_id = count % 4 + if type_id == 0: # path + yield entry.path + elif type_id == 1: # blob + yield Blob(rw_repo, entry.sha, entry.mode, entry.path) + elif type_id == 2: # BaseIndexEntry + yield BaseIndexEntry(entry[:4]) + elif type_id == 3: # IndexEntry + yield entry + else: + raise AssertionError("Invalid Type") + count += 1 + # END for each entry + # END mixed iterator + deleted_files = index.remove(mixed_iterator(), working_tree=False) + assert deleted_files + assert self._count_existing(rw_repo, deleted_files) == len(deleted_files) + assert len(index.entries) == 0 + + # reset the index to undo our changes + index.reset() + assert len(index.entries) == num_entries + + # remove with working copy + deleted_files = index.remove(mixed_iterator(), working_tree=True) + assert deleted_files + assert self._count_existing(rw_repo, deleted_files) == 0 + + # reset everything + index.reset(working_tree=True) + assert self._count_existing(rw_repo, deleted_files) == len(deleted_files) + + # invalid type + self.failUnlessRaises(TypeError, index.remove, [1]) + + # absolute path + deleted_files = index.remove([os.path.join(rw_repo.git.git_dir,"lib")], r=True) + assert len(deleted_files) > 1 + self.failUnlessRaises(ValueError, index.remove, ["/doesnt/exists"]) + + # re-add all files in lib + self.fail( "add, commit, working tree handling" ) -- cgit v1.2.3 From b999cae064fb6ac11a61a39856e074341baeefde Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 23:44:49 +0200 Subject: actor: added __eq__, __ne__ and __hash__ methods including simple test commit: Fixed long-standing issue during message parsing that would fail to parse properly in case we were created from data. Also it would strip white space from the messages although it shouldn't --- test/git/test_actor.py | 8 ++++++++ test/git/test_commit.py | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_actor.py b/test/git/test_actor.py index b7c2af7c..2941468d 100644 --- a/test/git/test_actor.py +++ b/test/git/test_actor.py @@ -13,6 +13,14 @@ class TestActor(object): a = Actor._from_string("Michael Trier ") assert_equal("Michael Trier", a.name) assert_equal("mtrier@example.com", a.email) + + # base type capabilities + assert a == a + assert not ( a != a ) + m = set() + m.add(a) + m.add(a) + assert len(m) == 1 def test_from_string_should_handle_just_name(self): a = Actor._from_string("Michael Trier") diff --git a/test/git/test_commit.py b/test/git/test_commit.py index c4ed4b72..da636a2b 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -16,6 +16,9 @@ class TestCommit(TestBase): assert_equal("Sebastian Thiel", commit.author.name) assert_equal("byronimo@gmail.com", commit.author.email) + assert commit.author == commit.committer + assert isinstance(commit.authored_date, int) and isinstance(commit.committed_date, int) + assert commit.message == "Added missing information to docstrings of commit and stats module" def test_stats(self): @@ -37,6 +40,14 @@ class TestCommit(TestBase): check_entries(d) # END for each stated file + # assure data is parsed properly + michael = Actor._from_string("Michael Trier ") + assert commit.author == michael + assert commit.committer == michael + assert commit.authored_date == 1210193388 + assert commit.committed_date == 1210193388 + assert commit.message == "initial project" + @patch_object(Git, '_call_process') def test_rev_list_bisect_all(self, git): """ @@ -52,7 +63,7 @@ class TestCommit(TestBase): bisect_all=True) assert_true(git.called) - commits = Commit._iter_from_process_or_stream(self.rorepo, ListProcessAdapter(revs)) + commits = Commit._iter_from_process_or_stream(self.rorepo, ListProcessAdapter(revs), True) expected_ids = ( 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', '33ebe7acec14b25c5f84f35a664803fcab2f7781', -- cgit v1.2.3 From f9cec00938d9059882bb8eabdaf2f775943e00e5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 24 Oct 2009 00:08:33 +0200 Subject: index.commit: implemented initial version, but in fact some more changes are required to have a nice API. Tests are not yet fully done either --- test/git/test_index.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 2f8fed32..0a5f4c35 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -236,6 +236,18 @@ class TestTree(TestBase): assert len(deleted_files) > 1 self.failUnlessRaises(ValueError, index.remove, ["/doesnt/exists"]) + # test committing + # commit changed index + cur_commit = rw_repo.head.commit + commit_message = "commit default head" + new_commit = index.commit(commit_message) + assert new_commit.message == commit_message + assert new_commit.parents[0] == cur_commit + + self.fail("commit with no parents") + self.fail("commit multiple parents") + + # re-add all files in lib self.fail( "add, commit, working tree handling" ) -- cgit v1.2.3 From 0725af77afc619cdfbe3cec727187e442cceaf97 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 26 Oct 2009 11:21:59 +0100 Subject: refs.SymoblicRef: implemented direcft setting of the symbolic references commit, which possibly dereferences to the respective head --- test/git/test_refs.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 696b95c7..979165ef 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -198,3 +198,21 @@ class TestRefs(TestBase): assert head.commit == old_commit # and the ref did not change head.object = head_tree assert head.object == head_tree + self.failUnlessRaises(TypeError, getattr, head, 'commit') # object is a tree, not a commit + + # set the commit directly using the head. This would never detach the head + assert not cur_head.is_detached + head.object = old_commit + cur_head.reference = head.commit + assert cur_head.is_detached + parent_commit = head.commit.parents[0] + assert cur_head.is_detached + cur_head.commit = parent_commit + assert cur_head.is_detached and cur_head.commit == parent_commit + + cur_head.reference = head + assert not cur_head.is_detached + cur_head.commit = parent_commit + assert not cur_head.is_detached + assert head.commit == parent_commit + -- cgit v1.2.3 From 5ba2aef8f59009756567a53daaf918afa851c304 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 26 Oct 2009 11:25:45 +0100 Subject: added head kwarg to reset and commit method, allowing to automatically change the head to the given commit, which makes the methods more versatile --- test/git/test_index.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 0a5f4c35..e25f3d2e 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -191,6 +191,8 @@ class TestTree(TestBase): def test_index_mutation(self, rw_repo): index = rw_repo.index num_entries = len(index.entries) + cur_head = rw_repo.head + # remove all of the files, provide a wild mix of paths, BaseIndexEntries, # IndexEntries def mixed_iterator(): @@ -236,18 +238,39 @@ class TestTree(TestBase): assert len(deleted_files) > 1 self.failUnlessRaises(ValueError, index.remove, ["/doesnt/exists"]) - # test committing + # TEST COMMITTING # commit changed index - cur_commit = rw_repo.head.commit + cur_commit = cur_head.commit commit_message = "commit default head" - new_commit = index.commit(commit_message) + + new_commit = index.commit(commit_message, head=False) assert new_commit.message == commit_message assert new_commit.parents[0] == cur_commit - - self.fail("commit with no parents") - self.fail("commit multiple parents") - + assert len(new_commit.parents) == 1 + assert cur_head.commit == cur_commit + + # same index, no parents + commit_message = "index without parents" + commit_no_parents = index.commit(commit_message, parent_commits=list(), head=True) + assert commit_no_parents.message == commit_message + assert len(commit_no_parents.parents) == 0 + assert cur_head.commit == commit_no_parents + + # same index, multiple parents + commit_message = "Index with multiple parents\n commit with another line" + commit_multi_parent = index.commit(commit_message,parent_commits=(commit_no_parents, new_commit)) + assert commit_multi_parent.message == commit_message + assert len(commit_multi_parent.parents) == 2 + assert commit_multi_parent.parents[0] == commit_no_parents + assert commit_multi_parent.parents[1] == new_commit + assert cur_head.commit == commit_multi_parent # re-add all files in lib - self.fail( "add, commit, working tree handling" ) + # get the lib folder back on disk, but get an index without it + index.reset(new_commit.parents[0], working_tree=True).reset(new_commit, working_tree=False) + lib_file_path = "lib/git/__init__.py" + assert (lib_file_path, 0) not in index.entries + assert os.path.isfile(os.path.join(rw_repo.git.git_dir, lib_file_path)) + + self.fail( "add file using simple path, blob, blob as symlink, entries with stages" ) -- cgit v1.2.3 From 0ef1f89abe5b2334705ee8f1a6da231b0b6c9a50 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 26 Oct 2009 22:37:48 +0100 Subject: index.add: Finished implemenation including through tests index.checkout: added simple method allowing to checkout files from the index, including simple test --- test/git/test_index.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index e25f3d2e..3312abe1 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -8,8 +8,10 @@ from test.testlib import * from git import * import inspect import os +import sys import tempfile import glob +from stat import * class TestTree(TestBase): @@ -174,6 +176,26 @@ class TestTree(TestBase): assert fp.read() != new_data finally: fp.close() + + # test full checkout + test_file = os.path.join(rw_repo.git.git_dir, "CHANGES") + os.remove(test_file) + index.checkout(None, force=True) + assert os.path.isfile(test_file) + + os.remove(test_file) + index.checkout(None, force=False) + assert os.path.isfile(test_file) + + # individual file + os.remove(test_file) + index.checkout(test_file) + assert os.path.exists(test_file) + + + + # currently it ignore non-existing paths + index.checkout(paths=["doesnt/exist"]) def _count_existing(self, repo, files): @@ -186,6 +208,17 @@ class TestTree(TestBase): # END num existing helper + def _make_file(self, rela_path, data, repo=None): + """ + Create a file at the given path relative to our repository, filled + with the given data. Returns absolute path to created file. + """ + repo = repo or self.rorepo + abs_path = os.path.join(repo.git.git_dir, rela_path) + fp = open(abs_path, "w") + fp.write(data) + fp.close() + return abs_path @with_rw_repo('0.1.6') def test_index_mutation(self, rw_repo): @@ -272,5 +305,51 @@ class TestTree(TestBase): assert (lib_file_path, 0) not in index.entries assert os.path.isfile(os.path.join(rw_repo.git.git_dir, lib_file_path)) - self.fail( "add file using simple path, blob, blob as symlink, entries with stages" ) + # directory + entries = index.add(['lib']) + assert len(entries)>1 + + # glob + entries = index.reset(new_commit).add(['lib/*.py']) + assert len(entries) == 14 + + # missing path + self.failUnlessRaises(GitCommandError, index.reset(new_commit).add, ['doesnt/exist/must/raise']) + + # blob from older revision overrides current index revision + old_blob = new_commit.parents[0].tree.blobs[0] + entries = index.reset(new_commit).add([old_blob]) + assert index.entries[(old_blob.path,0)].sha == old_blob.id and len(entries) == 1 + + # mode 0 not allowed + null_sha = "0"*40 + self.failUnlessRaises(ValueError, index.reset(new_commit).add, [BaseIndexEntry((0, null_sha,0,"doesntmatter"))]) + + # add new file + new_file_relapath = "my_new_file" + new_file_path = self._make_file(new_file_relapath, "hello world", rw_repo) + entries = index.reset(new_commit).add([BaseIndexEntry((010644, null_sha, 0, new_file_relapath))]) + assert len(entries) == 1 and entries[0].sha != null_sha + + # add symlink + if sys.platform != "win32": + link_file = os.path.join(rw_repo.git.git_dir, "my_real_symlink") + os.symlink("/etc/that", link_file) + entries = index.reset(new_commit).add([link_file]) + assert len(entries) == 1 and S_ISLNK(entries[0].mode) + print "%o" % entries[0].mode + # END real symlink test + + # add fake symlink and assure it checks-our as symlink + fake_symlink_relapath = "my_fake_symlink" + fake_symlink_path = self._make_file(fake_symlink_relapath, "/etc/that", rw_repo) + fake_entry = BaseIndexEntry((0120000, null_sha, 0, fake_symlink_relapath)) + entries = index.reset(new_commit).add([fake_entry]) + assert len(entries) == 1 and S_ISLNK(entries[0].mode) + + # checkout the fakelink, should be a link then + assert not S_ISLNK(os.stat(fake_symlink_path)[ST_MODE]) + os.remove(fake_symlink_path) + index.checkout(fake_symlink_path) + assert S_ISLNK(os.lstat(fake_symlink_path)[ST_MODE]) -- cgit v1.2.3 From 22757ed7b58862cccef64fdc09f93ea1ac72b1d2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 11:58:20 +0100 Subject: put _make_file helper method into TestBase class remote: prepared FetchInfo class to be returned by fetch and pull. About to implement tests --- test/git/test_index.py | 16 +++------------- test/git/test_remote.py | 11 +++++++++-- 2 files changed, 12 insertions(+), 15 deletions(-) (limited to 'test/git') diff --git a/test/git/test_index.py b/test/git/test_index.py index 3312abe1..3345949b 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -199,6 +199,9 @@ class TestTree(TestBase): def _count_existing(self, repo, files): + """ + Returns count of files that actually exist in the repository directory. + """ existing = 0 basedir = repo.git.git_dir for f in files: @@ -207,19 +210,6 @@ class TestTree(TestBase): return existing # END num existing helper - - def _make_file(self, rela_path, data, repo=None): - """ - Create a file at the given path relative to our repository, filled - with the given data. Returns absolute path to created file. - """ - repo = repo or self.rorepo - abs_path = os.path.join(repo.git.git_dir, rela_path) - fp = open(abs_path, "w") - fp.write(data) - fp.close() - return abs_path - @with_rw_repo('0.1.6') def test_index_mutation(self, rw_repo): index = rw_repo.index diff --git a/test/git/test_remote.py b/test/git/test_remote.py index ef00056d..f1e25ebf 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -59,11 +59,18 @@ class TestRemote(TestBase): assert remote.rename(prev_name).name == prev_name # END for each rename ( back to prev_name ) - remote.fetch() + # FETCH TESTING + assert len(remote.fetch()) == 1 + + + self.fail("rejected parsing") + self.fail("test parsing of each individual flag") + # PULL TESTING + # fails as we did not specify a branch and there is no configuration for it 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) -- cgit v1.2.3 From 5047344a22ed824735d6ed1c91008767ea6638b7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 20:09:50 +0100 Subject: Added testing frame for proper fetch testing to be very sure this works as expected. Plenty of cases still to be tested --- test/git/test_remote.py | 50 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index f1e25ebf..ae828cbc 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -7,8 +7,46 @@ from test.testlib import * from git import * +import os + class TestRemote(TestBase): + def _print_fetchhead(self, repo): + fp = open(os.path.join(repo.path, "FETCH_HEAD")) + print fp.read() + fp.close() + + + def _check_fetch_results(self, results, remote): + self._print_fetchhead(remote.repo) + assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) + for result in results: + assert result.flags != 0 + assert isinstance(result.remote_ref, (SymbolicReference, Reference)) + # END for each result + + def _test_fetch_info(self, repo): + self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense") + self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC") + + def _test_fetch(self,remote, rw_repo, remote_repo): + # specialized fetch testing to de-clutter the main test + self._test_fetch_info(rw_repo) + + fetch_result = remote.fetch() + self._check_fetch_results(fetch_result, remote) + + self.fail("rejected parsing") + self.fail("test parsing of each individual flag") + self.fail("tag handling") + + def _test_pull(self,remote, rw_repo, remote_repo): + # pull is essentially a fetch + merge, hence we just do a light + # test here, leave the reset to the actual merge testing + # fails as we did not specify a branch and there is no configuration for it + self.failUnlessRaises(GitCommandError, remote.pull) + remote.pull('master') + @with_rw_and_rw_remote_repo('0.1.6') def test_base(self, rw_repo, remote_repo): num_remotes = 0 @@ -60,18 +98,14 @@ class TestRemote(TestBase): # END for each rename ( back to prev_name ) # FETCH TESTING - assert len(remote.fetch()) == 1 - + self._test_fetch(remote, rw_repo, remote_repo) - self.fail("rejected parsing") - self.fail("test parsing of each individual flag") # PULL TESTING - # fails as we did not specify a branch and there is no configuration for it - self.failUnlessRaises(GitCommandError, remote.pull) - remote.pull('master') - remote.update() + self._test_pull(remote, rw_repo, remote_repo) + remote.update() # END for each remote + assert num_remotes assert num_remotes == len(remote_set) -- cgit v1.2.3 From 038f183313f796dc0313c03d652a2bcc1698e78e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 20:46:26 +0100 Subject: implemented test for rejection handling and fixed a bug when parsing remote reference paths --- test/git/test_remote.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index ae828cbc..3b145468 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -17,13 +17,18 @@ class TestRemote(TestBase): fp.close() - def _check_fetch_results(self, results, remote): - self._print_fetchhead(remote.repo) + def _test_fetch_result(self, results, remote): + # self._print_fetchhead(remote.repo) assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) - for result in results: - assert result.flags != 0 - assert isinstance(result.remote_ref, (SymbolicReference, Reference)) - # END for each result + for info in results: + assert info.flags != 0 + assert isinstance(info.remote_ref, (SymbolicReference, Reference)) + if info.flags & info.FORCED_UPDATE: + assert isinstance(info.commit_before_forced_update, Commit) + else: + assert info.commit_before_forced_update is None + # END forced update checking + # END for each info def _test_fetch_info(self, repo): self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense") @@ -33,10 +38,20 @@ class TestRemote(TestBase): # specialized fetch testing to de-clutter the main test self._test_fetch_info(rw_repo) - fetch_result = remote.fetch() - self._check_fetch_results(fetch_result, remote) + # put remote head to master as it is garantueed to exist + remote_repo.head.reference = remote_repo.heads.master + + res = remote.fetch() + self._test_fetch_result(res, remote) + + # rewind remote head to trigger rejection + # index must be false as remote is a bare repo + remote_repo.head.reset("HEAD~2", index=False) + res = remote.fetch() + self._test_fetch_result(res, remote) + master_info = res["%s/master" % remote] + assert master_info.flags & Remote.FetchInfo.FORCED_UPDATE and master_info.note is not None - self.fail("rejected parsing") self.fail("test parsing of each individual flag") self.fail("tag handling") -- cgit v1.2.3 From 138aa2b8b413a19ebf9b2bbb39860089c4436001 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 20:57:54 +0100 Subject: Added non-fast forward test case, fixed parsing issue caused by initial line stripping --- test/git/test_remote.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 3b145468..1d343c74 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -43,17 +43,28 @@ class TestRemote(TestBase): res = remote.fetch() self._test_fetch_result(res, remote) + # all uptodate + for info in res: + assert info.flags & info.BRANCH_UPTODATE # rewind remote head to trigger rejection # index must be false as remote is a bare repo - remote_repo.head.reset("HEAD~2", index=False) + rhead = remote_repo.head + remote_commit = rhead.commit + rhead.reset("HEAD~2", index=False) res = remote.fetch() self._test_fetch_result(res, remote) - master_info = res["%s/master" % remote] + mkey = "%s/master" % remote + master_info = res[mkey] assert master_info.flags & Remote.FetchInfo.FORCED_UPDATE and master_info.note is not None - self.fail("test parsing of each individual flag") - self.fail("tag handling") + # normal fast forward - set head back to previous one + rhead.commit = remote_commit + res = remote.fetch() + self._test_fetch_result(res, remote) + assert res[mkey].flags & Remote.FetchInfo.FAST_FORWARD + + self.fail("tag handling, tag uptodate, new tag, new branch") def _test_pull(self,remote, rw_repo, remote_repo): # pull is essentially a fetch + merge, hence we just do a light -- cgit v1.2.3 From b1f32e231d391f8e6051957ad947d3659c196b2b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 22:06:18 +0100 Subject: Added remote stale_refs property including test, tested new remote branch handling and deletion of stale remote branches --- test/git/test_remote.py | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 1d343c74..047ff8f2 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -38,11 +38,19 @@ class TestRemote(TestBase): # specialized fetch testing to de-clutter the main test self._test_fetch_info(rw_repo) + def fetch_and_test(remote): + res = remote.fetch() + self._test_fetch_result(res, remote) + return res + # END fetch and check + + def get_info(res, remote, name): + return res["%s/%s"%(remote,name)] + # put remote head to master as it is garantueed to exist remote_repo.head.reference = remote_repo.heads.master - res = remote.fetch() - self._test_fetch_result(res, remote) + res = fetch_and_test(remote) # all uptodate for info in res: assert info.flags & info.BRANCH_UPTODATE @@ -52,18 +60,40 @@ class TestRemote(TestBase): rhead = remote_repo.head remote_commit = rhead.commit rhead.reset("HEAD~2", index=False) - res = remote.fetch() - self._test_fetch_result(res, remote) - mkey = "%s/master" % remote + res = fetch_and_test(remote) + mkey = "%s/%s"%(remote,'master') master_info = res[mkey] assert master_info.flags & Remote.FetchInfo.FORCED_UPDATE and master_info.note is not None # normal fast forward - set head back to previous one rhead.commit = remote_commit - res = remote.fetch() - self._test_fetch_result(res, remote) + res = fetch_and_test(remote) assert res[mkey].flags & Remote.FetchInfo.FAST_FORWARD + # new remote branch + new_remote_branch = Head.create(remote_repo, "new_branch") + res = fetch_and_test(remote) + new_branch_info = get_info(res, remote, new_remote_branch) + assert new_branch_info.flags & Remote.FetchInfo.NEW_BRANCH + + # remote branch rename ( causes creation of a new one locally ) + new_remote_branch.rename("other_branch_name") + res = fetch_and_test(remote) + other_branch_info = get_info(res, remote, new_remote_branch) + assert other_branch_info.remote_ref.commit == new_branch_info.remote_ref.commit + + # remove new branch + Head.delete(new_remote_branch.repo, new_remote_branch) + res = fetch_and_test(remote) + # deleted remote will not be fetched + self.failUnlessRaises(IndexError, get_info, res, remote, new_remote_branch) + + # prune stale tracking branches + stale_refs = remote.stale_refs + assert len(stale_refs) == 2 and isinstance(stale_refs[0], RemoteReference) + RemoteReference.delete(rw_repo, *stale_refs) + + self.fail("tag handling, tag uptodate, new tag, new branch") def _test_pull(self,remote, rw_repo, remote_repo): @@ -89,7 +119,7 @@ class TestRemote(TestBase): assert refs for ref in refs: assert ref.remote_name == remote.name - assert ref.remote_branch + assert ref.remote_head # END for each ref # OPTIONS -- cgit v1.2.3 From 29c20c147b489d873fb988157a37bcf96f96ab45 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 22:36:41 +0100 Subject: Added special cases to test that shows we cannot yet: handle the FETCH_HEAD case and handle tags System needs to be adjusted to take the FETCH_HEAD info into account to cover the tags case --- test/git/test_remote.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 047ff8f2..91d63ffd 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -18,7 +18,7 @@ class TestRemote(TestBase): def _test_fetch_result(self, results, remote): - # self._print_fetchhead(remote.repo) + self._print_fetchhead(remote.repo) assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) for info in results: assert info.flags != 0 @@ -38,8 +38,8 @@ class TestRemote(TestBase): # specialized fetch testing to de-clutter the main test self._test_fetch_info(rw_repo) - def fetch_and_test(remote): - res = remote.fetch() + def fetch_and_test(remote, **kwargs): + res = remote.fetch(**kwargs) self._test_fetch_result(res, remote) return res # END fetch and check @@ -93,6 +93,23 @@ class TestRemote(TestBase): assert len(stale_refs) == 2 and isinstance(stale_refs[0], RemoteReference) RemoteReference.delete(rw_repo, *stale_refs) + # test single branch fetch with refspec + res = fetch_and_test(remote, refspec="master:refs/remotes/%s/master"%remote) + assert len(res) == 1 and get_info(res, remote, 'master') + + # without refspec + res = fetch_and_test(remote, refspec='master') + assert len(res) == 1 + + # add new tag reference + rtag = TagReference.create(remote_repo, "1.0-RV_hello.there") + res = fetch_and_test(remote, tags=True) + ltag = res[str(rtag)] + assert isinstance(ltag, TagReference) + + # delete tag + + # adjust tag commit self.fail("tag handling, tag uptodate, new tag, new branch") -- cgit v1.2.3 From 2f8e6f7ab1e6dbd95c268ba0fc827abc62009013 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 27 Oct 2009 23:12:10 +0100 Subject: Implemented handling of FETCH_HEAD and tags, some test cases still missing dealing with deletion and movements of remote tags ( which in fact is discouraged, but we should be able to deal with it, shouldnt we ;) --- test/git/test_remote.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 91d63ffd..638cb103 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -18,11 +18,13 @@ class TestRemote(TestBase): def _test_fetch_result(self, results, remote): - self._print_fetchhead(remote.repo) + # self._print_fetchhead(remote.repo) assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) for info in results: - assert info.flags != 0 - assert isinstance(info.remote_ref, (SymbolicReference, Reference)) + if isinstance(info.ref, Reference): + assert info.flags != 0 + # END referebce type flags handling + assert isinstance(info.ref, (SymbolicReference, Reference)) if info.flags & info.FORCED_UPDATE: assert isinstance(info.commit_before_forced_update, Commit) else: @@ -31,8 +33,8 @@ class TestRemote(TestBase): # END for each info def _test_fetch_info(self, repo): - self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense") - self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC") + self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense", '') + self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') def _test_fetch(self,remote, rw_repo, remote_repo): # specialized fetch testing to de-clutter the main test @@ -80,7 +82,7 @@ class TestRemote(TestBase): new_remote_branch.rename("other_branch_name") res = fetch_and_test(remote) other_branch_info = get_info(res, remote, new_remote_branch) - assert other_branch_info.remote_ref.commit == new_branch_info.remote_ref.commit + assert other_branch_info.ref.commit == new_branch_info.ref.commit # remove new branch Head.delete(new_remote_branch.repo, new_remote_branch) @@ -93,11 +95,11 @@ class TestRemote(TestBase): assert len(stale_refs) == 2 and isinstance(stale_refs[0], RemoteReference) RemoteReference.delete(rw_repo, *stale_refs) - # test single branch fetch with refspec + # test single branch fetch with refspec including target remote res = fetch_and_test(remote, refspec="master:refs/remotes/%s/master"%remote) assert len(res) == 1 and get_info(res, remote, 'master') - # without refspec + # ... with respec and no target res = fetch_and_test(remote, refspec='master') assert len(res) == 1 @@ -105,7 +107,7 @@ class TestRemote(TestBase): rtag = TagReference.create(remote_repo, "1.0-RV_hello.there") res = fetch_and_test(remote, tags=True) ltag = res[str(rtag)] - assert isinstance(ltag, TagReference) + assert isinstance(ltag.ref, TagReference) # delete tag -- cgit v1.2.3 From 87afd252bd11026b6ba3db8525f949cfb62c90fc Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 10:58:24 +0100 Subject: tag handling tests finished, unfortunately there is not yet a rejected case, but it will assuambly follow with the push tests --- test/git/test_remote.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 638cb103..6870e0e5 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -106,14 +106,22 @@ class TestRemote(TestBase): # add new tag reference rtag = TagReference.create(remote_repo, "1.0-RV_hello.there") res = fetch_and_test(remote, tags=True) - ltag = res[str(rtag)] - assert isinstance(ltag.ref, TagReference) - - # delete tag + tinfo = res[str(rtag)] + assert isinstance(tinfo.ref, TagReference) and tinfo.ref.commit == rtag.commit + assert tinfo.flags & tinfo.NEW_TAG # adjust tag commit + rtag.object = rhead.commit.parents[0].parents[0] + res = fetch_and_test(remote, tags=True) + tinfo = res[str(rtag)] + assert tinfo.commit == rtag.commit + assert tinfo.flags & tinfo.TAG_UPDATE + + # delete remote tag - local one will stay + TagReference.delete(remote_repo, rtag) + res = fetch_and_test(remote, tags=True) + self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) - self.fail("tag handling, tag uptodate, new tag, new branch") def _test_pull(self,remote, rw_repo, remote_repo): # pull is essentially a fetch + merge, hence we just do a light -- cgit v1.2.3 From 146a6fe18da94e12aa46ec74582db640e3bbb3a9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 12:00:58 +0100 Subject: IterableList: added support for prefix allowing remote.refs.master constructs, previously it was remote.refs['%s/master'%remote] Added first simple test for push support, which shows that much more work is needed on that side to allow just-in-time progress information --- test/git/test_remote.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 6870e0e5..37ba71f9 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -23,7 +23,7 @@ class TestRemote(TestBase): for info in results: if isinstance(info.ref, Reference): assert info.flags != 0 - # END referebce type flags handling + # END reference type flags handling assert isinstance(info.ref, (SymbolicReference, Reference)) if info.flags & info.FORCED_UPDATE: assert isinstance(info.commit_before_forced_update, Commit) @@ -122,8 +122,26 @@ class TestRemote(TestBase): res = fetch_and_test(remote, tags=True) self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) + def _test_push_and_pull(self,remote, rw_repo, remote_repo): + # push our changes + lhead = rw_repo.head + lindex = rw_repo.index + # assure we are on master and it is checked out where the remote is + lhead.reference = rw_repo.heads.master + lhead.reset(remote.refs.master, working_tree=True) + + # push without spec should fail ( without further configuration ) + # self.failUnlessRaises(GitCommandError, remote.push) + + new_file = self._make_file("new_file", "hello world", rw_repo) + lindex.add([new_file]) + lindex.commit("test commit") + remote.push(lhead.reference) + + self.fail("test --all") + self.fail("test rewind and force -push") + self.fail("test general fail due to invalid refspec") - def _test_pull(self,remote, rw_repo, remote_repo): # pull is essentially a fetch + merge, hence we just do a light # test here, leave the reset to the actual merge testing # fails as we did not specify a branch and there is no configuration for it @@ -184,7 +202,7 @@ class TestRemote(TestBase): self._test_fetch(remote, rw_repo, remote_repo) # PULL TESTING - self._test_pull(remote, rw_repo, remote_repo) + self._test_push_and_pull(remote, rw_repo, remote_repo) remote.update() # END for each remote -- cgit v1.2.3 From dc518251eb64c3ef90502697a7e08abe3f8310b2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 12:03:18 +0100 Subject: FetchInfo class is not a subclass of Remote class anymore, as more classes are to be added it cluttered up the view and made things more complex as well --- test/git/test_remote.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 37ba71f9..6f43e163 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -19,7 +19,7 @@ class TestRemote(TestBase): def _test_fetch_result(self, results, remote): # self._print_fetchhead(remote.repo) - assert len(results) > 0 and isinstance(results[0], remote.FetchInfo) + assert len(results) > 0 and isinstance(results[0], FetchInfo) for info in results: if isinstance(info.ref, Reference): assert info.flags != 0 @@ -33,8 +33,8 @@ class TestRemote(TestBase): # END for each info def _test_fetch_info(self, repo): - self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "nonsense", '') - self.failUnlessRaises(ValueError, Remote.FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') + self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "nonsense", '') + self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') def _test_fetch(self,remote, rw_repo, remote_repo): # specialized fetch testing to de-clutter the main test @@ -65,18 +65,18 @@ class TestRemote(TestBase): res = fetch_and_test(remote) mkey = "%s/%s"%(remote,'master') master_info = res[mkey] - assert master_info.flags & Remote.FetchInfo.FORCED_UPDATE and master_info.note is not None + assert master_info.flags & FetchInfo.FORCED_UPDATE and master_info.note is not None # normal fast forward - set head back to previous one rhead.commit = remote_commit res = fetch_and_test(remote) - assert res[mkey].flags & Remote.FetchInfo.FAST_FORWARD + assert res[mkey].flags & FetchInfo.FAST_FORWARD # new remote branch new_remote_branch = Head.create(remote_repo, "new_branch") res = fetch_and_test(remote) new_branch_info = get_info(res, remote, new_remote_branch) - assert new_branch_info.flags & Remote.FetchInfo.NEW_BRANCH + assert new_branch_info.flags & FetchInfo.NEW_BRANCH # remote branch rename ( causes creation of a new one locally ) new_remote_branch.rename("other_branch_name") @@ -122,6 +122,8 @@ class TestRemote(TestBase): res = fetch_and_test(remote, tags=True) self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) + self.fail("Test fetch with true remote side - plenty of possible output is ommitted right now") + def _test_push_and_pull(self,remote, rw_repo, remote_repo): # push our changes lhead = rw_repo.head -- cgit v1.2.3 From 4712c619ed6a2ce54b781fe404fedc269b77e5dd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 15:15:14 +0100 Subject: Fixed bug when listing remotes - it was based on references which is incorrect as it cannot always work --- test/git/test_remote.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 6f43e163..152ef5ab 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -122,8 +122,6 @@ class TestRemote(TestBase): res = fetch_and_test(remote, tags=True) self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) - self.fail("Test fetch with true remote side - plenty of possible output is ommitted right now") - def _test_push_and_pull(self,remote, rw_repo, remote_repo): # push our changes lhead = rw_repo.head @@ -151,9 +149,10 @@ class TestRemote(TestBase): remote.pull('master') @with_rw_and_rw_remote_repo('0.1.6') - def test_base(self, rw_repo, remote_repo): + def test_base(self, rw_repo, remote_repo, damon_handle): num_remotes = 0 remote_set = set() + for remote in rw_repo.remotes: num_remotes += 1 assert remote == remote @@ -221,6 +220,7 @@ class TestRemote(TestBase): arg_list = (new_name, "git@server:hello.git") remote = Remote.create(bare_rw_repo, *arg_list ) assert remote.name == "test_new_one" + assert remote in bare_rw_repo.remotes # create same one again self.failUnlessRaises(GitCommandError, Remote.create, bare_rw_repo, *arg_list) -- cgit v1.2.3 From a519942a295cc39af4eebb7ba74b184decae13fb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 18:09:18 +0100 Subject: Tried to use shallow repository - this works in case it is remote, but unfortunately, deepening the repository fails if the server is used. This is bad, but a workaround is to create another shared repo which pushes a changes that we fetch into our given repo. This should provide more output to properly test the fetch handling. Harder than I thought --- test/git/test_remote.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 152ef5ab..99f64756 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -6,7 +6,8 @@ from test.testlib import * from git import * - +import tempfile +import shutil import os class TestRemote(TestBase): @@ -122,6 +123,20 @@ class TestRemote(TestBase): res = fetch_and_test(remote, tags=True) self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) + # provoke to receive actual objects to see what kind of output we have to + # expect. Previously we did not really receive new objects + # This will only work for true remote repositories, not for local ones ! + if not remote.config_reader.get('url').startswith("git://"): + return + + shallow_repo_dir = tempfile.mktemp("shallow_repo") + shallow_repo = remote_repo.clone(shallow_repo_dir, depth=1, shared=False) + try: + res = shallow_repo.remotes.origin.fetch(depth=10) + finally: + shutil.rmtree(shallow_repo_dir) + # END test and cleanup + def _test_push_and_pull(self,remote, rw_repo, remote_repo): # push our changes lhead = rw_repo.head @@ -149,7 +164,7 @@ class TestRemote(TestBase): remote.pull('master') @with_rw_and_rw_remote_repo('0.1.6') - def test_base(self, rw_repo, remote_repo, damon_handle): + def test_base(self, rw_repo, remote_repo): num_remotes = 0 remote_set = set() -- cgit v1.2.3 From 685d6e651197d54e9a3e36f5adbadd4d21f4c7e5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 18:41:35 +0100 Subject: Added repo.refs for completeness (as remote.refs is there as well and quite nice to use) --- test/git/test_refs.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 979165ef..0a70af1f 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -68,6 +68,12 @@ class TestRefs(TestBase): assert prev_object is not cur_object # but are different instances # END for each head + def test_refs(self): + types_found = set() + for ref in self.rorepo.refs: + types_found.add(type(ref)) + assert len(types_found) == 3 + @with_rw_repo('0.1.6') def test_head_reset(self, rw_repo): cur_head = rw_repo.head -- cgit v1.2.3 From 8b5121414aaf2648b0e809e926d1016249c0222c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 22:17:39 +0100 Subject: Another attempt to make fetch emit progress information, but in fact its proven now that this is not happening if stderr is being redirected. A test is in place that will most likely fail in case this ever changes --- test/git/test_remote.py | 64 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 13 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 99f64756..e4ad5638 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -9,6 +9,10 @@ from git import * import tempfile import shutil import os +import random + +# assure we have repeatable results +random.seed(0) class TestRemote(TestBase): @@ -37,6 +41,15 @@ class TestRemote(TestBase): self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "nonsense", '') self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') + def _commit_random_file(self, repo): + #Create a file with a random name and random data and commit it to repo. + # Return the commited absolute file path + index = repo.index + new_file = self._make_file(os.path.basename(tempfile.mktemp()),str(random.random()), repo) + index.add([new_file]) + index.commit("Committing %s" % new_file) + return new_file + def _test_fetch(self,remote, rw_repo, remote_repo): # specialized fetch testing to de-clutter the main test self._test_fetch_info(rw_repo) @@ -124,20 +137,39 @@ class TestRemote(TestBase): self.failUnlessRaises(IndexError, get_info, res, remote, str(rtag)) # provoke to receive actual objects to see what kind of output we have to - # expect. Previously we did not really receive new objects - # This will only work for true remote repositories, not for local ones ! - if not remote.config_reader.get('url').startswith("git://"): - return - - shallow_repo_dir = tempfile.mktemp("shallow_repo") - shallow_repo = remote_repo.clone(shallow_repo_dir, depth=1, shared=False) + # expect. For that we need a remote transport protocol + # Create a new UN-shared repo and fetch into it after we pushed a change + # to the shared repo + other_repo_dir = tempfile.mktemp("other_repo") + # must clone with a local path for the repo implementation not to freak out + # as it wants local paths only ( which I can understand ) + other_repo = remote_repo.clone(other_repo_dir, shared=False) + remote_repo_url = "git://localhost%s"%remote_repo.path + + # put origin to git-url + other_origin = other_repo.remotes.origin + other_origin.config_writer.set("url", remote_repo_url) + # it automatically creates alternates as remote_repo is shared as well. + # It will use the transport though and ignore alternates when fetching + # assert not other_repo.alternates # this would fail + + # assure we are in the right state + rw_repo.head.reset(remote.refs.master, working_tree=True) try: - res = shallow_repo.remotes.origin.fetch(depth=10) + self._commit_random_file(rw_repo) + remote.push(rw_repo.head.reference) + + # here I would expect to see remote-information about packing + # objects and so on. Unfortunately, this does not happen + # if we are redirecting the output - git explicitly checks for this + # and only provides progress information to ttys + res = fetch_and_test(other_origin) finally: - shutil.rmtree(shallow_repo_dir) + shutil.rmtree(other_repo_dir) # END test and cleanup def _test_push_and_pull(self,remote, rw_repo, remote_repo): + return # push our changes lhead = rw_repo.head lindex = rw_repo.index @@ -146,11 +178,10 @@ class TestRemote(TestBase): lhead.reset(remote.refs.master, working_tree=True) # push without spec should fail ( without further configuration ) + # well, works # self.failUnlessRaises(GitCommandError, remote.push) - new_file = self._make_file("new_file", "hello world", rw_repo) - lindex.add([new_file]) - lindex.commit("test commit") + self._commit_random_file(rw_repo) remote.push(lhead.reference) self.fail("test --all") @@ -167,6 +198,7 @@ class TestRemote(TestBase): def test_base(self, rw_repo, remote_repo): num_remotes = 0 remote_set = set() + ran_fetch_test = False for remote in rw_repo.remotes: num_remotes += 1 @@ -215,7 +247,12 @@ class TestRemote(TestBase): # END for each rename ( back to prev_name ) # FETCH TESTING - self._test_fetch(remote, rw_repo, remote_repo) + # Only for remotes - local cases are the same or less complicated + # as additional progress information will never be emitted + if remote.name == "daemon_origin": + self._test_fetch(remote, rw_repo, remote_repo) + ran_fetch_test = True + # END fetch test # PULL TESTING self._test_push_and_pull(remote, rw_repo, remote_repo) @@ -223,6 +260,7 @@ class TestRemote(TestBase): remote.update() # END for each remote + assert ran_fetch_test assert num_remotes assert num_remotes == len(remote_set) -- cgit v1.2.3 From 461fd06e1f2d91dfbe47168b53815086212862e4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 23:35:41 +0100 Subject: Added frame for push testing and push implemenation --- test/git/test_remote.py | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index e4ad5638..d97bd773 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -14,6 +14,25 @@ import random # assure we have repeatable results random.seed(0) +class TestPushProgress(PushProgress): + def __init__(self): + self._seen_ops = 0 + self._stages_per_op = dict() + + def line_dropped(self, line): + print line + + def update(self, op_code, cur_count, max_count=None): + # check each stage only comes once + pass + + def make_assertion(self): + assert self._seen_ops == 3 + # must have seen all stages + for op, stages in self._stages_per_op.items(): + assert stages & self.STAGE_MASK == self.STAGE_MASK + # END for each op/stage + class TestRemote(TestBase): def _print_fetchhead(self, repo): @@ -69,7 +88,7 @@ class TestRemote(TestBase): res = fetch_and_test(remote) # all uptodate for info in res: - assert info.flags & info.BRANCH_UPTODATE + assert info.flags & info.HEAD_UPTODATE # rewind remote head to trigger rejection # index must be false as remote is a bare repo @@ -90,7 +109,7 @@ class TestRemote(TestBase): new_remote_branch = Head.create(remote_repo, "new_branch") res = fetch_and_test(remote) new_branch_info = get_info(res, remote, new_remote_branch) - assert new_branch_info.flags & FetchInfo.NEW_BRANCH + assert new_branch_info.flags & FetchInfo.NEW_HEAD # remote branch rename ( causes creation of a new one locally ) new_remote_branch.rename("other_branch_name") @@ -169,7 +188,6 @@ class TestRemote(TestBase): # END test and cleanup def _test_push_and_pull(self,remote, rw_repo, remote_repo): - return # push our changes lhead = rw_repo.head lindex = rw_repo.index @@ -182,7 +200,10 @@ class TestRemote(TestBase): # self.failUnlessRaises(GitCommandError, remote.push) self._commit_random_file(rw_repo) - remote.push(lhead.reference) + progress = TestPushProgress() + res = remote.push(lhead.reference, progress) + assert isinstance(res, IterableList) + progress.make_assertion() self.fail("test --all") self.fail("test rewind and force -push") @@ -246,6 +267,9 @@ class TestRemote(TestBase): assert remote.rename(prev_name).name == prev_name # END for each rename ( back to prev_name ) + # PUSH/PULL TESTING + self._test_push_and_pull(remote, rw_repo, remote_repo) + # FETCH TESTING # Only for remotes - local cases are the same or less complicated # as additional progress information will never be emitted @@ -254,9 +278,6 @@ class TestRemote(TestBase): ran_fetch_test = True # END fetch test - # PULL TESTING - self._test_push_and_pull(remote, rw_repo, remote_repo) - remote.update() # END for each remote -- cgit v1.2.3 From b2ccae0d7fca3a99fc6a3f85f554d162a3fdc916 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 2 Nov 2009 22:39:54 +0100 Subject: Implemented PushProgress and PushInfo class including basic test cases. Now many more test-cases need to be added to be sure we can truly deal with everything git throws at us --- test/git/test_remote.py | 54 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index d97bd773..602c74cf 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -15,19 +15,39 @@ import random random.seed(0) class TestPushProgress(PushProgress): + __slots__ = ( "_seen_lines", "_stages_per_op" ) def __init__(self): - self._seen_ops = 0 + super(TestPushProgress, self).__init__() + self._seen_lines = 0 self._stages_per_op = dict() + def _parse_progress_line(self, line): + super(TestPushProgress, self)._parse_progress_line(line) + assert len(line) > 1, "line %r too short" % line + self._seen_lines += 1 + def line_dropped(self, line): - print line + pass - def update(self, op_code, cur_count, max_count=None): + def update(self, op_code, cur_count, max_count=None, message=''): # check each stage only comes once - pass + op_id = op_code & self.OP_MASK + assert op_id in (self.COUNTING, self.COMPRESSING, self.WRITING) + + self._stages_per_op.setdefault(op_id, 0) + self._stages_per_op[ op_id ] = self._stages_per_op[ op_id ] | (op_code & self.STAGE_MASK) + + if op_code & (self.WRITING|self.END) == (self.WRITING|self.END): + assert message + # END check we get message def make_assertion(self): - assert self._seen_ops == 3 + if not self._seen_lines: + return + + assert len(self._seen_ops) == 3 + assert self._stages_per_op + # must have seen all stages for op, stages in self._stages_per_op.items(): assert stages & self.STAGE_MASK == self.STAGE_MASK @@ -56,6 +76,26 @@ class TestRemote(TestBase): # END forced update checking # END for each info + def _test_push_result(self, results, remote): + assert len(results) > 0 and isinstance(results[0], PushInfo) + for info in results: + assert info.flags + if info.old_commit is not None: + assert isinstance(info.old_commit, Commit) + if info.flags & info.ERROR: + has_one = False + for bitflag in (info.REJECTED, info.REMOTE_REJECTED, info.REMOTE_FAILURE): + has_one |= bool(info.flags & bitflag) + # END for each bitflag + assert has_one + else: + # there must be a remote commit + assert isinstance(info.local_ref, Reference) + assert type(info.remote_ref) in (TagReference, RemoteReference) + # END error checking + # END for each info + + def _test_fetch_info(self, repo): self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "nonsense", '') self.failUnlessRaises(ValueError, FetchInfo._from_line, repo, "? [up to date] 0.1.7RC -> origin/0.1.7RC", '') @@ -196,15 +236,17 @@ class TestRemote(TestBase): lhead.reset(remote.refs.master, working_tree=True) # push without spec should fail ( without further configuration ) - # well, works + # well, works nicely # self.failUnlessRaises(GitCommandError, remote.push) self._commit_random_file(rw_repo) progress = TestPushProgress() res = remote.push(lhead.reference, progress) assert isinstance(res, IterableList) + self._test_push_result(res, remote) progress.make_assertion() + self.fail("test --all") self.fail("test rewind and force -push") self.fail("test general fail due to invalid refspec") -- cgit v1.2.3 From e70f3218e910d2b3dcb8a5ab40c65b6bd7a8e9a8 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 14:04:32 +0100 Subject: Intermediate commit with a few added and improved tests as well as many fixes --- test/git/test_remote.py | 68 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 602c74cf..306d0da3 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -18,16 +18,21 @@ class TestPushProgress(PushProgress): __slots__ = ( "_seen_lines", "_stages_per_op" ) def __init__(self): super(TestPushProgress, self).__init__() - self._seen_lines = 0 + self._seen_lines = list() self._stages_per_op = dict() def _parse_progress_line(self, line): + # we may remove the line later if it is dropped + # Keep it for debugging + self._seen_lines.append(line) super(TestPushProgress, self)._parse_progress_line(line) assert len(line) > 1, "line %r too short" % line - self._seen_lines += 1 def line_dropped(self, line): - pass + try: + self._seen_lines.remove(line) + except ValueError: + pass def update(self, op_code, cur_count, max_count=None, message=''): # check each stage only comes once @@ -45,7 +50,8 @@ class TestPushProgress(PushProgress): if not self._seen_lines: return - assert len(self._seen_ops) == 3 + # sometimes objects are not compressed which is okay + assert len(self._seen_ops) in (2,3) assert self._stages_per_op # must have seen all stages @@ -90,7 +96,10 @@ class TestRemote(TestBase): assert has_one else: # there must be a remote commit - assert isinstance(info.local_ref, Reference) + if info.flags & info.DELETED == 0: + assert isinstance(info.local_ref, Reference) + else: + assert info.local_ref is None assert type(info.remote_ref) in (TagReference, RemoteReference) # END error checking # END for each info @@ -239,6 +248,7 @@ class TestRemote(TestBase): # well, works nicely # self.failUnlessRaises(GitCommandError, remote.push) + # simple file push self._commit_random_file(rw_repo) progress = TestPushProgress() res = remote.push(lhead.reference, progress) @@ -246,10 +256,54 @@ class TestRemote(TestBase): self._test_push_result(res, remote) progress.make_assertion() + # rejected - undo last commit + lhead.reset("HEAD~1") + res = remote.push(lhead.reference) + assert res[0].flags & PushInfo.ERROR + assert res[0].flags & PushInfo.REJECTED + self._test_push_result(res, remote) + + # force rejected pull + res = remote.push('+%s' % lhead.reference) + assert res[0].flags & PushInfo.ERROR == 0 + assert res[0].flags & PushInfo.FORCED_UPDATE + self._test_push_result(res, remote) + + # invalid refspec + res = remote.push("hellothere") + assert len(res) == 0 + + # push new tags + progress = TestPushProgress() + to_be_updated = "my_tag.1.0RV" + new_tag = TagReference.create(rw_repo, to_be_updated) + other_tag = TagReference.create(rw_repo, "my_obj_tag.2.1aRV", message="my message") + res = remote.push(progress=progress, tags=True) + assert res[-1].flags & PushInfo.NEW_TAG + progress.make_assertion() + self._test_push_result(res, remote) + + # update push new tags + # Rejection is default + new_tag = TagReference.create(rw_repo, to_be_updated, ref='HEAD~1', force=True) + res = remote.push(tags=True) + self._test_push_result(res, remote) + assert res[-1].flags & PushInfo.REJECTED and res[-1].flags & PushInfo.ERROR + + # push force this tag + res = remote.push("+%s" % new_tag.path) + assert res[-1].flags & PushInfo.ERROR == 0 and res[-1].flags & PushInfo.FORCED_UPDATE + + # delete tag - have to do it using refspec + res = remote.push(":%s" % new_tag.path) + self._test_push_result(res, remote) + assert res[0].flags & PushInfo.DELETED self.fail("test --all") - self.fail("test rewind and force -push") - self.fail("test general fail due to invalid refspec") + + # push new branch + + # delete new branch # pull is essentially a fetch + merge, hence we just do a light # test here, leave the reset to the actual merge testing -- cgit v1.2.3 From ec3d91644561ef59ecdde59ddced38660923e916 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 14:28:22 +0100 Subject: Finished all push tests I could think of so far. More error cases should be studied, but they would be hard to 'produce' --- test/git/test_remote.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 306d0da3..156e7764 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -299,17 +299,34 @@ class TestRemote(TestBase): self._test_push_result(res, remote) assert res[0].flags & PushInfo.DELETED - self.fail("test --all") - # push new branch + new_head = Head.create(rw_repo, "my_new_branch") + progress = TestPushProgress() + res = remote.push(new_head, progress) + assert res[0].flags & PushInfo.NEW_HEAD + progress.make_assertion() + self._test_push_result(res, remote) - # delete new branch + # delete new branch on the remote end and locally + res = remote.push(":%s" % new_head.path) + self._test_push_result(res, remote) + Head.delete(rw_repo, new_head) + assert res[-1].flags & PushInfo.DELETED + + # --all + res = remote.push(all=True) + self._test_push_result(res, remote) # pull is essentially a fetch + merge, hence we just do a light # test here, leave the reset to the actual merge testing # fails as we did not specify a branch and there is no configuration for it self.failUnlessRaises(GitCommandError, remote.pull) remote.pull('master') + + # cleanup - delete created tags and branches as we are in an innerloop on + # the same repository + TagReference.delete(rw_repo, new_tag, other_tag) + remote.push(":%s" % other_tag.path) @with_rw_and_rw_remote_repo('0.1.6') def test_base(self, rw_repo, remote_repo): -- cgit v1.2.3 From 6bca9899b5edeed7f964e3124e382c3573183c68 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 15:20:28 +0100 Subject: repo.is_dirty: is a method now - the property based interface didn't allow all parameters to be used. The test would not test everything either, and I would consider this a bug that slipped through --- test/git/test_repo.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 4995d901..464cb43f 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -154,19 +154,19 @@ class TestRepo(TestBase): def test_is_dirty_with_bare_repository(self): self.rorepo._bare = True - assert_false(self.rorepo.is_dirty) + assert_false(self.rorepo.is_dirty()) def test_is_dirty(self): self.rorepo._bare = False for index in (0,1): for working_tree in (0,1): for untracked_files in (0,1): - assert self.rorepo.is_dirty in (True, False) + assert self.rorepo.is_dirty(index, working_tree, untracked_files) in (True, False) # END untracked files # END working tree # END index self.rorepo._bare = True - assert self.rorepo.is_dirty == False + assert self.rorepo.is_dirty() == False def test_head(self): assert self.rorepo.head.reference.object == self.rorepo.active_branch.object -- cgit v1.2.3 From dbc18b92362f60afc05d4ddadd6e73902ae27ec7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 15:52:45 +0100 Subject: repo: added create_* and delete_* methods for refs ( head, tag, remote ) as a convenient shortcut to using the classes manually --- test/git/test_repo.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 464cb43f..146cff1a 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -251,3 +251,15 @@ class TestRepo(TestBase): # have no permissions pass # END for each config level + + def test_creation_deletion(self): + # just a very quick test to assure it generally works. There are + # specialized cases in the test_refs module + head = self.rorepo.create_head("new_head", "HEAD~1") + self.rorepo.delete_head(head) + + tag = self.rorepo.create_tag("new_tag", "HEAD~2") + self.rorepo.delete_tag(tag) + + remote = self.rorepo.create_remote("new_remote", "git@server:repo.git") + self.rorepo.delete_remote(remote) -- cgit v1.2.3 From 3cb5ba18ab1a875ef6b62c65342de476be47871b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 16:35:33 +0100 Subject: object: renamed id attribute to sha as it in fact is always being rewritten as sha, even if the passed in id was a ref. This is done to assure objects are uniquely identified and will compare correctly --- test/git/test_base.py | 4 ++-- test/git/test_blob.py | 6 +++--- test/git/test_commit.py | 16 ++++++++-------- test/git/test_index.py | 2 +- test/git/test_repo.py | 10 +++++----- test/git/test_tree.py | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) (limited to 'test/git') diff --git a/test/git/test_base.py b/test/git/test_base.py index 1b78786a..497f90fb 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -32,13 +32,13 @@ class TestBase(TestBase): for obj_type, (typename, hexsha) in zip(types, self.type_tuples): item = obj_type(self.rorepo,hexsha) num_objs += 1 - assert item.id == hexsha + assert item.sha == hexsha assert item.type == typename assert item.size assert item.data assert item == item assert not item != item - assert str(item) == item.id + assert str(item) == item.sha assert repr(item) s.add(item) diff --git a/test/git/test_blob.py b/test/git/test_blob.py index 1b3b68f8..464cfd6b 100644 --- a/test/git/test_blob.py +++ b/test/git/test_blob.py @@ -18,13 +18,13 @@ class TestBlob(TestBase): blob.size def test_mime_type_should_return_mime_type_for_known_types(self): - blob = Blob(self.rorepo, **{'id': 'abc', 'path': 'foo.png'}) + blob = Blob(self.rorepo, **{'sha': '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.rorepo, **{'id': 'abc','path': 'something'}) + blob = Blob(self.rorepo, **{'sha': 'abc','path': 'something'}) assert_equal("text/plain", blob.mime_type) def test_should_return_appropriate_representation(self): - blob = Blob(self.rorepo, **{'id': 'abc'}) + blob = Blob(self.rorepo, **{'sha': 'abc'}) assert_equal('', repr(blob)) diff --git a/test/git/test_commit.py b/test/git/test_commit.py index af952ed1..be6d1a28 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -11,7 +11,7 @@ class TestCommit(TestBase): def test_bake(self): - commit = Commit(self.rorepo, **{'id': '2454ae89983a4496a445ce347d7a41c0bb0ea7ae'}) + commit = Commit(self.rorepo, **{'sha': '2454ae89983a4496a445ce347d7a41c0bb0ea7ae'}) commit.author # bake assert_equal("Sebastian Thiel", commit.author.name) @@ -22,7 +22,7 @@ class TestCommit(TestBase): def test_stats(self): - commit = Commit(self.rorepo, id='33ebe7acec14b25c5f84f35a664803fcab2f7781') + commit = Commit(self.rorepo, '33ebe7acec14b25c5f84f35a664803fcab2f7781') stats = commit.stats def check_entries(d): @@ -72,7 +72,7 @@ class TestCommit(TestBase): 'c231551328faa864848bde6ff8127f59c9566e90', ) for sha1, commit in zip(expected_ids, commits): - assert_equal(sha1, commit.id) + assert_equal(sha1, commit.sha) def test_count(self): assert self.rorepo.tag('refs/tags/0.1.5').commit.count( ) == 141 @@ -81,17 +81,17 @@ class TestCommit(TestBase): assert isinstance(Commit.list_items(self.rorepo, '0.1.5', max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) def test_str(self): - commit = Commit(self.rorepo, id='abc') + commit = Commit(self.rorepo, 'abc') assert_equal ("abc", str(commit)) def test_repr(self): - commit = Commit(self.rorepo, id='abc') + commit = Commit(self.rorepo, 'abc') assert_equal('', repr(commit)) def test_equality(self): - commit1 = Commit(self.rorepo, id='abc') - commit2 = Commit(self.rorepo, id='abc') - commit3 = Commit(self.rorepo, id='zyx') + commit1 = Commit(self.rorepo, 'abc') + commit2 = Commit(self.rorepo, 'abc') + commit3 = Commit(self.rorepo, 'zyx') assert_equal(commit1, commit2) assert_not_equal(commit2, commit3) diff --git a/test/git/test_index.py b/test/git/test_index.py index 3345949b..e9541232 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -309,7 +309,7 @@ class TestTree(TestBase): # blob from older revision overrides current index revision old_blob = new_commit.parents[0].tree.blobs[0] entries = index.reset(new_commit).add([old_blob]) - assert index.entries[(old_blob.path,0)].sha == old_blob.id and len(entries) == 1 + assert index.entries[(old_blob.path,0)].sha == old_blob.sha and len(entries) == 1 # mode 0 not allowed null_sha = "0"*40 diff --git a/test/git/test_repo.py b/test/git/test_repo.py index 146cff1a..df495e71 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -46,9 +46,9 @@ class TestRepo(TestBase): commits = list( self.rorepo.iter_commits('master', max_count=10) ) c = commits[0] - assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id) - assert_equal(["634396b2f541a9f2d58b00be1a07f0c358b999b3"], [p.id for p in c.parents]) - assert_equal("672eca9b7f9e09c22dcb128c283e8c3c8d7697a4", c.tree.id) + assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.sha) + assert_equal(["634396b2f541a9f2d58b00be1a07f0c358b999b3"], [p.sha for p in c.parents]) + assert_equal("672eca9b7f9e09c22dcb128c283e8c3c8d7697a4", c.tree.sha) assert_equal("Tom Preston-Werner", c.author.name) assert_equal("tom@mojombo.com", c.author.email) assert_equal(1191999972, c.authored_date) @@ -61,7 +61,7 @@ class TestRepo(TestBase): assert_equal(tuple(), c.parents) c = commits[2] - assert_equal(["6e64c55896aabb9a7d8e9f8f296f426d21a78c2c", "7f874954efb9ba35210445be456c74e037ba6af2"], map(lambda p: p.id, c.parents)) + assert_equal(["6e64c55896aabb9a7d8e9f8f296f426d21a78c2c", "7f874954efb9ba35210445be456c74e037ba6af2"], map(lambda p: p.sha, c.parents)) assert_equal("Merge branch 'site'", c.summary) assert_true(git.called) @@ -195,7 +195,7 @@ class TestRepo(TestBase): assert_true(git.called) assert_equal(git.call_args, (('blame', 'master', '--', 'lib/git.py'), {'p': True})) - assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', c.id) + assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', c.sha) assert_equal('Tom Preston-Werner', c.author.name) assert_equal('tom@mojombo.com', c.author.email) assert_equal(1191997100, c.authored_date) diff --git a/test/git/test_tree.py b/test/git/test_tree.py index b359e2d2..64a7900a 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -45,5 +45,5 @@ class TestTree(TestCase): assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len( root.blobs ) def test_repr(self): - tree = Tree(self.repo, id='abc') + tree = Tree(self.repo, 'abc') assert_equal('', repr(tree)) -- cgit v1.2.3 From 572ace094208c28ab1a8641aedb038456d13f70b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 17:44:13 +0100 Subject: Now using git-update-ref and git-symbolic-ref to update references with reflog support. This should be manually implemented though for more performance, what it does is relatively easy --- test/git/test_refs.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 0a70af1f..f7f4f71a 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -200,11 +200,9 @@ class TestRefs(TestBase): # setting a non-commit as commit fails, but succeeds as object head_tree = head.commit.tree - self.failUnlessRaises(TypeError, setattr, head, 'commit', head_tree) + self.failUnlessRaises(GitCommandError, setattr, head, 'commit', head_tree) assert head.commit == old_commit # and the ref did not change - head.object = head_tree - assert head.object == head_tree - self.failUnlessRaises(TypeError, getattr, head, 'commit') # object is a tree, not a commit + self.failUnlessRaises(GitCommandError, setattr, head, 'object', head_tree) # set the commit directly using the head. This would never detach the head assert not cur_head.is_detached -- cgit v1.2.3 From 43ab2afba68fd0e1b5d138ed99ffc788dc685e36 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 20:59:24 +0100 Subject: refs: iter_items now imlemented natively for additional performance. We did not implement the crazy sorting feature found in git-for-each-ref though --- test/git/test_refs.py | 14 +++++--------- test/git/test_remote.py | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index f7f4f71a..6b3c2840 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -32,15 +32,6 @@ class TestRefs(TestBase): assert tag_object_refs assert isinstance(self.rorepo.tags['0.1.5'], TagReference) - @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.rorepo.heads[0] - - assert_equal('refactoring/feature1', head.name) - assert_true(git.called) - - def test_tags(self): # tag refs can point to tag objects or to commits s = set() @@ -220,3 +211,8 @@ class TestRefs(TestBase): assert not cur_head.is_detached assert head.commit == parent_commit + # test ref listing - assure we have packed refs + rw_repo.git.pack_refs(all=True) + assert rw_repo.heads + assert rw_repo.tags + diff --git a/test/git/test_remote.py b/test/git/test_remote.py index 156e7764..f049f6f7 100644 --- a/test/git/test_remote.py +++ b/test/git/test_remote.py @@ -63,7 +63,6 @@ class TestRemote(TestBase): def _print_fetchhead(self, repo): fp = open(os.path.join(repo.path, "FETCH_HEAD")) - print fp.read() fp.close() -- cgit v1.2.3 From c4cde8df886112ee32b0a09fcac90c28c85ded7f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 12:46:37 +0100 Subject: IndexObject: assured that .path fields are relative to the repository ( previously it would just be a name ) added abspath property and name property to provide easy access to most common paths of an index object --- test/git/test_tree.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/git') diff --git a/test/git/test_tree.py b/test/git/test_tree.py index 64a7900a..7b66743f 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -4,6 +4,7 @@ # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php +import os from test.testlib import * from git import * @@ -43,6 +44,19 @@ class TestTree(TestCase): # 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 ) + subitem = trees[0][0] + assert "/" in subitem.path + assert subitem.name == os.path.basename(subitem.path) + + # assure that at some point the traversed paths have a slash in them + found_slash = False + for item in root.traverse(): + assert os.path.isabs(item.abspath) + if '/' in item.path: + found_slash = True + break + # END for each item + assert found_slash def test_repr(self): tree = Tree(self.repo, 'abc') -- cgit v1.2.3 From f41d42ee7e264ce2fc32cea555e5f666fa1b1fe9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 13:17:37 +0100 Subject: Improved cmd error handling in case an invalid revision is specified for an object repo.tree: improved to be less restricting --- test/git/test_repo.py | 8 ++++++++ test/git/test_tree.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_repo.py b/test/git/test_repo.py index df495e71..0b196a1f 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -38,6 +38,14 @@ class TestRepo(TestBase): assert isinstance(self.rorepo.heads.master, Head) assert isinstance(self.rorepo.heads['master'], Head) + + def test_tree_from_revision(self): + tree = self.rorepo.tree('0.1.6') + assert tree.type == "tree" + assert self.rorepo.tree(tree) == tree + + # try from invalid revision that does not exist + self.failUnlessRaises(ValueError, self.rorepo.tree, 'hello world') @patch_object(Git, '_call_process') def test_commits(self, git): diff --git a/test/git/test_tree.py b/test/git/test_tree.py index 7b66743f..e0c1f134 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -16,7 +16,7 @@ class TestTree(TestCase): def test_traverse(self): - root = self.repo.tree() + root = self.repo.tree('0.1.6') num_recursive = 0 all_items = list() for obj in root.traverse(): -- cgit v1.2.3 From 52bb0046c0bf0e50598c513e43b76d593f2cbbff Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 16:26:03 +0100 Subject: added query for 'M' modified diffs to DiffIndex including test. The latter one was made faster by reducing the amount of permutations to the minimal value --- test/git/test_diff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_diff.py b/test/git/test_diff.py index ead231e5..9335aced 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -41,7 +41,7 @@ class TestDiff(TestBase): def test_diff_interface(self): # test a few variations of the main diff routine assertion_map = dict() - for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=10)): + for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=2)): diff_item = commit if i%2 == 0: diff_item = commit.tree -- cgit v1.2.3 From ace1fed6321bb8dd6d38b2f58d7cf815fa16db7a Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 19:36:29 +0100 Subject: head.checkout method added including test --- test/git/test_refs.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'test/git') diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 6b3c2840..32a6de1c 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -211,8 +211,29 @@ class TestRefs(TestBase): assert not cur_head.is_detached assert head.commit == parent_commit + # test checkout + active_branch = rw_repo.active_branch + for head in rw_repo.heads: + checked_out_head = head.checkout() + assert checked_out_head == head + # END for each head to checkout + + # checkout with branch creation + new_head = active_branch.checkout(b="new_head") + assert active_branch != rw_repo.active_branch + assert new_head == rw_repo.active_branch + + # checkout with force has we have a change + # clear file + open(new_head.commit.tree.blobs[-1].abspath,'w').close() + assert len(new_head.commit.diff(None)) == 1 + + # create a new branch that is likely to touch the file we changed + far_away_head = rw_repo.create_head("far_head",'HEAD~100') + self.failUnlessRaises(GitCommandError, far_away_head.checkout) + assert active_branch == active_branch.checkout(force=True) + # test ref listing - assure we have packed refs rw_repo.git.pack_refs(all=True) assert rw_repo.heads assert rw_repo.tags - -- cgit v1.2.3