| OLD | NEW | 
|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python | 
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 # pylint is too confused. | 8 # pylint is too confused. | 
| 9 # pylint: disable=E1101,E1103,R0201,W0212,W0403 | 9 # pylint: disable=E1101,E1103,R0201,W0212,W0403 | 
| 10 | 10 | 
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 411                                      'rU').AndReturn(self.presubmit_text) | 411                                      'rU').AndReturn(self.presubmit_text) | 
| 412     presubmit.gclient_utils.FileRead(haspresubmit_path, | 412     presubmit.gclient_utils.FileRead(haspresubmit_path, | 
| 413                                      'rU').AndReturn(self.presubmit_text) | 413                                      'rU').AndReturn(self.presubmit_text) | 
| 414     presubmit.random.randint(0, 4).AndReturn(1) | 414     presubmit.random.randint(0, 4).AndReturn(1) | 
| 415     self.mox.ReplayAll() | 415     self.mox.ReplayAll() | 
| 416 | 416 | 
| 417     input_buf = StringIO.StringIO('y\n') | 417     input_buf = StringIO.StringIO('y\n') | 
| 418     change = presubmit.Change('mychange', '\n'.join(description_lines), | 418     change = presubmit.Change('mychange', '\n'.join(description_lines), | 
| 419                               self.fake_root_dir, files, 0, 0) | 419                               self.fake_root_dir, files, 0, 0) | 
| 420     output = presubmit.DoPresubmitChecks( | 420     output = presubmit.DoPresubmitChecks( | 
| 421         change, False, True, None, input_buf, None, False) | 421         change, False, True, None, input_buf, None, False, False, None) | 
| 422     self.failIf(output.should_continue()) | 422     self.failIf(output.should_continue()) | 
| 423     self.assertEqual(output.getvalue().count('!!'), 2) | 423     self.assertEqual(output.getvalue().count('!!'), 2) | 
| 424     self.assertEqual(output.getvalue().count( | 424     self.assertEqual(output.getvalue().count( | 
| 425         'Running presubmit upload checks ...\n'), 1) | 425         'Running presubmit upload checks ...\n'), 1) | 
| 426 | 426 | 
| 427   def testDoPresubmitChecksPromptsAfterWarnings(self): | 427   def testDoPresubmitChecksPromptsAfterWarnings(self): | 
| 428     join = presubmit.os.path.join | 428     join = presubmit.os.path.join | 
| 429     description_lines = ('Hello there', | 429     description_lines = ('Hello there', | 
| 430                          'this is a change', | 430                          'this is a change', | 
| 431                          'NOSUCHKEY=http://tracker/123') | 431                          'NOSUCHKEY=http://tracker/123') | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 445       presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU' | 445       presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU' | 
| 446           ).AndReturn(self.presubmit_text) | 446           ).AndReturn(self.presubmit_text) | 
| 447     presubmit.random.randint(0, 4).AndReturn(1) | 447     presubmit.random.randint(0, 4).AndReturn(1) | 
| 448     presubmit.random.randint(0, 4).AndReturn(1) | 448     presubmit.random.randint(0, 4).AndReturn(1) | 
| 449     self.mox.ReplayAll() | 449     self.mox.ReplayAll() | 
| 450 | 450 | 
| 451     input_buf = StringIO.StringIO('n\n')  # say no to the warning | 451     input_buf = StringIO.StringIO('n\n')  # say no to the warning | 
| 452     change = presubmit.Change('mychange', '\n'.join(description_lines), | 452     change = presubmit.Change('mychange', '\n'.join(description_lines), | 
| 453                               self.fake_root_dir, files, 0, 0) | 453                               self.fake_root_dir, files, 0, 0) | 
| 454     output = presubmit.DoPresubmitChecks( | 454     output = presubmit.DoPresubmitChecks( | 
| 455         change, False, True, None, input_buf, None, True) | 455         change, False, True, None, input_buf, None, True, False, None) | 
| 456     self.failIf(output.should_continue()) | 456     self.failIf(output.should_continue()) | 
| 457     self.assertEqual(output.getvalue().count('??'), 2) | 457     self.assertEqual(output.getvalue().count('??'), 2) | 
| 458 | 458 | 
| 459     input_buf = StringIO.StringIO('y\n')  # say yes to the warning | 459     input_buf = StringIO.StringIO('y\n')  # say yes to the warning | 
| 460     output = presubmit.DoPresubmitChecks( | 460     output = presubmit.DoPresubmitChecks( | 
| 461         change, False, True, None, input_buf, None, True) | 461         change, False, True, None, input_buf, None, True, False, None) | 
| 462     self.failUnless(output.should_continue()) | 462     self.failUnless(output.should_continue()) | 
| 463     self.assertEquals(output.getvalue().count('??'), 2) | 463     self.assertEquals(output.getvalue().count('??'), 2) | 
| 464     self.assertEqual(output.getvalue().count( | 464     self.assertEqual(output.getvalue().count( | 
| 465         'Running presubmit upload checks ...\n'), 1) | 465         'Running presubmit upload checks ...\n'), 1) | 
| 466 | 466 | 
| 467   def testDoPresubmitChecksNoWarningPromptIfErrors(self): | 467   def testDoPresubmitChecksNoWarningPromptIfErrors(self): | 
| 468     join = presubmit.os.path.join | 468     join = presubmit.os.path.join | 
| 469     description_lines = ('Hello there', | 469     description_lines = ('Hello there', | 
| 470                          'this is a change', | 470                          'this is a change', | 
| 471                          'NOSUCHKEY=http://tracker/123', | 471                          'NOSUCHKEY=http://tracker/123', | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 484     presubmit.gclient_utils.FileRead(presubmit_path, 'rU' | 484     presubmit.gclient_utils.FileRead(presubmit_path, 'rU' | 
| 485                                      ).AndReturn(self.presubmit_text) | 485                                      ).AndReturn(self.presubmit_text) | 
| 486     presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU').AndReturn( | 486     presubmit.gclient_utils.FileRead(haspresubmit_path, 'rU').AndReturn( | 
| 487         self.presubmit_text) | 487         self.presubmit_text) | 
| 488     presubmit.random.randint(0, 4).AndReturn(1) | 488     presubmit.random.randint(0, 4).AndReturn(1) | 
| 489     self.mox.ReplayAll() | 489     self.mox.ReplayAll() | 
| 490 | 490 | 
| 491     change = presubmit.Change('mychange', '\n'.join(description_lines), | 491     change = presubmit.Change('mychange', '\n'.join(description_lines), | 
| 492                               self.fake_root_dir, files, 0, 0) | 492                               self.fake_root_dir, files, 0, 0) | 
| 493     output = presubmit.DoPresubmitChecks(change, False, True, None, None, | 493     output = presubmit.DoPresubmitChecks(change, False, True, None, None, | 
| 494         None, False) | 494         None, False, False, None) | 
| 495     self.assertEqual(output.getvalue().count('??'), 2) | 495     self.assertEqual(output.getvalue().count('??'), 2) | 
| 496     self.assertEqual(output.getvalue().count('XX!!XX'), 2) | 496     self.assertEqual(output.getvalue().count('XX!!XX'), 2) | 
| 497     self.assertEqual(output.getvalue().count('(y/N)'), 0) | 497     self.assertEqual(output.getvalue().count('(y/N)'), 0) | 
| 498     self.assertEqual(output.getvalue().count( | 498     self.assertEqual(output.getvalue().count( | 
| 499         'Running presubmit upload checks ...\n'), 1) | 499         'Running presubmit upload checks ...\n'), 1) | 
| 500 | 500 | 
| 501   def testDoDefaultPresubmitChecksAndFeedback(self): | 501   def testDoDefaultPresubmitChecksAndFeedback(self): | 
| 502     join = presubmit.os.path.join | 502     join = presubmit.os.path.join | 
| 503     description_lines = ('Hello there', | 503     description_lines = ('Hello there', | 
| 504                          'this is a change', | 504                          'this is a change', | 
| (...skipping 16 matching lines...) Expand all  Loading... | 
| 521                                   'haspresubmit', | 521                                   'haspresubmit', | 
| 522                                   'PRESUBMIT.py')).AndReturn(False) | 522                                   'PRESUBMIT.py')).AndReturn(False) | 
| 523     presubmit.random.randint(0, 4).AndReturn(0) | 523     presubmit.random.randint(0, 4).AndReturn(0) | 
| 524     self.mox.ReplayAll() | 524     self.mox.ReplayAll() | 
| 525 | 525 | 
| 526     input_buf = StringIO.StringIO('y\n') | 526     input_buf = StringIO.StringIO('y\n') | 
| 527     # Always fail. | 527     # Always fail. | 
| 528     change = presubmit.Change('mychange', '\n'.join(description_lines), | 528     change = presubmit.Change('mychange', '\n'.join(description_lines), | 
| 529                               self.fake_root_dir, files, 0, 0) | 529                               self.fake_root_dir, files, 0, 0) | 
| 530     output = presubmit.DoPresubmitChecks( | 530     output = presubmit.DoPresubmitChecks( | 
| 531         change, False, True, None, input_buf, DEFAULT_SCRIPT, False) | 531         change, False, True, None, input_buf, DEFAULT_SCRIPT, False, False, | 
|  | 532         None) | 
| 532     self.failIf(output.should_continue()) | 533     self.failIf(output.should_continue()) | 
| 533     text = ('Running presubmit upload checks ...\n' | 534     text = ('Running presubmit upload checks ...\n' | 
| 534             'Warning, no presubmit.py found.\n' | 535             'Warning, no presubmit.py found.\n' | 
| 535             'Running default presubmit script.\n' | 536             'Running default presubmit script.\n' | 
| 536             '\n' | 537             '\n' | 
| 537             '** Presubmit ERRORS **\n!!\n\n' | 538             '** Presubmit ERRORS **\n!!\n\n' | 
| 538             'Was the presubmit check useful? Please send feedback & hate mail ' | 539             'Was the presubmit check useful? Please send feedback & hate mail ' | 
| 539             'to maruel@chromium.org!\n') | 540             'to maruel@chromium.org!\n') | 
| 540     self.assertEquals(output.getvalue(), text) | 541     self.assertEquals(output.getvalue(), text) | 
| 541 | 542 | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 596                                           self._INHERIT_SETTINGS) | 597                                           self._INHERIT_SETTINGS) | 
| 597     presubmit.os.path.isfile(inherit_path).AndReturn(False) | 598     presubmit.os.path.isfile(inherit_path).AndReturn(False) | 
| 598     self.mox.ReplayAll() | 599     self.mox.ReplayAll() | 
| 599 | 600 | 
| 600     output = StringIO.StringIO() | 601     output = StringIO.StringIO() | 
| 601     input_buf = StringIO.StringIO('y\n') | 602     input_buf = StringIO.StringIO('y\n') | 
| 602     change = presubmit.Change( | 603     change = presubmit.Change( | 
| 603         'foo', "Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n", | 604         'foo', "Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n", | 
| 604         self.fake_root_dir, None, 0, 0) | 605         self.fake_root_dir, None, 0, 0) | 
| 605     self.failUnless(presubmit.DoPresubmitChecks( | 606     self.failUnless(presubmit.DoPresubmitChecks( | 
| 606         change, False, True, output, input_buf, DEFAULT_SCRIPT, False)) | 607         change, False, True, output, input_buf, DEFAULT_SCRIPT, False, False, | 
|  | 608         None)) | 
| 607     self.assertEquals(output.getvalue(), | 609     self.assertEquals(output.getvalue(), | 
| 608                       ('Running presubmit upload checks ...\n' | 610                       ('Running presubmit upload checks ...\n' | 
| 609                        'Warning, no presubmit.py found.\n' | 611                        'Warning, no presubmit.py found.\n' | 
| 610                        'Running default presubmit script.\n' | 612                        'Running default presubmit script.\n' | 
| 611                        '\n' | 613                        '\n' | 
| 612                        '** Presubmit Messages **\n' | 614                        '** Presubmit Messages **\n' | 
| 613                        'http://tracker.com/42\n' | 615                        'http://tracker.com/42\n' | 
| 614                        '\n' | 616                        '\n' | 
| 615                        'Presubmit checks passed.\n')) | 617                        'Presubmit checks passed.\n')) | 
| 616 | 618 | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 680     self.mox.StubOutWithMock(presubmit, 'ParseFiles') | 682     self.mox.StubOutWithMock(presubmit, 'ParseFiles') | 
| 681     presubmit.scm.determine_scm(self.fake_root_dir).AndReturn(None) | 683     presubmit.scm.determine_scm(self.fake_root_dir).AndReturn(None) | 
| 682     presubmit.ParseFiles(['random_file.txt'], None | 684     presubmit.ParseFiles(['random_file.txt'], None | 
| 683         ).AndReturn(['random_file.txt']) | 685         ).AndReturn(['random_file.txt']) | 
| 684     output = self.mox.CreateMock(presubmit.PresubmitOutput) | 686     output = self.mox.CreateMock(presubmit.PresubmitOutput) | 
| 685     output.should_continue().AndReturn(False) | 687     output.should_continue().AndReturn(False) | 
| 686 | 688 | 
| 687     presubmit.DoPresubmitChecks(mox.IgnoreArg(), False, False, | 689     presubmit.DoPresubmitChecks(mox.IgnoreArg(), False, False, | 
| 688                                 mox.IgnoreArg(), | 690                                 mox.IgnoreArg(), | 
| 689                                 mox.IgnoreArg(), | 691                                 mox.IgnoreArg(), | 
| 690                                 None, False).AndReturn(output) | 692                                 None, False, False, None).AndReturn(output) | 
| 691     self.mox.ReplayAll() | 693     self.mox.ReplayAll() | 
| 692 | 694 | 
| 693     self.assertEquals( | 695     self.assertEquals( | 
| 694         True, | 696         True, | 
| 695         presubmit.Main(['--root', self.fake_root_dir, 'random_file.txt'])) | 697         presubmit.Main(['--root', self.fake_root_dir, 'random_file.txt'])) | 
| 696 | 698 | 
| 697   def testMainUnversionedFail(self): | 699   def testMainUnversionedFail(self): | 
| 698     # OptParser calls presubmit.os.path.exists and is a pain when mocked. | 700     # OptParser calls presubmit.os.path.exists and is a pain when mocked. | 
| 699     self.UnMock(presubmit.os.path, 'exists') | 701     self.UnMock(presubmit.os.path, 'exists') | 
| 700     self.mox.StubOutWithMock(presubmit, 'DoPresubmitChecks') | 702     self.mox.StubOutWithMock(presubmit, 'DoPresubmitChecks') | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 723     members = [ | 725     members = [ | 
| 724       'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedSourceFiles', | 726       'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedSourceFiles', | 
| 725       'AffectedTextFiles', | 727       'AffectedTextFiles', | 
| 726       'DEFAULT_BLACK_LIST', 'DEFAULT_WHITE_LIST', | 728       'DEFAULT_BLACK_LIST', 'DEFAULT_WHITE_LIST', | 
| 727       'DepotToLocalPath', 'FilterSourceFile', 'LocalPaths', | 729       'DepotToLocalPath', 'FilterSourceFile', 'LocalPaths', | 
| 728       'LocalToDepotPath', | 730       'LocalToDepotPath', | 
| 729       'PresubmitLocalPath', 'ReadFile', 'RightHandSideLines', 'ServerPaths', | 731       'PresubmitLocalPath', 'ReadFile', 'RightHandSideLines', 'ServerPaths', | 
| 730       'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', 'environ', | 732       'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', 'environ', | 
| 731       'host_url', 'is_committing', 'json', 'marshal', 'os_listdir', 'os_walk', | 733       'host_url', 'is_committing', 'json', 'marshal', 'os_listdir', 'os_walk', | 
| 732       'os_path', 'owners_db', 'pickle', 'platform', 'python_executable', 're', | 734       'os_path', 'owners_db', 'pickle', 'platform', 'python_executable', 're', | 
| 733       'subprocess', 'tbr', 'tempfile', 'time', 'traceback', 'unittest', | 735       'rietveld', 'subprocess', 'tbr', 'tempfile', 'time', 'traceback', | 
| 734       'urllib2', 'version', 'verbose', | 736       'unittest', 'urllib2', 'version', 'verbose', | 
| 735     ] | 737     ] | 
| 736     # If this test fails, you should add the relevant test. | 738     # If this test fails, you should add the relevant test. | 
| 737     self.compareMembers( | 739     self.compareMembers( | 
| 738         presubmit.InputApi(self.fake_change, './.', False, False, None, False), | 740         presubmit.InputApi(self.fake_change, './.', False, False, None, False), | 
| 739         members) | 741         members) | 
| 740 | 742 | 
| 741   def testDepotToLocalPath(self): | 743   def testDepotToLocalPath(self): | 
| 742     presubmit.scm.SVN.CaptureInfo('svn://foo/smurf').AndReturn( | 744     presubmit.scm.SVN.CaptureInfo('svn://foo/smurf').AndReturn( | 
| 743         {'Path': 'prout'}) | 745         {'Path': 'prout'}) | 
| 744     presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({}) | 746     presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({}) | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 764     path = presubmit.InputApi( | 766     path = presubmit.InputApi( | 
| 765         self.fake_change, './p', False, False, None, False).LocalToDepotPath( | 767         self.fake_change, './p', False, False, None, False).LocalToDepotPath( | 
| 766             'notfound-food') | 768             'notfound-food') | 
| 767     self.assertEquals(path, None) | 769     self.assertEquals(path, None) | 
| 768 | 770 | 
| 769   def testInputApiConstruction(self): | 771   def testInputApiConstruction(self): | 
| 770     self.mox.ReplayAll() | 772     self.mox.ReplayAll() | 
| 771     api = presubmit.InputApi( | 773     api = presubmit.InputApi( | 
| 772         self.fake_change, | 774         self.fake_change, | 
| 773         presubmit_path='foo/path/PRESUBMIT.py', | 775         presubmit_path='foo/path/PRESUBMIT.py', | 
| 774         is_committing=False, tbr=False, host_url=None, verbose=False) | 776         is_committing=False, tbr=False, rietveld=None, verbose=False) | 
| 775     self.assertEquals(api.PresubmitLocalPath(), 'foo/path') | 777     self.assertEquals(api.PresubmitLocalPath(), 'foo/path') | 
| 776     self.assertEquals(api.change, self.fake_change) | 778     self.assertEquals(api.change, self.fake_change) | 
| 777     self.assertEquals(api.host_url, 'http://codereview.chromium.org') | 779     self.assertEquals(api.host_url, 'http://codereview.chromium.org') | 
| 778 | 780 | 
| 779   def testInputApiPresubmitScriptFiltering(self): | 781   def testInputApiPresubmitScriptFiltering(self): | 
| 780     join = presubmit.os.path.join | 782     join = presubmit.os.path.join | 
| 781     description_lines = ('Hello there', | 783     description_lines = ('Hello there', | 
| 782                          'this is a change', | 784                          'this is a change', | 
| 783                          'BUG=123', | 785                          'BUG=123', | 
| 784                          ' STORY =http://foo/  \t', | 786                          ' STORY =http://foo/  \t', | 
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1001                       normpath(join(self.fake_root_dir, 'isdir'))) | 1003                       normpath(join(self.fake_root_dir, 'isdir'))) | 
| 1002     self.assertEquals(affected_files[1].AbsoluteLocalPath(), | 1004     self.assertEquals(affected_files[1].AbsoluteLocalPath(), | 
| 1003                       normpath(join(self.fake_root_dir, 'isdir/blat.cc'))) | 1005                       normpath(join(self.fake_root_dir, 'isdir/blat.cc'))) | 
| 1004 | 1006 | 
| 1005     # New helper functions need to work | 1007     # New helper functions need to work | 
| 1006     paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) | 1008     paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) | 
| 1007     self.assertEqual(len(paths_from_change), 3) | 1009     self.assertEqual(len(paths_from_change), 3) | 
| 1008     presubmit_path = join(self.fake_root_dir, 'isdir', 'PRESUBMIT.py') | 1010     presubmit_path = join(self.fake_root_dir, 'isdir', 'PRESUBMIT.py') | 
| 1009     api = presubmit.InputApi( | 1011     api = presubmit.InputApi( | 
| 1010         change=change, presubmit_path=presubmit_path, | 1012         change=change, presubmit_path=presubmit_path, | 
| 1011         is_committing=True, tbr=False, host_url=None, verbose=False) | 1013         is_committing=True, tbr=False, rietveld=None, verbose=False) | 
| 1012     paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) | 1014     paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) | 
| 1013     self.assertEqual(len(paths_from_api), 2) | 1015     self.assertEqual(len(paths_from_api), 2) | 
| 1014     for absolute_paths in [paths_from_change, paths_from_api]: | 1016     for absolute_paths in [paths_from_change, paths_from_api]: | 
| 1015       self.assertEqual(absolute_paths[0], | 1017       self.assertEqual(absolute_paths[0], | 
| 1016                        normpath(join(self.fake_root_dir, 'isdir'))) | 1018                        normpath(join(self.fake_root_dir, 'isdir'))) | 
| 1017       self.assertEqual(absolute_paths[1], | 1019       self.assertEqual(absolute_paths[1], | 
| 1018                        normpath(join(self.fake_root_dir, 'isdir', 'blat.cc'))) | 1020                        normpath(join(self.fake_root_dir, 'isdir', 'blat.cc'))) | 
| 1019 | 1021 | 
| 1020   def testDeprecated(self): | 1022   def testDeprecated(self): | 
| 1021     presubmit.warn(mox.IgnoreArg(), category=mox.IgnoreArg(), stacklevel=2) | 1023     presubmit.warn(mox.IgnoreArg(), category=mox.IgnoreArg(), stacklevel=2) | 
| (...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2053         whitelist=['^a$', '^b$'], | 2055         whitelist=['^a$', '^b$'], | 
| 2054         blacklist=['a']) | 2056         blacklist=['a']) | 
| 2055     self.assertEqual(results, []) | 2057     self.assertEqual(results, []) | 
| 2056     self.checkstdout( | 2058     self.checkstdout( | 
| 2057         'Running %s\n' % presubmit.os.path.join('random_directory', 'b')) | 2059         'Running %s\n' % presubmit.os.path.join('random_directory', 'b')) | 
| 2058 | 2060 | 
| 2059 | 2061 | 
| 2060 if __name__ == '__main__': | 2062 if __name__ == '__main__': | 
| 2061   import unittest | 2063   import unittest | 
| 2062   unittest.main() | 2064   unittest.main() | 
| OLD | NEW | 
|---|