test_changesets.py
390 lines
| 14.4 KiB
| text/x-python
|
PythonLexer
|
r4187 | # encoding: utf8 | ||
import time | ||||
import datetime | ||||
|
r7045 | |||
|
r7046 | import pytest | ||
|
r7045 | |||
|
r4187 | from kallithea.lib import vcs | ||
from kallithea.lib.vcs.backends.base import BaseChangeset | ||||
from kallithea.lib.vcs.nodes import ( | ||||
FileNode, AddedFileNodesGenerator, | ||||
ChangedFileNodesGenerator, RemovedFileNodesGenerator | ||||
) | ||||
from kallithea.lib.vcs.exceptions import ( | ||||
BranchDoesNotExistError, ChangesetDoesNotExistError, | ||||
RepositoryError, EmptyRepositoryError | ||||
) | ||||
|
r7045 | |||
from kallithea.tests.vcs.base import _BackendTestMixin | ||||
from kallithea.tests.vcs.conf import SCM_TESTS, get_new_dir | ||||
|
r4187 | |||
|
r7046 | class TestBaseChangeset(object): | ||
|
r4187 | |||
def test_as_dict(self): | ||||
changeset = BaseChangeset() | ||||
changeset.id = 'ID' | ||||
changeset.raw_id = 'RAW_ID' | ||||
changeset.short_id = 'SHORT_ID' | ||||
changeset.revision = 1009 | ||||
changeset.date = datetime.datetime(2011, 1, 30, 1, 45) | ||||
changeset.message = 'Message of a commit' | ||||
changeset.author = 'Joe Doe <joe.doe@example.com>' | ||||
|
r6979 | changeset.added = [FileNode('foo/bar/baz'), FileNode(u'foobar'), FileNode(u'blåbærgrød')] | ||
|
r4187 | changeset.changed = [] | ||
changeset.removed = [] | ||||
|
r7046 | assert changeset.as_dict() == { | ||
|
r4187 | 'id': 'ID', | ||
'raw_id': 'RAW_ID', | ||||
'short_id': 'SHORT_ID', | ||||
'revision': 1009, | ||||
'date': datetime.datetime(2011, 1, 30, 1, 45), | ||||
'message': 'Message of a commit', | ||||
'author': { | ||||
'name': 'Joe Doe', | ||||
'email': 'joe.doe@example.com', | ||||
}, | ||||
|
r6979 | 'added': ['foo/bar/baz', 'foobar', u'bl\xe5b\xe6rgr\xf8d'], | ||
|
r4187 | 'changed': [], | ||
'removed': [], | ||||
|
r7046 | } | ||
|
r4187 | |||
|
r6789 | |||
|
r5051 | class _ChangesetsWithCommitsTestCaseixin(_BackendTestMixin): | ||
|
r4187 | recreate_repo_per_test = True | ||
@classmethod | ||||
def _get_commits(cls): | ||||
start_date = datetime.datetime(2010, 1, 1, 20) | ||||
for x in xrange(5): | ||||
yield { | ||||
'message': 'Commit %d' % x, | ||||
'author': 'Joe Doe <joe.doe@example.com>', | ||||
'date': start_date + datetime.timedelta(hours=12 * x), | ||||
'added': [ | ||||
FileNode('file_%d.txt' % x, content='Foobar %d' % x), | ||||
], | ||||
} | ||||
def test_new_branch(self): | ||||
self.imc.add(vcs.nodes.FileNode('docs/index.txt', | ||||
content='Documentation\n')) | ||||
foobar_tip = self.imc.commit( | ||||
message=u'New branch: foobar', | ||||
author=u'joe', | ||||
branch='foobar', | ||||
) | ||||
|
r7046 | assert 'foobar' in self.repo.branches | ||
assert foobar_tip.branch == 'foobar' | ||||
|
r4187 | # 'foobar' should be the only branch that contains the new commit | ||
|
r7051 | branch_tips = self.repo.branches.values() | ||
assert branch_tips.count(str(foobar_tip.raw_id)) == 1 | ||||
|
r4187 | |||
def test_new_head_in_default_branch(self): | ||||
tip = self.repo.get_changeset() | ||||
self.imc.add(vcs.nodes.FileNode('docs/index.txt', | ||||
content='Documentation\n')) | ||||
foobar_tip = self.imc.commit( | ||||
message=u'New branch: foobar', | ||||
author=u'joe', | ||||
branch='foobar', | ||||
parents=[tip], | ||||
) | ||||
self.imc.change(vcs.nodes.FileNode('docs/index.txt', | ||||
content='Documentation\nand more...\n')) | ||||
newtip = self.imc.commit( | ||||
message=u'At default branch', | ||||
author=u'joe', | ||||
branch=foobar_tip.branch, | ||||
parents=[foobar_tip], | ||||
) | ||||
newest_tip = self.imc.commit( | ||||
message=u'Merged with %s' % foobar_tip.raw_id, | ||||
author=u'joe', | ||||
branch=self.backend_class.DEFAULT_BRANCH_NAME, | ||||
parents=[newtip, foobar_tip], | ||||
) | ||||
|
r7046 | assert newest_tip.branch == self.backend_class.DEFAULT_BRANCH_NAME | ||
|
r4187 | |||
def test_get_changesets_respects_branch_name(self): | ||||
tip = self.repo.get_changeset() | ||||
self.imc.add(vcs.nodes.FileNode('docs/index.txt', | ||||
content='Documentation\n')) | ||||
doc_changeset = self.imc.commit( | ||||
message=u'New branch: docs', | ||||
author=u'joe', | ||||
branch='docs', | ||||
) | ||||
self.imc.add(vcs.nodes.FileNode('newfile', content='')) | ||||
self.imc.commit( | ||||
message=u'Back in default branch', | ||||
author=u'joe', | ||||
parents=[tip], | ||||
) | ||||
default_branch_changesets = self.repo.get_changesets( | ||||
branch_name=self.repo.DEFAULT_BRANCH_NAME) | ||||
|
r7046 | assert doc_changeset not in default_branch_changesets | ||
|
r4187 | |||
def test_get_changeset_by_branch(self): | ||||
for branch, sha in self.repo.branches.iteritems(): | ||||
|
r7046 | assert sha == self.repo.get_changeset(branch).raw_id | ||
|
r4187 | |||
def test_get_changeset_by_tag(self): | ||||
for tag, sha in self.repo.tags.iteritems(): | ||||
|
r7046 | assert sha == self.repo.get_changeset(tag).raw_id | ||
|
r4187 | |||
def test_get_changeset_parents(self): | ||||
for test_rev in [1, 2, 3]: | ||||
sha = self.repo.get_changeset(test_rev-1) | ||||
|
r7046 | assert [sha] == self.repo.get_changeset(test_rev).parents | ||
|
r4187 | |||
def test_get_changeset_children(self): | ||||
for test_rev in [1, 2, 3]: | ||||
sha = self.repo.get_changeset(test_rev+1) | ||||
|
r7046 | assert [sha] == self.repo.get_changeset(test_rev).children | ||
|
r4187 | |||
|
r5051 | class _ChangesetsTestCaseMixin(_BackendTestMixin): | ||
|
r4187 | recreate_repo_per_test = False | ||
@classmethod | ||||
def _get_commits(cls): | ||||
start_date = datetime.datetime(2010, 1, 1, 20) | ||||
for x in xrange(5): | ||||
yield { | ||||
'message': u'Commit %d' % x, | ||||
'author': u'Joe Doe <joe.doe@example.com>', | ||||
'date': start_date + datetime.timedelta(hours=12 * x), | ||||
'added': [ | ||||
FileNode('file_%d.txt' % x, content='Foobar %d' % x), | ||||
], | ||||
} | ||||
def test_simple(self): | ||||
tip = self.repo.get_changeset() | ||||
|
r7046 | assert tip.date == datetime.datetime(2010, 1, 3, 20) | ||
|
r4187 | |||
def test_get_changesets_is_ordered_by_date(self): | ||||
changesets = list(self.repo.get_changesets()) | ||||
ordered_by_date = sorted(changesets, | ||||
key=lambda cs: cs.date) | ||||
|
r7046 | |||
assert changesets == ordered_by_date | ||||
|
r4187 | |||
def test_get_changesets_respects_start(self): | ||||
second_id = self.repo.revisions[1] | ||||
changesets = list(self.repo.get_changesets(start=second_id)) | ||||
|
r7046 | assert len(changesets) == 4 | ||
|
r4187 | |||
def test_get_changesets_numerical_id_respects_start(self): | ||||
second_id = 1 | ||||
changesets = list(self.repo.get_changesets(start=second_id)) | ||||
|
r7046 | assert len(changesets) == 4 | ||
|
r4187 | |||
def test_get_changesets_includes_start_changeset(self): | ||||
second_id = self.repo.revisions[1] | ||||
changesets = list(self.repo.get_changesets(start=second_id)) | ||||
|
r7046 | assert changesets[0].raw_id == second_id | ||
|
r4187 | |||
def test_get_changesets_respects_end(self): | ||||
second_id = self.repo.revisions[1] | ||||
changesets = list(self.repo.get_changesets(end=second_id)) | ||||
|
r7046 | assert changesets[-1].raw_id == second_id | ||
assert len(changesets) == 2 | ||||
|
r4187 | |||
def test_get_changesets_numerical_id_respects_end(self): | ||||
second_id = 1 | ||||
changesets = list(self.repo.get_changesets(end=second_id)) | ||||
|
r7046 | assert changesets.index(changesets[-1]) == second_id | ||
assert len(changesets) == 2 | ||||
|
r4187 | |||
def test_get_changesets_respects_both_start_and_end(self): | ||||
second_id = self.repo.revisions[1] | ||||
third_id = self.repo.revisions[2] | ||||
changesets = list(self.repo.get_changesets(start=second_id, | ||||
end=third_id)) | ||||
|
r7046 | assert len(changesets) == 2 | ||
|
r4187 | |||
def test_get_changesets_numerical_id_respects_both_start_and_end(self): | ||||
changesets = list(self.repo.get_changesets(start=2, end=3)) | ||||
|
r7046 | assert len(changesets) == 2 | ||
|
r4187 | |||
def test_get_changesets_on_empty_repo_raises_EmptyRepository_error(self): | ||||
Backend = self.get_backend() | ||||
repo_path = get_new_dir(str(time.time())) | ||||
repo = Backend(repo_path, create=True) | ||||
|
r7046 | with pytest.raises(EmptyRepositoryError): | ||
|
r4187 | list(repo.get_changesets(start='foobar')) | ||
def test_get_changesets_includes_end_changeset(self): | ||||
second_id = self.repo.revisions[1] | ||||
changesets = list(self.repo.get_changesets(end=second_id)) | ||||
|
r7046 | assert changesets[-1].raw_id == second_id | ||
|
r4187 | |||
def test_get_changesets_respects_start_date(self): | ||||
start_date = datetime.datetime(2010, 2, 1) | ||||
for cs in self.repo.get_changesets(start_date=start_date): | ||||
|
r7046 | assert cs.date >= start_date | ||
|
r4187 | |||
def test_get_changesets_respects_end_date(self): | ||||
start_date = datetime.datetime(2010, 1, 1) | ||||
end_date = datetime.datetime(2010, 2, 1) | ||||
for cs in self.repo.get_changesets(start_date=start_date, | ||||
end_date=end_date): | ||||
|
r7046 | assert cs.date >= start_date | ||
assert cs.date <= end_date | ||||
|
r4187 | |||
def test_get_changesets_respects_start_date_and_end_date(self): | ||||
end_date = datetime.datetime(2010, 2, 1) | ||||
for cs in self.repo.get_changesets(end_date=end_date): | ||||
|
r7046 | assert cs.date <= end_date | ||
|
r4187 | |||
def test_get_changesets_respects_reverse(self): | ||||
changesets_id_list = [cs.raw_id for cs in | ||||
self.repo.get_changesets(reverse=True)] | ||||
|
r7046 | assert changesets_id_list == list(reversed(self.repo.revisions)) | ||
|
r4187 | |||
def test_get_filenodes_generator(self): | ||||
tip = self.repo.get_changeset() | ||||
filepaths = [node.path for node in tip.get_filenodes_generator()] | ||||
|
r7046 | assert filepaths == ['file_%d.txt' % x for x in xrange(5)] | ||
|
r4187 | |||
def test_size(self): | ||||
tip = self.repo.get_changeset() | ||||
size = 5 * len('Foobar N') # Size of 5 files | ||||
|
r7046 | assert tip.size == size | ||
|
r4187 | |||
def test_author(self): | ||||
tip = self.repo.get_changeset() | ||||
|
r7046 | assert tip.author == u'Joe Doe <joe.doe@example.com>' | ||
|
r4187 | |||
def test_author_name(self): | ||||
tip = self.repo.get_changeset() | ||||
|
r7046 | assert tip.author_name == u'Joe Doe' | ||
|
r4187 | |||
def test_author_email(self): | ||||
tip = self.repo.get_changeset() | ||||
|
r7046 | assert tip.author_email == u'joe.doe@example.com' | ||
|
r4187 | |||
def test_get_changesets_raise_changesetdoesnotexist_for_wrong_start(self): | ||||
|
r7046 | with pytest.raises(ChangesetDoesNotExistError): | ||
|
r4187 | list(self.repo.get_changesets(start='foobar')) | ||
def test_get_changesets_raise_changesetdoesnotexist_for_wrong_end(self): | ||||
|
r7046 | with pytest.raises(ChangesetDoesNotExistError): | ||
|
r4187 | list(self.repo.get_changesets(end='foobar')) | ||
def test_get_changesets_raise_branchdoesnotexist_for_wrong_branch_name(self): | ||||
|
r7046 | with pytest.raises(BranchDoesNotExistError): | ||
|
r4187 | list(self.repo.get_changesets(branch_name='foobar')) | ||
def test_get_changesets_raise_repositoryerror_for_wrong_start_end(self): | ||||
start = self.repo.revisions[-1] | ||||
end = self.repo.revisions[0] | ||||
|
r7046 | with pytest.raises(RepositoryError): | ||
|
r4187 | list(self.repo.get_changesets(start=start, end=end)) | ||
def test_get_changesets_numerical_id_reversed(self): | ||||
|
r7046 | with pytest.raises(RepositoryError): | ||
|
r4187 | [x for x in self.repo.get_changesets(start=3, end=2)] | ||
def test_get_changesets_numerical_id_respects_both_start_and_end_last(self): | ||||
|
r7046 | with pytest.raises(RepositoryError): | ||
|
r4187 | last = len(self.repo.revisions) | ||
list(self.repo.get_changesets(start=last-1, end=last-2)) | ||||
def test_get_changesets_numerical_id_last_zero_error(self): | ||||
|
r7046 | with pytest.raises(RepositoryError): | ||
|
r4187 | last = len(self.repo.revisions) | ||
list(self.repo.get_changesets(start=last-1, end=0)) | ||||
|
r5051 | class _ChangesetsChangesTestCaseMixin(_BackendTestMixin): | ||
|
r4187 | recreate_repo_per_test = False | ||
@classmethod | ||||
def _get_commits(cls): | ||||
return [ | ||||
{ | ||||
'message': u'Initial', | ||||
'author': u'Joe Doe <joe.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 20), | ||||
'added': [ | ||||
FileNode('foo/bar', content='foo'), | ||||
FileNode('foo/bał', content='foo'), | ||||
FileNode('foobar', content='foo'), | ||||
FileNode('qwe', content='foo'), | ||||
], | ||||
}, | ||||
{ | ||||
'message': u'Massive changes', | ||||
'author': u'Joe Doe <joe.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 22), | ||||
'added': [FileNode('fallout', content='War never changes')], | ||||
'changed': [ | ||||
FileNode('foo/bar', content='baz'), | ||||
FileNode('foobar', content='baz'), | ||||
], | ||||
'removed': [FileNode('qwe')], | ||||
}, | ||||
] | ||||
def test_initial_commit(self): | ||||
changeset = self.repo.get_changeset(0) | ||||
|
r7046 | assert sorted(list(changeset.added)) == sorted([ | ||
|
r4187 | changeset.get_node('foo/bar'), | ||
changeset.get_node('foo/bał'), | ||||
changeset.get_node('foobar'), | ||||
changeset.get_node('qwe'), | ||||
]) | ||||
|
r7046 | assert list(changeset.changed) == [] | ||
assert list(changeset.removed) == [] | ||||
|
r6979 | assert u'foo/ba\u0142' in changeset.as_dict()['added'] | ||
assert u'foo/ba\u0142' in changeset.__json__(with_file_list=True)['added'] | ||||
|
r4187 | |||
def test_head_added(self): | ||||
changeset = self.repo.get_changeset() | ||||
|
r7046 | assert isinstance(changeset.added, AddedFileNodesGenerator) | ||
assert list(changeset.added) == [ | ||||
|
r4187 | changeset.get_node('fallout'), | ||
|
r7046 | ] | ||
assert isinstance(changeset.changed, ChangedFileNodesGenerator) | ||||
assert list(changeset.changed) == [ | ||||
|
r4187 | changeset.get_node('foo/bar'), | ||
changeset.get_node('foobar'), | ||||
|
r7046 | ] | ||
assert isinstance(changeset.removed, RemovedFileNodesGenerator) | ||||
assert len(changeset.removed) == 1 | ||||
assert list(changeset.removed)[0].path == 'qwe' | ||||
|
r4187 | |||
def test_get_filemode(self): | ||||
changeset = self.repo.get_changeset() | ||||
|
r7046 | assert 33188 == changeset.get_file_mode('foo/bar') | ||
|
r4187 | |||
def test_get_filemode_non_ascii(self): | ||||
changeset = self.repo.get_changeset() | ||||
|
r7046 | assert 33188 == changeset.get_file_mode('foo/bał') | ||
assert 33188 == changeset.get_file_mode(u'foo/bał') | ||||
|
r4187 | |||
|
r6789 | |||
|
r4187 | # For each backend create test case class | ||
for alias in SCM_TESTS: | ||||
attrs = { | ||||
'backend_alias': alias, | ||||
} | ||||
# tests with additional commits | ||||
|
r7046 | cls_name = 'Test' + alias.title() + 'ChangesetsWithCommits' | ||
globals()[cls_name] = type(cls_name, (_ChangesetsWithCommitsTestCaseixin,), attrs) | ||||
|
r4187 | |||
# tests without additional commits | ||||
|
r7046 | cls_name = 'Test' + alias.title() + 'Changesets' | ||
globals()[cls_name] = type(cls_name, (_ChangesetsTestCaseMixin,), attrs) | ||||
|
r4187 | |||
# tests changes | ||||
|
r7046 | cls_name = 'Test' + alias.title() + 'ChangesetsChanges' | ||
globals()[cls_name] = type(cls_name, (_ChangesetsChangesTestCaseMixin,), attrs) | ||||