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 6import os 7import re 8import unittest 9 10import PRESUBMIT 11 12 13class 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 24class 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 52class 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 68class 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 76class 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 testSpecialFirstInclude6(self): 184 mock_input_api = MockInputApi() 185 contents = ['#include "some/other/path/foo_win.h"', 186 '#include <set>', 187 '#include "a/header.h"'] 188 mock_file = MockFile('some/path/foo_unittest_win.h', contents) 189 warnings = PRESUBMIT._CheckIncludeOrderInFile( 190 mock_input_api, mock_file, range(1, len(contents) + 1)) 191 self.assertEqual(0, len(warnings)) 192 193 def testOrderAlreadyWrong(self): 194 scope = [(1, '#include "b.h"'), 195 (2, '#include "a.h"'), 196 (3, '#include "c.h"')] 197 mock_input_api = MockInputApi() 198 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, 199 '', [3]) 200 self.assertEqual(0, len(warnings)) 201 202 def testConflictAdded1(self): 203 scope = [(1, '#include "a.h"'), 204 (2, '#include "c.h"'), 205 (3, '#include "b.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('3' in warnings[0]) 211 212 def testConflictAdded2(self): 213 scope = [(1, '#include "c.h"'), 214 (2, '#include "b.h"'), 215 (3, '#include "d.h"')] 216 mock_input_api = MockInputApi() 217 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api, 218 '', [2]) 219 self.assertEqual(1, len(warnings)) 220 self.assertTrue('2' in warnings[0]) 221 222 def testIfElifElseEndif(self): 223 mock_input_api = MockInputApi() 224 contents = ['#include "e.h"', 225 '#define foo', 226 '#include "f.h"', 227 '#undef foo', 228 '#include "e.h"', 229 '#if foo', 230 '#include "d.h"', 231 '#elif bar', 232 '#include "c.h"', 233 '#else', 234 '#include "b.h"', 235 '#endif', 236 '#include "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 testExcludedIncludes(self): 243 # #include <sys/...>'s can appear in any order. 244 mock_input_api = MockInputApi() 245 contents = ['#include <sys/b.h>', 246 '#include <sys/a.h>'] 247 mock_file = MockFile('', contents) 248 warnings = PRESUBMIT._CheckIncludeOrderInFile( 249 mock_input_api, mock_file, range(1, len(contents) + 1)) 250 self.assertEqual(0, len(warnings)) 251 252 contents = ['#include <atlbase.h>', 253 '#include <aaa.h>'] 254 mock_file = MockFile('', contents) 255 warnings = PRESUBMIT._CheckIncludeOrderInFile( 256 mock_input_api, mock_file, range(1, len(contents) + 1)) 257 self.assertEqual(0, len(warnings)) 258 259 contents = ['#include "build/build_config.h"', 260 '#include "aaa.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 def testCheckOnlyCFiles(self): 267 mock_input_api = MockInputApi() 268 mock_output_api = MockOutputApi() 269 contents = ['#include <b.h>', 270 '#include <a.h>'] 271 mock_file_cc = MockFile('something.cc', contents) 272 mock_file_h = MockFile('something.h', contents) 273 mock_file_other = MockFile('something.py', contents) 274 mock_input_api.files = [mock_file_cc, mock_file_h, mock_file_other] 275 warnings = PRESUBMIT._CheckIncludeOrder(mock_input_api, mock_output_api) 276 self.assertEqual(1, len(warnings)) 277 self.assertEqual(2, len(warnings[0].items)) 278 self.assertEqual('promptOrNotify', warnings[0].type) 279 280 def testUncheckableIncludes(self): 281 mock_input_api = MockInputApi() 282 contents = ['#include <windows.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 contents = ['#include "gpu/command_buffer/gles_autogen.h"', 291 '#include "b.h"' 292 '#include "a.h"'] 293 mock_file = MockFile('', contents) 294 warnings = PRESUBMIT._CheckIncludeOrderInFile( 295 mock_input_api, mock_file, range(1, len(contents) + 1)) 296 self.assertEqual(0, len(warnings)) 297 298 contents = ['#include "gl_mock_autogen.h"', 299 '#include "b.h"' 300 '#include "a.h"'] 301 mock_file = MockFile('', contents) 302 warnings = PRESUBMIT._CheckIncludeOrderInFile( 303 mock_input_api, mock_file, range(1, len(contents) + 1)) 304 self.assertEqual(0, len(warnings)) 305 306 contents = ['#include "ipc/some_macros.h"', 307 '#include "b.h"' 308 '#include "a.h"'] 309 mock_file = MockFile('', contents) 310 warnings = PRESUBMIT._CheckIncludeOrderInFile( 311 mock_input_api, mock_file, range(1, len(contents) + 1)) 312 self.assertEqual(0, len(warnings)) 313 314 315class VersionControlConflictsTest(unittest.TestCase): 316 def testTypicalConflict(self): 317 lines = ['<<<<<<< HEAD', 318 ' base::ScopedTempDir temp_dir_;', 319 '=======', 320 ' ScopedTempDir temp_dir_;', 321 '>>>>>>> master'] 322 errors = PRESUBMIT._CheckForVersionControlConflictsInFile( 323 MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) 324 self.assertEqual(3, len(errors)) 325 self.assertTrue('1' in errors[0]) 326 self.assertTrue('3' in errors[1]) 327 self.assertTrue('5' in errors[2]) 328 329 330class BadExtensionsTest(unittest.TestCase): 331 def testBadRejFile(self): 332 mock_input_api = MockInputApi() 333 mock_input_api.files = [ 334 MockFile('some/path/foo.cc', ''), 335 MockFile('some/path/foo.cc.rej', ''), 336 MockFile('some/path2/bar.h.rej', ''), 337 ] 338 339 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) 340 self.assertEqual(1, len(results)) 341 self.assertEqual(2, len(results[0].items)) 342 self.assertTrue('foo.cc.rej' in results[0].items[0]) 343 self.assertTrue('bar.h.rej' in results[0].items[1]) 344 345 def testBadOrigFile(self): 346 mock_input_api = MockInputApi() 347 mock_input_api.files = [ 348 MockFile('other/path/qux.h.orig', ''), 349 MockFile('other/path/qux.h', ''), 350 MockFile('other/path/qux.cc', ''), 351 ] 352 353 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) 354 self.assertEqual(1, len(results)) 355 self.assertEqual(1, len(results[0].items)) 356 self.assertTrue('qux.h.orig' in results[0].items[0]) 357 358 def testGoodFiles(self): 359 mock_input_api = MockInputApi() 360 mock_input_api.files = [ 361 MockFile('other/path/qux.h', ''), 362 MockFile('other/path/qux.cc', ''), 363 ] 364 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi()) 365 self.assertEqual(0, len(results)) 366 367 def testOnlyOwnersFiles(self): 368 mock_change = MockChange([ 369 'some/path/OWNERS', 370 'A\Windows\Path\OWNERS', 371 ]) 372 results = PRESUBMIT.GetPreferredTrySlaves(None, mock_change) 373 self.assertEqual(0, len(results)) 374 375 376class InvalidOSMacroNamesTest(unittest.TestCase): 377 def testInvalidOSMacroNames(self): 378 lines = ['#if defined(OS_WINDOWS)', 379 ' #elif defined(OS_WINDOW)', 380 ' # if defined(OS_MACOSX) || defined(OS_CHROME)', 381 '# else // defined(OS_MAC)', 382 '#endif // defined(OS_MACOS)'] 383 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile( 384 MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) 385 self.assertEqual(len(lines), len(errors)) 386 self.assertTrue(':1 OS_WINDOWS' in errors[0]) 387 self.assertTrue('(did you mean OS_WIN?)' in errors[0]) 388 389 def testValidOSMacroNames(self): 390 lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS] 391 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile( 392 MockInputApi(), MockFile('some/path/foo_platform.cc', lines)) 393 self.assertEqual(0, len(errors)) 394 395 396class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase): 397 def testDepsFilesToCheck(self): 398 changed_lines = [ 399 '"+breakpad",', 400 '"+chrome/installer",', 401 '"+chrome/plugin/chrome_content_plugin_client.h",', 402 '"+chrome/utility/chrome_content_utility_client.h",', 403 '"+chromeos/chromeos_paths.h",', 404 '"+components/breakpad",', 405 '"+components/nacl/common",', 406 '"+content/public/browser/render_process_host.h",', 407 '"+grit", # For generated headers', 408 '"+grit/generated_resources.h",', 409 '"+grit/",', 410 '"+policy", # For generated headers and source', 411 '"+sandbox",', 412 '"+tools/memory_watcher",', 413 '"+third_party/lss/linux_syscall_support.h",', 414 ] 415 files_to_check = PRESUBMIT._DepsFilesToCheck(re, changed_lines) 416 expected = set([ 417 'breakpad/DEPS', 418 'chrome/installer/DEPS', 419 'chrome/plugin/DEPS', 420 'chrome/utility/DEPS', 421 'chromeos/DEPS', 422 'components/breakpad/DEPS', 423 'components/nacl/common/DEPS', 424 'content/public/browser/DEPS', 425 'policy/DEPS', 426 'sandbox/DEPS', 427 'tools/memory_watcher/DEPS', 428 'third_party/lss/DEPS', 429 ]) 430 self.assertEqual(expected, files_to_check); 431 432 433if __name__ == '__main__': 434 unittest.main() 435