diff options
Diffstat (limited to 'git/test/test_index.py')
-rw-r--r-- | git/test/test_index.py | 300 |
1 files changed, 147 insertions, 153 deletions
diff --git a/git/test/test_index.py b/git/test/test_index.py index d532a3b4..f1f718cd 100644 --- a/git/test/test_index.py +++ b/git/test/test_index.py @@ -14,12 +14,13 @@ import glob import shutil from stat import * + class TestIndex(TestBase): - + def __init__(self, *args): super(TestIndex, self).__init__(*args) self._reset_progress() - + def _assert_fprogress(self, entries): assert len(entries) == len(self._fprogress_map) for path, call_count in self._fprogress_map.iteritems(): @@ -35,48 +36,48 @@ class TestIndex(TestBase): if curval == 1: assert done self._fprogress_map[path] = curval + 1 - + def _fprogress_add(self, path, done, item): - """Called as progress func - we keep track of the proper + """Called as progress func - we keep track of the proper call order""" assert item is not None self._fprogress(path, done, item) - + def _reset_progress(self): # maps paths to the count of calls self._fprogress_map = dict() - + def _assert_entries(self, entries): for entry in entries: assert isinstance(entry, BaseIndexEntry) assert not os.path.isabs(entry.path) assert not "\\" in entry.path # END for each entry - + def test_index_file_base(self): # read from file index = IndexFile(self.rorepo, fixture_path("index")) assert index.entries assert index.version > 0 - + # test entry last_val = None entry = index.entries.itervalues().next() - for attr in ("path","ctime","mtime","dev","inode","mode","uid", - "gid","size","binsha", "hexsha", "stage"): + for attr in ("path", "ctime", "mtime", "dev", "inode", "mode", "uid", + "gid", "size", "binsha", "hexsha", "stage"): 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 - assert len(list(e for e in index_merge.entries.itervalues() if e.stage != 0 )) - + assert len(list(e for e in index_merge.entries.itervalues() if e.stage != 0)) + # write the data - it must match the original tmpfile = tempfile.mktemp() index_merge.write(tmpfile) @@ -84,82 +85,80 @@ class TestIndex(TestBase): assert fp.read() == fixture("index_merge") fp.close() os.remove(tmpfile) - + def _cmp_tree_index(self, tree, index): # fail unless both objects contain the same paths and blobs if isinstance(tree, str): tree = self.rorepo.commit(tree).tree - + num_blobs = 0 blist = list() - for blob in tree.traverse(predicate = lambda e,d: e.type == "blob", branch_first=False): - assert (blob.path,0) in index.entries + for blob in tree.traverse(predicate=lambda e, d: e.type == "blob", branch_first=False): + assert (blob.path, 0) in index.entries blist.append(blob) # END for each blob in tree if len(blist) != len(index.entries): iset = set(k[0] for k in index.entries.keys()) bset = set(b.path for b in blist) - raise AssertionError( "CMP Failed: Missing entries in index: %s, missing in tree: %s" % (bset-iset, iset-bset) ) + raise AssertionError("CMP Failed: Missing entries in index: %s, missing in tree: %s" % (bset - iset, iset - bset)) # END assertion message - + @with_rw_repo('0.1.6') def test_index_file_from_tree(self, rw_repo): common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" - - # simple index from tree + + # simple index from tree base_index = IndexFile.from_tree(rw_repo, 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 = IndexFile.from_tree(rw_repo, 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 = IndexFile.from_tree(rw_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(three_way_index.iter_blobs(merge_required)) assert merge_blobs - assert merge_blobs[0][0] in (1,2,3) + assert merge_blobs[0][0] in (1, 2, 3) assert isinstance(merge_blobs[0][1], Blob) - + # test BlobFilter prefix = 'lib/git' for stage, blob in base_index.iter_blobs(BlobFilter([prefix])): - assert blob.path.startswith(prefix) - - + assert blob.path.startswith(prefix) + # writing a tree should fail with an unmerged index self.failUnlessRaises(UnmergedEntriesError, three_way_index.write_tree) - + # removed unmerged entries 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.resolve_blobs(l[0][1] for l in unmerged_blob_map.itervalues()) tree = three_way_index.write_tree() assert isinstance(tree, Tree) num_blobs = 0 - for blob in tree.traverse(predicate=lambda item,d: item.type == "blob"): - assert (blob.path,0) in three_way_index.entries + for blob in tree.traverse(predicate=lambda item, d: 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) - + @with_rw_repo('0.1.6') def test_index_merge_tree(self, rw_repo): - # A bit out of place, but we need a different repo for this: + # A bit out of place, but we need a different repo for this: assert self.rorepo != rw_repo and not (self.rorepo == rw_repo) assert len(set((self.rorepo, self.rorepo, rw_repo, rw_repo))) == 2 - + # SINGLE TREE MERGE # current index is at the (virtual) cur_commit next_commit = "4c39f9da792792d4e73fc3a5effde66576ae128c" @@ -169,107 +168,106 @@ class TestIndex(TestBase): rw_repo.index.merge_tree(next_commit) # only one change should be recorded assert manifest_entry.binsha != rw_repo.index.entries[manifest_key].binsha - + rw_repo.index.reset(rw_repo.head) assert rw_repo.index.entries[manifest_key].binsha == manifest_entry.binsha - + # FAKE MERGE ############# - # Add a change with a NULL sha that should conflict with next_commit. We - # pretend there was a change, but we do not even bother adding a proper + # Add a change with a NULL sha that should conflict with next_commit. We + # pretend there was a change, but we do not even bother adding a proper # sha for it ( which makes things faster of course ) - manifest_fake_entry = BaseIndexEntry((manifest_entry[0], "\0"*20, 0, manifest_entry[3])) + manifest_fake_entry = BaseIndexEntry((manifest_entry[0], "\0" * 20, 0, manifest_entry[3])) # try write flag self._assert_entries(rw_repo.index.add([manifest_fake_entry], write=False)) - # add actually resolves the null-hex-sha for us as a feature, but we can + # add actually resolves the null-hex-sha for us as a feature, but we can # edit the index manually assert rw_repo.index.entries[manifest_key].binsha != Object.NULL_BIN_SHA - # must operate on the same index for this ! Its a bit problematic as + # must operate on the same index for this ! Its a bit problematic as # it might confuse people - index = rw_repo.index + index = rw_repo.index index.entries[manifest_key] = IndexEntry.from_base(manifest_fake_entry) index.write() assert rw_repo.index.entries[manifest_key].hexsha == Diff.NULL_HEX_SHA - + # write an unchanged index ( just for the fun of it ) rw_repo.index.write() - - # a three way merge would result in a conflict and fails as the command will - # not overwrite any entries in our index and hence leave them unmerged. This is + + # a three way merge would result in a conflict and fails as the command will + # not overwrite any entries in our index and hence leave them unmerged. This is # mainly a protection feature as the current index is not yet in a tree self.failUnlessRaises(GitCommandError, index.merge_tree, next_commit, base=parent_commit) - - # the only way to get the merged entries is to safe the current index away into a tree, + + # the only way to get the merged entries is to safe the current index away into a tree, # which is like a temporary commit for us. This fails as well as the NULL sha deos not # have a corresponding object # NOTE: missing_ok is not a kwarg anymore, missing_ok is always true # self.failUnlessRaises(GitCommandError, index.write_tree) - + # if missing objects are okay, this would work though ( they are always okay now ) tree = index.write_tree() - + # now make a proper three way merge with unmerged entries unmerged_tree = IndexFile.from_tree(rw_repo, parent_commit, tree, next_commit) unmerged_blobs = unmerged_tree.unmerged_blobs() assert len(unmerged_blobs) == 1 and unmerged_blobs.keys()[0] == manifest_key[0] - - + @with_rw_repo('0.1.6') def test_index_file_diffing(self, rw_repo): # default Index instance points to our index index = IndexFile(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 + # 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.reference.commit ref = rw_repo.head.reset('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) - + # 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.working_tree_dir, "CHANGES") @@ -280,12 +278,12 @@ class TestIndex(TestBase): assert not index.diff(None) assert cur_branch == rw_repo.active_branch assert cur_commit == rw_repo.head.commit - fp = open(file_path,'rb') + fp = open(file_path, 'rb') try: assert fp.read() != new_data finally: fp.close() - + # test full checkout test_file = os.path.join(rw_repo.working_tree_dir, "CHANGES") open(test_file, 'ab').write("some data") @@ -293,24 +291,24 @@ class TestIndex(TestBase): assert 'CHANGES' in list(rval) self._assert_fprogress([None]) assert os.path.isfile(test_file) - + os.remove(test_file) rval = index.checkout(None, force=False, fprogress=self._fprogress) assert 'CHANGES' in list(rval) self._assert_fprogress([None]) assert os.path.isfile(test_file) - + # individual file os.remove(test_file) rval = index.checkout(test_file, fprogress=self._fprogress) assert list(rval)[0] == 'CHANGES' self._assert_fprogress([test_file]) assert os.path.exists(test_file) - + # checking out non-existing file throws self.failUnlessRaises(CheckoutError, index.checkout, "doesnt_exist_ever.txt.that") self.failUnlessRaises(CheckoutError, index.checkout, paths=["doesnt/exist"]) - + # checkout file with modifications append_data = "hello" fp = open(test_file, "ab") @@ -325,16 +323,16 @@ class TestIndex(TestBase): assert open(test_file).read().endswith(append_data) else: raise AssertionError("Exception CheckoutError not thrown") - + # if we force it it should work index.checkout(test_file, force=True) assert not open(test_file).read().endswith(append_data) - + # checkout directory shutil.rmtree(os.path.join(rw_repo.working_tree_dir, "lib")) rval = index.checkout('lib') assert len(list(rval)) > 1 - + def _count_existing(self, repo, files): """ Returns count of files that actually exist in the repository directory. @@ -346,24 +344,24 @@ class TestIndex(TestBase): # END for each deleted file return existing # END num existing helper - + @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 - + uname = "Some Developer" umail = "sd@company.com" rw_repo.config_writer().set_value("user", "name", uname) - rw_repo.config_writer().set_value("user", "email", umail) - - # remove all of the files, provide a wild mix of paths, BaseIndexEntries, + rw_repo.config_writer().set_value("user", "email", umail) + + # 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 + type_id = count % 4 if type_id == 0: # path yield entry.path elif type_id == 1: # blob @@ -375,39 +373,39 @@ class TestIndex(TestBase): else: raise AssertionError("Invalid Type") count += 1 - # END for each entry + # 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.working_tree_dir,"lib")], r=True) + deleted_files = index.remove([os.path.join(rw_repo.working_tree_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 cur_commit != new_commit assert new_commit.author.name == uname @@ -418,66 +416,66 @@ class TestIndex(TestBase): 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)) + 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 = os.path.join("lib", "git", "__init__.py") assert (lib_file_path, 0) not in index.entries assert os.path.isfile(os.path.join(rw_repo.working_tree_dir, lib_file_path)) - + # directory entries = index.add(['lib'], fprogress=self._fprogress_add) self._assert_entries(entries) self._assert_fprogress(entries) - assert len(entries)>1 - - # glob + assert len(entries) > 1 + + # glob entries = index.reset(new_commit).add([os.path.join('lib', 'git', '*.py')], fprogress=self._fprogress_add) self._assert_entries(entries) self._assert_fprogress(entries) assert len(entries) == 14 - - # same file - entries = index.reset(new_commit).add([os.path.abspath(os.path.join('lib', 'git', 'head.py'))]*2, fprogress=self._fprogress_add) + + # same file + entries = index.reset(new_commit).add([os.path.abspath(os.path.join('lib', 'git', 'head.py'))] * 2, fprogress=self._fprogress_add) self._assert_entries(entries) assert entries[0].mode & 0644 == 0644 # would fail, test is too primitive to handle this case # self._assert_fprogress(entries) self._reset_progress() assert len(entries) == 2 - + # missing path self.failUnlessRaises(OSError, 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], fprogress=self._fprogress_add) self._assert_entries(entries) self._assert_fprogress(entries) - assert index.entries[(old_blob.path,0)].hexsha == old_blob.hexsha and len(entries) == 1 - + assert index.entries[(old_blob.path, 0)].hexsha == old_blob.hexsha and len(entries) == 1 + # mode 0 not allowed null_hex_sha = Diff.NULL_HEX_SHA null_bin_sha = "\0" * 20 - self.failUnlessRaises(ValueError, index.reset(new_commit).add, [BaseIndexEntry((0, null_bin_sha,0,"doesntmatter"))]) - + self.failUnlessRaises(ValueError, index.reset(new_commit).add, [BaseIndexEntry((0, null_bin_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) @@ -485,7 +483,7 @@ class TestIndex(TestBase): self._assert_entries(entries) self._assert_fprogress(entries) assert len(entries) == 1 and entries[0].hexsha != null_hex_sha - + # add symlink if sys.platform != "win32": basename = "my_real_symlink" @@ -497,11 +495,11 @@ class TestIndex(TestBase): self._assert_fprogress(entries) assert len(entries) == 1 and S_ISLNK(entries[0].mode) assert S_ISLNK(index.entries[index.entry_key("my_real_symlink", 0)].mode) - + # we expect only the target to be written assert index.repo.odb.stream(entries[0].binsha).read() == target - # END real symlink test - + # END real symlink test + # add fake symlink and assure it checks-our as symlink fake_symlink_relapath = "my_fake_symlink" link_target = "/etc/that" @@ -512,83 +510,83 @@ class TestIndex(TestBase): self._assert_fprogress(entries) assert entries[0].hexsha != null_hex_sha assert len(entries) == 1 and S_ISLNK(entries[0].mode) - + # assure this also works with an alternate method full_index_entry = IndexEntry.from_base(BaseIndexEntry((0120000, entries[0].binsha, 0, entries[0].path))) entry_key = index.entry_key(full_index_entry) index.reset(new_commit) - + assert entry_key not in index.entries index.entries[entry_key] = full_index_entry index.write() index.update() # force reread of entries new_entry = index.entries[entry_key] assert S_ISLNK(new_entry.mode) - + # a tree created from this should contain the symlink tree = index.write_tree() assert fake_symlink_relapath in tree index.write() # flush our changes for the checkout - + # 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) - + # on windows we will never get symlinks if os.name == 'nt': - # simlinks should contain the link as text ( which is what a + # simlinks should contain the link as text ( which is what a # symlink actually is ) - open(fake_symlink_path,'rb').read() == link_target + open(fake_symlink_path, 'rb').read() == link_target else: assert S_ISLNK(os.lstat(fake_symlink_path)[ST_MODE]) - + # TEST RENAMING def assert_mv_rval(rval): for source, dest in rval: assert not os.path.exists(source) and os.path.exists(dest) # END for each renamed item # END move assertion utility - + self.failUnlessRaises(ValueError, index.move, ['just_one_path']) # file onto existing file files = ['AUTHORS', 'LICENSE'] self.failUnlessRaises(GitCommandError, index.move, files) - - # again, with force + + # again, with force assert_mv_rval(index.move(files, f=True)) - + # files into directory - dry run paths = ['LICENSE', 'VERSION', 'doc'] rval = index.move(paths, dry_run=True) assert len(rval) == 2 assert os.path.exists(paths[0]) - + # again, no dry run rval = index.move(paths) assert_mv_rval(rval) - + # dir into dir rval = index.move(['doc', 'test']) assert_mv_rval(rval) - - + # TEST PATH REWRITING ###################### count = [0] + def rewriter(entry): rval = str(count[0]) count[0] += 1 return rval # END rewriter - + def make_paths(): # two existing ones, one new one yield 'CHANGES' yield 'ez_setup.py' yield index.entries[index.entry_key('README', 0)] yield index.entries[index.entry_key('.gitignore', 0)] - + for fid in range(3): fname = 'newfile%i' % fid open(fname, 'wb').write("abcd") @@ -597,11 +595,10 @@ class TestIndex(TestBase): # END path producer paths = list(make_paths()) self._assert_entries(index.add(paths, path_rewriter=rewriter)) - + for filenum in range(len(paths)): assert index.entry_key(str(filenum), 0) in index.entries - - + # TEST RESET ON PATHS ###################### arela = "aa" @@ -613,34 +610,33 @@ class TestIndex(TestBase): keys = (akey, bkey) absfiles = (afile, bfile) files = (arela, brela) - + for fkey in keys: assert not fkey in index.entries - + index.add(files, write=True) nc = index.commit("2 files committed", head=False) - + for fkey in keys: assert fkey in index.entries - + # just the index index.reset(paths=(arela, afile)) assert not akey in index.entries assert bkey in index.entries - + # now with working tree - files on disk as well as entries must be recreated rw_repo.head.commit = nc for absfile in absfiles: os.remove(absfile) - + index.reset(working_tree=True, paths=files) - - for fkey in keys: + + for fkey in keys: assert fkey in index.entries for absfile in absfiles: assert os.path.isfile(absfile) - - + @with_rw_repo('HEAD') def test_compare_write_tree(self, rw_repo): # write all trees and compare them @@ -654,16 +650,14 @@ class TestIndex(TestBase): index = rw_repo.index.reset(commit) orig_tree = commit.tree assert index.write_tree() == orig_tree - # END for each commit - + # END for each commit + def test_index_new(self): B = self.rorepo.tree("6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e") H = self.rorepo.tree("25dca42bac17d511b7e2ebdd9d1d679e7626db5f") M = self.rorepo.tree("e746f96bcc29238b79118123028ca170adc4ff0f") - - for args in ((B,), (B,H), (B,H,M)): + + for args in ((B,), (B, H), (B, H, M)): index = IndexFile.new(self.rorepo, *args) assert isinstance(index, IndexFile) # END for each arg tuple - - |