##// END OF EJS Templates
codingstyle: rename variable "hex" (conflicting with builtin)
Lars Kruse -
r6795:20f32aeb default
parent child Browse files
Show More
@@ -1,851 +1,851 b''
1
1
2 import os
2 import os
3 import sys
3 import sys
4 import mock
4 import mock
5 import datetime
5 import datetime
6 import urllib2
6 import urllib2
7
7
8 import pytest
8 import pytest
9
9
10 from kallithea.lib.vcs.backends.git import GitRepository, GitChangeset
10 from kallithea.lib.vcs.backends.git import GitRepository, GitChangeset
11 from kallithea.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
11 from kallithea.lib.vcs.exceptions import RepositoryError, VCSError, NodeDoesNotExistError
12 from kallithea.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState
12 from kallithea.lib.vcs.nodes import NodeKind, FileNode, DirNode, NodeState
13 from kallithea.lib.vcs.utils.compat import unittest
13 from kallithea.lib.vcs.utils.compat import unittest
14 from kallithea.model.scm import ScmModel
14 from kallithea.model.scm import ScmModel
15 from kallithea.tests.vcs.base import _BackendTestMixin
15 from kallithea.tests.vcs.base import _BackendTestMixin
16 from kallithea.tests.vcs.conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, TEST_TMP_PATH, get_new_dir
16 from kallithea.tests.vcs.conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, TEST_TMP_PATH, get_new_dir
17
17
18
18
19 class GitRepositoryTest(unittest.TestCase):
19 class GitRepositoryTest(unittest.TestCase):
20
20
21 def __check_for_existing_repo(self):
21 def __check_for_existing_repo(self):
22 if os.path.exists(TEST_GIT_REPO_CLONE):
22 if os.path.exists(TEST_GIT_REPO_CLONE):
23 pytest.fail('Cannot test git clone repo as location %s already '
23 pytest.fail('Cannot test git clone repo as location %s already '
24 'exists. You should manually remove it first.'
24 'exists. You should manually remove it first.'
25 % TEST_GIT_REPO_CLONE)
25 % TEST_GIT_REPO_CLONE)
26
26
27 def setUp(self):
27 def setUp(self):
28 self.repo = GitRepository(TEST_GIT_REPO)
28 self.repo = GitRepository(TEST_GIT_REPO)
29
29
30 def test_wrong_repo_path(self):
30 def test_wrong_repo_path(self):
31 wrong_repo_path = os.path.join(TEST_TMP_PATH, 'errorrepo')
31 wrong_repo_path = os.path.join(TEST_TMP_PATH, 'errorrepo')
32 self.assertRaises(RepositoryError, GitRepository, wrong_repo_path)
32 self.assertRaises(RepositoryError, GitRepository, wrong_repo_path)
33
33
34 def test_git_cmd_injection(self):
34 def test_git_cmd_injection(self):
35 repo_inject_path = TEST_GIT_REPO + '; echo "Cake";'
35 repo_inject_path = TEST_GIT_REPO + '; echo "Cake";'
36 with self.assertRaises(urllib2.URLError):
36 with self.assertRaises(urllib2.URLError):
37 # Should fail because URL will contain the parts after ; too
37 # Should fail because URL will contain the parts after ; too
38 urlerror_fail_repo = GitRepository(get_new_dir('injection-repo'), src_url=repo_inject_path, update_after_clone=True, create=True)
38 urlerror_fail_repo = GitRepository(get_new_dir('injection-repo'), src_url=repo_inject_path, update_after_clone=True, create=True)
39
39
40 with self.assertRaises(RepositoryError):
40 with self.assertRaises(RepositoryError):
41 # Should fail on direct clone call, which as of this writing does not happen outside of class
41 # Should fail on direct clone call, which as of this writing does not happen outside of class
42 clone_fail_repo = GitRepository(get_new_dir('injection-repo'), create=True)
42 clone_fail_repo = GitRepository(get_new_dir('injection-repo'), create=True)
43 clone_fail_repo.clone(repo_inject_path, update_after_clone=True,)
43 clone_fail_repo.clone(repo_inject_path, update_after_clone=True,)
44
44
45 # Verify correct quoting of evil characters that should work on posix file systems
45 # Verify correct quoting of evil characters that should work on posix file systems
46 if sys.platform == 'win32':
46 if sys.platform == 'win32':
47 # windows does not allow '"' in dir names
47 # windows does not allow '"' in dir names
48 # and some versions of the git client don't like ` and '
48 # and some versions of the git client don't like ` and '
49 tricky_path = get_new_dir("tricky-path-repo-$")
49 tricky_path = get_new_dir("tricky-path-repo-$")
50 else:
50 else:
51 tricky_path = get_new_dir("tricky-path-repo-$'\"`")
51 tricky_path = get_new_dir("tricky-path-repo-$'\"`")
52 successfully_cloned = GitRepository(tricky_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
52 successfully_cloned = GitRepository(tricky_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
53 # Repo should have been created
53 # Repo should have been created
54 self.assertFalse(successfully_cloned._repo.bare)
54 self.assertFalse(successfully_cloned._repo.bare)
55
55
56 if sys.platform == 'win32':
56 if sys.platform == 'win32':
57 # windows does not allow '"' in dir names
57 # windows does not allow '"' in dir names
58 # and some versions of the git client don't like ` and '
58 # and some versions of the git client don't like ` and '
59 tricky_path_2 = get_new_dir("tricky-path-2-repo-$")
59 tricky_path_2 = get_new_dir("tricky-path-2-repo-$")
60 else:
60 else:
61 tricky_path_2 = get_new_dir("tricky-path-2-repo-$'\"`")
61 tricky_path_2 = get_new_dir("tricky-path-2-repo-$'\"`")
62 successfully_cloned2 = GitRepository(tricky_path_2, src_url=tricky_path, bare=True, create=True)
62 successfully_cloned2 = GitRepository(tricky_path_2, src_url=tricky_path, bare=True, create=True)
63 # Repo should have been created and thus used correct quoting for clone
63 # Repo should have been created and thus used correct quoting for clone
64 self.assertTrue(successfully_cloned2._repo.bare)
64 self.assertTrue(successfully_cloned2._repo.bare)
65
65
66 # Should pass because URL has been properly quoted
66 # Should pass because URL has been properly quoted
67 successfully_cloned.pull(tricky_path_2)
67 successfully_cloned.pull(tricky_path_2)
68 successfully_cloned2.fetch(tricky_path)
68 successfully_cloned2.fetch(tricky_path)
69
69
70 def test_repo_create_with_spaces_in_path(self):
70 def test_repo_create_with_spaces_in_path(self):
71 repo_path = get_new_dir("path with spaces")
71 repo_path = get_new_dir("path with spaces")
72 repo = GitRepository(repo_path, src_url=None, bare=True, create=True)
72 repo = GitRepository(repo_path, src_url=None, bare=True, create=True)
73 # Repo should have been created
73 # Repo should have been created
74 self.assertTrue(repo._repo.bare)
74 self.assertTrue(repo._repo.bare)
75
75
76 def test_repo_clone(self):
76 def test_repo_clone(self):
77 self.__check_for_existing_repo()
77 self.__check_for_existing_repo()
78 repo = GitRepository(TEST_GIT_REPO)
78 repo = GitRepository(TEST_GIT_REPO)
79 repo_clone = GitRepository(TEST_GIT_REPO_CLONE,
79 repo_clone = GitRepository(TEST_GIT_REPO_CLONE,
80 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
80 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
81 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
81 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
82 # Checking hashes of changesets should be enough
82 # Checking hashes of changesets should be enough
83 for changeset in repo.get_changesets():
83 for changeset in repo.get_changesets():
84 raw_id = changeset.raw_id
84 raw_id = changeset.raw_id
85 self.assertEqual(raw_id, repo_clone.get_changeset(raw_id).raw_id)
85 self.assertEqual(raw_id, repo_clone.get_changeset(raw_id).raw_id)
86
86
87 def test_repo_clone_with_spaces_in_path(self):
87 def test_repo_clone_with_spaces_in_path(self):
88 repo_path = get_new_dir("path with spaces")
88 repo_path = get_new_dir("path with spaces")
89 successfully_cloned = GitRepository(repo_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
89 successfully_cloned = GitRepository(repo_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
90 # Repo should have been created
90 # Repo should have been created
91 self.assertFalse(successfully_cloned._repo.bare)
91 self.assertFalse(successfully_cloned._repo.bare)
92
92
93 successfully_cloned.pull(TEST_GIT_REPO)
93 successfully_cloned.pull(TEST_GIT_REPO)
94 self.repo.fetch(repo_path)
94 self.repo.fetch(repo_path)
95
95
96 def test_repo_clone_without_create(self):
96 def test_repo_clone_without_create(self):
97 self.assertRaises(RepositoryError, GitRepository,
97 self.assertRaises(RepositoryError, GitRepository,
98 TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
98 TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
99
99
100 def test_repo_clone_with_update(self):
100 def test_repo_clone_with_update(self):
101 repo = GitRepository(TEST_GIT_REPO)
101 repo = GitRepository(TEST_GIT_REPO)
102 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
102 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
103 repo_clone = GitRepository(clone_path,
103 repo_clone = GitRepository(clone_path,
104 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
104 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
105 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
105 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
106
106
107 # check if current workdir was updated
107 # check if current workdir was updated
108 fpath = os.path.join(clone_path, 'MANIFEST.in')
108 fpath = os.path.join(clone_path, 'MANIFEST.in')
109 self.assertEqual(True, os.path.isfile(fpath),
109 self.assertEqual(True, os.path.isfile(fpath),
110 'Repo was cloned and updated but file %s could not be found'
110 'Repo was cloned and updated but file %s could not be found'
111 % fpath)
111 % fpath)
112
112
113 def test_repo_clone_without_update(self):
113 def test_repo_clone_without_update(self):
114 repo = GitRepository(TEST_GIT_REPO)
114 repo = GitRepository(TEST_GIT_REPO)
115 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
115 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
116 repo_clone = GitRepository(clone_path,
116 repo_clone = GitRepository(clone_path,
117 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
117 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
118 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
118 self.assertEqual(len(repo.revisions), len(repo_clone.revisions))
119 # check if current workdir was *NOT* updated
119 # check if current workdir was *NOT* updated
120 fpath = os.path.join(clone_path, 'MANIFEST.in')
120 fpath = os.path.join(clone_path, 'MANIFEST.in')
121 # Make sure it's not bare repo
121 # Make sure it's not bare repo
122 self.assertFalse(repo_clone._repo.bare)
122 self.assertFalse(repo_clone._repo.bare)
123 self.assertEqual(False, os.path.isfile(fpath),
123 self.assertEqual(False, os.path.isfile(fpath),
124 'Repo was cloned and updated but file %s was found'
124 'Repo was cloned and updated but file %s was found'
125 % fpath)
125 % fpath)
126
126
127 def test_repo_clone_into_bare_repo(self):
127 def test_repo_clone_into_bare_repo(self):
128 repo = GitRepository(TEST_GIT_REPO)
128 repo = GitRepository(TEST_GIT_REPO)
129 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
129 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
130 repo_clone = GitRepository(clone_path, create=True,
130 repo_clone = GitRepository(clone_path, create=True,
131 src_url=repo.path, bare=True)
131 src_url=repo.path, bare=True)
132 self.assertTrue(repo_clone._repo.bare)
132 self.assertTrue(repo_clone._repo.bare)
133
133
134 def test_create_repo_is_not_bare_by_default(self):
134 def test_create_repo_is_not_bare_by_default(self):
135 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
135 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
136 self.assertFalse(repo._repo.bare)
136 self.assertFalse(repo._repo.bare)
137
137
138 def test_create_bare_repo(self):
138 def test_create_bare_repo(self):
139 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
139 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
140 self.assertTrue(repo._repo.bare)
140 self.assertTrue(repo._repo.bare)
141
141
142 def test_revisions(self):
142 def test_revisions(self):
143 # there are 112 revisions (by now)
143 # there are 112 revisions (by now)
144 # so we can assume they would be available from now on
144 # so we can assume they would be available from now on
145 subset = set([
145 subset = set([
146 'c1214f7e79e02fc37156ff215cd71275450cffc3',
146 'c1214f7e79e02fc37156ff215cd71275450cffc3',
147 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
147 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
148 'fa6600f6848800641328adbf7811fd2372c02ab2',
148 'fa6600f6848800641328adbf7811fd2372c02ab2',
149 '102607b09cdd60e2793929c4f90478be29f85a17',
149 '102607b09cdd60e2793929c4f90478be29f85a17',
150 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
150 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
151 '2d1028c054665b962fa3d307adfc923ddd528038',
151 '2d1028c054665b962fa3d307adfc923ddd528038',
152 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
152 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
153 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
153 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
154 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
154 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
155 '8430a588b43b5d6da365400117c89400326e7992',
155 '8430a588b43b5d6da365400117c89400326e7992',
156 'd955cd312c17b02143c04fa1099a352b04368118',
156 'd955cd312c17b02143c04fa1099a352b04368118',
157 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
157 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
158 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
158 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
159 'f298fe1189f1b69779a4423f40b48edf92a703fc',
159 'f298fe1189f1b69779a4423f40b48edf92a703fc',
160 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
160 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
161 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
161 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
162 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
162 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
163 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
163 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
164 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
164 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
165 '45223f8f114c64bf4d6f853e3c35a369a6305520',
165 '45223f8f114c64bf4d6f853e3c35a369a6305520',
166 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
166 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
167 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
167 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
168 '27d48942240f5b91dfda77accd2caac94708cc7d',
168 '27d48942240f5b91dfda77accd2caac94708cc7d',
169 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
169 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
170 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
170 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
171 self.assertTrue(subset.issubset(set(self.repo.revisions)))
171 self.assertTrue(subset.issubset(set(self.repo.revisions)))
172
172
173 def test_slicing(self):
173 def test_slicing(self):
174 # 4 1 5 10 95
174 # 4 1 5 10 95
175 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
175 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
176 (10, 20, 10), (5, 100, 95)]:
176 (10, 20, 10), (5, 100, 95)]:
177 revs = list(self.repo[sfrom:sto])
177 revs = list(self.repo[sfrom:sto])
178 self.assertEqual(len(revs), size)
178 self.assertEqual(len(revs), size)
179 self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
179 self.assertEqual(revs[0], self.repo.get_changeset(sfrom))
180 self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
180 self.assertEqual(revs[-1], self.repo.get_changeset(sto - 1))
181
181
182 def test_branches(self):
182 def test_branches(self):
183 # TODO: Need more tests here
183 # TODO: Need more tests here
184 # Removed (those are 'remotes' branches for cloned repo)
184 # Removed (those are 'remotes' branches for cloned repo)
185 #self.assertTrue('master' in self.repo.branches)
185 #self.assertTrue('master' in self.repo.branches)
186 #self.assertTrue('gittree' in self.repo.branches)
186 #self.assertTrue('gittree' in self.repo.branches)
187 #self.assertTrue('web-branch' in self.repo.branches)
187 #self.assertTrue('web-branch' in self.repo.branches)
188 for name, id in self.repo.branches.items():
188 for name, id in self.repo.branches.items():
189 self.assertTrue(isinstance(
189 self.assertTrue(isinstance(
190 self.repo.get_changeset(id), GitChangeset))
190 self.repo.get_changeset(id), GitChangeset))
191
191
192 def test_tags(self):
192 def test_tags(self):
193 # TODO: Need more tests here
193 # TODO: Need more tests here
194 self.assertTrue('v0.1.1' in self.repo.tags)
194 self.assertTrue('v0.1.1' in self.repo.tags)
195 self.assertTrue('v0.1.2' in self.repo.tags)
195 self.assertTrue('v0.1.2' in self.repo.tags)
196 for name, id in self.repo.tags.items():
196 for name, id in self.repo.tags.items():
197 self.assertTrue(isinstance(
197 self.assertTrue(isinstance(
198 self.repo.get_changeset(id), GitChangeset))
198 self.repo.get_changeset(id), GitChangeset))
199
199
200 def _test_single_changeset_cache(self, revision):
200 def _test_single_changeset_cache(self, revision):
201 chset = self.repo.get_changeset(revision)
201 chset = self.repo.get_changeset(revision)
202 self.assertTrue(revision in self.repo.changesets)
202 self.assertTrue(revision in self.repo.changesets)
203 self.assertTrue(chset is self.repo.changesets[revision])
203 self.assertTrue(chset is self.repo.changesets[revision])
204
204
205 def test_initial_changeset(self):
205 def test_initial_changeset(self):
206 id = self.repo.revisions[0]
206 id = self.repo.revisions[0]
207 init_chset = self.repo.get_changeset(id)
207 init_chset = self.repo.get_changeset(id)
208 self.assertEqual(init_chset.message, 'initial import\n')
208 self.assertEqual(init_chset.message, 'initial import\n')
209 self.assertEqual(init_chset.author,
209 self.assertEqual(init_chset.author,
210 'Marcin Kuzminski <marcin@python-blog.com>')
210 'Marcin Kuzminski <marcin@python-blog.com>')
211 for path in ('vcs/__init__.py',
211 for path in ('vcs/__init__.py',
212 'vcs/backends/BaseRepository.py',
212 'vcs/backends/BaseRepository.py',
213 'vcs/backends/__init__.py'):
213 'vcs/backends/__init__.py'):
214 self.assertTrue(isinstance(init_chset.get_node(path), FileNode))
214 self.assertTrue(isinstance(init_chset.get_node(path), FileNode))
215 for path in ('', 'vcs', 'vcs/backends'):
215 for path in ('', 'vcs', 'vcs/backends'):
216 self.assertTrue(isinstance(init_chset.get_node(path), DirNode))
216 self.assertTrue(isinstance(init_chset.get_node(path), DirNode))
217
217
218 self.assertRaises(NodeDoesNotExistError, init_chset.get_node, path='foobar')
218 self.assertRaises(NodeDoesNotExistError, init_chset.get_node, path='foobar')
219
219
220 node = init_chset.get_node('vcs/')
220 node = init_chset.get_node('vcs/')
221 self.assertTrue(hasattr(node, 'kind'))
221 self.assertTrue(hasattr(node, 'kind'))
222 self.assertEqual(node.kind, NodeKind.DIR)
222 self.assertEqual(node.kind, NodeKind.DIR)
223
223
224 node = init_chset.get_node('vcs')
224 node = init_chset.get_node('vcs')
225 self.assertTrue(hasattr(node, 'kind'))
225 self.assertTrue(hasattr(node, 'kind'))
226 self.assertEqual(node.kind, NodeKind.DIR)
226 self.assertEqual(node.kind, NodeKind.DIR)
227
227
228 node = init_chset.get_node('vcs/__init__.py')
228 node = init_chset.get_node('vcs/__init__.py')
229 self.assertTrue(hasattr(node, 'kind'))
229 self.assertTrue(hasattr(node, 'kind'))
230 self.assertEqual(node.kind, NodeKind.FILE)
230 self.assertEqual(node.kind, NodeKind.FILE)
231
231
232 def test_not_existing_changeset(self):
232 def test_not_existing_changeset(self):
233 self.assertRaises(RepositoryError, self.repo.get_changeset,
233 self.assertRaises(RepositoryError, self.repo.get_changeset,
234 'f' * 40)
234 'f' * 40)
235
235
236 def test_changeset10(self):
236 def test_changeset10(self):
237
237
238 chset10 = self.repo.get_changeset(self.repo.revisions[9])
238 chset10 = self.repo.get_changeset(self.repo.revisions[9])
239 readme = """===
239 readme = """===
240 VCS
240 VCS
241 ===
241 ===
242
242
243 Various Version Control System management abstraction layer for Python.
243 Various Version Control System management abstraction layer for Python.
244
244
245 Introduction
245 Introduction
246 ------------
246 ------------
247
247
248 TODO: To be written...
248 TODO: To be written...
249
249
250 """
250 """
251 node = chset10.get_node('README.rst')
251 node = chset10.get_node('README.rst')
252 self.assertEqual(node.kind, NodeKind.FILE)
252 self.assertEqual(node.kind, NodeKind.FILE)
253 self.assertEqual(node.content, readme)
253 self.assertEqual(node.content, readme)
254
254
255
255
256 class GitChangesetTest(unittest.TestCase):
256 class GitChangesetTest(unittest.TestCase):
257
257
258 def setUp(self):
258 def setUp(self):
259 self.repo = GitRepository(TEST_GIT_REPO)
259 self.repo = GitRepository(TEST_GIT_REPO)
260
260
261 def test_default_changeset(self):
261 def test_default_changeset(self):
262 tip = self.repo.get_changeset()
262 tip = self.repo.get_changeset()
263 self.assertEqual(tip, self.repo.get_changeset(None))
263 self.assertEqual(tip, self.repo.get_changeset(None))
264 self.assertEqual(tip, self.repo.get_changeset('tip'))
264 self.assertEqual(tip, self.repo.get_changeset('tip'))
265
265
266 def test_root_node(self):
266 def test_root_node(self):
267 tip = self.repo.get_changeset()
267 tip = self.repo.get_changeset()
268 self.assertTrue(tip.root is tip.get_node(''))
268 self.assertTrue(tip.root is tip.get_node(''))
269
269
270 def test_lazy_fetch(self):
270 def test_lazy_fetch(self):
271 """
271 """
272 Test if changeset's nodes expands and are cached as we walk through
272 Test if changeset's nodes expands and are cached as we walk through
273 the revision. This test is somewhat hard to write as order of tests
273 the revision. This test is somewhat hard to write as order of tests
274 is a key here. Written by running command after command in a shell.
274 is a key here. Written by running command after command in a shell.
275 """
275 """
276 hex = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
276 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
277 self.assertTrue(hex in self.repo.revisions)
277 self.assertTrue(commit_id in self.repo.revisions)
278 chset = self.repo.get_changeset(hex)
278 chset = self.repo.get_changeset(commit_id)
279 self.assertTrue(len(chset.nodes) == 0)
279 self.assertTrue(len(chset.nodes) == 0)
280 root = chset.root
280 root = chset.root
281 self.assertTrue(len(chset.nodes) == 1)
281 self.assertTrue(len(chset.nodes) == 1)
282 self.assertTrue(len(root.nodes) == 8)
282 self.assertTrue(len(root.nodes) == 8)
283 # accessing root.nodes updates chset.nodes
283 # accessing root.nodes updates chset.nodes
284 self.assertTrue(len(chset.nodes) == 9)
284 self.assertTrue(len(chset.nodes) == 9)
285
285
286 docs = root.get_node('docs')
286 docs = root.get_node('docs')
287 # we haven't yet accessed anything new as docs dir was already cached
287 # we haven't yet accessed anything new as docs dir was already cached
288 self.assertTrue(len(chset.nodes) == 9)
288 self.assertTrue(len(chset.nodes) == 9)
289 self.assertTrue(len(docs.nodes) == 8)
289 self.assertTrue(len(docs.nodes) == 8)
290 # accessing docs.nodes updates chset.nodes
290 # accessing docs.nodes updates chset.nodes
291 self.assertTrue(len(chset.nodes) == 17)
291 self.assertTrue(len(chset.nodes) == 17)
292
292
293 self.assertTrue(docs is chset.get_node('docs'))
293 self.assertTrue(docs is chset.get_node('docs'))
294 self.assertTrue(docs is root.nodes[0])
294 self.assertTrue(docs is root.nodes[0])
295 self.assertTrue(docs is root.dirs[0])
295 self.assertTrue(docs is root.dirs[0])
296 self.assertTrue(docs is chset.get_node('docs'))
296 self.assertTrue(docs is chset.get_node('docs'))
297
297
298 def test_nodes_with_changeset(self):
298 def test_nodes_with_changeset(self):
299 hex = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
299 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
300 chset = self.repo.get_changeset(hex)
300 chset = self.repo.get_changeset(commit_id)
301 root = chset.root
301 root = chset.root
302 docs = root.get_node('docs')
302 docs = root.get_node('docs')
303 self.assertTrue(docs is chset.get_node('docs'))
303 self.assertTrue(docs is chset.get_node('docs'))
304 api = docs.get_node('api')
304 api = docs.get_node('api')
305 self.assertTrue(api is chset.get_node('docs/api'))
305 self.assertTrue(api is chset.get_node('docs/api'))
306 index = api.get_node('index.rst')
306 index = api.get_node('index.rst')
307 self.assertTrue(index is chset.get_node('docs/api/index.rst'))
307 self.assertTrue(index is chset.get_node('docs/api/index.rst'))
308 self.assertTrue(index is chset.get_node('docs') \
308 self.assertTrue(index is chset.get_node('docs') \
309 .get_node('api') \
309 .get_node('api') \
310 .get_node('index.rst'))
310 .get_node('index.rst'))
311
311
312 def test_branch_and_tags(self):
312 def test_branch_and_tags(self):
313 """
313 """
314 rev0 = self.repo.revisions[0]
314 rev0 = self.repo.revisions[0]
315 chset0 = self.repo.get_changeset(rev0)
315 chset0 = self.repo.get_changeset(rev0)
316 self.assertEqual(chset0.branch, 'master')
316 self.assertEqual(chset0.branch, 'master')
317 self.assertEqual(chset0.tags, [])
317 self.assertEqual(chset0.tags, [])
318
318
319 rev10 = self.repo.revisions[10]
319 rev10 = self.repo.revisions[10]
320 chset10 = self.repo.get_changeset(rev10)
320 chset10 = self.repo.get_changeset(rev10)
321 self.assertEqual(chset10.branch, 'master')
321 self.assertEqual(chset10.branch, 'master')
322 self.assertEqual(chset10.tags, [])
322 self.assertEqual(chset10.tags, [])
323
323
324 rev44 = self.repo.revisions[44]
324 rev44 = self.repo.revisions[44]
325 chset44 = self.repo.get_changeset(rev44)
325 chset44 = self.repo.get_changeset(rev44)
326 self.assertEqual(chset44.branch, 'web-branch')
326 self.assertEqual(chset44.branch, 'web-branch')
327
327
328 tip = self.repo.get_changeset('tip')
328 tip = self.repo.get_changeset('tip')
329 self.assertTrue('tip' in tip.tags)
329 self.assertTrue('tip' in tip.tags)
330 """
330 """
331 # Those tests would fail - branches are now going
331 # Those tests would fail - branches are now going
332 # to be changed at main API in order to support git backend
332 # to be changed at main API in order to support git backend
333 pass
333 pass
334
334
335 def _test_slices(self, limit, offset):
335 def _test_slices(self, limit, offset):
336 count = self.repo.count()
336 count = self.repo.count()
337 changesets = self.repo.get_changesets(limit=limit, offset=offset)
337 changesets = self.repo.get_changesets(limit=limit, offset=offset)
338 idx = 0
338 idx = 0
339 for changeset in changesets:
339 for changeset in changesets:
340 rev = offset + idx
340 rev = offset + idx
341 idx += 1
341 idx += 1
342 rev_id = self.repo.revisions[rev]
342 rev_id = self.repo.revisions[rev]
343 if idx > limit:
343 if idx > limit:
344 pytest.fail("Exceeded limit already (getting revision %s, "
344 pytest.fail("Exceeded limit already (getting revision %s, "
345 "there are %s total revisions, offset=%s, limit=%s)"
345 "there are %s total revisions, offset=%s, limit=%s)"
346 % (rev_id, count, offset, limit))
346 % (rev_id, count, offset, limit))
347 self.assertEqual(changeset, self.repo.get_changeset(rev_id))
347 self.assertEqual(changeset, self.repo.get_changeset(rev_id))
348 result = list(self.repo.get_changesets(limit=limit, offset=offset))
348 result = list(self.repo.get_changesets(limit=limit, offset=offset))
349 start = offset
349 start = offset
350 end = limit and offset + limit or None
350 end = limit and offset + limit or None
351 sliced = list(self.repo[start:end])
351 sliced = list(self.repo[start:end])
352 pytest.failUnlessEqual(result, sliced,
352 pytest.failUnlessEqual(result, sliced,
353 msg="Comparison failed for limit=%s, offset=%s"
353 msg="Comparison failed for limit=%s, offset=%s"
354 "(get_changeset returned: %s and sliced: %s"
354 "(get_changeset returned: %s and sliced: %s"
355 % (limit, offset, result, sliced))
355 % (limit, offset, result, sliced))
356
356
357 def _test_file_size(self, revision, path, size):
357 def _test_file_size(self, revision, path, size):
358 node = self.repo.get_changeset(revision).get_node(path)
358 node = self.repo.get_changeset(revision).get_node(path)
359 self.assertTrue(node.is_file())
359 self.assertTrue(node.is_file())
360 self.assertEqual(node.size, size)
360 self.assertEqual(node.size, size)
361
361
362 def test_file_size(self):
362 def test_file_size(self):
363 to_check = (
363 to_check = (
364 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
364 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
365 'vcs/backends/BaseRepository.py', 502),
365 'vcs/backends/BaseRepository.py', 502),
366 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
366 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
367 'vcs/backends/hg.py', 854),
367 'vcs/backends/hg.py', 854),
368 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
368 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
369 'setup.py', 1068),
369 'setup.py', 1068),
370 ('d955cd312c17b02143c04fa1099a352b04368118',
370 ('d955cd312c17b02143c04fa1099a352b04368118',
371 'vcs/backends/base.py', 2921),
371 'vcs/backends/base.py', 2921),
372 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
372 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
373 'vcs/backends/base.py', 3936),
373 'vcs/backends/base.py', 3936),
374 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
374 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
375 'vcs/backends/base.py', 6189),
375 'vcs/backends/base.py', 6189),
376 )
376 )
377 for revision, path, size in to_check:
377 for revision, path, size in to_check:
378 self._test_file_size(revision, path, size)
378 self._test_file_size(revision, path, size)
379
379
380 def _test_dir_size(self, revision, path, size):
380 def _test_dir_size(self, revision, path, size):
381 node = self.repo.get_changeset(revision).get_node(path)
381 node = self.repo.get_changeset(revision).get_node(path)
382 self.assertEqual(node.size, size)
382 self.assertEqual(node.size, size)
383
383
384 def test_dir_size(self):
384 def test_dir_size(self):
385 to_check = (
385 to_check = (
386 ('5f2c6ee195929b0be80749243c18121c9864a3b3', '/', 674076),
386 ('5f2c6ee195929b0be80749243c18121c9864a3b3', '/', 674076),
387 ('7ab37bc680b4aa72c34d07b230c866c28e9fc204', '/', 674049),
387 ('7ab37bc680b4aa72c34d07b230c866c28e9fc204', '/', 674049),
388 ('6892503fb8f2a552cef5f4d4cc2cdbd13ae1cd2f', '/', 671830),
388 ('6892503fb8f2a552cef5f4d4cc2cdbd13ae1cd2f', '/', 671830),
389 )
389 )
390 for revision, path, size in to_check:
390 for revision, path, size in to_check:
391 self._test_dir_size(revision, path, size)
391 self._test_dir_size(revision, path, size)
392
392
393 def test_repo_size(self):
393 def test_repo_size(self):
394 self.assertEqual(self.repo.size, 674076)
394 self.assertEqual(self.repo.size, 674076)
395
395
396 def test_file_history(self):
396 def test_file_history(self):
397 # we can only check if those revisions are present in the history
397 # we can only check if those revisions are present in the history
398 # as we cannot update this test every time file is changed
398 # as we cannot update this test every time file is changed
399 files = {
399 files = {
400 'setup.py': [
400 'setup.py': [
401 '54386793436c938cff89326944d4c2702340037d',
401 '54386793436c938cff89326944d4c2702340037d',
402 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
402 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
403 '998ed409c795fec2012b1c0ca054d99888b22090',
403 '998ed409c795fec2012b1c0ca054d99888b22090',
404 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
404 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
405 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
405 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
406 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
406 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
407 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
407 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
408 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
408 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
409 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
409 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
410 ],
410 ],
411 'vcs/nodes.py': [
411 'vcs/nodes.py': [
412 '33fa3223355104431402a888fa77a4e9956feb3e',
412 '33fa3223355104431402a888fa77a4e9956feb3e',
413 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
413 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
414 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
414 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
415 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
415 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
416 'c877b68d18e792a66b7f4c529ea02c8f80801542',
416 'c877b68d18e792a66b7f4c529ea02c8f80801542',
417 '4313566d2e417cb382948f8d9d7c765330356054',
417 '4313566d2e417cb382948f8d9d7c765330356054',
418 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
418 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
419 '54386793436c938cff89326944d4c2702340037d',
419 '54386793436c938cff89326944d4c2702340037d',
420 '54000345d2e78b03a99d561399e8e548de3f3203',
420 '54000345d2e78b03a99d561399e8e548de3f3203',
421 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
421 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
422 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
422 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
423 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
423 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
424 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
424 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
425 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
425 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
426 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
426 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
427 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
427 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
428 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
428 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
429 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
429 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
430 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
430 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
431 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
431 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
432 'f15c21f97864b4f071cddfbf2750ec2e23859414',
432 'f15c21f97864b4f071cddfbf2750ec2e23859414',
433 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
433 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
434 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
434 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
435 '84dec09632a4458f79f50ddbbd155506c460b4f9',
435 '84dec09632a4458f79f50ddbbd155506c460b4f9',
436 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
436 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
437 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
437 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
438 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
438 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
439 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
439 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
440 '6970b057cffe4aab0a792aa634c89f4bebf01441',
440 '6970b057cffe4aab0a792aa634c89f4bebf01441',
441 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
441 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
442 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
442 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
443 ],
443 ],
444 'vcs/backends/git.py': [
444 'vcs/backends/git.py': [
445 '4cf116ad5a457530381135e2f4c453e68a1b0105',
445 '4cf116ad5a457530381135e2f4c453e68a1b0105',
446 '9a751d84d8e9408e736329767387f41b36935153',
446 '9a751d84d8e9408e736329767387f41b36935153',
447 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
447 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
448 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
448 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
449 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
449 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
450 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
450 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
451 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
451 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
452 '54000345d2e78b03a99d561399e8e548de3f3203',
452 '54000345d2e78b03a99d561399e8e548de3f3203',
453 ],
453 ],
454 }
454 }
455 for path, revs in files.items():
455 for path, revs in files.items():
456 node = self.repo.get_changeset(revs[0]).get_node(path)
456 node = self.repo.get_changeset(revs[0]).get_node(path)
457 node_revs = [chset.raw_id for chset in node.history]
457 node_revs = [chset.raw_id for chset in node.history]
458 self.assertTrue(set(revs).issubset(set(node_revs)),
458 self.assertTrue(set(revs).issubset(set(node_revs)),
459 "We assumed that %s is subset of revisions for which file %s "
459 "We assumed that %s is subset of revisions for which file %s "
460 "has been changed, and history of that node returned: %s"
460 "has been changed, and history of that node returned: %s"
461 % (revs, path, node_revs))
461 % (revs, path, node_revs))
462
462
463 def test_file_annotate(self):
463 def test_file_annotate(self):
464 files = {
464 files = {
465 'vcs/backends/__init__.py': {
465 'vcs/backends/__init__.py': {
466 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
466 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
467 'lines_no': 1,
467 'lines_no': 1,
468 'changesets': [
468 'changesets': [
469 'c1214f7e79e02fc37156ff215cd71275450cffc3',
469 'c1214f7e79e02fc37156ff215cd71275450cffc3',
470 ],
470 ],
471 },
471 },
472 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
472 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
473 'lines_no': 21,
473 'lines_no': 21,
474 'changesets': [
474 'changesets': [
475 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
475 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
476 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
476 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
477 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
477 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
478 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
478 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
479 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
479 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
480 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
480 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
481 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
481 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
482 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
482 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
483 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
483 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
484 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
484 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
485 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
485 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
486 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
486 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
487 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
487 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
488 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
488 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
489 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
489 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
490 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
490 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
491 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
491 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
492 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
492 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
493 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
493 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
494 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
494 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
495 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
495 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
496 ],
496 ],
497 },
497 },
498 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
498 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
499 'lines_no': 32,
499 'lines_no': 32,
500 'changesets': [
500 'changesets': [
501 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
501 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
502 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
502 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
503 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
503 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
504 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
504 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
505 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
505 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
506 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
506 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
507 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
507 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
508 '54000345d2e78b03a99d561399e8e548de3f3203',
508 '54000345d2e78b03a99d561399e8e548de3f3203',
509 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
509 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
510 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
510 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
511 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
511 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
512 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
512 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
513 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
513 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
514 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
514 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
515 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
515 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
516 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
516 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
517 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
517 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
518 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
518 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
519 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
519 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
520 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
520 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
521 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
521 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
522 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
522 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
523 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
523 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
524 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
524 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
525 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
525 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
526 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
526 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
527 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
527 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
528 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
528 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
529 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
529 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
530 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
530 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
531 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
531 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
532 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
532 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
533 ],
533 ],
534 },
534 },
535 },
535 },
536 }
536 }
537
537
538 for fname, revision_dict in files.items():
538 for fname, revision_dict in files.items():
539 for rev, data in revision_dict.items():
539 for rev, data in revision_dict.items():
540 cs = self.repo.get_changeset(rev)
540 cs = self.repo.get_changeset(rev)
541
541
542 l1_1 = [x[1] for x in cs.get_file_annotate(fname)]
542 l1_1 = [x[1] for x in cs.get_file_annotate(fname)]
543 l1_2 = [x[2]().raw_id for x in cs.get_file_annotate(fname)]
543 l1_2 = [x[2]().raw_id for x in cs.get_file_annotate(fname)]
544 self.assertEqual(l1_1, l1_2)
544 self.assertEqual(l1_1, l1_2)
545 l1 = l1_1
545 l1 = l1_1
546 l2 = files[fname][rev]['changesets']
546 l2 = files[fname][rev]['changesets']
547 self.assertTrue(l1 == l2, "The lists of revision for %s@rev %s"
547 self.assertTrue(l1 == l2, "The lists of revision for %s@rev %s"
548 "from annotation list should match each other, "
548 "from annotation list should match each other, "
549 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
549 "got \n%s \nvs \n%s " % (fname, rev, l1, l2))
550
550
551 def test_files_state(self):
551 def test_files_state(self):
552 """
552 """
553 Tests state of FileNodes.
553 Tests state of FileNodes.
554 """
554 """
555 node = self.repo \
555 node = self.repo \
556 .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0') \
556 .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0') \
557 .get_node('vcs/utils/diffs.py')
557 .get_node('vcs/utils/diffs.py')
558 self.assertTrue(node.state, NodeState.ADDED)
558 self.assertTrue(node.state, NodeState.ADDED)
559 self.assertTrue(node.added)
559 self.assertTrue(node.added)
560 self.assertFalse(node.changed)
560 self.assertFalse(node.changed)
561 self.assertFalse(node.not_changed)
561 self.assertFalse(node.not_changed)
562 self.assertFalse(node.removed)
562 self.assertFalse(node.removed)
563
563
564 node = self.repo \
564 node = self.repo \
565 .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e') \
565 .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e') \
566 .get_node('.hgignore')
566 .get_node('.hgignore')
567 self.assertTrue(node.state, NodeState.CHANGED)
567 self.assertTrue(node.state, NodeState.CHANGED)
568 self.assertFalse(node.added)
568 self.assertFalse(node.added)
569 self.assertTrue(node.changed)
569 self.assertTrue(node.changed)
570 self.assertFalse(node.not_changed)
570 self.assertFalse(node.not_changed)
571 self.assertFalse(node.removed)
571 self.assertFalse(node.removed)
572
572
573 node = self.repo \
573 node = self.repo \
574 .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064') \
574 .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064') \
575 .get_node('setup.py')
575 .get_node('setup.py')
576 self.assertTrue(node.state, NodeState.NOT_CHANGED)
576 self.assertTrue(node.state, NodeState.NOT_CHANGED)
577 self.assertFalse(node.added)
577 self.assertFalse(node.added)
578 self.assertFalse(node.changed)
578 self.assertFalse(node.changed)
579 self.assertTrue(node.not_changed)
579 self.assertTrue(node.not_changed)
580 self.assertFalse(node.removed)
580 self.assertFalse(node.removed)
581
581
582 # If node has REMOVED state then trying to fetch it would raise
582 # If node has REMOVED state then trying to fetch it would raise
583 # ChangesetError exception
583 # ChangesetError exception
584 chset = self.repo.get_changeset(
584 chset = self.repo.get_changeset(
585 'fa6600f6848800641328adbf7811fd2372c02ab2')
585 'fa6600f6848800641328adbf7811fd2372c02ab2')
586 path = 'vcs/backends/BaseRepository.py'
586 path = 'vcs/backends/BaseRepository.py'
587 self.assertRaises(NodeDoesNotExistError, chset.get_node, path)
587 self.assertRaises(NodeDoesNotExistError, chset.get_node, path)
588 # but it would be one of ``removed`` (changeset's attribute)
588 # but it would be one of ``removed`` (changeset's attribute)
589 self.assertTrue(path in [rf.path for rf in chset.removed])
589 self.assertTrue(path in [rf.path for rf in chset.removed])
590
590
591 chset = self.repo.get_changeset(
591 chset = self.repo.get_changeset(
592 '54386793436c938cff89326944d4c2702340037d')
592 '54386793436c938cff89326944d4c2702340037d')
593 changed = ['setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
593 changed = ['setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
594 'vcs/nodes.py']
594 'vcs/nodes.py']
595 self.assertEqual(set(changed), set([f.path for f in chset.changed]))
595 self.assertEqual(set(changed), set([f.path for f in chset.changed]))
596
596
597 def test_commit_message_is_unicode(self):
597 def test_commit_message_is_unicode(self):
598 for cs in self.repo:
598 for cs in self.repo:
599 self.assertEqual(type(cs.message), unicode)
599 self.assertEqual(type(cs.message), unicode)
600
600
601 def test_changeset_author_is_unicode(self):
601 def test_changeset_author_is_unicode(self):
602 for cs in self.repo:
602 for cs in self.repo:
603 self.assertEqual(type(cs.author), unicode)
603 self.assertEqual(type(cs.author), unicode)
604
604
605 def test_repo_files_content_is_unicode(self):
605 def test_repo_files_content_is_unicode(self):
606 changeset = self.repo.get_changeset()
606 changeset = self.repo.get_changeset()
607 for node in changeset.get_node('/'):
607 for node in changeset.get_node('/'):
608 if node.is_file():
608 if node.is_file():
609 self.assertEqual(type(node.content), unicode)
609 self.assertEqual(type(node.content), unicode)
610
610
611 def test_wrong_path(self):
611 def test_wrong_path(self):
612 # There is 'setup.py' in the root dir but not there:
612 # There is 'setup.py' in the root dir but not there:
613 path = 'foo/bar/setup.py'
613 path = 'foo/bar/setup.py'
614 tip = self.repo.get_changeset()
614 tip = self.repo.get_changeset()
615 self.assertRaises(VCSError, tip.get_node, path)
615 self.assertRaises(VCSError, tip.get_node, path)
616
616
617 def test_author_email(self):
617 def test_author_email(self):
618 self.assertEqual('marcin@python-blog.com',
618 self.assertEqual('marcin@python-blog.com',
619 self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
619 self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
620 .author_email)
620 .author_email)
621 self.assertEqual('lukasz.balcerzak@python-center.pl',
621 self.assertEqual('lukasz.balcerzak@python-center.pl',
622 self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
622 self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
623 .author_email)
623 .author_email)
624 self.assertEqual('',
624 self.assertEqual('',
625 self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
625 self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
626 .author_email)
626 .author_email)
627
627
628 def test_author_username(self):
628 def test_author_username(self):
629 self.assertEqual('Marcin Kuzminski',
629 self.assertEqual('Marcin Kuzminski',
630 self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
630 self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3') \
631 .author_name)
631 .author_name)
632 self.assertEqual('Lukasz Balcerzak',
632 self.assertEqual('Lukasz Balcerzak',
633 self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
633 self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b') \
634 .author_name)
634 .author_name)
635 self.assertEqual('marcink none@none',
635 self.assertEqual('marcink none@none',
636 self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
636 self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992') \
637 .author_name)
637 .author_name)
638
638
639
639
640 class GitSpecificTest(unittest.TestCase):
640 class GitSpecificTest(unittest.TestCase):
641
641
642 def test_error_is_raised_for_added_if_diff_name_status_is_wrong(self):
642 def test_error_is_raised_for_added_if_diff_name_status_is_wrong(self):
643 repo = mock.MagicMock()
643 repo = mock.MagicMock()
644 changeset = GitChangeset(repo, 'foobar')
644 changeset = GitChangeset(repo, 'foobar')
645 changeset._diff_name_status = 'foobar'
645 changeset._diff_name_status = 'foobar'
646 with self.assertRaises(VCSError):
646 with self.assertRaises(VCSError):
647 changeset.added
647 changeset.added
648
648
649 def test_error_is_raised_for_changed_if_diff_name_status_is_wrong(self):
649 def test_error_is_raised_for_changed_if_diff_name_status_is_wrong(self):
650 repo = mock.MagicMock()
650 repo = mock.MagicMock()
651 changeset = GitChangeset(repo, 'foobar')
651 changeset = GitChangeset(repo, 'foobar')
652 changeset._diff_name_status = 'foobar'
652 changeset._diff_name_status = 'foobar'
653 with self.assertRaises(VCSError):
653 with self.assertRaises(VCSError):
654 changeset.added
654 changeset.added
655
655
656 def test_error_is_raised_for_removed_if_diff_name_status_is_wrong(self):
656 def test_error_is_raised_for_removed_if_diff_name_status_is_wrong(self):
657 repo = mock.MagicMock()
657 repo = mock.MagicMock()
658 changeset = GitChangeset(repo, 'foobar')
658 changeset = GitChangeset(repo, 'foobar')
659 changeset._diff_name_status = 'foobar'
659 changeset._diff_name_status = 'foobar'
660 with self.assertRaises(VCSError):
660 with self.assertRaises(VCSError):
661 changeset.added
661 changeset.added
662
662
663
663
664 class GitSpecificWithRepoTest(_BackendTestMixin, unittest.TestCase):
664 class GitSpecificWithRepoTest(_BackendTestMixin, unittest.TestCase):
665 backend_alias = 'git'
665 backend_alias = 'git'
666
666
667 @classmethod
667 @classmethod
668 def _get_commits(cls):
668 def _get_commits(cls):
669 return [
669 return [
670 {
670 {
671 'message': 'Initial',
671 'message': 'Initial',
672 'author': 'Joe Doe <joe.doe@example.com>',
672 'author': 'Joe Doe <joe.doe@example.com>',
673 'date': datetime.datetime(2010, 1, 1, 20),
673 'date': datetime.datetime(2010, 1, 1, 20),
674 'added': [
674 'added': [
675 FileNode('foobar/static/js/admin/base.js', content='base'),
675 FileNode('foobar/static/js/admin/base.js', content='base'),
676 FileNode('foobar/static/admin', content='admin',
676 FileNode('foobar/static/admin', content='admin',
677 mode=0120000), # this is a link
677 mode=0120000), # this is a link
678 FileNode('foo', content='foo'),
678 FileNode('foo', content='foo'),
679 ],
679 ],
680 },
680 },
681 {
681 {
682 'message': 'Second',
682 'message': 'Second',
683 'author': 'Joe Doe <joe.doe@example.com>',
683 'author': 'Joe Doe <joe.doe@example.com>',
684 'date': datetime.datetime(2010, 1, 1, 22),
684 'date': datetime.datetime(2010, 1, 1, 22),
685 'added': [
685 'added': [
686 FileNode('foo2', content='foo2'),
686 FileNode('foo2', content='foo2'),
687 ],
687 ],
688 },
688 },
689 ]
689 ]
690
690
691 def test_paths_slow_traversing(self):
691 def test_paths_slow_traversing(self):
692 cs = self.repo.get_changeset()
692 cs = self.repo.get_changeset()
693 self.assertEqual(cs.get_node('foobar').get_node('static').get_node('js')
693 self.assertEqual(cs.get_node('foobar').get_node('static').get_node('js')
694 .get_node('admin').get_node('base.js').content, 'base')
694 .get_node('admin').get_node('base.js').content, 'base')
695
695
696 def test_paths_fast_traversing(self):
696 def test_paths_fast_traversing(self):
697 cs = self.repo.get_changeset()
697 cs = self.repo.get_changeset()
698 self.assertEqual(cs.get_node('foobar/static/js/admin/base.js').content,
698 self.assertEqual(cs.get_node('foobar/static/js/admin/base.js').content,
699 'base')
699 'base')
700
700
701 def test_workdir_get_branch(self):
701 def test_workdir_get_branch(self):
702 self.repo.run_git_command(['checkout', '-b', 'production'])
702 self.repo.run_git_command(['checkout', '-b', 'production'])
703 # Regression test: one of following would fail if we don't check
703 # Regression test: one of following would fail if we don't check
704 # .git/HEAD file
704 # .git/HEAD file
705 self.repo.run_git_command(['checkout', 'production'])
705 self.repo.run_git_command(['checkout', 'production'])
706 self.assertEqual(self.repo.workdir.get_branch(), 'production')
706 self.assertEqual(self.repo.workdir.get_branch(), 'production')
707 self.repo.run_git_command(['checkout', 'master'])
707 self.repo.run_git_command(['checkout', 'master'])
708 self.assertEqual(self.repo.workdir.get_branch(), 'master')
708 self.assertEqual(self.repo.workdir.get_branch(), 'master')
709
709
710 def test_get_diff_runs_git_command_with_hashes(self):
710 def test_get_diff_runs_git_command_with_hashes(self):
711 self.repo.run_git_command = mock.Mock(return_value=['', ''])
711 self.repo.run_git_command = mock.Mock(return_value=['', ''])
712 self.repo.get_diff(0, 1)
712 self.repo.get_diff(0, 1)
713 self.repo.run_git_command.assert_called_once_with(
713 self.repo.run_git_command.assert_called_once_with(
714 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
714 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
715 self.repo._get_revision(0), self.repo._get_revision(1)])
715 self.repo._get_revision(0), self.repo._get_revision(1)])
716
716
717 def test_get_diff_runs_git_command_with_str_hashes(self):
717 def test_get_diff_runs_git_command_with_str_hashes(self):
718 self.repo.run_git_command = mock.Mock(return_value=['', ''])
718 self.repo.run_git_command = mock.Mock(return_value=['', ''])
719 self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1)
719 self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1)
720 self.repo.run_git_command.assert_called_once_with(
720 self.repo.run_git_command.assert_called_once_with(
721 ['show', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
721 ['show', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
722 self.repo._get_revision(1)])
722 self.repo._get_revision(1)])
723
723
724 def test_get_diff_runs_git_command_with_path_if_its_given(self):
724 def test_get_diff_runs_git_command_with_path_if_its_given(self):
725 self.repo.run_git_command = mock.Mock(return_value=['', ''])
725 self.repo.run_git_command = mock.Mock(return_value=['', ''])
726 self.repo.get_diff(0, 1, 'foo')
726 self.repo.get_diff(0, 1, 'foo')
727 self.repo.run_git_command.assert_called_once_with(
727 self.repo.run_git_command.assert_called_once_with(
728 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
728 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
729 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'])
729 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'])
730
730
731
731
732 class GitRegressionTest(_BackendTestMixin, unittest.TestCase):
732 class GitRegressionTest(_BackendTestMixin, unittest.TestCase):
733 backend_alias = 'git'
733 backend_alias = 'git'
734
734
735 @classmethod
735 @classmethod
736 def _get_commits(cls):
736 def _get_commits(cls):
737 return [
737 return [
738 {
738 {
739 'message': 'Initial',
739 'message': 'Initial',
740 'author': 'Joe Doe <joe.doe@example.com>',
740 'author': 'Joe Doe <joe.doe@example.com>',
741 'date': datetime.datetime(2010, 1, 1, 20),
741 'date': datetime.datetime(2010, 1, 1, 20),
742 'added': [
742 'added': [
743 FileNode('bot/__init__.py', content='base'),
743 FileNode('bot/__init__.py', content='base'),
744 FileNode('bot/templates/404.html', content='base'),
744 FileNode('bot/templates/404.html', content='base'),
745 FileNode('bot/templates/500.html', content='base'),
745 FileNode('bot/templates/500.html', content='base'),
746 ],
746 ],
747 },
747 },
748 {
748 {
749 'message': 'Second',
749 'message': 'Second',
750 'author': 'Joe Doe <joe.doe@example.com>',
750 'author': 'Joe Doe <joe.doe@example.com>',
751 'date': datetime.datetime(2010, 1, 1, 22),
751 'date': datetime.datetime(2010, 1, 1, 22),
752 'added': [
752 'added': [
753 FileNode('bot/build/migrations/1.py', content='foo2'),
753 FileNode('bot/build/migrations/1.py', content='foo2'),
754 FileNode('bot/build/migrations/2.py', content='foo2'),
754 FileNode('bot/build/migrations/2.py', content='foo2'),
755 FileNode('bot/build/static/templates/f.html', content='foo2'),
755 FileNode('bot/build/static/templates/f.html', content='foo2'),
756 FileNode('bot/build/static/templates/f1.html', content='foo2'),
756 FileNode('bot/build/static/templates/f1.html', content='foo2'),
757 FileNode('bot/build/templates/err.html', content='foo2'),
757 FileNode('bot/build/templates/err.html', content='foo2'),
758 FileNode('bot/build/templates/err2.html', content='foo2'),
758 FileNode('bot/build/templates/err2.html', content='foo2'),
759 ],
759 ],
760 },
760 },
761 ]
761 ]
762
762
763 def test_similar_paths(self):
763 def test_similar_paths(self):
764 cs = self.repo.get_changeset()
764 cs = self.repo.get_changeset()
765 paths = lambda *n: [x.path for x in n]
765 paths = lambda *n: [x.path for x in n]
766 self.assertEqual(paths(*cs.get_nodes('bot')), ['bot/build', 'bot/templates', 'bot/__init__.py'])
766 self.assertEqual(paths(*cs.get_nodes('bot')), ['bot/build', 'bot/templates', 'bot/__init__.py'])
767 self.assertEqual(paths(*cs.get_nodes('bot/build')), ['bot/build/migrations', 'bot/build/static', 'bot/build/templates'])
767 self.assertEqual(paths(*cs.get_nodes('bot/build')), ['bot/build/migrations', 'bot/build/static', 'bot/build/templates'])
768 self.assertEqual(paths(*cs.get_nodes('bot/build/static')), ['bot/build/static/templates'])
768 self.assertEqual(paths(*cs.get_nodes('bot/build/static')), ['bot/build/static/templates'])
769 # this get_nodes below causes troubles !
769 # this get_nodes below causes troubles !
770 self.assertEqual(paths(*cs.get_nodes('bot/build/static/templates')), ['bot/build/static/templates/f.html', 'bot/build/static/templates/f1.html'])
770 self.assertEqual(paths(*cs.get_nodes('bot/build/static/templates')), ['bot/build/static/templates/f.html', 'bot/build/static/templates/f1.html'])
771 self.assertEqual(paths(*cs.get_nodes('bot/build/templates')), ['bot/build/templates/err.html', 'bot/build/templates/err2.html'])
771 self.assertEqual(paths(*cs.get_nodes('bot/build/templates')), ['bot/build/templates/err.html', 'bot/build/templates/err2.html'])
772 self.assertEqual(paths(*cs.get_nodes('bot/templates/')), ['bot/templates/404.html', 'bot/templates/500.html'])
772 self.assertEqual(paths(*cs.get_nodes('bot/templates/')), ['bot/templates/404.html', 'bot/templates/500.html'])
773
773
774
774
775 class GitHooksTest(unittest.TestCase):
775 class GitHooksTest(unittest.TestCase):
776 """
776 """
777 Tests related to hook functionality of Git repositories.
777 Tests related to hook functionality of Git repositories.
778 """
778 """
779
779
780 def setUp(self):
780 def setUp(self):
781 # For each run we want a fresh repo.
781 # For each run we want a fresh repo.
782 self.repo_directory = get_new_dir("githookrepo")
782 self.repo_directory = get_new_dir("githookrepo")
783 self.repo = GitRepository(self.repo_directory, create=True)
783 self.repo = GitRepository(self.repo_directory, create=True)
784
784
785 # Create a dictionary where keys are hook names, and values are paths to
785 # Create a dictionary where keys are hook names, and values are paths to
786 # them. Deduplicates code in tests a bit.
786 # them. Deduplicates code in tests a bit.
787 self.hook_directory = self.repo.get_hook_location()
787 self.hook_directory = self.repo.get_hook_location()
788 self.kallithea_hooks = dict((h, os.path.join(self.hook_directory, h)) for h in ("pre-receive", "post-receive"))
788 self.kallithea_hooks = dict((h, os.path.join(self.hook_directory, h)) for h in ("pre-receive", "post-receive"))
789
789
790 def test_hooks_created_if_missing(self):
790 def test_hooks_created_if_missing(self):
791 """
791 """
792 Tests if hooks are installed in repository if they are missing.
792 Tests if hooks are installed in repository if they are missing.
793 """
793 """
794
794
795 for hook, hook_path in self.kallithea_hooks.iteritems():
795 for hook, hook_path in self.kallithea_hooks.iteritems():
796 if os.path.exists(hook_path):
796 if os.path.exists(hook_path):
797 os.remove(hook_path)
797 os.remove(hook_path)
798
798
799 ScmModel().install_git_hooks(repo=self.repo)
799 ScmModel().install_git_hooks(repo=self.repo)
800
800
801 for hook, hook_path in self.kallithea_hooks.iteritems():
801 for hook, hook_path in self.kallithea_hooks.iteritems():
802 self.assertTrue(os.path.exists(hook_path))
802 self.assertTrue(os.path.exists(hook_path))
803
803
804 def test_kallithea_hooks_updated(self):
804 def test_kallithea_hooks_updated(self):
805 """
805 """
806 Tests if hooks are updated if they are Kallithea hooks already.
806 Tests if hooks are updated if they are Kallithea hooks already.
807 """
807 """
808
808
809 for hook, hook_path in self.kallithea_hooks.iteritems():
809 for hook, hook_path in self.kallithea_hooks.iteritems():
810 with open(hook_path, "w") as f:
810 with open(hook_path, "w") as f:
811 f.write("KALLITHEA_HOOK_VER=0.0.0\nJUST_BOGUS")
811 f.write("KALLITHEA_HOOK_VER=0.0.0\nJUST_BOGUS")
812
812
813 ScmModel().install_git_hooks(repo=self.repo)
813 ScmModel().install_git_hooks(repo=self.repo)
814
814
815 for hook, hook_path in self.kallithea_hooks.iteritems():
815 for hook, hook_path in self.kallithea_hooks.iteritems():
816 with open(hook_path) as f:
816 with open(hook_path) as f:
817 self.assertNotIn("JUST_BOGUS", f.read())
817 self.assertNotIn("JUST_BOGUS", f.read())
818
818
819 def test_custom_hooks_untouched(self):
819 def test_custom_hooks_untouched(self):
820 """
820 """
821 Tests if hooks are left untouched if they are not Kallithea hooks.
821 Tests if hooks are left untouched if they are not Kallithea hooks.
822 """
822 """
823
823
824 for hook, hook_path in self.kallithea_hooks.iteritems():
824 for hook, hook_path in self.kallithea_hooks.iteritems():
825 with open(hook_path, "w") as f:
825 with open(hook_path, "w") as f:
826 f.write("#!/bin/bash\n#CUSTOM_HOOK")
826 f.write("#!/bin/bash\n#CUSTOM_HOOK")
827
827
828 ScmModel().install_git_hooks(repo=self.repo)
828 ScmModel().install_git_hooks(repo=self.repo)
829
829
830 for hook, hook_path in self.kallithea_hooks.iteritems():
830 for hook, hook_path in self.kallithea_hooks.iteritems():
831 with open(hook_path) as f:
831 with open(hook_path) as f:
832 self.assertIn("CUSTOM_HOOK", f.read())
832 self.assertIn("CUSTOM_HOOK", f.read())
833
833
834 def test_custom_hooks_forced_update(self):
834 def test_custom_hooks_forced_update(self):
835 """
835 """
836 Tests if hooks are forcefully updated even though they are custom hooks.
836 Tests if hooks are forcefully updated even though they are custom hooks.
837 """
837 """
838
838
839 for hook, hook_path in self.kallithea_hooks.iteritems():
839 for hook, hook_path in self.kallithea_hooks.iteritems():
840 with open(hook_path, "w") as f:
840 with open(hook_path, "w") as f:
841 f.write("#!/bin/bash\n#CUSTOM_HOOK")
841 f.write("#!/bin/bash\n#CUSTOM_HOOK")
842
842
843 ScmModel().install_git_hooks(repo=self.repo, force_create=True)
843 ScmModel().install_git_hooks(repo=self.repo, force_create=True)
844
844
845 for hook, hook_path in self.kallithea_hooks.iteritems():
845 for hook, hook_path in self.kallithea_hooks.iteritems():
846 with open(hook_path) as f:
846 with open(hook_path) as f:
847 self.assertIn("KALLITHEA_HOOK_VER", f.read())
847 self.assertIn("KALLITHEA_HOOK_VER", f.read())
848
848
849
849
850 if __name__ == '__main__':
850 if __name__ == '__main__':
851 unittest.main()
851 unittest.main()
General Comments 0
You need to be logged in to leave comments. Login now