| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Unit tests for presubmit_support.py and presubmit_canned_checks.py.""" | 6 """Unit tests for presubmit_support.py and presubmit_canned_checks.py.""" |
| 7 | 7 |
| 8 import os | 8 import os |
| 9 import StringIO | 9 import StringIO |
| 10 import sys | 10 import sys |
| 11 import unittest | 11 import unittest |
| 12 import warnings | |
| 13 | 12 |
| 14 # Local imports | 13 # Local imports |
| 15 import __init__ | 14 import __init__ |
| 16 import gcl | 15 import gcl |
| 17 import gclient | 16 import gclient |
| 18 import presubmit_support as presubmit | 17 import presubmit_support as presubmit |
| 19 import presubmit_canned_checks | 18 import presubmit_canned_checks |
| 20 mox = __init__.mox | 19 mox = __init__.mox |
| 21 | 20 |
| 22 | 21 |
| 23 class PresubmitTestsBase(unittest.TestCase): | 22 class PresubmitTestsBase(mox.MoxTestBase): |
| 24 """Setups and tear downs the mocks but doesn't test anything as-is.""" | 23 """Setups and tear downs the mocks but doesn't test anything as-is.""" |
| 25 def setUp(self): | 24 def setUp(self): |
| 26 if hasattr(warnings, 'catch_warnings'): | 25 super(PresubmitTestsBase, self).setUp() |
| 27 self._warnings_stack = warnings.catch_warnings() | 26 self.mox.StubOutWithMock(presubmit, 'warnings') |
| 28 else: | |
| 29 self._warnings_stack = None | |
| 30 warnings.simplefilter("ignore", DeprecationWarning) | |
| 31 self.mox = mox.Mox() | |
| 32 self.original_IsFile = os.path.isfile | 27 self.original_IsFile = os.path.isfile |
| 33 def MockIsFile(f): | 28 def MockIsFile(f): |
| 34 dir = os.path.dirname(f) | 29 dir = os.path.dirname(f) |
| 35 return dir.endswith('haspresubmit') or dir == '' | 30 return dir.endswith('haspresubmit') or dir == '' |
| 36 os.path.isfile = MockIsFile | 31 os.path.isfile = MockIsFile |
| 37 | 32 |
| 38 self.original_CaptureSVNInfo = gclient.CaptureSVNInfo | 33 self.original_CaptureSVNInfo = gclient.CaptureSVNInfo |
| 39 def MockCaptureSVNInfo(path): | 34 def MockCaptureSVNInfo(path): |
| 40 if path.count('notfound'): | 35 if path.count('notfound'): |
| 41 return {} | 36 return {} |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 | 95 |
| 101 def tearDown(self): | 96 def tearDown(self): |
| 102 os.path.isfile = self.original_IsFile | 97 os.path.isfile = self.original_IsFile |
| 103 gclient.CaptureSVNInfo = self.original_CaptureSVNInfo | 98 gclient.CaptureSVNInfo = self.original_CaptureSVNInfo |
| 104 gcl.GetSVNFileProperty = self.original_GetSVNFileProperty | 99 gcl.GetSVNFileProperty = self.original_GetSVNFileProperty |
| 105 gcl.ReadFile = self.original_ReadFile | 100 gcl.ReadFile = self.original_ReadFile |
| 106 gcl.GetRepositoryRoot = self.original_GetRepositoryRoot | 101 gcl.GetRepositoryRoot = self.original_GetRepositoryRoot |
| 107 sys.stdout = self._sys_stdout | 102 sys.stdout = self._sys_stdout |
| 108 os.path.exists = self._os_path_exists | 103 os.path.exists = self._os_path_exists |
| 109 os.path.isdir = self._os_path_isdir | 104 os.path.isdir = self._os_path_isdir |
| 110 self._warnings_stack = None | |
| 111 | 105 |
| 112 @staticmethod | 106 @staticmethod |
| 113 def MakeBasicChange(name, description): | 107 def MakeBasicChange(name, description): |
| 114 ci = gcl.ChangeInfo(name=name, | 108 ci = gcl.ChangeInfo(name=name, |
| 115 description=description, | 109 description=description, |
| 116 files=[]) | 110 files=[]) |
| 117 change = presubmit.GclChange(ci) | 111 change = presubmit.GclChange(ci) |
| 118 return change | 112 return change |
| 119 | 113 |
| 120 def compareMembers(self, object, members): | 114 def compareMembers(self, object, members): |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 | 188 |
| 195 self.failUnless(change.BUG == '123') | 189 self.failUnless(change.BUG == '123') |
| 196 self.failUnless(change.STORY == 'http://foo/') | 190 self.failUnless(change.STORY == 'http://foo/') |
| 197 | 191 |
| 198 self.failUnless(len(change.AffectedFiles()) == 4) | 192 self.failUnless(len(change.AffectedFiles()) == 4) |
| 199 self.failUnless(len(change.AffectedFiles(include_dirs=True)) == 5) | 193 self.failUnless(len(change.AffectedFiles(include_dirs=True)) == 5) |
| 200 self.failUnless(len(change.AffectedFiles(include_deletes=False)) == 3) | 194 self.failUnless(len(change.AffectedFiles(include_deletes=False)) == 3) |
| 201 self.failUnless(len(change.AffectedFiles(include_dirs=True, | 195 self.failUnless(len(change.AffectedFiles(include_dirs=True, |
| 202 include_deletes=False)) == 4) | 196 include_deletes=False)) == 4) |
| 203 | 197 |
| 204 affected_text_files = change.AffectedTextFiles(include_deletes=True) | 198 affected_text_files = change.AffectedTextFiles() |
| 205 self.failUnless(len(affected_text_files) == 3) | 199 self.failUnless(len(affected_text_files) == 2) |
| 206 self.failIf(filter(lambda x: x.LocalPath() == 'binary.dll', | 200 self.failIf(filter(lambda x: x.LocalPath() == 'binary.dll', |
| 207 affected_text_files)) | 201 affected_text_files)) |
| 208 | 202 |
| 209 local_paths = change.LocalPaths() | 203 local_paths = change.LocalPaths() |
| 210 expected_paths = [presubmit.normpath(f[1]) for f in files] | 204 expected_paths = [presubmit.normpath(f[1]) for f in files] |
| 211 self.failUnless( | 205 self.failUnless( |
| 212 len(filter(lambda x: x in expected_paths, local_paths)) == 4) | 206 len(filter(lambda x: x in expected_paths, local_paths)) == 4) |
| 213 | 207 |
| 214 server_paths = change.ServerPaths() | 208 server_paths = change.ServerPaths() |
| 215 expected_paths = ['svn:/foo/%s' % f[1] for f in files if | 209 expected_paths = ['svn:/foo/%s' % f[1] for f in files if |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 'Running default presubmit script.\n\n' | 457 'Running default presubmit script.\n\n' |
| 464 '** Presubmit Messages **\n\n' | 458 '** Presubmit Messages **\n\n' |
| 465 'http://tracker.com/42\n\n')) | 459 'http://tracker.com/42\n\n')) |
| 466 | 460 |
| 467 | 461 |
| 468 class InputApiUnittest(PresubmitTestsBase): | 462 class InputApiUnittest(PresubmitTestsBase): |
| 469 """Tests presubmit.InputApi.""" | 463 """Tests presubmit.InputApi.""" |
| 470 def testMembersChanged(self): | 464 def testMembersChanged(self): |
| 471 members = [ | 465 members = [ |
| 472 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles', | 466 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles', |
| 473 'DepotToLocalPath', 'FilterTextFiles', 'LocalPaths', 'LocalToDepotPath', | 467 'DepotToLocalPath', 'LocalPaths', 'LocalToDepotPath', |
| 474 'PresubmitLocalPath', 'RightHandSideLines', 'ServerPaths', | 468 'PresubmitLocalPath', 'RightHandSideLines', 'ServerPaths', |
| 475 'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', | 469 'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', |
| 476 'marshal', 'os_path', 'pickle', 'platform', | 470 'marshal', 'os_path', 'pickle', 'platform', |
| 477 're', 'subprocess', 'tempfile', 'urllib2', 'version', | 471 're', 'subprocess', 'tempfile', 'urllib2', 'version', |
| 478 ] | 472 ] |
| 479 # If this test fails, you should add the relevant test. | 473 # If this test fails, you should add the relevant test. |
| 480 self.compareMembers(presubmit.InputApi(None, './.'), members) | 474 self.compareMembers(presubmit.InputApi(None, './.'), members) |
| 481 | 475 |
| 482 def testDepotToLocalPath(self): | 476 def testDepotToLocalPath(self): |
| 483 path = presubmit.InputApi(None, './p').DepotToLocalPath('svn:/foo/smurf') | 477 path = presubmit.InputApi(None, './p').DepotToLocalPath('svn:/foo/smurf') |
| 484 self.failUnless(path == 'smurf') | 478 self.failUnless(path == 'smurf') |
| 485 path = presubmit.InputApi(None, './p').DepotToLocalPath( | 479 path = presubmit.InputApi(None, './p').DepotToLocalPath( |
| 486 'svn:/foo/notfound/burp') | 480 'svn:/foo/notfound/burp') |
| 487 self.failUnless(path == None) | 481 self.failUnless(path == None) |
| 488 | 482 |
| 489 def testLocalToDepotPath(self): | 483 def testLocalToDepotPath(self): |
| 490 path = presubmit.InputApi(None, './p').LocalToDepotPath('smurf') | 484 path = presubmit.InputApi(None, './p').LocalToDepotPath('smurf') |
| 491 self.failUnless(path == 'svn:/foo/smurf') | 485 self.failUnless(path == 'svn:/foo/smurf') |
| 492 path = presubmit.InputApi(None, './p').LocalToDepotPath('notfound-food') | 486 path = presubmit.InputApi(None, './p').LocalToDepotPath('notfound-food') |
| 493 self.failUnless(path == None) | 487 self.failUnless(path == None) |
| 494 | 488 |
| 495 def testInputApiConstruction(self): | 489 def testInputApiConstruction(self): |
| 496 # Fudge the change object, it's not used during construction anyway | 490 # Fudge the change object, it's not used during construction anyway |
| 497 api = presubmit.InputApi(change=42, presubmit_path='foo/path/PRESUBMIT.py') | 491 api = presubmit.InputApi(change=42, presubmit_path='foo/path/PRESUBMIT.py') |
| 498 self.failUnless(api.PresubmitLocalPath() == 'foo/path') | 492 self.failUnless(api.PresubmitLocalPath() == 'foo/path') |
| 499 self.failUnless(api.change == 42) | 493 self.failUnless(api.change == 42) |
| 500 | 494 |
| 501 def testFilterTextFiles(self): | |
| 502 class MockAffectedFile(object): | |
| 503 def __init__(self, path, action): | |
| 504 self.path = path | |
| 505 self.action = action | |
| 506 def Action(self): | |
| 507 return self.action | |
| 508 def LocalPath(self): | |
| 509 return self.path | |
| 510 def AbsoluteLocalPath(self): | |
| 511 return self.path | |
| 512 | |
| 513 list = [MockAffectedFile('foo/blat.txt', 'M'), | |
| 514 MockAffectedFile('foo/binary.blob', 'M'), | |
| 515 MockAffectedFile('blat/flop.txt', 'D')] | |
| 516 | |
| 517 output = presubmit.InputApi.FilterTextFiles(list, include_deletes=True) | |
| 518 self.failUnless(len(output) == 2) | |
| 519 self.failUnless(list[0] in output and list[2] in output) | |
| 520 | |
| 521 output = presubmit.InputApi.FilterTextFiles(list, include_deletes=False) | |
| 522 self.failUnless(len(output) == 1) | |
| 523 self.failUnless(list[0] in output) | |
| 524 | |
| 525 def testInputApiPresubmitScriptFiltering(self): | 495 def testInputApiPresubmitScriptFiltering(self): |
| 526 description_lines = ('Hello there', | 496 description_lines = ('Hello there', |
| 527 'this is a change', | 497 'this is a change', |
| 528 'BUG=123', | 498 'BUG=123', |
| 529 ' STORY =http://foo/ \t', | 499 ' STORY =http://foo/ \t', |
| 530 'and some more regular text') | 500 'and some more regular text') |
| 531 files = [ | 501 files = [ |
| 532 ['A', os.path.join('foo', 'blat.cc')], | 502 ['A', os.path.join('foo', 'blat.cc')], |
| 533 ['M', os.path.join('foo', 'blat', 'binary.dll')], | 503 ['M', os.path.join('foo', 'blat', 'binary.dll')], |
| 534 ['D', 'foo/mat/beingdeleted.txt'], | 504 ['D', 'foo/mat/beingdeleted.txt'], |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 # New helper functions need to work | 571 # New helper functions need to work |
| 602 absolute_paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) | 572 absolute_paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) |
| 603 api = presubmit.InputApi(change=change, presubmit_path='isdir/PRESUBMIT.py') | 573 api = presubmit.InputApi(change=change, presubmit_path='isdir/PRESUBMIT.py') |
| 604 absolute_paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) | 574 absolute_paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) |
| 605 for absolute_paths in [absolute_paths_from_change, | 575 for absolute_paths in [absolute_paths_from_change, |
| 606 absolute_paths_from_api]: | 576 absolute_paths_from_api]: |
| 607 self.failUnless(absolute_paths[0] == presubmit.normpath('c:/temp/isdir')) | 577 self.failUnless(absolute_paths[0] == presubmit.normpath('c:/temp/isdir')) |
| 608 self.failUnless(absolute_paths[1] == | 578 self.failUnless(absolute_paths[1] == |
| 609 presubmit.normpath('c:/temp/isdir/blat.cc')) | 579 presubmit.normpath('c:/temp/isdir/blat.cc')) |
| 610 | 580 |
| 581 def testDeprecated(self): |
| 582 presubmit.warnings.warn(mox.IgnoreArg(), category=mox.IgnoreArg(), |
| 583 stacklevel=2) |
| 584 self.mox.ReplayAll() |
| 585 change = presubmit.GclChange(gcl.ChangeInfo(name='mychange', |
| 586 description='Bleh\n')) |
| 587 api = presubmit.InputApi(change, 'foo/PRESUBMIT.py') |
| 588 api.AffectedTextFiles(include_deletes=False) |
| 589 self.mox.VerifyAll() |
| 590 |
| 611 | 591 |
| 612 class OuputApiUnittest(PresubmitTestsBase): | 592 class OuputApiUnittest(PresubmitTestsBase): |
| 613 """Tests presubmit.OutputApi.""" | 593 """Tests presubmit.OutputApi.""" |
| 614 def testMembersChanged(self): | 594 def testMembersChanged(self): |
| 615 members = [ | 595 members = [ |
| 616 'MailTextResult', 'PresubmitError', 'PresubmitNotifyResult', | 596 'MailTextResult', 'PresubmitError', 'PresubmitNotifyResult', |
| 617 'PresubmitPromptWarning', 'PresubmitResult', | 597 'PresubmitPromptWarning', 'PresubmitResult', |
| 618 ] | 598 ] |
| 619 # If this test fails, you should add the relevant test. | 599 # If this test fails, you should add the relevant test. |
| 620 self.compareMembers(presubmit.OutputApi(), members) | 600 self.compareMembers(presubmit.OutputApi(), members) |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 def testIsDirectory(self): | 684 def testIsDirectory(self): |
| 705 os.path.exists('foo.cc').AndReturn(True) | 685 os.path.exists('foo.cc').AndReturn(True) |
| 706 os.path.isdir('foo.cc').AndReturn(True) | 686 os.path.isdir('foo.cc').AndReturn(True) |
| 707 self.mox.ReplayAll() | 687 self.mox.ReplayAll() |
| 708 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') | 688 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') |
| 709 # Verify cache coherency. | 689 # Verify cache coherency. |
| 710 self.failUnless(affected_file.IsDirectory()) | 690 self.failUnless(affected_file.IsDirectory()) |
| 711 self.failUnless(affected_file.IsDirectory()) | 691 self.failUnless(affected_file.IsDirectory()) |
| 712 self.mox.VerifyAll() | 692 self.mox.VerifyAll() |
| 713 | 693 |
| 694 def testIsTextFile(self): |
| 695 list = [presubmit.SvnAffectedFile('foo/blat.txt', 'M'), |
| 696 presubmit.SvnAffectedFile('foo/binary.blob', 'M'), |
| 697 presubmit.SvnAffectedFile('blat/flop.txt', 'D')] |
| 698 os.path.exists(os.path.join('foo', 'blat.txt')).AndReturn(True) |
| 699 os.path.isdir(os.path.join('foo', 'blat.txt')).AndReturn(False) |
| 700 os.path.exists(os.path.join('foo', 'binary.blob')).AndReturn(True) |
| 701 os.path.isdir(os.path.join('foo', 'binary.blob')).AndReturn(False) |
| 702 self.mox.ReplayAll() |
| 703 |
| 704 output = filter(lambda x: x.IsTextFile(), list) |
| 705 self.failUnless(len(output) == 1) |
| 706 self.failUnless(list[0] == output[0]) |
| 707 self.mox.VerifyAll() |
| 708 |
| 714 | 709 |
| 715 class CannedChecksUnittest(PresubmitTestsBase): | 710 class CannedChecksUnittest(PresubmitTestsBase): |
| 716 """Tests presubmit_canned_checks.py.""" | 711 """Tests presubmit_canned_checks.py.""" |
| 717 class MockInputApi(object): | 712 class MockInputApi(object): |
| 718 class MockUrllib2(object): | 713 class MockUrllib2(object): |
| 719 class urlopen(object): | 714 class urlopen(object): |
| 720 def __init__(self, url): | 715 def __init__(self, url): |
| 721 if url == 'url_to_open': | 716 if url == 'url_to_open': |
| 722 self.result = '1' | 717 self.result = '1' |
| 723 else: | 718 else: |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 # TODO(maruel): Add real tests. | 842 # TODO(maruel): Add real tests. |
| 848 self.failIf(presubmit_canned_checks.RunPythonUnitTests( | 843 self.failIf(presubmit_canned_checks.RunPythonUnitTests( |
| 849 self.MockInputApi(), | 844 self.MockInputApi(), |
| 850 presubmit.OutputApi, [])) | 845 presubmit.OutputApi, [])) |
| 851 self.failUnless(presubmit_canned_checks.RunPythonUnitTests( | 846 self.failUnless(presubmit_canned_checks.RunPythonUnitTests( |
| 852 self.MockInputApi(), | 847 self.MockInputApi(), |
| 853 presubmit.OutputApi, ['non_existent_module'])) | 848 presubmit.OutputApi, ['non_existent_module'])) |
| 854 | 849 |
| 855 if __name__ == '__main__': | 850 if __name__ == '__main__': |
| 856 unittest.main() | 851 unittest.main() |
| OLD | NEW |