Home | History | Annotate | Download | only in chromium_org
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import os
      7 import re
      8 import unittest
      9 
     10 import PRESUBMIT
     11 
     12 
     13 class MockInputApi(object):
     14   def __init__(self):
     15     self.re = re
     16     self.os_path = os.path
     17     self.files = []
     18     self.is_committing = False
     19 
     20   def AffectedFiles(self):
     21     return self.files
     22 
     23 
     24 class MockOutputApi(object):
     25   class PresubmitResult(object):
     26     def __init__(self, message, items=None, long_text=''):
     27       self.message = message
     28       self.items = items
     29       self.long_text = long_text
     30 
     31   class PresubmitError(PresubmitResult):
     32     def __init__(self, message, items, long_text=''):
     33       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     34       self.type = 'error'
     35 
     36   class PresubmitPromptWarning(PresubmitResult):
     37     def __init__(self, message, items, long_text=''):
     38       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     39       self.type = 'warning'
     40 
     41   class PresubmitNotifyResult(PresubmitResult):
     42     def __init__(self, message, items, long_text=''):
     43       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     44       self.type = 'notify'
     45 
     46   class PresubmitPromptOrNotify(PresubmitResult):
     47     def __init__(self, message, items, long_text=''):
     48       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     49       self.type = 'promptOrNotify'
     50 
     51 
     52 class MockFile(object):
     53   def __init__(self, local_path, new_contents):
     54     self._local_path = local_path
     55     self._new_contents = new_contents
     56     self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
     57 
     58   def ChangedContents(self):
     59     return self._changed_contents
     60 
     61   def NewContents(self):
     62     return self._new_contents
     63 
     64   def LocalPath(self):
     65     return self._local_path
     66 
     67 
     68 class MockChange(object):
     69   def __init__(self, changed_files):
     70     self._changed_files = changed_files
     71 
     72   def LocalPaths(self):
     73     return self._changed_files
     74 
     75 
     76 class IncludeOrderTest(unittest.TestCase):
     77   def testSystemHeaderOrder(self):
     78     scope = [(1, '#include <csystem.h>'),
     79              (2, '#include <cppsystem>'),
     80              (3, '#include "acustom.h"')]
     81     all_linenums = [linenum for (linenum, _) in scope]
     82     mock_input_api = MockInputApi()
     83     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
     84                                                     '', all_linenums)
     85     self.assertEqual(0, len(warnings))
     86 
     87   def testSystemHeaderOrderMismatch1(self):
     88     scope = [(10, '#include <cppsystem>'),
     89              (20, '#include <csystem.h>'),
     90              (30, '#include "acustom.h"')]
     91     all_linenums = [linenum for (linenum, _) in scope]
     92     mock_input_api = MockInputApi()
     93     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
     94                                                     '', all_linenums)
     95     self.assertEqual(1, len(warnings))
     96     self.assertTrue('20' in warnings[0])
     97 
     98   def testSystemHeaderOrderMismatch2(self):
     99     scope = [(10, '#include <cppsystem>'),
    100              (20, '#include "acustom.h"'),
    101              (30, '#include <csystem.h>')]
    102     all_linenums = [linenum for (linenum, _) in scope]
    103     mock_input_api = MockInputApi()
    104     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    105                                                     '', all_linenums)
    106     self.assertEqual(1, len(warnings))
    107     self.assertTrue('30' in warnings[0])
    108 
    109   def testSystemHeaderOrderMismatch3(self):
    110     scope = [(10, '#include "acustom.h"'),
    111              (20, '#include <csystem.h>'),
    112              (30, '#include <cppsystem>')]
    113     all_linenums = [linenum for (linenum, _) in scope]
    114     mock_input_api = MockInputApi()
    115     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    116                                                     '', all_linenums)
    117     self.assertEqual(2, len(warnings))
    118     self.assertTrue('20' in warnings[0])
    119     self.assertTrue('30' in warnings[1])
    120 
    121   def testAlphabeticalOrderMismatch(self):
    122     scope = [(10, '#include <csystem.h>'),
    123              (15, '#include <bsystem.h>'),
    124              (20, '#include <cppsystem>'),
    125              (25, '#include <bppsystem>'),
    126              (30, '#include "bcustom.h"'),
    127              (35, '#include "acustom.h"')]
    128     all_linenums = [linenum for (linenum, _) in scope]
    129     mock_input_api = MockInputApi()
    130     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    131                                                     '', all_linenums)
    132     self.assertEqual(3, len(warnings))
    133     self.assertTrue('15' in warnings[0])
    134     self.assertTrue('25' in warnings[1])
    135     self.assertTrue('35' in warnings[2])
    136 
    137   def testSpecialFirstInclude1(self):
    138     mock_input_api = MockInputApi()
    139     contents = ['#include "some/path/foo.h"',
    140                 '#include "a/header.h"']
    141     mock_file = MockFile('some/path/foo.cc', contents)
    142     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    143         mock_input_api, mock_file, range(1, len(contents) + 1))
    144     self.assertEqual(0, len(warnings))
    145 
    146   def testSpecialFirstInclude2(self):
    147     mock_input_api = MockInputApi()
    148     contents = ['#include "some/other/path/foo.h"',
    149                 '#include "a/header.h"']
    150     mock_file = MockFile('some/path/foo.cc', contents)
    151     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    152         mock_input_api, mock_file, range(1, len(contents) + 1))
    153     self.assertEqual(0, len(warnings))
    154 
    155   def testSpecialFirstInclude3(self):
    156     mock_input_api = MockInputApi()
    157     contents = ['#include "some/path/foo.h"',
    158                 '#include "a/header.h"']
    159     mock_file = MockFile('some/path/foo_platform.cc', contents)
    160     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    161         mock_input_api, mock_file, range(1, len(contents) + 1))
    162     self.assertEqual(0, len(warnings))
    163 
    164   def testSpecialFirstInclude4(self):
    165     mock_input_api = MockInputApi()
    166     contents = ['#include "some/path/bar.h"',
    167                 '#include "a/header.h"']
    168     mock_file = MockFile('some/path/foo_platform.cc', contents)
    169     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    170         mock_input_api, mock_file, range(1, len(contents) + 1))
    171     self.assertEqual(1, len(warnings))
    172     self.assertTrue('2' in warnings[0])
    173 
    174   def testSpecialFirstInclude5(self):
    175     mock_input_api = MockInputApi()
    176     contents = ['#include "some/other/path/foo.h"',
    177                 '#include "a/header.h"']
    178     mock_file = MockFile('some/path/foo-suffix.h', contents)
    179     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    180         mock_input_api, mock_file, range(1, len(contents) + 1))
    181     self.assertEqual(0, len(warnings))
    182 
    183   def testOrderAlreadyWrong(self):
    184     scope = [(1, '#include "b.h"'),
    185              (2, '#include "a.h"'),
    186              (3, '#include "c.h"')]
    187     mock_input_api = MockInputApi()
    188     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    189                                                     '', [3])
    190     self.assertEqual(0, len(warnings))
    191 
    192   def testConflictAdded1(self):
    193     scope = [(1, '#include "a.h"'),
    194              (2, '#include "c.h"'),
    195              (3, '#include "b.h"')]
    196     mock_input_api = MockInputApi()
    197     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    198                                                     '', [2])
    199     self.assertEqual(1, len(warnings))
    200     self.assertTrue('3' in warnings[0])
    201 
    202   def testConflictAdded2(self):
    203     scope = [(1, '#include "c.h"'),
    204              (2, '#include "b.h"'),
    205              (3, '#include "d.h"')]
    206     mock_input_api = MockInputApi()
    207     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    208                                                     '', [2])
    209     self.assertEqual(1, len(warnings))
    210     self.assertTrue('2' in warnings[0])
    211 
    212   def testIfElifElseEndif(self):
    213     mock_input_api = MockInputApi()
    214     contents = ['#include "e.h"',
    215                 '#define foo',
    216                 '#include "f.h"',
    217                 '#undef foo',
    218                 '#include "e.h"',
    219                 '#if foo',
    220                 '#include "d.h"',
    221                 '#elif bar',
    222                 '#include "c.h"',
    223                 '#else',
    224                 '#include "b.h"',
    225                 '#endif',
    226                 '#include "a.h"']
    227     mock_file = MockFile('', contents)
    228     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    229         mock_input_api, mock_file, range(1, len(contents) + 1))
    230     self.assertEqual(0, len(warnings))
    231 
    232   def testSysIncludes(self):
    233     # #include <sys/...>'s can appear in any order.
    234     mock_input_api = MockInputApi()
    235     contents = ['#include <sys/b.h>',
    236                 '#include <sys/a.h>']
    237     mock_file = MockFile('', contents)
    238     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    239         mock_input_api, mock_file, range(1, len(contents) + 1))
    240     self.assertEqual(0, len(warnings))
    241 
    242   def testCheckOnlyCFiles(self):
    243     mock_input_api = MockInputApi()
    244     mock_output_api = MockOutputApi()
    245     contents = ['#include <b.h>',
    246                 '#include <a.h>']
    247     mock_file_cc = MockFile('something.cc', contents)
    248     mock_file_h = MockFile('something.h', contents)
    249     mock_file_other = MockFile('something.py', contents)
    250     mock_input_api.files = [mock_file_cc, mock_file_h, mock_file_other]
    251     warnings = PRESUBMIT._CheckIncludeOrder(mock_input_api, mock_output_api)
    252     self.assertEqual(1, len(warnings))
    253     self.assertEqual(2, len(warnings[0].items))
    254     self.assertEqual('promptOrNotify', warnings[0].type)
    255 
    256   def testUncheckableIncludes(self):
    257     mock_input_api = MockInputApi()
    258     contents = ['#include <windows.h>',
    259                 '#include "b.h"'
    260                 '#include "a.h"']
    261     mock_file = MockFile('', contents)
    262     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    263         mock_input_api, mock_file, range(1, len(contents) + 1))
    264     self.assertEqual(0, len(warnings))
    265 
    266     contents = ['#include "gpu/command_buffer/gles_autogen.h"',
    267                 '#include "b.h"'
    268                 '#include "a.h"']
    269     mock_file = MockFile('', contents)
    270     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    271         mock_input_api, mock_file, range(1, len(contents) + 1))
    272     self.assertEqual(0, len(warnings))
    273 
    274     contents = ['#include "gl_mock_autogen.h"',
    275                 '#include "b.h"'
    276                 '#include "a.h"']
    277     mock_file = MockFile('', contents)
    278     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    279         mock_input_api, mock_file, range(1, len(contents) + 1))
    280     self.assertEqual(0, len(warnings))
    281 
    282     contents = ['#include "ipc/some_macros.h"',
    283                 '#include "b.h"'
    284                 '#include "a.h"']
    285     mock_file = MockFile('', contents)
    286     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    287         mock_input_api, mock_file, range(1, len(contents) + 1))
    288     self.assertEqual(0, len(warnings))
    289 
    290 
    291 class VersionControlConflictsTest(unittest.TestCase):
    292   def testTypicalConflict(self):
    293     lines = ['<<<<<<< HEAD',
    294              '  base::ScopedTempDir temp_dir_;',
    295              '=======',
    296              '  ScopedTempDir temp_dir_;',
    297              '>>>>>>> master']
    298     errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
    299         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    300     self.assertEqual(3, len(errors))
    301     self.assertTrue('1' in errors[0])
    302     self.assertTrue('3' in errors[1])
    303     self.assertTrue('5' in errors[2])
    304 
    305 
    306 class BadExtensionsTest(unittest.TestCase):
    307   def testBadRejFile(self):
    308     mock_input_api = MockInputApi()
    309     mock_input_api.files = [
    310       MockFile('some/path/foo.cc', ''),
    311       MockFile('some/path/foo.cc.rej', ''),
    312       MockFile('some/path2/bar.h.rej', ''),
    313     ]
    314 
    315     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    316     self.assertEqual(1, len(results))
    317     self.assertEqual(2, len(results[0].items))
    318     self.assertTrue('foo.cc.rej' in results[0].items[0])
    319     self.assertTrue('bar.h.rej' in results[0].items[1])
    320 
    321   def testBadOrigFile(self):
    322     mock_input_api = MockInputApi()
    323     mock_input_api.files = [
    324       MockFile('other/path/qux.h.orig', ''),
    325       MockFile('other/path/qux.h', ''),
    326       MockFile('other/path/qux.cc', ''),
    327     ]
    328 
    329     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    330     self.assertEqual(1, len(results))
    331     self.assertEqual(1, len(results[0].items))
    332     self.assertTrue('qux.h.orig' in results[0].items[0])
    333 
    334   def testGoodFiles(self):
    335     mock_input_api = MockInputApi()
    336     mock_input_api.files = [
    337       MockFile('other/path/qux.h', ''),
    338       MockFile('other/path/qux.cc', ''),
    339     ]
    340     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    341     self.assertEqual(0, len(results))
    342 
    343   def testOnlyOwnersFiles(self):
    344     mock_change = MockChange([
    345       'some/path/OWNERS',
    346       'A\Windows\Path\OWNERS',
    347     ])
    348     results = PRESUBMIT.GetPreferredTrySlaves(None, mock_change)
    349     self.assertEqual(0, len(results))
    350 
    351 
    352 class InvalidOSMacroNamesTest(unittest.TestCase):
    353   def testInvalidOSMacroNames(self):
    354     lines = ['#if defined(OS_WINDOWS)',
    355              ' #elif defined(OS_WINDOW)',
    356              ' # if defined(OS_MACOSX) || defined(OS_CHROME)',
    357              '# else  // defined(OS_MAC)',
    358              '#endif  // defined(OS_MACOS)']
    359     errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
    360         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    361     self.assertEqual(len(lines), len(errors))
    362     self.assertTrue(':1 OS_WINDOWS' in errors[0])
    363     self.assertTrue('(did you mean OS_WIN?)' in errors[0])
    364 
    365   def testValidOSMacroNames(self):
    366     lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS]
    367     errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
    368         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    369     self.assertEqual(0, len(errors))
    370 
    371 
    372 class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
    373   def testDepsFilesToCheck(self):
    374     changed_lines = [
    375       '"+breakpad",',
    376       '"+chrome/installer",',
    377       '"+chrome/plugin/chrome_content_plugin_client.h",',
    378       '"+chrome/utility/chrome_content_utility_client.h",',
    379       '"+chromeos/chromeos_paths.h",',
    380       '"+components/breakpad",',
    381       '"+components/nacl/common",',
    382       '"+content/public/browser/render_process_host.h",',
    383       '"+grit",  # For generated headers',
    384       '"+grit/generated_resources.h",',
    385       '"+grit/",',
    386       '"+policy",  # For generated headers and source',
    387       '"+sandbox",',
    388       '"+tools/memory_watcher",',
    389       '"+third_party/lss/linux_syscall_support.h",',
    390     ]
    391     files_to_check = PRESUBMIT._DepsFilesToCheck(re, changed_lines)
    392     expected = set([
    393       'breakpad/DEPS',
    394       'chrome/installer/DEPS',
    395       'chrome/plugin/DEPS',
    396       'chrome/utility/DEPS',
    397       'chromeos/DEPS',
    398       'components/breakpad/DEPS',
    399       'components/nacl/common/DEPS',
    400       'content/public/browser/DEPS',
    401       'policy/DEPS',
    402       'sandbox/DEPS',
    403       'tools/memory_watcher/DEPS',
    404       'third_party/lss/DEPS',
    405     ])
    406     self.assertEqual(expected, files_to_check);
    407 
    408 
    409 if __name__ == '__main__':
    410   unittest.main()
    411