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 glob
      7 import json
      8 import os
      9 import re
     10 import subprocess
     11 import sys
     12 import unittest
     13 
     14 import PRESUBMIT
     15 
     16 
     17 _TEST_DATA_DIR = 'base/test/data/presubmit'
     18 
     19 
     20 class MockInputApi(object):
     21   def __init__(self):
     22     self.json = json
     23     self.re = re
     24     self.os_path = os.path
     25     self.python_executable = sys.executable
     26     self.subprocess = subprocess
     27     self.files = []
     28     self.is_committing = False
     29 
     30   def AffectedFiles(self, file_filter=None):
     31     return self.files
     32 
     33   def PresubmitLocalPath(self):
     34     return os.path.dirname(__file__)
     35 
     36   def ReadFile(self, filename, mode='rU'):
     37     for file_ in self.files:
     38       if file_.LocalPath() == filename:
     39         return '\n'.join(file_.NewContents())
     40     # Otherwise, file is not in our mock API.
     41     raise IOError, "No such file or directory: '%s'" % filename
     42 
     43 
     44 class MockOutputApi(object):
     45   class PresubmitResult(object):
     46     def __init__(self, message, items=None, long_text=''):
     47       self.message = message
     48       self.items = items
     49       self.long_text = long_text
     50 
     51   class PresubmitError(PresubmitResult):
     52     def __init__(self, message, items, long_text=''):
     53       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     54       self.type = 'error'
     55 
     56   class PresubmitPromptWarning(PresubmitResult):
     57     def __init__(self, message, items, long_text=''):
     58       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     59       self.type = 'warning'
     60 
     61   class PresubmitNotifyResult(PresubmitResult):
     62     def __init__(self, message, items, long_text=''):
     63       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     64       self.type = 'notify'
     65 
     66   class PresubmitPromptOrNotify(PresubmitResult):
     67     def __init__(self, message, items, long_text=''):
     68       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
     69       self.type = 'promptOrNotify'
     70 
     71 
     72 class MockFile(object):
     73   def __init__(self, local_path, new_contents):
     74     self._local_path = local_path
     75     self._new_contents = new_contents
     76     self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
     77 
     78   def ChangedContents(self):
     79     return self._changed_contents
     80 
     81   def NewContents(self):
     82     return self._new_contents
     83 
     84   def LocalPath(self):
     85     return self._local_path
     86 
     87 
     88 class MockChange(object):
     89   def __init__(self, changed_files):
     90     self._changed_files = changed_files
     91 
     92   def LocalPaths(self):
     93     return self._changed_files
     94 
     95 
     96 class IncludeOrderTest(unittest.TestCase):
     97   def testSystemHeaderOrder(self):
     98     scope = [(1, '#include <csystem.h>'),
     99              (2, '#include <cppsystem>'),
    100              (3, '#include "acustom.h"')]
    101     all_linenums = [linenum for (linenum, _) in scope]
    102     mock_input_api = MockInputApi()
    103     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    104                                                     '', all_linenums)
    105     self.assertEqual(0, len(warnings))
    106 
    107   def testSystemHeaderOrderMismatch1(self):
    108     scope = [(10, '#include <cppsystem>'),
    109              (20, '#include <csystem.h>'),
    110              (30, '#include "acustom.h"')]
    111     all_linenums = [linenum for (linenum, _) in scope]
    112     mock_input_api = MockInputApi()
    113     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    114                                                     '', all_linenums)
    115     self.assertEqual(1, len(warnings))
    116     self.assertTrue('20' in warnings[0])
    117 
    118   def testSystemHeaderOrderMismatch2(self):
    119     scope = [(10, '#include <cppsystem>'),
    120              (20, '#include "acustom.h"'),
    121              (30, '#include <csystem.h>')]
    122     all_linenums = [linenum for (linenum, _) in scope]
    123     mock_input_api = MockInputApi()
    124     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    125                                                     '', all_linenums)
    126     self.assertEqual(1, len(warnings))
    127     self.assertTrue('30' in warnings[0])
    128 
    129   def testSystemHeaderOrderMismatch3(self):
    130     scope = [(10, '#include "acustom.h"'),
    131              (20, '#include <csystem.h>'),
    132              (30, '#include <cppsystem>')]
    133     all_linenums = [linenum for (linenum, _) in scope]
    134     mock_input_api = MockInputApi()
    135     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    136                                                     '', all_linenums)
    137     self.assertEqual(2, len(warnings))
    138     self.assertTrue('20' in warnings[0])
    139     self.assertTrue('30' in warnings[1])
    140 
    141   def testAlphabeticalOrderMismatch(self):
    142     scope = [(10, '#include <csystem.h>'),
    143              (15, '#include <bsystem.h>'),
    144              (20, '#include <cppsystem>'),
    145              (25, '#include <bppsystem>'),
    146              (30, '#include "bcustom.h"'),
    147              (35, '#include "acustom.h"')]
    148     all_linenums = [linenum for (linenum, _) in scope]
    149     mock_input_api = MockInputApi()
    150     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    151                                                     '', all_linenums)
    152     self.assertEqual(3, len(warnings))
    153     self.assertTrue('15' in warnings[0])
    154     self.assertTrue('25' in warnings[1])
    155     self.assertTrue('35' in warnings[2])
    156 
    157   def testSpecialFirstInclude1(self):
    158     mock_input_api = MockInputApi()
    159     contents = ['#include "some/path/foo.h"',
    160                 '#include "a/header.h"']
    161     mock_file = MockFile('some/path/foo.cc', contents)
    162     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    163         mock_input_api, mock_file, range(1, len(contents) + 1))
    164     self.assertEqual(0, len(warnings))
    165 
    166   def testSpecialFirstInclude2(self):
    167     mock_input_api = MockInputApi()
    168     contents = ['#include "some/other/path/foo.h"',
    169                 '#include "a/header.h"']
    170     mock_file = MockFile('some/path/foo.cc', contents)
    171     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    172         mock_input_api, mock_file, range(1, len(contents) + 1))
    173     self.assertEqual(0, len(warnings))
    174 
    175   def testSpecialFirstInclude3(self):
    176     mock_input_api = MockInputApi()
    177     contents = ['#include "some/path/foo.h"',
    178                 '#include "a/header.h"']
    179     mock_file = MockFile('some/path/foo_platform.cc', contents)
    180     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    181         mock_input_api, mock_file, range(1, len(contents) + 1))
    182     self.assertEqual(0, len(warnings))
    183 
    184   def testSpecialFirstInclude4(self):
    185     mock_input_api = MockInputApi()
    186     contents = ['#include "some/path/bar.h"',
    187                 '#include "a/header.h"']
    188     mock_file = MockFile('some/path/foo_platform.cc', contents)
    189     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    190         mock_input_api, mock_file, range(1, len(contents) + 1))
    191     self.assertEqual(1, len(warnings))
    192     self.assertTrue('2' in warnings[0])
    193 
    194   def testSpecialFirstInclude5(self):
    195     mock_input_api = MockInputApi()
    196     contents = ['#include "some/other/path/foo.h"',
    197                 '#include "a/header.h"']
    198     mock_file = MockFile('some/path/foo-suffix.h', contents)
    199     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    200         mock_input_api, mock_file, range(1, len(contents) + 1))
    201     self.assertEqual(0, len(warnings))
    202 
    203   def testSpecialFirstInclude6(self):
    204     mock_input_api = MockInputApi()
    205     contents = ['#include "some/other/path/foo_win.h"',
    206                 '#include <set>',
    207                 '#include "a/header.h"']
    208     mock_file = MockFile('some/path/foo_unittest_win.h', contents)
    209     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    210         mock_input_api, mock_file, range(1, len(contents) + 1))
    211     self.assertEqual(0, len(warnings))
    212 
    213   def testOrderAlreadyWrong(self):
    214     scope = [(1, '#include "b.h"'),
    215              (2, '#include "a.h"'),
    216              (3, '#include "c.h"')]
    217     mock_input_api = MockInputApi()
    218     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    219                                                     '', [3])
    220     self.assertEqual(0, len(warnings))
    221 
    222   def testConflictAdded1(self):
    223     scope = [(1, '#include "a.h"'),
    224              (2, '#include "c.h"'),
    225              (3, '#include "b.h"')]
    226     mock_input_api = MockInputApi()
    227     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    228                                                     '', [2])
    229     self.assertEqual(1, len(warnings))
    230     self.assertTrue('3' in warnings[0])
    231 
    232   def testConflictAdded2(self):
    233     scope = [(1, '#include "c.h"'),
    234              (2, '#include "b.h"'),
    235              (3, '#include "d.h"')]
    236     mock_input_api = MockInputApi()
    237     warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
    238                                                     '', [2])
    239     self.assertEqual(1, len(warnings))
    240     self.assertTrue('2' in warnings[0])
    241 
    242   def testIfElifElseEndif(self):
    243     mock_input_api = MockInputApi()
    244     contents = ['#include "e.h"',
    245                 '#define foo',
    246                 '#include "f.h"',
    247                 '#undef foo',
    248                 '#include "e.h"',
    249                 '#if foo',
    250                 '#include "d.h"',
    251                 '#elif bar',
    252                 '#include "c.h"',
    253                 '#else',
    254                 '#include "b.h"',
    255                 '#endif',
    256                 '#include "a.h"']
    257     mock_file = MockFile('', contents)
    258     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    259         mock_input_api, mock_file, range(1, len(contents) + 1))
    260     self.assertEqual(0, len(warnings))
    261 
    262   def testExcludedIncludes(self):
    263     # #include <sys/...>'s can appear in any order.
    264     mock_input_api = MockInputApi()
    265     contents = ['#include <sys/b.h>',
    266                 '#include <sys/a.h>']
    267     mock_file = MockFile('', contents)
    268     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    269         mock_input_api, mock_file, range(1, len(contents) + 1))
    270     self.assertEqual(0, len(warnings))
    271 
    272     contents = ['#include <atlbase.h>',
    273                 '#include <aaa.h>']
    274     mock_file = MockFile('', contents)
    275     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    276         mock_input_api, mock_file, range(1, len(contents) + 1))
    277     self.assertEqual(0, len(warnings))
    278 
    279     contents = ['#include "build/build_config.h"',
    280                 '#include "aaa.h"']
    281     mock_file = MockFile('', contents)
    282     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    283         mock_input_api, mock_file, range(1, len(contents) + 1))
    284     self.assertEqual(0, len(warnings))
    285 
    286   def testCheckOnlyCFiles(self):
    287     mock_input_api = MockInputApi()
    288     mock_output_api = MockOutputApi()
    289     contents = ['#include <b.h>',
    290                 '#include <a.h>']
    291     mock_file_cc = MockFile('something.cc', contents)
    292     mock_file_h = MockFile('something.h', contents)
    293     mock_file_other = MockFile('something.py', contents)
    294     mock_input_api.files = [mock_file_cc, mock_file_h, mock_file_other]
    295     warnings = PRESUBMIT._CheckIncludeOrder(mock_input_api, mock_output_api)
    296     self.assertEqual(1, len(warnings))
    297     self.assertEqual(2, len(warnings[0].items))
    298     self.assertEqual('promptOrNotify', warnings[0].type)
    299 
    300   def testUncheckableIncludes(self):
    301     mock_input_api = MockInputApi()
    302     contents = ['#include <windows.h>',
    303                 '#include "b.h"',
    304                 '#include "a.h"']
    305     mock_file = MockFile('', contents)
    306     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    307         mock_input_api, mock_file, range(1, len(contents) + 1))
    308     self.assertEqual(1, len(warnings))
    309 
    310     contents = ['#include "gpu/command_buffer/gles_autogen.h"',
    311                 '#include "b.h"',
    312                 '#include "a.h"']
    313     mock_file = MockFile('', contents)
    314     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    315         mock_input_api, mock_file, range(1, len(contents) + 1))
    316     self.assertEqual(1, len(warnings))
    317 
    318     contents = ['#include "gl_mock_autogen.h"',
    319                 '#include "b.h"',
    320                 '#include "a.h"']
    321     mock_file = MockFile('', contents)
    322     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    323         mock_input_api, mock_file, range(1, len(contents) + 1))
    324     self.assertEqual(1, len(warnings))
    325 
    326     contents = ['#include "ipc/some_macros.h"',
    327                 '#include "b.h"',
    328                 '#include "a.h"']
    329     mock_file = MockFile('', contents)
    330     warnings = PRESUBMIT._CheckIncludeOrderInFile(
    331         mock_input_api, mock_file, range(1, len(contents) + 1))
    332     self.assertEqual(1, len(warnings))
    333 
    334 
    335 class VersionControlConflictsTest(unittest.TestCase):
    336   def testTypicalConflict(self):
    337     lines = ['<<<<<<< HEAD',
    338              '  base::ScopedTempDir temp_dir_;',
    339              '=======',
    340              '  ScopedTempDir temp_dir_;',
    341              '>>>>>>> master']
    342     errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
    343         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    344     self.assertEqual(3, len(errors))
    345     self.assertTrue('1' in errors[0])
    346     self.assertTrue('3' in errors[1])
    347     self.assertTrue('5' in errors[2])
    348 
    349 
    350 class BadExtensionsTest(unittest.TestCase):
    351   def testBadRejFile(self):
    352     mock_input_api = MockInputApi()
    353     mock_input_api.files = [
    354       MockFile('some/path/foo.cc', ''),
    355       MockFile('some/path/foo.cc.rej', ''),
    356       MockFile('some/path2/bar.h.rej', ''),
    357     ]
    358 
    359     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    360     self.assertEqual(1, len(results))
    361     self.assertEqual(2, len(results[0].items))
    362     self.assertTrue('foo.cc.rej' in results[0].items[0])
    363     self.assertTrue('bar.h.rej' in results[0].items[1])
    364 
    365   def testBadOrigFile(self):
    366     mock_input_api = MockInputApi()
    367     mock_input_api.files = [
    368       MockFile('other/path/qux.h.orig', ''),
    369       MockFile('other/path/qux.h', ''),
    370       MockFile('other/path/qux.cc', ''),
    371     ]
    372 
    373     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    374     self.assertEqual(1, len(results))
    375     self.assertEqual(1, len(results[0].items))
    376     self.assertTrue('qux.h.orig' in results[0].items[0])
    377 
    378   def testGoodFiles(self):
    379     mock_input_api = MockInputApi()
    380     mock_input_api.files = [
    381       MockFile('other/path/qux.h', ''),
    382       MockFile('other/path/qux.cc', ''),
    383     ]
    384     results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
    385     self.assertEqual(0, len(results))
    386 
    387   def testOnlyOwnersFiles(self):
    388     mock_change = MockChange([
    389       'some/path/OWNERS',
    390       'A\Windows\Path\OWNERS',
    391     ])
    392     results = PRESUBMIT.GetPreferredTryMasters(None, mock_change)
    393     self.assertEqual({}, results)
    394 
    395 
    396 class InvalidOSMacroNamesTest(unittest.TestCase):
    397   def testInvalidOSMacroNames(self):
    398     lines = ['#if defined(OS_WINDOWS)',
    399              ' #elif defined(OS_WINDOW)',
    400              ' # if defined(OS_MACOSX) || defined(OS_CHROME)',
    401              '# else  // defined(OS_MAC)',
    402              '#endif  // defined(OS_MACOS)']
    403     errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
    404         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    405     self.assertEqual(len(lines), len(errors))
    406     self.assertTrue(':1 OS_WINDOWS' in errors[0])
    407     self.assertTrue('(did you mean OS_WIN?)' in errors[0])
    408 
    409   def testValidOSMacroNames(self):
    410     lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS]
    411     errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
    412         MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
    413     self.assertEqual(0, len(errors))
    414 
    415 
    416 class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
    417   def testFilesToCheckForIncomingDeps(self):
    418     changed_lines = [
    419       '"+breakpad",',
    420       '"+chrome/installer",',
    421       '"+chrome/plugin/chrome_content_plugin_client.h",',
    422       '"+chrome/utility/chrome_content_utility_client.h",',
    423       '"+chromeos/chromeos_paths.h",',
    424       '"+components/crash",',
    425       '"+components/nacl/common",',
    426       '"+content/public/browser/render_process_host.h",',
    427       '"+jni/fooblat.h",',
    428       '"+grit",  # For generated headers',
    429       '"+grit/generated_resources.h",',
    430       '"+grit/",',
    431       '"+policy",  # For generated headers and source',
    432       '"+sandbox",',
    433       '"+tools/memory_watcher",',
    434       '"+third_party/lss/linux_syscall_support.h",',
    435     ]
    436     files_to_check = PRESUBMIT._FilesToCheckForIncomingDeps(re, changed_lines)
    437     expected = set([
    438       'breakpad/DEPS',
    439       'chrome/installer/DEPS',
    440       'chrome/plugin/chrome_content_plugin_client.h',
    441       'chrome/utility/chrome_content_utility_client.h',
    442       'chromeos/chromeos_paths.h',
    443       'components/crash/DEPS',
    444       'components/nacl/common/DEPS',
    445       'content/public/browser/render_process_host.h',
    446       'policy/DEPS',
    447       'sandbox/DEPS',
    448       'tools/memory_watcher/DEPS',
    449       'third_party/lss/linux_syscall_support.h',
    450     ])
    451     self.assertEqual(expected, files_to_check);
    452 
    453 
    454 class JSONParsingTest(unittest.TestCase):
    455   def testSuccess(self):
    456     input_api = MockInputApi()
    457     filename = 'valid_json.json'
    458     contents = ['// This is a comment.',
    459                 '{',
    460                 '  "key1": ["value1", "value2"],',
    461                 '  "key2": 3  // This is an inline comment.',
    462                 '}'
    463                 ]
    464     input_api.files = [MockFile(filename, contents)]
    465     self.assertEqual(None,
    466                      PRESUBMIT._GetJSONParseError(input_api, filename))
    467 
    468   def testFailure(self):
    469     input_api = MockInputApi()
    470     test_data = [
    471       ('invalid_json_1.json',
    472        ['{ x }'],
    473        'Expecting property name:'),
    474       ('invalid_json_2.json',
    475        ['// Hello world!',
    476         '{ "hello": "world }'],
    477        'Unterminated string starting at:'),
    478       ('invalid_json_3.json',
    479        ['{ "a": "b", "c": "d", }'],
    480        'Expecting property name:'),
    481       ('invalid_json_4.json',
    482        ['{ "a": "b" "c": "d" }'],
    483        'Expecting , delimiter:'),
    484       ]
    485 
    486     input_api.files = [MockFile(filename, contents)
    487                        for (filename, contents, _) in test_data]
    488 
    489     for (filename, _, expected_error) in test_data:
    490       actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
    491       self.assertTrue(expected_error in str(actual_error),
    492                       "'%s' not found in '%s'" % (expected_error, actual_error))
    493 
    494   def testNoEatComments(self):
    495     input_api = MockInputApi()
    496     file_with_comments = 'file_with_comments.json'
    497     contents_with_comments = ['// This is a comment.',
    498                               '{',
    499                               '  "key1": ["value1", "value2"],',
    500                               '  "key2": 3  // This is an inline comment.',
    501                               '}'
    502                               ]
    503     file_without_comments = 'file_without_comments.json'
    504     contents_without_comments = ['{',
    505                                  '  "key1": ["value1", "value2"],',
    506                                  '  "key2": 3',
    507                                  '}'
    508                                  ]
    509     input_api.files = [MockFile(file_with_comments, contents_with_comments),
    510                        MockFile(file_without_comments,
    511                                 contents_without_comments)]
    512 
    513     self.assertEqual('No JSON object could be decoded',
    514                      str(PRESUBMIT._GetJSONParseError(input_api,
    515                                                       file_with_comments,
    516                                                       eat_comments=False)))
    517     self.assertEqual(None,
    518                      PRESUBMIT._GetJSONParseError(input_api,
    519                                                   file_without_comments,
    520                                                   eat_comments=False))
    521 
    522 
    523 class IDLParsingTest(unittest.TestCase):
    524   def testSuccess(self):
    525     input_api = MockInputApi()
    526     filename = 'valid_idl_basics.idl'
    527     contents = ['// Tests a valid IDL file.',
    528                 'namespace idl_basics {',
    529                 '  enum EnumType {',
    530                 '    name1,',
    531                 '    name2',
    532                 '  };',
    533                 '',
    534                 '  dictionary MyType1 {',
    535                 '    DOMString a;',
    536                 '  };',
    537                 '',
    538                 '  callback Callback1 = void();',
    539                 '  callback Callback2 = void(long x);',
    540                 '  callback Callback3 = void(MyType1 arg);',
    541                 '  callback Callback4 = void(EnumType type);',
    542                 '',
    543                 '  interface Functions {',
    544                 '    static void function1();',
    545                 '    static void function2(long x);',
    546                 '    static void function3(MyType1 arg);',
    547                 '    static void function4(Callback1 cb);',
    548                 '    static void function5(Callback2 cb);',
    549                 '    static void function6(Callback3 cb);',
    550                 '    static void function7(Callback4 cb);',
    551                 '  };',
    552                 '',
    553                 '  interface Events {',
    554                 '    static void onFoo1();',
    555                 '    static void onFoo2(long x);',
    556                 '    static void onFoo2(MyType1 arg);',
    557                 '    static void onFoo3(EnumType type);',
    558                 '  };',
    559                 '};'
    560                 ]
    561     input_api.files = [MockFile(filename, contents)]
    562     self.assertEqual(None,
    563                      PRESUBMIT._GetIDLParseError(input_api, filename))
    564 
    565   def testFailure(self):
    566     input_api = MockInputApi()
    567     test_data = [
    568       ('invalid_idl_1.idl',
    569        ['//',
    570         'namespace test {',
    571         '  dictionary {',
    572         '    DOMString s;',
    573         '  };',
    574         '};'],
    575        'Unexpected "{" after keyword "dictionary".\n'),
    576       # TODO(yoz): Disabled because it causes the IDL parser to hang.
    577       # See crbug.com/363830.
    578       # ('invalid_idl_2.idl',
    579       #  (['namespace test {',
    580       #    '  dictionary MissingSemicolon {',
    581       #    '    DOMString a',
    582       #    '    DOMString b;',
    583       #    '  };',
    584       #    '};'],
    585       #   'Unexpected symbol DOMString after symbol a.'),
    586       ('invalid_idl_3.idl',
    587        ['//',
    588         'namespace test {',
    589         '  enum MissingComma {',
    590         '    name1',
    591         '    name2',
    592         '  };',
    593         '};'],
    594        'Unexpected symbol name2 after symbol name1.'),
    595       ('invalid_idl_4.idl',
    596        ['//',
    597         'namespace test {',
    598         '  enum TrailingComma {',
    599         '    name1,',
    600         '    name2,',
    601         '  };',
    602         '};'],
    603        'Trailing comma in block.'),
    604       ('invalid_idl_5.idl',
    605        ['//',
    606         'namespace test {',
    607         '  callback Callback1 = void(;',
    608         '};'],
    609        'Unexpected ";" after "(".'),
    610       ('invalid_idl_6.idl',
    611        ['//',
    612         'namespace test {',
    613         '  callback Callback1 = void(long );',
    614         '};'],
    615        'Unexpected ")" after symbol long.'),
    616       ('invalid_idl_7.idl',
    617        ['//',
    618         'namespace test {',
    619         '  interace Events {',
    620         '    static void onFoo1();',
    621         '  };',
    622         '};'],
    623        'Unexpected symbol Events after symbol interace.'),
    624       ('invalid_idl_8.idl',
    625        ['//',
    626         'namespace test {',
    627         '  interface NotEvent {',
    628         '    static void onFoo1();',
    629         '  };',
    630         '};'],
    631        'Did not process Interface Interface(NotEvent)'),
    632       ('invalid_idl_9.idl',
    633        ['//',
    634         'namespace test {',
    635         '  interface {',
    636         '    static void function1();',
    637         '  };',
    638         '};'],
    639        'Interface missing name.'),
    640       ]
    641 
    642     input_api.files = [MockFile(filename, contents)
    643                        for (filename, contents, _) in test_data]
    644 
    645     for (filename, _, expected_error) in test_data:
    646       actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
    647       self.assertTrue(expected_error in str(actual_error),
    648                       "'%s' not found in '%s'" % (expected_error, actual_error))
    649 
    650 
    651 class TryServerMasterTest(unittest.TestCase):
    652   def testTryServerMasters(self):
    653     bots = {
    654         'tryserver.chromium.gpu': [
    655             'mac_gpu',
    656             'mac_gpu_triggered_tests',
    657             'linux_gpu',
    658             'linux_gpu_triggered_tests',
    659             'win_gpu',
    660             'win_gpu_triggered_tests',
    661         ],
    662         'tryserver.chromium.mac': [
    663             'ios_dbg_simulator',
    664             'ios_rel_device',
    665             'ios_rel_device_ninja',
    666             'mac_asan',
    667             'mac_asan_64',
    668             'mac_chromium_compile_dbg',
    669             'mac_chromium_compile_rel',
    670             'mac_chromium_dbg',
    671             'mac_chromium_rel',
    672             'mac_chromium_rel_swarming',
    673             'mac_nacl_sdk',
    674             'mac_nacl_sdk_build',
    675             'mac_rel_naclmore',
    676             'mac_valgrind',
    677             'mac_x64_rel',
    678             'mac_xcodebuild',
    679         ],
    680         'tryserver.chromium.linux': [
    681             'android_aosp',
    682             'android_chromium_gn_compile_dbg',
    683             'android_chromium_gn_compile_rel',
    684             'android_clang_dbg',
    685             'android_dbg',
    686             'android_dbg_recipe',
    687             'android_dbg_triggered_tests',
    688             'android_dbg_triggered_tests_recipe',
    689             'android_fyi_dbg',
    690             'android_fyi_dbg_triggered_tests',
    691             'android_rel',
    692             'android_rel_triggered_tests',
    693             'android_x86_dbg',
    694             'blink_android_compile_dbg',
    695             'blink_android_compile_rel',
    696             'blink_presubmit',
    697             'chromium_presubmit',
    698             'linux_arm_cross_compile',
    699             'linux_arm_tester',
    700             'linux_asan',
    701             'linux_browser_asan',
    702             'linux_chromeos_asan',
    703             'linux_chromeos_browser_asan',
    704             'linux_chromeos_valgrind',
    705             'linux_chromium_chromeos_clang_dbg',
    706             'linux_chromium_chromeos_clang_rel',
    707             'linux_chromium_chromeos_dbg',
    708             'linux_chromium_chromeos_rel',
    709             'linux_chromium_clang_dbg',
    710             'linux_chromium_clang_rel',
    711             'linux_chromium_compile_dbg',
    712             'linux_chromium_compile_rel',
    713             'linux_chromium_dbg',
    714             'linux_chromium_gn_dbg',
    715             'linux_chromium_gn_rel',
    716             'linux_chromium_rel',
    717             'linux_chromium_rel_swarming',
    718             'linux_chromium_trusty32_dbg',
    719             'linux_chromium_trusty32_rel',
    720             'linux_chromium_trusty_dbg',
    721             'linux_chromium_trusty_rel',
    722             'linux_clang_tsan',
    723             'linux_ecs_ozone',
    724             'linux_layout',
    725             'linux_layout_asan',
    726             'linux_layout_rel',
    727             'linux_layout_rel_32',
    728             'linux_nacl_sdk',
    729             'linux_nacl_sdk_bionic',
    730             'linux_nacl_sdk_bionic_build',
    731             'linux_nacl_sdk_build',
    732             'linux_redux',
    733             'linux_rel_naclmore',
    734             'linux_rel_precise32',
    735             'linux_valgrind',
    736             'tools_build_presubmit',
    737         ],
    738         'tryserver.chromium.win': [
    739             'win8_aura',
    740             'win8_chromium_dbg',
    741             'win8_chromium_rel',
    742             'win_chromium_compile_dbg',
    743             'win_chromium_compile_rel',
    744             'win_chromium_dbg',
    745             'win_chromium_rel',
    746             'win_chromium_rel',
    747             'win_chromium_rel_swarming',
    748             'win_chromium_rel_swarming',
    749             'win_chromium_x64_dbg',
    750             'win_chromium_x64_rel',
    751             'win_drmemory',
    752             'win_nacl_sdk',
    753             'win_nacl_sdk_build',
    754             'win_rel_naclmore',
    755          ],
    756     }
    757     for master, bots in bots.iteritems():
    758       for bot in bots:
    759         self.assertEqual(master, PRESUBMIT.GetTryServerMasterForBot(bot),
    760                          'bot=%s: expected %s, computed %s' % (
    761             bot, master, PRESUBMIT.GetTryServerMasterForBot(bot)))
    762 
    763 
    764 if __name__ == '__main__':
    765   unittest.main()
    766