| | 1 | # -*- coding: utf-8 -*- |
| | 2 | # |
| | 3 | # Copyright (C) 2017 Edgewall Software |
| | 4 | # All rights reserved. |
| | 5 | # |
| | 6 | # This software is licensed as described in the file COPYING, which |
| | 7 | # you should have received as part of this distribution. The terms |
| | 8 | # are also available at http://trac.edgewall.org/wiki/TracLicense. |
| | 9 | # |
| | 10 | # This software consists of voluntary contributions made by many |
| | 11 | # individuals. For the exact contribution history, see the revision |
| | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| | 13 | |
| | 14 | import io |
| | 15 | import os |
| | 16 | import sys |
| | 17 | import shutil |
| | 18 | import unittest |
| | 19 | from datetime import datetime, timedelta |
| | 20 | from subprocess import PIPE |
| | 21 | |
| | 22 | from trac.core import TracError |
| | 23 | from trac.test import EnvironmentStub, MockRequest, locate, mkdtemp |
| | 24 | from trac.tests.compat import rmtree |
| | 25 | from trac.util import create_file, makedirs |
| | 26 | from trac.util.compat import Popen, close_fds |
| | 27 | from trac.util.datefmt import to_timestamp, utc |
| | 28 | from trac.util.text import to_utf8 |
| | 29 | from trac.versioncontrol.api import Changeset, DbRepositoryProvider, \ |
| | 30 | InvalidRepository, Node, \ |
| | 31 | NoSuchChangeset, NoSuchNode, \ |
| | 32 | RepositoryManager |
| | 33 | from trac.versioncontrol.web_ui.browser import BrowserModule |
| | 34 | from trac.versioncontrol.web_ui.log import LogModule |
| | 35 | from tracopt.versioncontrol.hg.hg_fs import HgRepository |
| | 36 | |
| | 37 | |
| | 38 | class HgCommandMixin(object): |
| | 39 | |
| | 40 | hg_bin = locate('hg') |
| | 41 | |
| | 42 | def _hg_commit(self, *args, **kwargs): |
| | 43 | args2 = ['commit', '--config', 'ui.username=Joe <joe@example.com>'] |
| | 44 | if 'date' in kwargs: |
| | 45 | args2.append('--date') |
| | 46 | args2.append(str(kwargs.pop('date'))) |
| | 47 | args2 += args |
| | 48 | return self._hg(*args2, **kwargs) |
| | 49 | |
| | 50 | def _spawn_hg(self, *args, **kwargs): |
| | 51 | args = map(to_utf8, (self.hg_bin,) + args) |
| | 52 | kwargs.setdefault('stdin', PIPE) |
| | 53 | kwargs.setdefault('stdout', PIPE) |
| | 54 | kwargs.setdefault('stderr', PIPE) |
| | 55 | kwargs.setdefault('cwd', self.repos_path) |
| | 56 | return Popen(args, close_fds=close_fds, **kwargs) |
| | 57 | |
| | 58 | def _hg(self, *args, **kwargs): |
| | 59 | with self._spawn_hg(*args, **kwargs) as proc: |
| | 60 | stdout, stderr = proc.communicate() |
| | 61 | self.assertEqual(0, proc.returncode, |
| | 62 | 'hg exits with %r, args %r, kwargs %r, stdout %r, ' |
| | 63 | 'stderr %r' % |
| | 64 | (proc.returncode, args, kwargs, stdout, stderr)) |
| | 65 | return proc |
| | 66 | |
| | 67 | |
| | 68 | class BaseTestCase(unittest.TestCase, HgCommandMixin): |
| | 69 | |
| | 70 | def setUp(self): |
| | 71 | self.env = EnvironmentStub() |
| | 72 | self.repos_path = mkdtemp() |
| | 73 | |
| | 74 | def tearDown(self): |
| | 75 | for repos in self._repomgr.get_real_repositories(): |
| | 76 | repos.close() |
| | 77 | self._repomgr.reload_repositories() |
| | 78 | self.env.reset_db() |
| | 79 | if os.path.isdir(self.repos_path): |
| | 80 | rmtree(self.repos_path) |
| | 81 | |
| | 82 | @property |
| | 83 | def _repomgr(self): |
| | 84 | return RepositoryManager(self.env) |
| | 85 | |
| | 86 | @property |
| | 87 | def _dbrepoprov(self): |
| | 88 | return DbRepositoryProvider(self.env) |
| | 89 | |
| | 90 | def _add_repository(self, reponame='hgrepos'): |
| | 91 | path = self.repos_path |
| | 92 | self._dbrepoprov.add_repository(reponame, path, 'hg') |
| | 93 | |
| | 94 | def _hg_init(self, data=True): |
| | 95 | self._hg('init') |
| | 96 | if data: |
| | 97 | create_file(os.path.join(self.repos_path, '.hgignore')) |
| | 98 | self._hg('add', '.hgignore') |
| | 99 | self._hg_commit('-m', 'test', |
| | 100 | date=datetime(2001, 1, 29, 16, 39, 56)) |
| | 101 | |
| | 102 | |
| | 103 | class SanityCheckingTestCase(BaseTestCase): |
| | 104 | |
| | 105 | def test(self): |
| | 106 | self._hg_init() |
| | 107 | self._dbrepoprov.add_repository('hgrepos.1', self.repos_path, 'hg') |
| | 108 | self._repomgr.get_repository('hgrepos.1') |
| | 109 | self._dbrepoprov.add_repository('hgrepos.2', self.repos_path, 'hg') |
| | 110 | self._repomgr.get_repository('hgrepos.2') |
| | 111 | |
| | 112 | |
| | 113 | class HistoryTimeRangeTestCase(BaseTestCase): |
| | 114 | |
| | 115 | def test(self): |
| | 116 | self._hg_init() |
| | 117 | filename = os.path.join(self.repos_path, '.hgignore') |
| | 118 | start = datetime(2000, 1, 1, 0, 0, 0, 0, utc) |
| | 119 | ts = datetime(2014, 2, 5, 15, 24, 6, 0, utc) |
| | 120 | for idx in xrange(3): |
| | 121 | create_file(filename, 'commit-%d.txt' % idx) |
| | 122 | self._hg_commit('-m', 'commit %d' % idx, date=ts) |
| | 123 | self._add_repository() |
| | 124 | repos = self._repomgr.get_repository('hgrepos') |
| | 125 | repos.sync() |
| | 126 | |
| | 127 | revs = [repos.youngest_rev] |
| | 128 | while True: |
| | 129 | parents = repos.parent_revs(revs[-1]) |
| | 130 | if not parents: |
| | 131 | break |
| | 132 | revs.extend(parents) |
| | 133 | self.assertEqual(4, len(revs)) |
| | 134 | |
| | 135 | csets = list(repos.get_changesets(start, ts)) |
| | 136 | self.assertEqual(1, len(csets)) |
| | 137 | self.assertEqual(revs[-1], csets[0].rev) # is oldest rev |
| | 138 | |
| | 139 | csets = list(repos.get_changesets(start, ts + timedelta(seconds=1))) |
| | 140 | self.assertEqual(revs, [cset.rev for cset in csets]) |
| | 141 | |
| | 142 | |
| | 143 | class HgNormalTestCase(BaseTestCase): |
| | 144 | |
| | 145 | def test_get_node(self): |
| | 146 | self._hg_init() |
| | 147 | self._add_repository() |
| | 148 | repos = self._repomgr.get_repository('hgrepos') |
| | 149 | rev = repos.youngest_rev |
| | 150 | self.assertNotEqual(None, rev) |
| | 151 | self.assertEqual(40, len(rev)) |
| | 152 | |
| | 153 | self.assertEqual(rev, repos.get_node('/').rev) |
| | 154 | self.assertEqual(rev, repos.get_node('/', rev[:7]).rev) |
| | 155 | self.assertEqual(rev, repos.get_node('/.hgignore').rev) |
| | 156 | self.assertEqual(rev, repos.get_node('/.hgignore', rev[:7]).rev) |
| | 157 | |
| | 158 | self.assertRaises(NoSuchNode, repos.get_node, '/non-existent') |
| | 159 | self.assertRaises(NoSuchNode, repos.get_node, '/non-existent', rev[:7]) |
| | 160 | self.assertRaises(NoSuchNode, repos.get_node, '/non-existent', rev) |
| | 161 | self.assertRaises(NoSuchChangeset, |
| | 162 | repos.get_node, '/', 'invalid-revision') |
| | 163 | self.assertRaises(NoSuchChangeset, |
| | 164 | repos.get_node, '/.hgignore', 'invalid-revision') |
| | 165 | self.assertRaises(NoSuchChangeset, |
| | 166 | repos.get_node, '/non-existent', 'invalid-revision') |
| | 167 | |
| | 168 | self._hg('bookmark', 'abc') |
| | 169 | repos.sync() |
| | 170 | self.assertEqual(rev, repos.get_node('/', 'abc').rev) |
| | 171 | self.assertEqual(rev, repos.get_node('/.hgignore', 'abc').rev) |
| | 172 | |
| | 173 | def test_on_empty_repos(self): |
| | 174 | self._hg_init(data=False) |
| | 175 | self._add_repository() |
| | 176 | repos = self._repomgr.get_repository('hgrepos') |
| | 177 | repos.sync() |
| | 178 | youngest_rev = repos.youngest_rev |
| | 179 | self.assertEqual(None, youngest_rev) |
| | 180 | self.assertEqual(None, repos.oldest_rev) |
| | 181 | self.assertEqual(None, repos.normalize_rev('')) |
| | 182 | self.assertEqual(None, repos.normalize_rev(None)) |
| | 183 | self.assertEqual(None, repos.display_rev('')) |
| | 184 | self.assertEqual(None, repos.display_rev(None)) |
| | 185 | self.assertEqual(None, repos.short_rev('')) |
| | 186 | self.assertEqual(None, repos.short_rev(None)) |
| | 187 | |
| | 188 | node = repos.get_node('/', youngest_rev) |
| | 189 | self.assertEqual([], list(node.get_entries())) |
| | 190 | self.assertEqual([], list(node.get_history())) |
| | 191 | self.assertRaises(NoSuchNode, repos.get_node, '/path', youngest_rev) |
| | 192 | |
| | 193 | req = MockRequest(self.env, path_info='/browser/hgrepos') |
| | 194 | browser_mod = BrowserModule(self.env) |
| | 195 | self.assertTrue(browser_mod.match_request(req)) |
| | 196 | rv = browser_mod.process_request(req) |
| | 197 | self.assertEqual('browser.html', rv[0]) |
| | 198 | self.assertEqual(None, rv[1]['rev']) |
| | 199 | |
| | 200 | req = MockRequest(self.env, path_info='/log/hgrepos') |
| | 201 | log_mod = LogModule(self.env) |
| | 202 | self.assertTrue(log_mod.match_request(req)) |
| | 203 | rv = log_mod.process_request(req) |
| | 204 | self.assertEqual('revisionlog.html', rv[0]) |
| | 205 | self.assertEqual([], rv[1]['items']) |
| | 206 | |
| | 207 | |
| | 208 | class HgRepositoryTestCase(BaseTestCase): |
| | 209 | |
| | 210 | def _create_merge_commit(self): |
| | 211 | for idx, branch in enumerate(('alpha', 'beta')): |
| | 212 | self._hg('update', 'default') |
| | 213 | self._hg('branch', branch) |
| | 214 | for n in xrange(2): |
| | 215 | filename = 'file-%s-%d.txt' % (branch, n) |
| | 216 | create_file(os.path.join(self.repos_path, filename)) |
| | 217 | self._hg('add', filename) |
| | 218 | self._hg_commit('-m', filename, |
| | 219 | date=datetime(2014, 2, 2, 17, 12, |
| | 220 | n * 2 + idx)) |
| | 221 | self._hg('update', 'alpha') |
| | 222 | self._hg('merge', 'beta') |
| | 223 | self._hg_commit('-m', 'Merge branch "beta" to "alpha"') |
| | 224 | |
| | 225 | def test_invalid_path_raises(self): |
| | 226 | self.assertRaises(InvalidRepository, HgRepository, self.env, |
| | 227 | '/the/invalid/path', [], self.env.log) |
| | 228 | |
| | 229 | def test_repository_instance(self): |
| | 230 | self._hg_init() |
| | 231 | self._add_repository('hgrepos') |
| | 232 | self.assertEqual(HgRepository, |
| | 233 | type(self._repomgr.get_repository('hgrepos'))) |
| | 234 | |
| | 235 | def test_reset_head(self): |
| | 236 | self._hg_init() |
| | 237 | create_file(os.path.join(self.repos_path, 'file.txt'), 'text') |
| | 238 | self._hg('add', 'file.txt') |
| | 239 | self._hg_commit('-m', 'test', |
| | 240 | date=datetime(2014, 2, 2, 17, 12, 18)) |
| | 241 | self._add_repository('hgrepos') |
| | 242 | repos = self._repomgr.get_repository('hgrepos') |
| | 243 | repos.sync() |
| | 244 | youngest_rev = repos.youngest_rev |
| | 245 | entries = list(repos.get_node('').get_history()) |
| | 246 | self.assertEqual(2, len(entries)) |
| | 247 | self.assertEqual('', entries[0][0]) |
| | 248 | self.assertEqual(Changeset.EDIT, entries[0][2]) |
| | 249 | self.assertEqual('', entries[1][0]) |
| | 250 | self.assertEqual(Changeset.ADD, entries[1][2]) |
| | 251 | |
| | 252 | self._hg('--config', "'extensions.strip='", 'strip', '--rev', '.') |
| | 253 | repos.sync() |
| | 254 | new_entries = list(repos.get_node('').get_history()) |
| | 255 | self.assertEqual(1, len(new_entries)) |
| | 256 | self.assertEqual(new_entries[0], entries[1]) |
| | 257 | self.assertNotEqual(youngest_rev, repos.youngest_rev) |
| | 258 | |
| | 259 | def test_tags(self): |
| | 260 | self._hg_init() |
| | 261 | self._add_repository('hgrepos') |
| | 262 | repos = self._repomgr.get_repository('hgrepos') |
| | 263 | repos.sync() |
| | 264 | self.assertEqual(['default', 'tip'], self._get_quickjump_names(repos)) |
| | 265 | self._hg('tag', 'v1.0') |
| | 266 | repos.sync() |
| | 267 | self.assertEqual(['default', 'tip', 'v1.0'], |
| | 268 | self._get_quickjump_names(repos)) |
| | 269 | self._hg('tag', '--remove', 'v1.0') |
| | 270 | repos.sync() |
| | 271 | self.assertEqual(['default', 'tip'], self._get_quickjump_names(repos)) |
| | 272 | |
| | 273 | def test_bookmarks(self): |
| | 274 | self._hg_init() |
| | 275 | self._add_repository('hgrepos') |
| | 276 | repos = self._repomgr.get_repository('hgrepos') |
| | 277 | repos.sync() |
| | 278 | self.assertEqual(['default', 'tip'], self._get_quickjump_names(repos)) |
| | 279 | self._hg('bookmarks', 'alpha') |
| | 280 | repos.sync() |
| | 281 | self.assertEqual(['default', 'alpha', 'tip'], |
| | 282 | self._get_quickjump_names(repos)) |
| | 283 | self._hg('bookmark', '-m', 'alpha', 'beta') |
| | 284 | repos.sync() |
| | 285 | self.assertEqual(['default', 'beta', 'tip'], |
| | 286 | self._get_quickjump_names(repos)) |
| | 287 | self._hg('bookmark', '-d', 'beta') |
| | 288 | repos.sync() |
| | 289 | self.assertEqual(['default', 'tip'], self._get_quickjump_names(repos)) |
| | 290 | |
| | 291 | def _get_quickjump_names(self, repos): |
| | 292 | return list(name for type, name, path, rev |
| | 293 | in repos.get_quickjump_entries('tip')) |
| | 294 | |
| | 295 | def test_changeset_bookmarks_tags(self): |
| | 296 | self._hg_init() |
| | 297 | self._hg('tag', '0.0.1') |
| | 298 | self._hg('tag', '-m', 'Root commit', 'initial', '-r', '0.0.1') |
| | 299 | self._hg('bookmark', 'root', '-r', '0.0.1') |
| | 300 | self._hg('bookmark', 'dev', '-r', '0.0.1') |
| | 301 | create_file(os.path.join(self.repos_path, 'file.txt'), 'text') |
| | 302 | self._hg('add', 'file.txt') |
| | 303 | self._hg_commit('-m', 'Summary') |
| | 304 | self._hg('bookmark', 'dev', '-i') |
| | 305 | self._hg('tag', '0.1.0dev') |
| | 306 | self._hg('tag', '0.1.0a', '-r', '0.1.0dev') |
| | 307 | self._add_repository('hgrepos') |
| | 308 | repos = self._repomgr.get_repository('hgrepos') |
| | 309 | repos.sync() |
| | 310 | |
| | 311 | def get_branches(repos, rev): |
| | 312 | rev = repos.normalize_rev(rev) |
| | 313 | return list(repos.get_changeset(rev).get_branches()) |
| | 314 | |
| | 315 | def get_bookmarks(repos, rev): |
| | 316 | rev = repos.normalize_rev(rev) |
| | 317 | return list(repos.get_changeset(rev).get_bookmarks()) |
| | 318 | |
| | 319 | def get_tags(repos, rev): |
| | 320 | rev = repos.normalize_rev(rev) |
| | 321 | return list(repos.get_changeset(rev).get_tags()) |
| | 322 | |
| | 323 | self.assertEqual([('default', False)], |
| | 324 | get_branches(repos, '0.0.1')) |
| | 325 | self.assertEqual([('default', True)], |
| | 326 | get_branches(repos, 'tip')) |
| | 327 | self.assertEqual(['root'], |
| | 328 | get_bookmarks(repos, '0.0.1')) |
| | 329 | self.assertEqual(['dev'], get_bookmarks(repos, '0.1.0dev')) |
| | 330 | self.assertEqual(['0.0.1', 'initial'], get_tags(repos, '0.0.1')) |
| | 331 | self.assertEqual(['0.0.1', 'initial'], get_tags(repos, 'initial')) |
| | 332 | self.assertEqual(['0.1.0a', '0.1.0dev'], get_tags(repos, '0.1.0dev')) |
| | 333 | |
| | 334 | def test_parent_child_revs(self): |
| | 335 | self._hg_init() |
| | 336 | self._hg('bookmark', 'initial', '-i') # root commit |
| | 337 | self._create_merge_commit() |
| | 338 | self._hg('bookmark', 'latest', '-i') |
| | 339 | |
| | 340 | self._add_repository('hgrepos') |
| | 341 | repos = self._repomgr.get_repository('hgrepos') |
| | 342 | repos.sync() |
| | 343 | |
| | 344 | rev = repos.normalize_rev('initial') |
| | 345 | children = repos.child_revs(rev) |
| | 346 | self.assertEqual(2, len(children), 'child_revs: %r' % children) |
| | 347 | parents = repos.parent_revs(rev) |
| | 348 | self.assertEqual(0, len(parents), 'parent_revs: %r' % parents) |
| | 349 | self.assertEqual(1, len(repos.child_revs(children[0]))) |
| | 350 | self.assertEqual(1, len(repos.child_revs(children[1]))) |
| | 351 | self.assertEqual([('.hgignore', Node.FILE, Changeset.ADD, None, |
| | 352 | None)], |
| | 353 | sorted(repos.get_changeset(rev).get_changes())) |
| | 354 | |
| | 355 | rev = repos.normalize_rev('latest') |
| | 356 | cset = repos.get_changeset(rev) |
| | 357 | children = repos.child_revs(rev) |
| | 358 | self.assertEqual(0, len(children), 'child_revs: %r' % children) |
| | 359 | parents = repos.parent_revs(rev) |
| | 360 | self.assertEqual(2, len(parents), 'parent_revs: %r' % parents) |
| | 361 | self.assertEqual(1, len(repos.parent_revs(parents[0]))) |
| | 362 | self.assertEqual(1, len(repos.parent_revs(parents[1]))) |
| | 363 | |
| | 364 | # check the differences against the first parent |
| | 365 | def fn_repos_changes(entry): |
| | 366 | old_node, new_node, kind, change = entry |
| | 367 | if old_node: |
| | 368 | old_path, old_rev = old_node.path, old_node.rev |
| | 369 | else: |
| | 370 | old_path, old_rev = None, None |
| | 371 | return new_node.path, kind, change, old_path, old_rev |
| | 372 | self.assertEqual(sorted(map(fn_repos_changes, |
| | 373 | repos.get_changes('/', parents[0], '/', |
| | 374 | rev))), |
| | 375 | sorted(cset.get_changes())) |
| | 376 | |
| | 377 | _data_annotation1 = """\ |
| | 378 | one |
| | 379 | two |
| | 380 | three |
| | 381 | """ |
| | 382 | |
| | 383 | _data_annotation2 = """\ |
| | 384 | one |
| | 385 | two |
| | 386 | three |
| | 387 | four |
| | 388 | five |
| | 389 | six |
| | 390 | seven |
| | 391 | eight |
| | 392 | nine |
| | 393 | ten |
| | 394 | """ |
| | 395 | |
| | 396 | _data_annotation3 = """\ |
| | 397 | one |
| | 398 | two |
| | 399 | 3 |
| | 400 | four |
| | 401 | five |
| | 402 | 6 |
| | 403 | seven |
| | 404 | eight |
| | 405 | 9 |
| | 406 | ten |
| | 407 | """ |
| | 408 | |
| | 409 | def test_get_annotations(self): |
| | 410 | self._hg_init(data=False) |
| | 411 | filename = 'test.txt' |
| | 412 | path = os.path.join(self.repos_path, filename) |
| | 413 | create_file(path, self._data_annotation1) |
| | 414 | self._hg('add', filename) |
| | 415 | self._hg_commit('-m', 'blame') |
| | 416 | create_file(path, self._data_annotation2) |
| | 417 | self._hg_commit('-m', 'add lines') |
| | 418 | create_file(path, self._data_annotation3) |
| | 419 | self._hg_commit('-m', 'modify lines') |
| | 420 | self._add_repository('hgrepos') |
| | 421 | repos = self._repomgr.get_repository('hgrepos') |
| | 422 | repos.sync() |
| | 423 | |
| | 424 | rev1 = repos.oldest_rev |
| | 425 | rev2 = repos.next_rev(rev1) |
| | 426 | rev3 = repos.youngest_rev |
| | 427 | |
| | 428 | self.assertEqual([rev1] * 3, |
| | 429 | repos.get_node('test.txt', rev1).get_annotations()) |
| | 430 | self.assertEqual([rev1] * 3 + [rev2] * 7, |
| | 431 | repos.get_node('test.txt', rev2).get_annotations()) |
| | 432 | |
| | 433 | expected = [rev1, rev1, rev3, rev2, rev2, rev3, rev2, rev2, rev3, rev2] |
| | 434 | self.assertEqual(expected, |
| | 435 | repos.get_node('test.txt', rev3).get_annotations()) |
| | 436 | self.assertEqual(expected, |
| | 437 | repos.get_node('test.txt', 'tip').get_annotations()) |
| | 438 | self.assertEqual(expected, |
| | 439 | repos.get_node('test.txt').get_annotations()) |
| | 440 | |
| | 441 | # * 7 Merge branch 'A' |
| | 442 | # |\ |
| | 443 | # | * 6 Merge branch 'B' into A |
| | 444 | # | |\ |
| | 445 | # | | * 5 Changed a1 |
| | 446 | # | * | 4 Changed a2 |
| | 447 | # * | | 3 Changed b2 |
| | 448 | # | |/ |
| | 449 | # |/| |
| | 450 | # * | 2 Changed b2 |
| | 451 | # * | 1 Changed b1 |
| | 452 | # |/ |
| | 453 | # * 0 First commit |
| | 454 | |
| | 455 | def test_iter_nodes(self): |
| | 456 | self._hg_init(data=False) |
| | 457 | a1_filename = 'A/a1.txt' |
| | 458 | a2_filename = 'A/a2.txt' |
| | 459 | b1_filename = 'B/b1.txt' |
| | 460 | b2_filename = 'B/b2.txt' |
| | 461 | a1_path = os.path.join(self.repos_path, a1_filename) |
| | 462 | a2_path = os.path.join(self.repos_path, a2_filename) |
| | 463 | b1_path = os.path.join(self.repos_path, b1_filename) |
| | 464 | b2_path = os.path.join(self.repos_path, b2_filename) |
| | 465 | makedirs(os.path.join(self.repos_path, 'A')) |
| | 466 | makedirs(os.path.join(self.repos_path, 'B')) |
| | 467 | create_file(a1_path, 'a1') |
| | 468 | create_file(a2_path, 'a2') |
| | 469 | create_file(b1_path, 'b1') |
| | 470 | create_file(b2_path, 'b2') |
| | 471 | self._hg('add', a1_filename) |
| | 472 | self._hg('add', a2_filename) |
| | 473 | self._hg('add', b1_filename) |
| | 474 | self._hg('add', b2_filename) |
| | 475 | self._hg_commit('-m', 'First commit') |
| | 476 | create_file(b1_path, 'b1-1') |
| | 477 | self._hg_commit('-m', 'Changed b1') |
| | 478 | create_file(b2_path, 'b2-1') |
| | 479 | self._hg_commit('-m', 'Changed b2') |
| | 480 | |
| | 481 | create_file(b2_path, 'b2-2') |
| | 482 | self._hg_commit('-m', 'Changed b2') |
| | 483 | self._hg('update', '0') |
| | 484 | create_file(a2_path, 'a2-1') |
| | 485 | self._hg_commit('-m', 'Changed a2') |
| | 486 | self._hg('update', '2') |
| | 487 | create_file(a1_path, 'a1-1') |
| | 488 | self._hg_commit('-m', 'Changed 12') |
| | 489 | |
| | 490 | self._hg('merge', '4') |
| | 491 | self._hg_commit('-m', "Merge branch 'B' into A") |
| | 492 | self._hg('merge', '3') |
| | 493 | self._hg_commit('-m', "Merge branch 'A'") |
| | 494 | |
| | 495 | self._add_repository('hgrepos') |
| | 496 | repos = self._repomgr.get_repository('hgrepos') |
| | 497 | repos.sync() |
| | 498 | mod = BrowserModule(self.env) |
| | 499 | |
| | 500 | r0 = repos.normalize_rev('0') |
| | 501 | r1 = repos.normalize_rev('1') |
| | 502 | r2 = repos.normalize_rev('2') |
| | 503 | r3 = repos.normalize_rev('3') |
| | 504 | r4 = repos.normalize_rev('4') |
| | 505 | r5 = repos.normalize_rev('5') |
| | 506 | r6 = repos.normalize_rev('6') |
| | 507 | r7 = repos.normalize_rev('7') |
| | 508 | |
| | 509 | root_node = repos.get_node('') |
| | 510 | nodes = list(mod._iter_nodes(root_node)) |
| | 511 | self.assertEqual([r7] * 7, |
| | 512 | [node.rev for node in nodes]) |
| | 513 | self.assertEqual([ |
| | 514 | (r7, ''), |
| | 515 | (r5, 'A'), |
| | 516 | (r5, 'A/a1.txt'), |
| | 517 | (r4, 'A/a2.txt'), |
| | 518 | (r3, 'B'), |
| | 519 | (r1, 'B/b1.txt'), |
| | 520 | (r3, 'B/b2.txt'), |
| | 521 | ], [(node.created_rev, node.path) for node in nodes]) |
| | 522 | |
| | 523 | root_node = repos.get_node('', |
| | 524 | r6) |
| | 525 | nodes = list(mod._iter_nodes(root_node)) |
| | 526 | self.assertEqual([r6] * 7, |
| | 527 | [node.rev for node in nodes]) |
| | 528 | self.assertEqual([ |
| | 529 | (r6, ''), |
| | 530 | (r5, 'A'), |
| | 531 | (r5, 'A/a1.txt'), |
| | 532 | (r4, 'A/a2.txt'), |
| | 533 | (r2, 'B'), |
| | 534 | (r1, 'B/b1.txt'), |
| | 535 | (r2, 'B/b2.txt'), |
| | 536 | ], [(node.created_rev, node.path) for node in nodes]) |
| | 537 | |
| | 538 | root_commit = r0 |
| | 539 | root_node = repos.get_node('', root_commit) |
| | 540 | nodes = list(mod._iter_nodes(root_node)) |
| | 541 | self.assertEqual([root_commit] * 7, [node.rev for node in nodes]) |
| | 542 | self.assertEqual([ |
| | 543 | (root_commit, ''), |
| | 544 | (root_commit, 'A'), |
| | 545 | (root_commit, 'A/a1.txt'), |
| | 546 | (root_commit, 'A/a2.txt'), |
| | 547 | (root_commit, 'B'), |
| | 548 | (root_commit, 'B/b1.txt'), |
| | 549 | (root_commit, 'B/b2.txt'), |
| | 550 | ], [(node.created_rev, node.path) for node in nodes]) |
| | 551 | |
| | 552 | |
| | 553 | def test_suite(): |
| | 554 | suite = unittest.TestSuite() |
| | 555 | if HgCommandMixin.hg_bin: |
| | 556 | suite.addTest(unittest.makeSuite(SanityCheckingTestCase)) |
| | 557 | suite.addTest(unittest.makeSuite(HistoryTimeRangeTestCase)) |
| | 558 | suite.addTest(unittest.makeSuite(HgNormalTestCase)) |
| | 559 | suite.addTest(unittest.makeSuite(HgRepositoryTestCase)) |
| | 560 | else: |
| | 561 | print("SKIP: tracopt/versioncontrol/hg/tests/hg_fs.py (hg cli " |
| | 562 | "binary, 'hg', not found)") |
| | 563 | return suite |
| | 564 | |
| | 565 | |
| | 566 | if __name__ == '__main__': |
| | 567 | unittest.main(defaultTest='test_suite') |