OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """Unittest for the autolink feature.""" |
| 7 |
| 8 import re |
| 9 import unittest |
| 10 |
| 11 from features import autolink |
| 12 from framework import template_helpers |
| 13 from proto import tracker_pb2 |
| 14 from testing import fake |
| 15 from testing import testing_helpers |
| 16 |
| 17 |
| 18 SIMPLE_EMAIL_RE = re.compile(r'([a-z]+)@([a-z]+)\.com') |
| 19 OVER_AMBITIOUS_DOMAIN_RE = re.compile(r'([a-z]+)\.(com|net|org)') |
| 20 |
| 21 |
| 22 class AutolinkTest(unittest.TestCase): |
| 23 |
| 24 def RegisterEmailCallbacks(self, aa): |
| 25 |
| 26 def LookupUsers(_mr, all_addresses): |
| 27 """Return user objects for only users who are at trusted domains.""" |
| 28 return [addr for addr in all_addresses |
| 29 if addr.endswith('@example.com')] |
| 30 |
| 31 def Match2Addresses(_mr, match): |
| 32 return [match.group(0)] |
| 33 |
| 34 def MakeMailtoLink(_mr, match, comp_ref_artifacts): |
| 35 email = match.group(0) |
| 36 if email in comp_ref_artifacts: |
| 37 return [template_helpers.TextRun( |
| 38 tag='a', href='mailto:%s' % email, content=email)] |
| 39 else: |
| 40 return [template_helpers.TextRun('%s AT %s.com' % match.group(1, 2))] |
| 41 |
| 42 aa.RegisterComponent('testcomp', |
| 43 LookupUsers, |
| 44 Match2Addresses, |
| 45 {SIMPLE_EMAIL_RE: MakeMailtoLink}) |
| 46 |
| 47 def RegisterDomainCallbacks(self, aa): |
| 48 |
| 49 def LookupDomains(_mr, _all_refs): |
| 50 """Return business objects for only real domains. Always just True.""" |
| 51 return True # We don't have domain business objects, accept anything. |
| 52 |
| 53 def Match2Domains(_mr, match): |
| 54 return [match.group(0)] |
| 55 |
| 56 def MakeHyperLink(_mr, match, _comp_ref_artifacts): |
| 57 domain = match.group(0) |
| 58 return [template_helpers.TextRun(tag='a', href=domain, content=domain)] |
| 59 |
| 60 aa.RegisterComponent('testcomp2', |
| 61 LookupDomains, |
| 62 Match2Domains, |
| 63 {OVER_AMBITIOUS_DOMAIN_RE: MakeHyperLink}) |
| 64 |
| 65 def setUp(self): |
| 66 self.aa = autolink.Autolink() |
| 67 self.RegisterEmailCallbacks(self.aa) |
| 68 self.comment1 = ('Feel free to contact me at a@other.com, ' |
| 69 'or b@example.com, or c@example.org.') |
| 70 self.comment2 = 'no matches in this comment' |
| 71 self.comment3 = 'just matches with no ref: a@other.com, c@example.org' |
| 72 self.comments = [self.comment1, self.comment2, self.comment3] |
| 73 |
| 74 def testRegisterComponent(self): |
| 75 self.assertIn('testcomp', self.aa.registry) |
| 76 |
| 77 def testGetAllReferencedArtifacts(self): |
| 78 all_ref_artifacts = self.aa.GetAllReferencedArtifacts( |
| 79 None, self.comments) |
| 80 |
| 81 self.assertIn('testcomp', all_ref_artifacts) |
| 82 comp_refs = all_ref_artifacts['testcomp'] |
| 83 self.assertIn('b@example.com', comp_refs) |
| 84 self.assertTrue(len(comp_refs) == 1) |
| 85 |
| 86 def testMarkupAutolinks(self): |
| 87 all_ref_artifacts = self.aa.GetAllReferencedArtifacts(None, self.comments) |
| 88 result = self.aa.MarkupAutolinks( |
| 89 None, [template_helpers.TextRun(self.comment1)], all_ref_artifacts) |
| 90 self.assertEqual('Feel free to contact me at ', result[0].content) |
| 91 self.assertEqual('a AT other.com', result[1].content) |
| 92 self.assertEqual(', or ', result[2].content) |
| 93 self.assertEqual('b@example.com', result[3].content) |
| 94 self.assertEqual('mailto:b@example.com', result[3].href) |
| 95 self.assertEqual(', or c@example.org.', result[4].content) |
| 96 |
| 97 result = self.aa.MarkupAutolinks( |
| 98 None, [template_helpers.TextRun(self.comment2)], all_ref_artifacts) |
| 99 self.assertEqual('no matches in this comment', result[0].content) |
| 100 |
| 101 result = self.aa.MarkupAutolinks( |
| 102 None, [template_helpers.TextRun(self.comment3)], all_ref_artifacts) |
| 103 self.assertEqual('just matches with no ref: ', result[0].content) |
| 104 self.assertEqual('a AT other.com', result[1].content) |
| 105 self.assertEqual(', c@example.org', result[2].content) |
| 106 |
| 107 def testNonnestedAutolinks(self): |
| 108 """Test that when a substitution yields plain text, others are applied.""" |
| 109 self.RegisterDomainCallbacks(self.aa) |
| 110 all_ref_artifacts = self.aa.GetAllReferencedArtifacts(None, self.comments) |
| 111 result = self.aa.MarkupAutolinks( |
| 112 None, [template_helpers.TextRun(self.comment1)], all_ref_artifacts) |
| 113 self.assertEqual('Feel free to contact me at ', result[0].content) |
| 114 self.assertEqual('a AT ', result[1].content) |
| 115 self.assertEqual('other.com', result[2].content) |
| 116 self.assertEqual('other.com', result[2].href) |
| 117 self.assertEqual(', or ', result[3].content) |
| 118 self.assertEqual('b@example.com', result[4].content) |
| 119 self.assertEqual('mailto:b@example.com', result[4].href) |
| 120 self.assertEqual(', or c@', result[5].content) |
| 121 self.assertEqual('example.org', result[6].content) |
| 122 self.assertEqual('example.org', result[6].href) |
| 123 self.assertEqual('.', result[7].content) |
| 124 |
| 125 result = self.aa.MarkupAutolinks( |
| 126 None, [template_helpers.TextRun(self.comment2)], all_ref_artifacts) |
| 127 self.assertEqual('no matches in this comment', result[0].content) |
| 128 result = self.aa.MarkupAutolinks( |
| 129 None, [template_helpers.TextRun(self.comment3)], all_ref_artifacts) |
| 130 self.assertEqual('just matches with no ref: ', result[0].content) |
| 131 self.assertEqual('a AT ', result[1].content) |
| 132 self.assertEqual('other.com', result[2].content) |
| 133 self.assertEqual('other.com', result[2].href) |
| 134 self.assertEqual(', c@', result[3].content) |
| 135 self.assertEqual('example.org', result[4].content) |
| 136 self.assertEqual('example.org', result[4].href) |
| 137 |
| 138 |
| 139 class URLAutolinkTest(unittest.TestCase): |
| 140 |
| 141 def DoLinkify(self, content): |
| 142 """Calls the linkify method and returns the result. |
| 143 |
| 144 Args: |
| 145 content: string with a hyperlink. |
| 146 |
| 147 Returns: |
| 148 A list of TextRuns with some runs will have the embedded URL hyperlinked. |
| 149 Or, None if no link was detected. |
| 150 """ |
| 151 match = autolink._IS_A_LINK_RE.search(content) |
| 152 if not match: |
| 153 return None |
| 154 |
| 155 replacement_runs = autolink.Linkify(None, match, None) |
| 156 return replacement_runs |
| 157 |
| 158 def testLinkify(self): |
| 159 """Test that given url is autolinked when put in the given context.""" |
| 160 # Disallow the linking of URLs with user names and passwords. |
| 161 test = 'http://user:pass@www.yahoo.com' |
| 162 result = self.DoLinkify('What about %s' % test) |
| 163 self.assertEqual(None, result[0].tag) |
| 164 self.assertEqual(None, result[0].href) |
| 165 self.assertEqual(test, result[0].content) |
| 166 |
| 167 # Disallow the linking of non-HTTP(S) links |
| 168 test = 'nntp://news.google.com' |
| 169 result = self.DoLinkify('%s' % test) |
| 170 self.assertEqual(None, result) |
| 171 |
| 172 # Disallow the linking of file links |
| 173 test = 'file://C:/Windows/System32/cmd.exe' |
| 174 result = self.DoLinkify('%s' % test) |
| 175 self.assertEqual(None, result) |
| 176 |
| 177 # Test some known URLs |
| 178 test = 'http://www.example.com' |
| 179 result = self.DoLinkify('What about %s' % test) |
| 180 self.assertEqual(test, result[0].href) |
| 181 self.assertEqual(test, result[0].content) |
| 182 |
| 183 def testLinkify_FTP(self): |
| 184 """Test that FTP urls are linked.""" |
| 185 # Check for a standard ftp link |
| 186 test = 'ftp://ftp.example.com' |
| 187 result = self.DoLinkify('%s' % test) |
| 188 self.assertEqual(test, result[0].href) |
| 189 self.assertEqual(test, result[0].content) |
| 190 |
| 191 def testLinkify_Context(self): |
| 192 """Test that surrounding syntax is not considered part of the url.""" |
| 193 test = 'http://www.example.com' |
| 194 |
| 195 # Check for a link followed by a comma at end of English phrase. |
| 196 result = self.DoLinkify('The URL %s, points to a great website.' % test) |
| 197 self.assertEqual(test, result[0].href) |
| 198 self.assertEqual(test, result[0].content) |
| 199 self.assertEqual(',', result[1].content) |
| 200 |
| 201 # Check for a link followed by a period at end of English sentence. |
| 202 result = self.DoLinkify('The best site ever, %s.' % test) |
| 203 self.assertEqual(test, result[0].href) |
| 204 self.assertEqual(test, result[0].content) |
| 205 self.assertEqual('.', result[1].content) |
| 206 |
| 207 # Check for a link in paranthesis (), [], or {} |
| 208 result = self.DoLinkify('My fav site (%s).' % test) |
| 209 self.assertEqual(test, result[0].href) |
| 210 self.assertEqual(test, result[0].content) |
| 211 self.assertEqual(').', result[1].content) |
| 212 |
| 213 result = self.DoLinkify('My fav site [%s].' % test) |
| 214 self.assertEqual(test, result[0].href) |
| 215 self.assertEqual(test, result[0].content) |
| 216 self.assertEqual('].', result[1].content) |
| 217 |
| 218 result = self.DoLinkify('My fav site {%s}.' % test) |
| 219 self.assertEqual(test, result[0].href) |
| 220 self.assertEqual(test, result[0].content) |
| 221 self.assertEqual('}.', result[1].content) |
| 222 |
| 223 # Check for a link with trailing colon |
| 224 result = self.DoLinkify('Hit %s: you will love it.' % test) |
| 225 self.assertEqual(test, result[0].href) |
| 226 self.assertEqual(test, result[0].content) |
| 227 self.assertEqual(':', result[1].content) |
| 228 |
| 229 # Check link with commas in query string, but don't include trailing comma. |
| 230 test = 'http://www.example.com/?v=1,2,3' |
| 231 result = self.DoLinkify('Try %s, ok?' % test) |
| 232 self.assertEqual(test, result[0].href) |
| 233 self.assertEqual(test, result[0].content) |
| 234 |
| 235 # Check link surrounded by angle-brackets, or quotes. |
| 236 result = self.DoLinkify('<%s>' % test) |
| 237 self.assertEqual(test, result[0].href) |
| 238 self.assertEqual(test, result[0].content) |
| 239 self.assertEqual('>', result[1].content) |
| 240 |
| 241 result = self.DoLinkify('"%s"' % test) |
| 242 self.assertEqual(test, result[0].href) |
| 243 self.assertEqual(test, result[0].content) |
| 244 self.assertEqual('"', result[1].content) |
| 245 |
| 246 # Check link with embedded quotes. |
| 247 test = 'http://www.example.com/?q="a+b+c"' |
| 248 result = self.DoLinkify('Try %s, ok?' % test) |
| 249 self.assertEqual(test, result[0].href) |
| 250 self.assertEqual(test, result[0].content) |
| 251 self.assertEqual(',', result[1].content) |
| 252 |
| 253 # Check link with embedded parens. |
| 254 test = 'http://www.example.com/funky(foo)and(bar).asp' |
| 255 result = self.DoLinkify('Try %s, ok?' % test) |
| 256 self.assertEqual(test, result[0].href) |
| 257 self.assertEqual(test, result[0].content) |
| 258 self.assertEqual(',', result[1].content) |
| 259 |
| 260 test = 'http://www.example.com/funky(foo)and(bar).asp' |
| 261 result = self.DoLinkify('My fav site <%s>' % test) |
| 262 self.assertEqual(test, result[0].href) |
| 263 self.assertEqual(test, result[0].content) |
| 264 self.assertEqual('>', result[1].content) |
| 265 |
| 266 # Check link with embedded brackets and braces. |
| 267 test = 'http://www.example.com/funky[foo]and{bar}.asp' |
| 268 result = self.DoLinkify('My fav site <%s>' % test) |
| 269 self.assertEqual(test, result[0].href) |
| 270 self.assertEqual(test, result[0].content) |
| 271 self.assertEqual('>', result[1].content) |
| 272 |
| 273 # Check link with mismatched delimeters inside it or outside it. |
| 274 test = 'http://www.example.com/funky"(foo]and>bar}.asp' |
| 275 result = self.DoLinkify('My fav site <%s>' % test) |
| 276 self.assertEqual(test, result[0].href) |
| 277 self.assertEqual(test, result[0].content) |
| 278 self.assertEqual('>', result[1].content) |
| 279 |
| 280 test = 'http://www.example.com/funky"(foo]and>bar}.asp' |
| 281 result = self.DoLinkify('My fav site {%s' % test) |
| 282 self.assertEqual(test, result[0].href) |
| 283 self.assertEqual(test, result[0].content) |
| 284 |
| 285 test = 'http://www.example.com/funky"(foo]and>bar}.asp' |
| 286 result = self.DoLinkify('My fav site %s}' % test) |
| 287 self.assertEqual(test, result[0].href) |
| 288 self.assertEqual(test, result[0].content) |
| 289 self.assertEqual('}', result[1].content) |
| 290 |
| 291 # Link as part of an HTML example. |
| 292 test = 'http://www.example.com/' |
| 293 result = self.DoLinkify('<a href="%s">' % test) |
| 294 self.assertEqual(test, result[0].href) |
| 295 self.assertEqual(test, result[0].content) |
| 296 self.assertEqual('">', result[1].content) |
| 297 |
| 298 # Link nested in an HTML tag. |
| 299 result = self.DoLinkify('<span>%s</span>' % test) |
| 300 self.assertEqual(test, result[0].href) |
| 301 self.assertEqual(test, result[0].content) |
| 302 |
| 303 # Link followed by HTML tag - same bug as above. |
| 304 result = self.DoLinkify('%s<span>foo</span>' % test) |
| 305 self.assertEqual(test, result[0].href) |
| 306 self.assertEqual(test, result[0].content) |
| 307 |
| 308 # Link followed by unescaped HTML tag. |
| 309 result = self.DoLinkify('%s<span>foo</span>' % test) |
| 310 self.assertEqual(test, result[0].href) |
| 311 self.assertEqual(test, result[0].content) |
| 312 |
| 313 def testLinkify_UnicodeContext(self): |
| 314 """Test that unicode context does not mess up the link.""" |
| 315 test = 'http://www.example.com' |
| 316 |
| 317 # This string has a non-breaking space \xa0. |
| 318 result = self.DoLinkify(u'The correct RFC link is\xa0%s' % test) |
| 319 self.assertEqual(test, result[0].content) |
| 320 self.assertEqual(test, result[0].href) |
| 321 |
| 322 def testLinkify_UnicodeLink(self): |
| 323 """Test that unicode in a link is OK.""" |
| 324 test = u'http://www.example.com?q=division\xc3\xb7sign' |
| 325 |
| 326 # This string has a non-breaking space \xa0. |
| 327 result = self.DoLinkify(u'The unicode link is %s' % test) |
| 328 self.assertEqual(test, result[0].content) |
| 329 self.assertEqual(test, result[0].href) |
| 330 |
| 331 def testLinkify_LinkTextEscapingDisabled(self): |
| 332 """Test that url-like things that miss validation aren't linked.""" |
| 333 # Link matched by the regex but not accepted by the validator. |
| 334 test = 'http://crash/reportdetail?reportid=35aa03e04772358b' |
| 335 result = self.DoLinkify('<span>%s</span>' % test) |
| 336 self.assertEqual(None, result[0].href) |
| 337 self.assertEqual(test, result[0].content) |
| 338 |
| 339 |
| 340 def _Issue(project_name, local_id, summary, status): |
| 341 issue = tracker_pb2.Issue() |
| 342 issue.project_name = project_name |
| 343 issue.local_id = local_id |
| 344 issue.summary = summary |
| 345 issue.status = status |
| 346 return issue |
| 347 |
| 348 |
| 349 class TrackerAutolinkTest(unittest.TestCase): |
| 350 |
| 351 COMMENT_TEXT = ( |
| 352 'This relates to issue 1, issue #2, and issue3 \n' |
| 353 'as well as bug 4, bug #5, and bug6 \n' |
| 354 'with issue other-project:12 and issue other-project#13. \n' |
| 355 'Watch out for issues 21, 22, and 23 with oxford comma. \n' |
| 356 'And also bugs 31, 32 and 33 with no oxford comma\n' |
| 357 'We do not match when an issue\n' |
| 358 '999. Is split across lines.' |
| 359 ) |
| 360 |
| 361 def testExtractProjectAndIssueId(self): |
| 362 mr = testing_helpers.MakeMonorailRequest( |
| 363 path='/p/proj/issues/detail?id=1') |
| 364 ref_batches = [] |
| 365 for match in autolink._ISSUE_REF_RE.finditer(self.COMMENT_TEXT): |
| 366 new_refs = autolink.ExtractProjectAndIssueIds(mr, match) |
| 367 ref_batches.append(new_refs) |
| 368 |
| 369 self.assertEquals( |
| 370 ref_batches, |
| 371 [[(None, 1)], |
| 372 [(None, 2)], |
| 373 [(None, 3)], |
| 374 [(None, 4)], |
| 375 [(None, 5)], |
| 376 [(None, 6)], |
| 377 [('other-project', 12)], |
| 378 [('other-project', 13)], |
| 379 [(None, 21), (None, 22), (None, 23)], |
| 380 [(None, 31), (None, 32), (None, 33)], |
| 381 ]) |
| 382 |
| 383 def DoReplaceIssueRef(self, content): |
| 384 """Calls the ReplaceIssueRef method and returns the result. |
| 385 |
| 386 Args: |
| 387 content: string that may have a textual reference to an issue. |
| 388 |
| 389 Returns: |
| 390 A list of TextRuns with some runs will have the reference hyperlinked. |
| 391 Or, None if no reference detected. |
| 392 """ |
| 393 match = autolink._ISSUE_REF_RE.search(content) |
| 394 if not match: |
| 395 return None |
| 396 |
| 397 open_dict = {'proj:1': _Issue('proj', 1, 'summary-PROJ-1', 'New'), |
| 398 # Assume there is no issue 3 in PROJ |
| 399 'proj:4': _Issue('proj', 4, 'summary-PROJ-4', 'New'), |
| 400 'proj:6': _Issue('proj', 6, 'summary-PROJ-6', 'New'), |
| 401 'other-project:12': _Issue('other-project', 12, |
| 402 'summary-OP-12', 'Accepted'), |
| 403 } |
| 404 closed_dict = {'proj:2': _Issue('proj', 2, 'summary-PROJ-2', 'Fixed'), |
| 405 'proj:5': _Issue('proj', 5, 'summary-PROJ-5', 'Fixed'), |
| 406 'other-project:13': _Issue('other-project', 13, |
| 407 'summary-OP-12', 'Invalid'), |
| 408 } |
| 409 comp_ref_artifacts = (open_dict, closed_dict,) |
| 410 |
| 411 mr = testing_helpers.MakeMonorailRequest(path='/p/proj/issues/detail?r=1') |
| 412 replacement_runs = autolink.ReplaceIssueRef(mr, match, comp_ref_artifacts) |
| 413 return replacement_runs |
| 414 |
| 415 def testReplaceIssueRef(self): |
| 416 |
| 417 result = self.DoReplaceIssueRef('This relates to issue 1') |
| 418 self.assertEquals('/p/proj/issues/detail?id=1', result[0].href) |
| 419 self.assertEquals('issue 1', result[0].content) |
| 420 self.assertEquals(None, result[0].css_class) |
| 421 self.assertEquals('summary-PROJ-1', result[0].title) |
| 422 self.assertEquals('a', result[0].tag) |
| 423 |
| 424 result = self.DoReplaceIssueRef(', issue #2') |
| 425 self.assertEquals('/p/proj/issues/detail?id=2', result[0].href) |
| 426 self.assertEquals('issue #2', result[0].content) |
| 427 self.assertEquals('closed_ref', result[0].css_class) |
| 428 self.assertEquals('summary-PROJ-2', result[0].title) |
| 429 self.assertEquals('a', result[0].tag) |
| 430 |
| 431 result = self.DoReplaceIssueRef(', and issue3 ') |
| 432 self.assertEquals(None, result[0].href) # There is no issue 3 |
| 433 self.assertEquals('issue3', result[0].content) |
| 434 |
| 435 result = self.DoReplaceIssueRef('as well as bug 4') |
| 436 self.assertEquals('/p/proj/issues/detail?id=4', result[0].href) |
| 437 self.assertEquals('bug 4', result[0].content) |
| 438 |
| 439 result = self.DoReplaceIssueRef(', bug #5, ') |
| 440 self.assertEquals('/p/proj/issues/detail?id=5', result[0].href) |
| 441 self.assertEquals('bug #5', result[0].content) |
| 442 |
| 443 result = self.DoReplaceIssueRef('and bug6') |
| 444 self.assertEquals('/p/proj/issues/detail?id=6', result[0].href) |
| 445 self.assertEquals('bug6', result[0].content) |
| 446 |
| 447 result = self.DoReplaceIssueRef('with issue other-project:12') |
| 448 self.assertEquals('/p/other-project/issues/detail?id=12', result[0].href) |
| 449 self.assertEquals('issue other-project:12', result[0].content) |
| 450 |
| 451 result = self.DoReplaceIssueRef('and issue other-project#13') |
| 452 self.assertEquals('/p/other-project/issues/detail?id=13', result[0].href) |
| 453 self.assertEquals('issue other-project#13', result[0].content) |
| 454 |
| 455 def testParseProjectNameMatch(self): |
| 456 golden = 'project-name' |
| 457 variations = ['%s', ' %s', '%s ', '%s:', '%s#', '%s#:', '%s:#', '%s :#', |
| 458 '\t%s', '%s\t', '\t%s\t', '\t\t%s\t\t', '\n%s', '%s\n', |
| 459 '\n%s\n', '\n\n%s\n\n', '\t\n%s', '\n\t%s', '%s\t\n', |
| 460 '%s\n\t', '\t\n%s#', '\n\t%s#', '%s\t\n#', '%s\n\t#', |
| 461 '\t\n%s:', '\n\t%s:', '%s\t\n:', '%s\n\t:' |
| 462 ] |
| 463 |
| 464 # First pass checks all valid project name results |
| 465 for pattern in variations: |
| 466 self.assertEquals( |
| 467 golden, autolink._ParseProjectNameMatch(pattern % golden)) |
| 468 |
| 469 # Second pass tests all inputs that should result in None |
| 470 for pattern in variations: |
| 471 self.assert_( |
| 472 autolink._ParseProjectNameMatch(pattern % '') in [None, '']) |
| 473 |
| 474 |
| 475 class VCAutolinkTest(unittest.TestCase): |
| 476 |
| 477 GIT_HASH_1 = '1' * 40 |
| 478 GIT_HASH_2 = '2' * 40 |
| 479 GIT_HASH_3 = 'a1' * 20 |
| 480 GIT_COMMENT_TEXT = ( |
| 481 'This is a fix for r%s and R%s, by r2d2, who also authored revision %s, ' |
| 482 'revision #%s, revision %s, and revision %s' % ( |
| 483 GIT_HASH_1, GIT_HASH_2, GIT_HASH_3, |
| 484 GIT_HASH_1.upper(), GIT_HASH_2.upper(), GIT_HASH_3.upper())) |
| 485 SVN_COMMENT_TEXT = ( |
| 486 'This is a fix for r12 and R34, by r2d2, who also authored revision r4, ' |
| 487 'revision #1234567, revision 789, and revision 9025. If you have ' |
| 488 'questions, call me at 18005551212') |
| 489 |
| 490 def testGetReferencedRevisions(self): |
| 491 refs = ['1', '2', '3'] |
| 492 # For now, we do not look up revision objects, result is always None |
| 493 self.assertIsNone(autolink.GetReferencedRevisions(None, refs)) |
| 494 |
| 495 def testExtractGitHashes(self): |
| 496 refs = [] |
| 497 for match in autolink._GIT_HASH_RE.finditer(self.GIT_COMMENT_TEXT): |
| 498 new_refs = autolink.ExtractRevNums(None, match) |
| 499 refs.extend(new_refs) |
| 500 |
| 501 self.assertEquals( |
| 502 refs, [self.GIT_HASH_1, self.GIT_HASH_2, self.GIT_HASH_3, |
| 503 self.GIT_HASH_1.upper(), self.GIT_HASH_2.upper(), |
| 504 self.GIT_HASH_3.upper()]) |
| 505 |
| 506 def testExtractRevNums(self): |
| 507 refs = [] |
| 508 for match in autolink._SVN_REF_RE.finditer(self.SVN_COMMENT_TEXT): |
| 509 new_refs = autolink.ExtractRevNums(None, match) |
| 510 refs.extend(new_refs) |
| 511 |
| 512 self.assertEquals( |
| 513 refs, ['12', '34', '4', '1234567', '789', '9025']) |
| 514 |
| 515 |
| 516 def DoReplaceRevisionRef(self, content, project=None): |
| 517 """Calls the ReplaceRevisionRef method and returns the result. |
| 518 |
| 519 Args: |
| 520 content: string with a hyperlink. |
| 521 project: optional project. |
| 522 |
| 523 Returns: |
| 524 A list of TextRuns with some runs will have the embedded URL hyperlinked. |
| 525 Or, None if no link was detected. |
| 526 """ |
| 527 match = autolink._GIT_HASH_RE.search(content) |
| 528 if not match: |
| 529 return None |
| 530 |
| 531 mr = testing_helpers.MakeMonorailRequest( |
| 532 path='/p/proj/source/detail?r=1', project=project) |
| 533 replacement_runs = autolink.ReplaceRevisionRef(mr, match, None) |
| 534 return replacement_runs |
| 535 |
| 536 def testReplaceRevisionRef(self): |
| 537 result = self.DoReplaceRevisionRef( |
| 538 'This is a fix for r%s' % self.GIT_HASH_1) |
| 539 self.assertEquals('https://crrev.com/%s' % self.GIT_HASH_1, result[0].href) |
| 540 self.assertEquals('r%s' % self.GIT_HASH_1, result[0].content) |
| 541 |
| 542 result = self.DoReplaceRevisionRef( |
| 543 'and R%s, by r2d2, who ' % self.GIT_HASH_2) |
| 544 self.assertEquals('https://crrev.com/%s' % self.GIT_HASH_2, result[0].href) |
| 545 self.assertEquals('R%s' % self.GIT_HASH_2, result[0].content) |
| 546 |
| 547 result = self.DoReplaceRevisionRef('by r2d2, who ') |
| 548 self.assertEquals(None, result) |
| 549 |
| 550 result = self.DoReplaceRevisionRef( |
| 551 'also authored revision %s, ' % self.GIT_HASH_3) |
| 552 self.assertEquals('https://crrev.com/%s' % self.GIT_HASH_3, result[0].href) |
| 553 self.assertEquals('revision %s' % self.GIT_HASH_3, result[0].content) |
| 554 |
| 555 result = self.DoReplaceRevisionRef( |
| 556 'revision #%s, ' % self.GIT_HASH_1.upper()) |
| 557 self.assertEquals( |
| 558 'https://crrev.com/%s' % self.GIT_HASH_1.upper(), result[0].href) |
| 559 self.assertEquals( |
| 560 'revision #%s' % self.GIT_HASH_1.upper(), result[0].content) |
| 561 |
| 562 result = self.DoReplaceRevisionRef( |
| 563 'revision %s, ' % self.GIT_HASH_2.upper()) |
| 564 self.assertEquals( |
| 565 'https://crrev.com/%s' % self.GIT_HASH_2.upper(), result[0].href) |
| 566 self.assertEquals( |
| 567 'revision %s' % self.GIT_HASH_2.upper(), result[0].content) |
| 568 |
| 569 result = self.DoReplaceRevisionRef( |
| 570 'and revision %s' % self.GIT_HASH_3.upper()) |
| 571 self.assertEquals( |
| 572 'https://crrev.com/%s' % self.GIT_HASH_3.upper(), result[0].href) |
| 573 self.assertEquals( |
| 574 'revision %s' % self.GIT_HASH_3.upper(), result[0].content) |
| 575 |
| 576 def testReplaceRevisionRef_CustomURL(self): |
| 577 """A project can override the URL used for revision links.""" |
| 578 project = fake.Project() |
| 579 project.revision_url_format = 'http://example.com/+/{revnum}' |
| 580 result = self.DoReplaceRevisionRef( |
| 581 'This is a fix for r%s' % self.GIT_HASH_1, project=project) |
| 582 self.assertEquals( |
| 583 'http://example.com/+/%s' % self.GIT_HASH_1, result[0].href) |
| 584 self.assertEquals('r%s' % self.GIT_HASH_1, result[0].content) |
| 585 |
| 586 |
| 587 if __name__ == '__main__': |
| 588 unittest.main() |
OLD | NEW |