diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/git/test_actor.py | 8 | ||||
-rw-r--r-- | test/git/test_commit.py | 13 | ||||
-rw-r--r-- | test/git/test_index.py | 243 | ||||
-rw-r--r-- | test/git/test_refs.py | 108 | ||||
-rw-r--r-- | test/git/test_repo.py | 6 |
5 files changed, 359 insertions, 19 deletions
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 <mtrier@example.com>") 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 251387bd..af952ed1 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 <mtrier@gmail.com>") + 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', diff --git a/test/git/test_index.py b/test/git/test_index.py index 7bc2ad7e..3312abe1 100644 --- a/test/git/test_index.py +++ b/test/git/test_index.py @@ -8,13 +8,16 @@ from test.testlib import * from git import * import inspect import os +import sys import tempfile +import glob +from stat import * 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 @@ -26,21 +29,22 @@ 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 = 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 +59,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 +106,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) @@ -144,3 +148,208 @@ class TestTree(TestBase): # against something unusual self.failUnlessRaises(ValueError, index.diff, int) + + # 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() + + # 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): + 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 + + + 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 + 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(): + 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"]) + + # TEST COMMITTING + # commit changed index + cur_commit = cur_head.commit + commit_message = "commit default head" + + new_commit = index.commit(commit_message, head=False) + assert new_commit.message == commit_message + assert new_commit.parents[0] == cur_commit + 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 + # 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)) + + # 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]) + diff --git a/test/git/test_refs.py b/test/git/test_refs.py index 1562310a..979165ef 100644 --- a/test/git/test_refs.py +++ b/test/git/test_refs.py @@ -108,3 +108,111 @@ 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") + + # 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 + + # 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 + 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 + 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 |