[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/og-python-scripts/GitPython/0.2/test/git/test_refs.py [Back]  [Original]

# 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
import os

class TestRefs(TestBase):

    def test_from_path(self):
        # should be able to create any reference directly
        for ref_type in ( Reference, Head, TagReference, RemoteReference ):
            for name in ('rela_name', 'path/rela_name'):
                full_path = ref_type.to_full_path(name)
                instance = ref_type.from_path(self.rorepo, full_path)
                assert isinstance(instance, ref_type)
            # END for each name 
        # END for each type
    
    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 isinstance( tagobj.tagger_tz_offset, 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)
        
    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
        
    def test_refs(self):
        types_found = set()
        for ref in self.rorepo.refs:
            types_found.add(type(ref))
        assert len(types_found) == 3 
        
    def test_is_valid(self):
        assert Reference(self.rorepo, 'refs/doesnt/exist').is_valid() == False
        assert self.rorepo.head.is_valid()
        assert self.rorepo.head.reference.is_valid()
        assert SymbolicReference(self.rorepo, 'hellothere').is_valid() == False
        
    @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]
        cur_head.reset(new_head_commit, index=True) # index only
        assert cur_head.reference.commit == new_head_commit
        
        self.failUnlessRaises(ValueError, cur_head.reset, new_head_commit, index=False, working_tree=True)
        new_head_commit = new_head_commit.parents[0]
        cur_head.reset(new_head_commit, index=True, working_tree=True)  # index + wt
        assert cur_head.reference.commit == new_head_commit
        
        # 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 isinstance(cur_head.reference, Head)
            assert cur_head.commit == head.commit
            assert not cur_head.is_detached
        # END for each head
        
        # detach
        active_head = heads[0]
        curhead_commit = active_head.commit
        cur_head.reference = curhead_commit
        assert cur_head.commit == curhead_commit
        assert cur_head.is_detached
        self.failUnlessRaises(TypeError, getattr, cur_head, "reference")
        
        # tags are references, hence we can point to them
        some_tag = rw_repo.tags[0]
        cur_head.reference = some_tag
        assert not cur_head.is_detached
        assert cur_head.commit == some_tag.commit
        assert isinstance(cur_head.reference, TagReference) 
        
        # put HEAD back to a real head, otherwise everything else fails
        cur_head.reference = active_head
        
        # 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(ValueError, setattr, head, 'commit', head_tree)
        assert head.commit == old_commit        # and the ref did not change
        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
        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
        
        # 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 as we have a changed a file
        # clear file
        open(new_head.commit.tree.blobs[-1].abspath,'w').close()
        assert len(new_head.commit.diff(None))
        
        # 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)
        assert rw_repo.head.reference != far_away_head
        
        # test reference creation
        partial_ref = 'sub/ref'
        full_ref = 'refs/%s' % partial_ref
        ref = Reference.create(rw_repo, partial_ref)
        assert ref.path == full_ref
        assert ref.object == rw_repo.head.commit
        
        self.failUnlessRaises(OSError, Reference.create, rw_repo, full_ref, 'HEAD~20')
        # it works if it is at the same spot though and points to the same reference
        assert Reference.create(rw_repo, full_ref, 'HEAD').path == full_ref
        Reference.delete(rw_repo, full_ref)
        
        # recreate the reference using a full_ref
        ref = Reference.create(rw_repo, full_ref)
        assert ref.path == full_ref
        assert ref.object == rw_repo.head.commit
        
        # recreate using force
        ref = Reference.create(rw_repo, partial_ref, 'HEAD~1', force=True)
        assert ref.path == full_ref
        assert ref.object == rw_repo.head.commit.parents[0]
        
        # rename it
        orig_obj = ref.object
        for name in ('refs/absname', 'rela_name', 'feature/rela_name'):
            ref_new_name = ref.rename(name)
            assert isinstance(ref_new_name, Reference)
            assert name in ref_new_name.path
            assert ref_new_name.object == orig_obj
            assert ref_new_name == ref
        # END for each name type
        
        # References that don't exist trigger an error if we want to access them
        self.failUnlessRaises(ValueError, getattr, Reference(rw_repo, "refs/doesntexist"), 'commit')
        
        # exists, fail unless we force
        ex_ref_path = far_away_head.path
        self.failUnlessRaises(OSError, ref.rename, ex_ref_path)
        # if it points to the same commit it works
        far_away_head.commit = ref.commit
        ref.rename(ex_ref_path)
        assert ref.path == ex_ref_path and ref.object == orig_obj
        assert ref.rename(ref.path).path == ex_ref_path # rename to same name
        
        # create symbolic refs
        symref_path = "symrefs/sym"
        symref = SymbolicReference.create(rw_repo, symref_path, cur_head.reference)
        assert symref.path == symref_path
        assert symref.reference == cur_head.reference
        
        self.failUnlessRaises(OSError, SymbolicReference.create, rw_repo, symref_path, cur_head.reference.commit)
        # it works if the new ref points to the same reference 
        SymbolicReference.create(rw_repo, symref.path, symref.reference).path == symref.path
        SymbolicReference.delete(rw_repo, symref)
        # would raise if the symref wouldn't have been deletedpbl
        symref = SymbolicReference.create(rw_repo, symref_path, cur_head.reference)
        
        # test symbolic references which are not at default locations like HEAD
        # or FETCH_HEAD - they may also be at spots in refs of course
        symbol_ref_path = "refs/symbol_ref"
        symref = SymbolicReference(rw_repo, symbol_ref_path)
        assert symref.path == symbol_ref_path
        symbol_ref_abspath = os.path.join(rw_repo.git_dir, symref.path)
        
        # set it
        symref.reference = new_head
        assert symref.reference == new_head
        assert os.path.isfile(symbol_ref_abspath)
        assert symref.commit == new_head.commit
        
        for name in ('absname','folder/rela_name'):
            symref_new_name = symref.rename(name)
            assert isinstance(symref_new_name, SymbolicReference)
            assert name in symref_new_name.path
            assert symref_new_name.reference == new_head
            assert symref_new_name == symref
            assert not symref.is_detached
        # END for each ref
        
        # create a new non-head ref just to be sure we handle it even if packed
        Reference.create(rw_repo, full_ref)
        
        # test ref listing - assure we have packed refs
        rw_repo.git.pack_refs(all=True, prune=True)
        heads = rw_repo.heads
        assert heads
        assert new_head in heads
        assert active_branch in heads
        assert rw_repo.tags
        
        # we should be able to iterate all symbolic refs as well - in that case
        # we should expect only symbolic references to be returned
        for symref in SymbolicReference.iter_items(rw_repo):
            assert not symref.is_detached
            
        # when iterating references, we can get references and symrefs
        # when deleting all refs, I'd expect them to be gone ! Even from 
        # the packed ones
        # For this to work, we must not be on any branch
        rw_repo.head.reference = rw_repo.head.commit
        deleted_refs = set()
        for ref in Reference.iter_items(rw_repo):
            if ref.is_detached:
                ref.delete(rw_repo, ref)
                deleted_refs.add(ref)
            # END delete ref
        # END for each ref to iterate and to delete
        assert deleted_refs
        
        for ref in Reference.iter_items(rw_repo):
            if ref.is_detached:
                assert ref not in deleted_refs
        # END for each ref
        
        # reattach head - head will not be returned if it is not a symbolic 
        # ref
        rw_repo.head.reference = Head.create(rw_repo, "master")
        
        # At least the head should still exist
        assert os.path.isfile(os.path.join(rw_repo.git_dir, 'HEAD'))
        refs = list(SymbolicReference.iter_items(rw_repo))
        assert len(refs) == 1



Web Proxy Viewer  |  New URL  |  Original Page