1# -*- coding: utf-8 -*- 2# 3# Copyright (C) 2006-2021 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 https://trac.edgewall.com/license.html. 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 https://trac.edgewall.org/. 13 14import unittest 15 16from trac.test import Mock 17from trac.versioncontrol.api import * 18from trac.versioncontrol.web_ui import * 19from trac.wiki.tests import formatter 20 21 22YOUNGEST_REV = 200 23 24 25def _get_changeset(rev): 26 if rev == '1': 27 return Mock(message="start", is_viewable=lambda perm: True) 28 else: 29 raise NoSuchChangeset(rev) 30 31 32def _normalize_rev(rev): 33 if rev is None or rev in ('', 'head'): 34 return YOUNGEST_REV 35 try: 36 nrev = int(rev) 37 if nrev <= YOUNGEST_REV: 38 return nrev 39 except ValueError: 40 pass 41 raise NoSuchChangeset(rev) 42 43 44def _get_node(path, rev=None): 45 if path == 'foo': 46 return Mock(path=path, rev=rev, isfile=False, 47 is_viewable=lambda resource: True) 48 elif path == 'missing/file': 49 raise NoSuchNode(path, rev) 50 else: 51 return Mock(path=path, rev=rev, isfile=True, 52 is_viewable=lambda resource: True) 53 54 55class GitRepositoryStub(object): 56 57 has_linear_changesets = False 58 59 _revs = [ 60 ('ffffffffffffffffffffffffffffffffffffffff', ('HEAD',)), 61 ('deadbef222222222222222222222222222222222', ('1.0-stable', 62 '1.0-stáblé')), 63 ('deadbef111111111111111111111111111111111', ('v1.0.1', 'vér1.0.1')), 64 ('deadbef000000000000000000000000000000000', ('v1.0', 'vér1.0')), 65 ('deadbeefffffffffffffffffffffffffffffffff', ('0.12-stable', 66 '0.12-stáblé')), 67 ('0000009876543210987654321098765432109876', ()), # only digits 68 ('0000001234567890123456789012345678901234', ()), 69 ('1111111111111111111111111111111111111111', ()), # oldest rev 70 ] 71 72 def __init__(self, reponame): 73 self.reponame = reponame 74 self.resource = Resource('repository', self.reponame) 75 self.youngest_rev = 'ffffffffffffffffffffffffffffffffffffffff' 76 self.oldest_rev = '1111111111111111111111111111111111111111' 77 78 def get_changeset(self, rev): 79 nrev = None 80 if not rev: 81 nrev = self.youngest_rev 82 else: 83 revs = [r for r, names in self._revs if r.startswith(rev)] 84 if len(revs) == 1: 85 nrev = revs[0] 86 else: 87 for r, names in self._revs: 88 if rev in names: 89 nrev = r 90 break 91 if nrev: 92 return Mock(repos=self, rev=nrev, message='message %s' % nrev[:8], 93 author='trac', is_viewable=lambda perm: True) 94 raise NoSuchChangeset(rev) 95 96 def normalize_rev(self, rev): 97 cset = self.get_changeset(rev) 98 return cset.rev 99 100 def get_node(self, path, rev=None): 101 return _get_node(path, rev) 102 103 104def _get_repository(reponame): 105 if reponame.endswith('.git'): 106 return GitRepositoryStub(reponame) 107 return Mock(reponame=reponame, youngest_rev=YOUNGEST_REV, 108 get_changeset=_get_changeset, get_node=_get_node, 109 normalize_rev=_normalize_rev, 110 has_linear_changesets=True, 111 resource=Resource('repository', reponame)) 112 113 114def _get_all_repositories(): 115 return {'': {}, 'trac.git': {}} 116 117 118def repository_setup(tc): 119 setattr(RepositoryManager(tc.env), 'get_repository', _get_repository) 120 setattr(RepositoryManager(tc.env), 'get_all_repositories', 121 _get_all_repositories) 122 123 124CHANGESET_TEST_CASES = """ 125============================== changeset: link resolver 126changeset:1 127changeset:12 128changeset:abc 129changeset:1, changeset:1/README.txt 130------------------------------ 131<p> 132<a class="changeset" href="/changeset/1" title="start">changeset:1</a> 133<a class="missing changeset" title="No changeset 12 in the repository">changeset:12</a> 134<a class="missing changeset" title="No changeset abc in the repository">changeset:abc</a> 135<a class="changeset" href="/changeset/1" title="start">changeset:1</a>, <a class="changeset" href="/changeset/1/README.txt" title="start">changeset:1/README.txt</a> 136</p> 137------------------------------ 138============================== changeset: link resolver + query and fragment 139changeset:1?format=diff 140changeset:1#file0 141------------------------------ 142<p> 143<a class="changeset" href="/changeset/1?format=diff" title="start">changeset:1?format=diff</a> 144<a class="changeset" href="/changeset/1#file0" title="start">changeset:1#file0</a> 145</p> 146------------------------------ 147============================== changeset shorthand syntax 148[1], r1 149[12], r12, rABC 150[1/README.txt], r1/trunk, rABC/trunk 151------------------------------ 152<p> 153<a class="changeset" href="/changeset/1" title="start">[1]</a>, <a class="changeset" href="/changeset/1" title="start">r1</a> 154<a class="missing changeset" title="No changeset 12 in the repository">[12]</a>, <a class="missing changeset" title="No changeset 12 in the repository">r12</a>, rABC 155<a class="changeset" href="/changeset/1/README.txt" title="start">[1/README.txt]</a>, <a class="changeset" href="/changeset/1/trunk" title="start">r1/trunk</a>, rABC/trunk 156</p> 157------------------------------ 158============================== changeset shorthand syntax + query and fragment 159[1?format=diff] 160[1#file0] 161[1/README.txt?format=diff] 162[1/README.txt#file0] 163------------------------------ 164<p> 165<a class="changeset" href="/changeset/1?format=diff" title="start">[1?format=diff]</a> 166<a class="changeset" href="/changeset/1#file0" title="start">[1#file0]</a> 167<a class="changeset" href="/changeset/1/README.txt?format=diff" title="start">[1/README.txt?format=diff]</a> 168<a class="changeset" href="/changeset/1/README.txt#file0" title="start">[1/README.txt#file0]</a> 169</p> 170------------------------------ 171============================== escaping the above 172![1], !r1 173------------------------------ 174<p> 175[1], r1 176</p> 177------------------------------ 178============================== unicode digits 179[₁₂₃], r₁₂₃, [₀A₁B₂C₃D] 180------------------------------ 181<p> 182[₁₂₃], r₁₂₃, [₀A₁B₂C₃D] 183</p> 184------------------------------ 185============================== Link resolver counter examples 186Change:[10] There should be a link to changeset [10] 187 188rfc and rfc:4180 should not be changeset links, neither should rfc4180 189------------------------------ 190<p> 191Change:<a class="missing changeset" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" title="No changeset 10 in the repository">[10]</a> 192</p> 193<p> 194rfc and rfc:4180 should not be changeset links, neither should rfc4180 195</p> 196------------------------------ 197Change:<a class="missing changeset" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" title="No changeset 10 in the repository">[10]</a> 198 199rfc and rfc:4180 should not be changeset links, neither should rfc4180 200============================== InterTrac for changesets 201trac:changeset:2081 202[trac:changeset:2081 Trac r2081] 203------------------------------ 204<p> 205<a class="ext-link" href="https://trac.edgewall.org/intertrac/changeset%3A2081" title="changeset:2081 in The Trac Project"><span class="icon"></span>trac:changeset:2081</a> 206<a class="ext-link" href="https://trac.edgewall.org/intertrac/changeset%3A2081" title="changeset:2081 in The Trac Project"><span class="icon"></span>Trac r2081</a> 207</p> 208------------------------------ 209============================== Changeset InterTrac shorthands 210[T2081] 211[trac 2081] 212[trac 2081/trunk] 213T:r2081 214------------------------------ 215<p> 216<a class="ext-link" href="https://trac.edgewall.org/intertrac/changeset%3A2081" title="changeset:2081 in The Trac Project"><span class="icon"></span>[T2081]</a> 217<a class="ext-link" href="https://trac.edgewall.org/intertrac/changeset%3A2081" title="changeset:2081 in The Trac Project"><span class="icon"></span>[trac 2081]</a> 218<a class="ext-link" href="https://trac.edgewall.org/intertrac/changeset%3A2081/trunk" title="changeset:2081/trunk in The Trac Project"><span class="icon"></span>[trac 2081/trunk]</a> 219<a class="ext-link" href="https://trac.edgewall.org/intertrac/r2081" title="r2081 in The Trac Project"><span class="icon"></span>T:r2081</a> 220</p> 221------------------------------ 222""" #" 223 224 225LOG_TEST_CASES = """ 226============================== Log range TracLinks 227[1:2], r1:2, [12:23], r12:23 228[1:2/trunk], r1:2/trunk 229[2:1/trunk] reversed, r2:1/trunk reversed 230------------------------------ 231<p> 232<a class="source" href="/log/?revs=1-2">[1:2]</a>, <a class="source" href="/log/?revs=1-2">r1:2</a>, <a class="source" href="/log/?revs=12-23">[12:23]</a>, <a class="source" href="/log/?revs=12-23">r12:23</a> 233<a class="source" href="/log/trunk?revs=1-2">[1:2/trunk]</a>, <a class="source" href="/log/trunk?revs=1-2">r1:2/trunk</a> 234<a class="source" href="/log/trunk?revs=1-2">[2:1/trunk]</a> reversed, <a class="source" href="/log/trunk?revs=1-2">r2:1/trunk</a> reversed 235</p> 236------------------------------ 237============================== changeset and log shorthand syntax with hash ids 238[deadbeef/trac.git] 239[deadbeef/trac.git/trac] 240[deadbeef:deadbef1/trac.git] 241[deadbeef:deadbef1/trac.git/trac] 242------------------------------ 243<p> 244<a class="changeset" href="/changeset/deadbeef/trac.git" title="message deadbeef">[deadbeef/trac.git]</a> 245<a class="changeset" href="/changeset/deadbeef/trac.git/trac" title="message deadbeef">[deadbeef/trac.git/trac]</a> 246<a class="source" href="/log/trac.git/?revs=deadbeef%3Adeadbef1">[deadbeef:deadbef1/trac.git]</a> 247<a class="source" href="/log/trac.git/trac?revs=deadbeef%3Adeadbef1">[deadbeef:deadbef1/trac.git/trac]</a> 248</p> 249------------------------------ 250============================== changeset and log with digit hash on non linear changesets 251[00000012/trac.git] 252[00000012/trac.git/trac] 253[00000012:00000098/trac.git] 254[00000012:00000098/trac.git/trac] 255------------------------------ 256<p> 257<a class="changeset" href="/changeset/00000012/trac.git" title="message 00000012">[00000012/trac.git]</a> 258<a class="changeset" href="/changeset/00000012/trac.git/trac" title="message 00000012">[00000012/trac.git/trac]</a> 259<a class="source" href="/log/trac.git/?revs=00000012%3A00000098">[00000012:00000098/trac.git]</a> 260<a class="source" href="/log/trac.git/trac?revs=00000012%3A00000098">[00000012:00000098/trac.git/trac]</a> 261</p> 262------------------------------ 263============================== Big ranges (#9955 regression) 264[1234567890:12345678901] 265------------------------------ 266<p> 267<a class="source" href="/log/?revs=1234567890-12345678901">[1234567890:12345678901]</a> 268</p> 269------------------------------ 270<a class="source" href="/log/?revs=1234567890-12345678901">[1234567890:12345678901]</a> 271============================== Escaping Log range TracLinks 272![1:2], !r1:2, ![12:23], !r12:23 273------------------------------ 274<p> 275[1:2], r1:2, [12:23], r12:23 276</p> 277------------------------------ 278[1:2], r1:2, [12:23], r12:23 279============================== log: link resolver 280log:@12 281log:trunk 282log:trunk@head 283log:trunk@12 284log:trunk@12:23 285log:trunk@12-23 286log:trunk:12:23 287log:trunk:12-23 288log:trunk@12:head 289log:trunk:12-head 290log:trunk:12@23 291------------------------------ 292<p> 293<a class="source" href="/log/?rev=12">log:@12</a> 294<a class="source" href="/log/trunk">log:trunk</a> 295<a class="source" href="/log/trunk?rev=head">log:trunk@head</a> 296<a class="source" href="/log/trunk?rev=12">log:trunk@12</a> 297<a class="source" href="/log/trunk?revs=12-23">log:trunk@12:23</a> 298<a class="source" href="/log/trunk?revs=12-23">log:trunk@12-23</a> 299<a class="source" href="/log/trunk?revs=12-23">log:trunk:12:23</a> 300<a class="source" href="/log/trunk?revs=12-23">log:trunk:12-23</a> 301<a class="source" href="/log/trunk?revs=12-head">log:trunk@12:head</a> 302<a class="source" href="/log/trunk?revs=12-head">log:trunk:12-head</a> 303<a class="missing source" title="No changeset 12@23 in the repository">log:trunk:12@23</a> 304</p> 305------------------------------ 306============================== log: link resolver with hash revs and named revs 307log:trac.git@fffffff 308log:trac.git/trunk 309log:trac.git/trunk@HEAD 310log:trac.git/trunk@deadbeef 311log:trac.git/trunk@deadbeef:deadbef1 312log:trac.git/trunk@deadbeef-deadbef1 313log:trac.git/trunk:deadbeef:deadbef1 314log:trac.git/trunk:deadbeef-deadbef1 315log:trac.git/trunk@deadbeef:HEAD 316log:trac.git/trunk:deadbeef-HEAD 317log:trac.git/trunk:deadbeef@deadbef1 318log:trac.git/trunk@1.0-stable 319log:trac.git/trunk@0.12-stable:1.0-stable 320log:trac.git/trunk@v1.0-v1.0.1 321log:trac.git/trunk@0.12-stáblé:1.0-stáblé 322log:trac.git/trunk@vér1.0-vér1.0.1 323------------------------------ 324<p> 325<a class="source" href="/log/trac.git/?rev=fffffff">log:trac.git@fffffff</a> 326<a class="source" href="/log/trac.git/trunk">log:trac.git/trunk</a> 327<a class="source" href="/log/trac.git/trunk?rev=HEAD">log:trac.git/trunk@HEAD</a> 328<a class="source" href="/log/trac.git/trunk?rev=deadbeef">log:trac.git/trunk@deadbeef</a> 329<a class="source" href="/log/trac.git/trunk?revs=deadbeef%3Adeadbef1">log:trac.git/trunk@deadbeef:deadbef1</a> 330<a class="source" href="/log/trac.git/trunk?revs=deadbeef%3Adeadbef1">log:trac.git/trunk@deadbeef-deadbef1</a> 331<a class="source" href="/log/trac.git/trunk?revs=deadbeef%3Adeadbef1">log:trac.git/trunk:deadbeef:deadbef1</a> 332<a class="source" href="/log/trac.git/trunk?revs=deadbeef%3Adeadbef1">log:trac.git/trunk:deadbeef-deadbef1</a> 333<a class="source" href="/log/trac.git/trunk?revs=deadbeef%3AHEAD">log:trac.git/trunk@deadbeef:HEAD</a> 334<a class="missing source" title="No changeset deadbeef-HEAD in the repository">log:trac.git/trunk:deadbeef-HEAD</a> 335<a class="missing source" title="No changeset deadbeef@deadbef1 in the repository">log:trac.git/trunk:deadbeef@deadbef1</a> 336<a class="source" href="/log/trac.git/trunk?rev=1.0-stable">log:trac.git/trunk@1.0-stable</a> 337<a class="source" href="/log/trac.git/trunk?revs=0.12-stable%3A1.0-stable">log:trac.git/trunk@0.12-stable:1.0-stable</a> 338<a class="missing source" title="No changeset v1.0-v1.0.1 in the repository">log:trac.git/trunk@v1.0-v1.0.1</a> 339<a class="source" href="/log/trac.git/trunk?revs=0.12-st%C3%A1bl%C3%A9%3A1.0-st%C3%A1bl%C3%A9">log:trac.git/trunk@0.12-stáblé:1.0-stáblé</a> 340<a class="missing source" title="No changeset vér1.0-vér1.0.1 in the repository">log:trac.git/trunk@vér1.0-vér1.0.1</a> 341</p> 342------------------------------ 343============================== log: link resolver with missing revisions 344log:@4242 345log:@4242-4243 346log:@notfound 347log:@deadbeef:deadbef0 348log:trunk@4243 349log:trunk@notfound 350[4242:4243] 351------------------------------ 352<p> 353<a class="missing source" title="No changeset 4242 in the repository">log:@4242</a> 354<a class="source" href="/log/?revs=4242-4243">log:@4242-4243</a> 355<a class="missing source" title="No changeset notfound in the repository">log:@notfound</a> 356<a class="source" href="/log/?revs=deadbeef-deadbef0">log:@deadbeef:deadbef0</a> 357<a class="missing source" title="No changeset 4243 in the repository">log:trunk@4243</a> 358<a class="missing source" title="No changeset notfound in the repository">log:trunk@notfound</a> 359<a class="source" href="/log/?revs=4242-4243">[4242:4243]</a> 360</p> 361------------------------------ 362============================== log: link resolver + query 363log:?limit=10 364log:@12?limit=10 365log:trunk?limit=10 366log:trunk@12?limit=10 367[10:20?verbose=yes&format=changelog] 368[10:20/trunk?verbose=yes&format=changelog] 369------------------------------ 370<p> 371<a class="source" href="/log/?limit=10">log:?limit=10</a> 372<a class="source" href="/log/?rev=12&limit=10">log:@12?limit=10</a> 373<a class="source" href="/log/trunk?limit=10">log:trunk?limit=10</a> 374<a class="source" href="/log/trunk?rev=12&limit=10">log:trunk@12?limit=10</a> 375<a class="source" href="/log/?revs=10-20&verbose=yes&format=changelog">[10:20?verbose=yes&format=changelog]</a> 376<a class="source" href="/log/trunk?revs=10-20&verbose=yes&format=changelog">[10:20/trunk?verbose=yes&format=changelog]</a> 377</p> 378------------------------------ 379============================== log: link resolver + invalid ranges 380log:@10-20-30 381log:@10,20-30,40-50-60 382log:@10:20:30 383[10-20-30] 384[10:20:30] 385------------------------------ 386<p> 387<a class="missing source" title="No changeset 10-20-30 in the repository">log:@10-20-30</a> 388<a class="source" href="/log/?revs=10%2C20-30%2C40-50-60">log:@10,20-30,40-50-60</a> 389<a class="missing source" title="No changeset 10:20:30 in the repository">log:@10:20:30</a> 390[10-20-30] 391[10:20:30] 392</p> 393------------------------------ 394============================== Multiple Log ranges 395r12:20,25,35:56,68,69,100-120 396[12:20,25,35:56,68,69,100-120] 397[12:20,25,88:head,68,69] (not supported) 398------------------------------ 399<p> 400<a class="source" href="/log/?revs=12-20%2C25%2C35-56%2C68-69%2C100-120">r12:20,25,35:56,68,69,100-120</a> 401<a class="source" href="/log/?revs=12-20%2C25%2C35-56%2C68-69%2C100-120">[12:20,25,35:56,68,69,100-120]</a> 402[12:20,25,88:head,68,69] (not supported) 403</p> 404------------------------------ 405============================== Link resolver counter examples 406rfc:4180 should not be a log link 407------------------------------ 408<p> 409rfc:4180 should not be a log link 410</p> 411------------------------------ 412============================== Log range InterTrac shorthands 413[T3317:3318] 414[trac 3317:3318] 415[trac 3317:3318/trunk] 416------------------------------ 417<p> 418<a class="ext-link" href="https://trac.edgewall.org/intertrac/log%3A/%403317%3A3318" title="log:/@3317:3318 in The Trac Project"><span class="icon"></span>[T3317:3318]</a> 419<a class="ext-link" href="https://trac.edgewall.org/intertrac/log%3A/%403317%3A3318" title="log:/@3317:3318 in The Trac Project"><span class="icon"></span>[trac 3317:3318]</a> 420<a class="ext-link" href="https://trac.edgewall.org/intertrac/log%3A/trunk%403317%3A3318" title="log:/trunk@3317:3318 in The Trac Project"><span class="icon"></span>[trac 3317:3318/trunk]</a> 421</p> 422------------------------------ 423============================== Log range with unicode digits 424r₁₂:₂₀,₂₅,₃₀-₃₅ 425[₁₂:₂₀,₂₅,₃₀-₃₅] 426[T₃₃₁₇:₃₃₁₈] 427[trac ₃₃₁₇:₃₃₁₈] 428------------------------------ 429<p> 430r₁₂:₂₀,₂₅,₃₀-₃₅ 431[₁₂:₂₀,₂₅,₃₀-₃₅] 432[T₃₃₁₇:₃₃₁₈] 433[trac ₃₃₁₇:₃₃₁₈] 434</p> 435------------------------------ 436""" 437 438 439DIFF_TEST_CASES = """ 440============================== diff: link resolver 441diff:trunk//branch 442diff:trunk@12//branch@23 443diff:trunk@12:23 444diff:@12:23 445------------------------------ 446<p> 447<a class="changeset" href="/changeset?new_path=branch&old_path=trunk" title="Diff from trunk@latest to branch@latest">diff:trunk//branch</a> 448<a class="changeset" href="/changeset?new=23&new_path=branch&old=12&old_path=trunk" title="Diff from trunk@12 to branch@23">diff:trunk@12//branch@23</a> 449<a class="changeset" href="/changeset?new=23&new_path=trunk&old=12&old_path=trunk" title="Diff [12:23] for trunk">diff:trunk@12:23</a> 450<a class="changeset" href="/changeset?new=23&old=12" title="Diff [12:23] for /">diff:@12:23</a> 451</p> 452------------------------------ 453============================== diff: link resolver + query 454diff:trunk//branch?format=diff 455------------------------------ 456<p> 457<a class="changeset" href="/changeset?new_path=branch&old_path=trunk&format=diff" title="Diff from trunk@latest to branch@latest">diff:trunk//branch?format=diff</a> 458</p> 459------------------------------ 460============================== diff: link, empty diff 461diff:// 462------------------------------ 463<p> 464<a class="changeset" title="Diff [latest:latest] for /">diff://</a> 465</p> 466------------------------------ 467""" 468 469 470SOURCE_TEST_CASES = """ 471============================== source: link resolver 472source:/foo/bar 473source:/foo/bar#42 # no long works as rev spec 474source:/foo/bar#head # 475source:/foo/bar@42 476source:/foo/bar@head 477source:/foo%20bar/baz%2Bquux 478source:@42 479source:/foo/bar@42#L20 480source:/foo/bar@head#L20 481source:/foo/bar@#L20 482source:/missing/file 483------------------------------ 484<p> 485<a class="source" href="/browser/foo/bar">source:/foo/bar</a><a class="trac-rawlink" href="/export/HEAD/foo/bar" title="Download"></a> 486<a class="source" href="/browser/foo/bar#42">source:/foo/bar#42</a><a class="trac-rawlink" href="/export/HEAD/foo/bar#42" title="Download"></a> # no long works as rev spec 487<a class="source" href="/browser/foo/bar#head">source:/foo/bar#head</a><a class="trac-rawlink" href="/export/HEAD/foo/bar#head" title="Download"></a> # 488<a class="source" href="/browser/foo/bar?rev=42">source:/foo/bar@42</a><a class="trac-rawlink" href="/export/42/foo/bar" title="Download"></a> 489<a class="source" href="/browser/foo/bar?rev=head">source:/foo/bar@head</a><a class="trac-rawlink" href="/export/head/foo/bar" title="Download"></a> 490<a class="source" href="/browser/foo%2520bar/baz%252Bquux">source:/foo%20bar/baz%2Bquux</a><a class="trac-rawlink" href="/export/HEAD/foo%2520bar/baz%252Bquux" title="Download"></a> 491<a class="source" href="/browser/?rev=42">source:@42</a><a class="trac-rawlink" href="/export/42/" title="Download"></a> 492<a class="source" href="/browser/foo/bar?rev=42#L20">source:/foo/bar@42#L20</a><a class="trac-rawlink" href="/export/42/foo/bar#L20" title="Download"></a> 493<a class="source" href="/browser/foo/bar?rev=head#L20">source:/foo/bar@head#L20</a><a class="trac-rawlink" href="/export/head/foo/bar#L20" title="Download"></a> 494<a class="source" href="/browser/foo/bar#L20">source:/foo/bar@#L20</a><a class="trac-rawlink" href="/export/HEAD/foo/bar#L20" title="Download"></a> 495<a class="missing source">source:/missing/file</a> 496</p> 497------------------------------ 498============================== source: link resolver + query 499source:/foo?order=size&desc=1 500source:/foo/bar?format=raw 501------------------------------ 502<p> 503<a class="source" href="/browser/foo?order=size&desc=1">source:/foo?order=size&desc=1</a> 504<a class="source" href="/browser/foo/bar?format=raw">source:/foo/bar?format=raw</a><a class="trac-rawlink" href="/export/HEAD/foo/bar" title="Download"></a> 505</p> 506------------------------------ 507============================== source: provider, with quoting 508source:'even with whitespaces' 509source:"even with whitespaces" 510[source:'even with whitespaces' Path with spaces] 511[source:"even with whitespaces" Path with spaces] 512------------------------------ 513<p> 514<a class="source" href="/browser/even%20with%20whitespaces">source:'even with whitespaces'</a><a class="trac-rawlink" href="/export/HEAD/even%20with%20whitespaces" title="Download"></a> 515<a class="source" href="/browser/even%20with%20whitespaces">source:"even with whitespaces"</a><a class="trac-rawlink" href="/export/HEAD/even%20with%20whitespaces" title="Download"></a> 516<a class="source" href="/browser/even%20with%20whitespaces">Path with spaces</a><a class="trac-rawlink" href="/export/HEAD/even%20with%20whitespaces" title="Download"></a> 517<a class="source" href="/browser/even%20with%20whitespaces">Path with spaces</a><a class="trac-rawlink" href="/export/HEAD/even%20with%20whitespaces" title="Download"></a> 518</p> 519------------------------------ 520============================== export: link resolver 521export:/foo/bar.html 522export:123:/foo/pict.gif 523export:/foo/pict.gif@123 524------------------------------ 525<p> 526<a class="export" href="/export/HEAD/foo/bar.html" title="Download">export:/foo/bar.html</a> 527<a class="export" href="/export/123/foo/pict.gif" title="Download">export:123:/foo/pict.gif</a> 528<a class="export" href="/export/123/foo/pict.gif" title="Download">export:/foo/pict.gif@123</a> 529</p> 530------------------------------ 531============================== export: link resolver + fragment 532export:/foo/bar.html#header 533------------------------------ 534<p> 535<a class="export" href="/export/HEAD/foo/bar.html#header" title="Download">export:/foo/bar.html#header</a> 536</p> 537------------------------------ 538""" # " (be Emacs friendly...) 539 540 541def test_suite(): 542 suite = unittest.TestSuite() 543 suite.addTest(formatter.test_suite(CHANGESET_TEST_CASES, repository_setup, 544 __file__)) 545 suite.addTest(formatter.test_suite(LOG_TEST_CASES, repository_setup, 546 __file__)) 547 suite.addTest(formatter.test_suite(DIFF_TEST_CASES, file=__file__)) 548 suite.addTest(formatter.test_suite(SOURCE_TEST_CASES, repository_setup, 549 __file__)) 550 return suite 551 552 553if __name__ == '__main__': 554 unittest.main(defaultTest='test_suite') 555