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