comparison rhodecode/tests/vcs/test_git.py @ 2451:402a96fcfa22 beta

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