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