Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / PRESUBMIT_test.py
blob4d40d8f9712239289a44046608b0f4c8d04e9cf8
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.
6 import glob
7 import json
8 import os
9 import re
10 import subprocess
11 import sys
12 import unittest
14 import PRESUBMIT
15 from PRESUBMIT_test_mocks import MockChange, MockFile, MockAffectedFile
16 from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
18 _TEST_DATA_DIR = 'base/test/data/presubmit'
20 class IncludeOrderTest(unittest.TestCase):
21 def testSystemHeaderOrder(self):
22 scope = [(1, '#include <csystem.h>'),
23 (2, '#include <cppsystem>'),
24 (3, '#include "acustom.h"')]
25 all_linenums = [linenum for (linenum, _) in scope]
26 mock_input_api = MockInputApi()
27 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
28 '', all_linenums)
29 self.assertEqual(0, len(warnings))
31 def testSystemHeaderOrderMismatch1(self):
32 scope = [(10, '#include <cppsystem>'),
33 (20, '#include <csystem.h>'),
34 (30, '#include "acustom.h"')]
35 all_linenums = [linenum for (linenum, _) in scope]
36 mock_input_api = MockInputApi()
37 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
38 '', all_linenums)
39 self.assertEqual(1, len(warnings))
40 self.assertTrue('20' in warnings[0])
42 def testSystemHeaderOrderMismatch2(self):
43 scope = [(10, '#include <cppsystem>'),
44 (20, '#include "acustom.h"'),
45 (30, '#include <csystem.h>')]
46 all_linenums = [linenum for (linenum, _) in scope]
47 mock_input_api = MockInputApi()
48 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
49 '', all_linenums)
50 self.assertEqual(1, len(warnings))
51 self.assertTrue('30' in warnings[0])
53 def testSystemHeaderOrderMismatch3(self):
54 scope = [(10, '#include "acustom.h"'),
55 (20, '#include <csystem.h>'),
56 (30, '#include <cppsystem>')]
57 all_linenums = [linenum for (linenum, _) in scope]
58 mock_input_api = MockInputApi()
59 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
60 '', all_linenums)
61 self.assertEqual(2, len(warnings))
62 self.assertTrue('20' in warnings[0])
63 self.assertTrue('30' in warnings[1])
65 def testAlphabeticalOrderMismatch(self):
66 scope = [(10, '#include <csystem.h>'),
67 (15, '#include <bsystem.h>'),
68 (20, '#include <cppsystem>'),
69 (25, '#include <bppsystem>'),
70 (30, '#include "bcustom.h"'),
71 (35, '#include "acustom.h"')]
72 all_linenums = [linenum for (linenum, _) in scope]
73 mock_input_api = MockInputApi()
74 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
75 '', all_linenums)
76 self.assertEqual(3, len(warnings))
77 self.assertTrue('15' in warnings[0])
78 self.assertTrue('25' in warnings[1])
79 self.assertTrue('35' in warnings[2])
81 def testSpecialFirstInclude1(self):
82 mock_input_api = MockInputApi()
83 contents = ['#include "some/path/foo.h"',
84 '#include "a/header.h"']
85 mock_file = MockFile('some/path/foo.cc', contents)
86 warnings = PRESUBMIT._CheckIncludeOrderInFile(
87 mock_input_api, mock_file, range(1, len(contents) + 1))
88 self.assertEqual(0, len(warnings))
90 def testSpecialFirstInclude2(self):
91 mock_input_api = MockInputApi()
92 contents = ['#include "some/other/path/foo.h"',
93 '#include "a/header.h"']
94 mock_file = MockFile('some/path/foo.cc', contents)
95 warnings = PRESUBMIT._CheckIncludeOrderInFile(
96 mock_input_api, mock_file, range(1, len(contents) + 1))
97 self.assertEqual(0, len(warnings))
99 def testSpecialFirstInclude3(self):
100 mock_input_api = MockInputApi()
101 contents = ['#include "some/path/foo.h"',
102 '#include "a/header.h"']
103 mock_file = MockFile('some/path/foo_platform.cc', contents)
104 warnings = PRESUBMIT._CheckIncludeOrderInFile(
105 mock_input_api, mock_file, range(1, len(contents) + 1))
106 self.assertEqual(0, len(warnings))
108 def testSpecialFirstInclude4(self):
109 mock_input_api = MockInputApi()
110 contents = ['#include "some/path/bar.h"',
111 '#include "a/header.h"']
112 mock_file = MockFile('some/path/foo_platform.cc', contents)
113 warnings = PRESUBMIT._CheckIncludeOrderInFile(
114 mock_input_api, mock_file, range(1, len(contents) + 1))
115 self.assertEqual(1, len(warnings))
116 self.assertTrue('2' in warnings[0])
118 def testSpecialFirstInclude5(self):
119 mock_input_api = MockInputApi()
120 contents = ['#include "some/other/path/foo.h"',
121 '#include "a/header.h"']
122 mock_file = MockFile('some/path/foo-suffix.h', contents)
123 warnings = PRESUBMIT._CheckIncludeOrderInFile(
124 mock_input_api, mock_file, range(1, len(contents) + 1))
125 self.assertEqual(0, len(warnings))
127 def testSpecialFirstInclude6(self):
128 mock_input_api = MockInputApi()
129 contents = ['#include "some/other/path/foo_win.h"',
130 '#include <set>',
131 '#include "a/header.h"']
132 mock_file = MockFile('some/path/foo_unittest_win.h', contents)
133 warnings = PRESUBMIT._CheckIncludeOrderInFile(
134 mock_input_api, mock_file, range(1, len(contents) + 1))
135 self.assertEqual(0, len(warnings))
137 def testOrderAlreadyWrong(self):
138 scope = [(1, '#include "b.h"'),
139 (2, '#include "a.h"'),
140 (3, '#include "c.h"')]
141 mock_input_api = MockInputApi()
142 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
143 '', [3])
144 self.assertEqual(0, len(warnings))
146 def testConflictAdded1(self):
147 scope = [(1, '#include "a.h"'),
148 (2, '#include "c.h"'),
149 (3, '#include "b.h"')]
150 mock_input_api = MockInputApi()
151 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
152 '', [2])
153 self.assertEqual(1, len(warnings))
154 self.assertTrue('3' in warnings[0])
156 def testConflictAdded2(self):
157 scope = [(1, '#include "c.h"'),
158 (2, '#include "b.h"'),
159 (3, '#include "d.h"')]
160 mock_input_api = MockInputApi()
161 warnings = PRESUBMIT._CheckIncludeOrderForScope(scope, mock_input_api,
162 '', [2])
163 self.assertEqual(1, len(warnings))
164 self.assertTrue('2' in warnings[0])
166 def testIfElifElseEndif(self):
167 mock_input_api = MockInputApi()
168 contents = ['#include "e.h"',
169 '#define foo',
170 '#include "f.h"',
171 '#undef foo',
172 '#include "e.h"',
173 '#if foo',
174 '#include "d.h"',
175 '#elif bar',
176 '#include "c.h"',
177 '#else',
178 '#include "b.h"',
179 '#endif',
180 '#include "a.h"']
181 mock_file = MockFile('', contents)
182 warnings = PRESUBMIT._CheckIncludeOrderInFile(
183 mock_input_api, mock_file, range(1, len(contents) + 1))
184 self.assertEqual(0, len(warnings))
186 def testExcludedIncludes(self):
187 # #include <sys/...>'s can appear in any order.
188 mock_input_api = MockInputApi()
189 contents = ['#include <sys/b.h>',
190 '#include <sys/a.h>']
191 mock_file = MockFile('', contents)
192 warnings = PRESUBMIT._CheckIncludeOrderInFile(
193 mock_input_api, mock_file, range(1, len(contents) + 1))
194 self.assertEqual(0, len(warnings))
196 contents = ['#include <atlbase.h>',
197 '#include <aaa.h>']
198 mock_file = MockFile('', contents)
199 warnings = PRESUBMIT._CheckIncludeOrderInFile(
200 mock_input_api, mock_file, range(1, len(contents) + 1))
201 self.assertEqual(0, len(warnings))
203 contents = ['#include "build/build_config.h"',
204 '#include "aaa.h"']
205 mock_file = MockFile('', contents)
206 warnings = PRESUBMIT._CheckIncludeOrderInFile(
207 mock_input_api, mock_file, range(1, len(contents) + 1))
208 self.assertEqual(0, len(warnings))
210 def testCheckOnlyCFiles(self):
211 mock_input_api = MockInputApi()
212 mock_output_api = MockOutputApi()
213 contents = ['#include <b.h>',
214 '#include <a.h>']
215 mock_file_cc = MockFile('something.cc', contents)
216 mock_file_h = MockFile('something.h', contents)
217 mock_file_other = MockFile('something.py', contents)
218 mock_input_api.files = [mock_file_cc, mock_file_h, mock_file_other]
219 warnings = PRESUBMIT._CheckIncludeOrder(mock_input_api, mock_output_api)
220 self.assertEqual(1, len(warnings))
221 self.assertEqual(2, len(warnings[0].items))
222 self.assertEqual('promptOrNotify', warnings[0].type)
224 def testUncheckableIncludes(self):
225 mock_input_api = MockInputApi()
226 contents = ['#include <windows.h>',
227 '#include "b.h"',
228 '#include "a.h"']
229 mock_file = MockFile('', contents)
230 warnings = PRESUBMIT._CheckIncludeOrderInFile(
231 mock_input_api, mock_file, range(1, len(contents) + 1))
232 self.assertEqual(1, len(warnings))
234 contents = ['#include "gpu/command_buffer/gles_autogen.h"',
235 '#include "b.h"',
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(1, len(warnings))
242 contents = ['#include "gl_mock_autogen.h"',
243 '#include "b.h"',
244 '#include "a.h"']
245 mock_file = MockFile('', contents)
246 warnings = PRESUBMIT._CheckIncludeOrderInFile(
247 mock_input_api, mock_file, range(1, len(contents) + 1))
248 self.assertEqual(1, len(warnings))
250 contents = ['#include "ipc/some_macros.h"',
251 '#include "b.h"',
252 '#include "a.h"']
253 mock_file = MockFile('', contents)
254 warnings = PRESUBMIT._CheckIncludeOrderInFile(
255 mock_input_api, mock_file, range(1, len(contents) + 1))
256 self.assertEqual(1, len(warnings))
259 class VersionControlConflictsTest(unittest.TestCase):
260 def testTypicalConflict(self):
261 lines = ['<<<<<<< HEAD',
262 ' base::ScopedTempDir temp_dir_;',
263 '=======',
264 ' ScopedTempDir temp_dir_;',
265 '>>>>>>> master']
266 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
267 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
268 self.assertEqual(3, len(errors))
269 self.assertTrue('1' in errors[0])
270 self.assertTrue('3' in errors[1])
271 self.assertTrue('5' in errors[2])
273 def testIgnoresReadmes(self):
274 lines = ['A First Level Header',
275 '====================',
277 'A Second Level Header',
278 '---------------------']
279 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
280 MockInputApi(), MockFile('some/polymer/README.md', lines))
281 self.assertEqual(0, len(errors))
283 class UmaHistogramChangeMatchedOrNotTest(unittest.TestCase):
284 def testTypicalCorrectlyMatchedChange(self):
285 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
286 diff_xml = ['<histogram name="Bla.Foo.Dummy"> </histogram>']
287 mock_input_api = MockInputApi()
288 mock_input_api.files = [
289 MockFile('some/path/foo.cc', diff_cc),
290 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
292 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
293 MockOutputApi())
294 self.assertEqual(0, len(warnings))
296 def testTypicalNotMatchedChange(self):
297 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
298 mock_input_api = MockInputApi()
299 mock_input_api.files = [MockFile('some/path/foo.cc', diff_cc)]
300 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
301 MockOutputApi())
302 self.assertEqual(1, len(warnings))
303 self.assertEqual('warning', warnings[0].type)
305 def testTypicalNotMatchedChangeViaSuffixes(self):
306 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
307 diff_xml = ['<histogram_suffixes name="SuperHistogram">',
308 ' <suffix name="Dummy"/>',
309 ' <affected-histogram name="Snafu.Dummy"/>',
310 '</histogram>']
311 mock_input_api = MockInputApi()
312 mock_input_api.files = [
313 MockFile('some/path/foo.cc', diff_cc),
314 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
316 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
317 MockOutputApi())
318 self.assertEqual(1, len(warnings))
319 self.assertEqual('warning', warnings[0].type)
321 def testTypicalCorrectlyMatchedChangeViaSuffixes(self):
322 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
323 diff_xml = ['<histogram_suffixes name="SuperHistogram">',
324 ' <suffix name="Dummy"/>',
325 ' <affected-histogram name="Bla.Foo"/>',
326 '</histogram>']
327 mock_input_api = MockInputApi()
328 mock_input_api.files = [
329 MockFile('some/path/foo.cc', diff_cc),
330 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
332 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
333 MockOutputApi())
334 self.assertEqual(0, len(warnings))
336 def testTypicalCorrectlyMatchedChangeViaSuffixesWithSeparator(self):
337 diff_cc = ['UMA_HISTOGRAM_BOOL("Snafu_Dummy", true)']
338 diff_xml = ['<histogram_suffixes name="SuperHistogram" separator="_">',
339 ' <suffix name="Dummy"/>',
340 ' <affected-histogram name="Snafu"/>',
341 '</histogram>']
342 mock_input_api = MockInputApi()
343 mock_input_api.files = [
344 MockFile('some/path/foo.cc', diff_cc),
345 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
347 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
348 MockOutputApi())
349 self.assertEqual(0, len(warnings))
351 class BadExtensionsTest(unittest.TestCase):
352 def testBadRejFile(self):
353 mock_input_api = MockInputApi()
354 mock_input_api.files = [
355 MockFile('some/path/foo.cc', ''),
356 MockFile('some/path/foo.cc.rej', ''),
357 MockFile('some/path2/bar.h.rej', ''),
360 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
361 self.assertEqual(1, len(results))
362 self.assertEqual(2, len(results[0].items))
363 self.assertTrue('foo.cc.rej' in results[0].items[0])
364 self.assertTrue('bar.h.rej' in results[0].items[1])
366 def testBadOrigFile(self):
367 mock_input_api = MockInputApi()
368 mock_input_api.files = [
369 MockFile('other/path/qux.h.orig', ''),
370 MockFile('other/path/qux.h', ''),
371 MockFile('other/path/qux.cc', ''),
374 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
375 self.assertEqual(1, len(results))
376 self.assertEqual(1, len(results[0].items))
377 self.assertTrue('qux.h.orig' in results[0].items[0])
379 def testGoodFiles(self):
380 mock_input_api = MockInputApi()
381 mock_input_api.files = [
382 MockFile('other/path/qux.h', ''),
383 MockFile('other/path/qux.cc', ''),
385 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
386 self.assertEqual(0, len(results))
389 class CheckSingletonInHeadersTest(unittest.TestCase):
390 def testSingletonInArbitraryHeader(self):
391 diff_singleton_h = ['base::subtle::AtomicWord '
392 'base::Singleton<Type, Traits, DifferentiatingType>::']
393 diff_foo_h = ['// base::Singleton<Foo> in comment.',
394 'friend class base::Singleton<Foo>']
395 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
396 mock_input_api = MockInputApi()
397 mock_input_api.files = [MockAffectedFile('base/memory/singleton.h',
398 diff_singleton_h),
399 MockAffectedFile('foo.h', diff_foo_h),
400 MockAffectedFile('bad.h', diff_bad_h)]
401 warnings = PRESUBMIT._CheckSingletonInHeaders(mock_input_api,
402 MockOutputApi())
403 self.assertEqual(1, len(warnings))
404 self.assertEqual('error', warnings[0].type)
405 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
407 def testSingletonInCC(self):
408 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
409 mock_input_api = MockInputApi()
410 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
411 warnings = PRESUBMIT._CheckSingletonInHeaders(mock_input_api,
412 MockOutputApi())
413 self.assertEqual(0, len(warnings))
416 class InvalidOSMacroNamesTest(unittest.TestCase):
417 def testInvalidOSMacroNames(self):
418 lines = ['#if defined(OS_WINDOWS)',
419 ' #elif defined(OS_WINDOW)',
420 ' # if defined(OS_MACOSX) || defined(OS_CHROME)',
421 '# else // defined(OS_MAC)',
422 '#endif // defined(OS_MACOS)']
423 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
424 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
425 self.assertEqual(len(lines), len(errors))
426 self.assertTrue(':1 OS_WINDOWS' in errors[0])
427 self.assertTrue('(did you mean OS_WIN?)' in errors[0])
429 def testValidOSMacroNames(self):
430 lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS]
431 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
432 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
433 self.assertEqual(0, len(errors))
436 class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
437 def testInvalidIfDefinedMacroNames(self):
438 lines = ['#if defined(TARGET_IPHONE_SIMULATOR)',
439 '#if !defined(TARGET_IPHONE_SIMULATOR)',
440 '#elif defined(TARGET_IPHONE_SIMULATOR)',
441 '#ifdef TARGET_IPHONE_SIMULATOR',
442 ' # ifdef TARGET_IPHONE_SIMULATOR',
443 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
444 '# else // defined(TARGET_IPHONE_SIMULATOR)',
445 '#endif // defined(TARGET_IPHONE_SIMULATOR)',]
446 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
447 MockInputApi(), MockFile('some/path/source.mm', lines))
448 self.assertEqual(len(lines), len(errors))
450 def testValidIfDefinedMacroNames(self):
451 lines = ['#if defined(FOO)',
452 '#ifdef BAR',]
453 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
454 MockInputApi(), MockFile('some/path/source.cc', lines))
455 self.assertEqual(0, len(errors))
458 class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
459 def testFilesToCheckForIncomingDeps(self):
460 changed_lines = [
461 '"+breakpad",',
462 '"+chrome/installer",',
463 '"+chrome/plugin/chrome_content_plugin_client.h",',
464 '"+chrome/utility/chrome_content_utility_client.h",',
465 '"+chromeos/chromeos_paths.h",',
466 '"+components/crash/content",',
467 '"+components/nacl/common",',
468 '"+content/public/browser/render_process_host.h",',
469 '"+jni/fooblat.h",',
470 '"+grit", # For generated headers',
471 '"+grit/generated_resources.h",',
472 '"+grit/",',
473 '"+policy", # For generated headers and source',
474 '"+sandbox",',
475 '"+tools/memory_watcher",',
476 '"+third_party/lss/linux_syscall_support.h",',
478 files_to_check = PRESUBMIT._FilesToCheckForIncomingDeps(re, changed_lines)
479 expected = set([
480 'breakpad/DEPS',
481 'chrome/installer/DEPS',
482 'chrome/plugin/chrome_content_plugin_client.h',
483 'chrome/utility/chrome_content_utility_client.h',
484 'chromeos/chromeos_paths.h',
485 'components/crash/content/DEPS',
486 'components/nacl/common/DEPS',
487 'content/public/browser/render_process_host.h',
488 'policy/DEPS',
489 'sandbox/DEPS',
490 'tools/memory_watcher/DEPS',
491 'third_party/lss/linux_syscall_support.h',
493 self.assertEqual(expected, files_to_check);
496 class JSONParsingTest(unittest.TestCase):
497 def testSuccess(self):
498 input_api = MockInputApi()
499 filename = 'valid_json.json'
500 contents = ['// This is a comment.',
501 '{',
502 ' "key1": ["value1", "value2"],',
503 ' "key2": 3 // This is an inline comment.',
506 input_api.files = [MockFile(filename, contents)]
507 self.assertEqual(None,
508 PRESUBMIT._GetJSONParseError(input_api, filename))
510 def testFailure(self):
511 input_api = MockInputApi()
512 test_data = [
513 ('invalid_json_1.json',
514 ['{ x }'],
515 'Expecting property name:'),
516 ('invalid_json_2.json',
517 ['// Hello world!',
518 '{ "hello": "world }'],
519 'Unterminated string starting at:'),
520 ('invalid_json_3.json',
521 ['{ "a": "b", "c": "d", }'],
522 'Expecting property name:'),
523 ('invalid_json_4.json',
524 ['{ "a": "b" "c": "d" }'],
525 'Expecting , delimiter:'),
528 input_api.files = [MockFile(filename, contents)
529 for (filename, contents, _) in test_data]
531 for (filename, _, expected_error) in test_data:
532 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
533 self.assertTrue(expected_error in str(actual_error),
534 "'%s' not found in '%s'" % (expected_error, actual_error))
536 def testNoEatComments(self):
537 input_api = MockInputApi()
538 file_with_comments = 'file_with_comments.json'
539 contents_with_comments = ['// This is a comment.',
540 '{',
541 ' "key1": ["value1", "value2"],',
542 ' "key2": 3 // This is an inline comment.',
545 file_without_comments = 'file_without_comments.json'
546 contents_without_comments = ['{',
547 ' "key1": ["value1", "value2"],',
548 ' "key2": 3',
551 input_api.files = [MockFile(file_with_comments, contents_with_comments),
552 MockFile(file_without_comments,
553 contents_without_comments)]
555 self.assertEqual('No JSON object could be decoded',
556 str(PRESUBMIT._GetJSONParseError(input_api,
557 file_with_comments,
558 eat_comments=False)))
559 self.assertEqual(None,
560 PRESUBMIT._GetJSONParseError(input_api,
561 file_without_comments,
562 eat_comments=False))
565 class IDLParsingTest(unittest.TestCase):
566 def testSuccess(self):
567 input_api = MockInputApi()
568 filename = 'valid_idl_basics.idl'
569 contents = ['// Tests a valid IDL file.',
570 'namespace idl_basics {',
571 ' enum EnumType {',
572 ' name1,',
573 ' name2',
574 ' };',
576 ' dictionary MyType1 {',
577 ' DOMString a;',
578 ' };',
580 ' callback Callback1 = void();',
581 ' callback Callback2 = void(long x);',
582 ' callback Callback3 = void(MyType1 arg);',
583 ' callback Callback4 = void(EnumType type);',
585 ' interface Functions {',
586 ' static void function1();',
587 ' static void function2(long x);',
588 ' static void function3(MyType1 arg);',
589 ' static void function4(Callback1 cb);',
590 ' static void function5(Callback2 cb);',
591 ' static void function6(Callback3 cb);',
592 ' static void function7(Callback4 cb);',
593 ' };',
595 ' interface Events {',
596 ' static void onFoo1();',
597 ' static void onFoo2(long x);',
598 ' static void onFoo2(MyType1 arg);',
599 ' static void onFoo3(EnumType type);',
600 ' };',
601 '};'
603 input_api.files = [MockFile(filename, contents)]
604 self.assertEqual(None,
605 PRESUBMIT._GetIDLParseError(input_api, filename))
607 def testFailure(self):
608 input_api = MockInputApi()
609 test_data = [
610 ('invalid_idl_1.idl',
611 ['//',
612 'namespace test {',
613 ' dictionary {',
614 ' DOMString s;',
615 ' };',
616 '};'],
617 'Unexpected "{" after keyword "dictionary".\n'),
618 # TODO(yoz): Disabled because it causes the IDL parser to hang.
619 # See crbug.com/363830.
620 # ('invalid_idl_2.idl',
621 # (['namespace test {',
622 # ' dictionary MissingSemicolon {',
623 # ' DOMString a',
624 # ' DOMString b;',
625 # ' };',
626 # '};'],
627 # 'Unexpected symbol DOMString after symbol a.'),
628 ('invalid_idl_3.idl',
629 ['//',
630 'namespace test {',
631 ' enum MissingComma {',
632 ' name1',
633 ' name2',
634 ' };',
635 '};'],
636 'Unexpected symbol name2 after symbol name1.'),
637 ('invalid_idl_4.idl',
638 ['//',
639 'namespace test {',
640 ' enum TrailingComma {',
641 ' name1,',
642 ' name2,',
643 ' };',
644 '};'],
645 'Trailing comma in block.'),
646 ('invalid_idl_5.idl',
647 ['//',
648 'namespace test {',
649 ' callback Callback1 = void(;',
650 '};'],
651 'Unexpected ";" after "(".'),
652 ('invalid_idl_6.idl',
653 ['//',
654 'namespace test {',
655 ' callback Callback1 = void(long );',
656 '};'],
657 'Unexpected ")" after symbol long.'),
658 ('invalid_idl_7.idl',
659 ['//',
660 'namespace test {',
661 ' interace Events {',
662 ' static void onFoo1();',
663 ' };',
664 '};'],
665 'Unexpected symbol Events after symbol interace.'),
666 ('invalid_idl_8.idl',
667 ['//',
668 'namespace test {',
669 ' interface NotEvent {',
670 ' static void onFoo1();',
671 ' };',
672 '};'],
673 'Did not process Interface Interface(NotEvent)'),
674 ('invalid_idl_9.idl',
675 ['//',
676 'namespace test {',
677 ' interface {',
678 ' static void function1();',
679 ' };',
680 '};'],
681 'Interface missing name.'),
684 input_api.files = [MockFile(filename, contents)
685 for (filename, contents, _) in test_data]
687 for (filename, _, expected_error) in test_data:
688 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
689 self.assertTrue(expected_error in str(actual_error),
690 "'%s' not found in '%s'" % (expected_error, actual_error))
693 class TryServerMasterTest(unittest.TestCase):
694 def testTryServerMasters(self):
695 bots = {
696 'tryserver.chromium.mac': [
697 'ios_dbg_simulator',
698 'ios_rel_device',
699 'ios_rel_device_ninja',
700 'mac_asan',
701 'mac_asan_64',
702 'mac_chromium_compile_dbg',
703 'mac_chromium_compile_rel',
704 'mac_chromium_dbg',
705 'mac_chromium_rel',
706 'mac_nacl_sdk',
707 'mac_nacl_sdk_build',
708 'mac_rel_naclmore',
709 'mac_valgrind',
710 'mac_x64_rel',
711 'mac_xcodebuild',
713 'tryserver.chromium.linux': [
714 'android_aosp',
715 'android_chromium_gn_compile_dbg',
716 'android_chromium_gn_compile_rel',
717 'android_clang_dbg',
718 'android_dbg',
719 'android_dbg_recipe',
720 'android_dbg_triggered_tests',
721 'android_dbg_triggered_tests_recipe',
722 'android_fyi_dbg',
723 'android_fyi_dbg_triggered_tests',
724 'android_rel',
725 'android_rel_triggered_tests',
726 'android_x86_dbg',
727 'blink_android_compile_dbg',
728 'blink_android_compile_rel',
729 'blink_presubmit',
730 'chromium_presubmit',
731 'linux_arm_cross_compile',
732 'linux_arm_tester',
733 'linux_chromeos_asan',
734 'linux_chromeos_browser_asan',
735 'linux_chromeos_valgrind',
736 'linux_chromium_chromeos_dbg',
737 'linux_chromium_chromeos_rel',
738 'linux_chromium_compile_dbg',
739 'linux_chromium_compile_rel',
740 'linux_chromium_dbg',
741 'linux_chromium_gn_dbg',
742 'linux_chromium_gn_rel',
743 'linux_chromium_rel',
744 'linux_chromium_trusty32_dbg',
745 'linux_chromium_trusty32_rel',
746 'linux_chromium_trusty_dbg',
747 'linux_chromium_trusty_rel',
748 'linux_clang_tsan',
749 'linux_ecs_ozone',
750 'linux_layout',
751 'linux_layout_asan',
752 'linux_layout_rel',
753 'linux_layout_rel_32',
754 'linux_nacl_sdk',
755 'linux_nacl_sdk_bionic',
756 'linux_nacl_sdk_bionic_build',
757 'linux_nacl_sdk_build',
758 'linux_redux',
759 'linux_rel_naclmore',
760 'linux_rel_precise32',
761 'linux_valgrind',
762 'tools_build_presubmit',
764 'tryserver.chromium.win': [
765 'win8_aura',
766 'win8_chromium_dbg',
767 'win8_chromium_rel',
768 'win_chromium_compile_dbg',
769 'win_chromium_compile_rel',
770 'win_chromium_dbg',
771 'win_chromium_rel',
772 'win_chromium_rel',
773 'win_chromium_x64_dbg',
774 'win_chromium_x64_rel',
775 'win_drmemory',
776 'win_nacl_sdk',
777 'win_nacl_sdk_build',
778 'win_rel_naclmore',
781 for master, bots in bots.iteritems():
782 for bot in bots:
783 self.assertEqual(master, PRESUBMIT.GetTryServerMasterForBot(bot),
784 'bot=%s: expected %s, computed %s' % (
785 bot, master, PRESUBMIT.GetTryServerMasterForBot(bot)))
788 class UserMetricsActionTest(unittest.TestCase):
789 def testUserMetricsActionInActions(self):
790 input_api = MockInputApi()
791 file_with_user_action = 'file_with_user_action.cc'
792 contents_with_user_action = [
793 'base::UserMetricsAction("AboutChrome")'
796 input_api.files = [MockFile(file_with_user_action,
797 contents_with_user_action)]
799 self.assertEqual(
800 [], PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi()))
803 def testUserMetricsActionNotAddedToActions(self):
804 input_api = MockInputApi()
805 file_with_user_action = 'file_with_user_action.cc'
806 contents_with_user_action = [
807 'base::UserMetricsAction("NotInActionsXml")'
810 input_api.files = [MockFile(file_with_user_action,
811 contents_with_user_action)]
813 output = PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi())
814 self.assertEqual(
815 ('File %s line %d: %s is missing in '
816 'tools/metrics/actions/actions.xml. Please run '
817 'tools/metrics/actions/extract_actions.py to update.'
818 % (file_with_user_action, 1, 'NotInActionsXml')),
819 output[0].message)
822 class LogUsageTest(unittest.TestCase):
824 def testCheckAndroidCrLogUsage(self):
825 mock_input_api = MockInputApi()
826 mock_output_api = MockOutputApi()
828 mock_input_api.files = [
829 MockAffectedFile('RandomStuff.java', [
830 'random stuff'
832 MockAffectedFile('HasAndroidLog.java', [
833 'import android.util.Log;',
834 'some random stuff',
835 'Log.d("TAG", "foo");',
837 MockAffectedFile('HasExplicitUtilLog.java', [
838 'some random stuff',
839 'android.util.Log.d("TAG", "foo");',
841 MockAffectedFile('IsInBasePackage.java', [
842 'package org.chromium.base;',
843 'private static final String TAG = "cr_Foo";',
844 'Log.d(TAG, "foo");',
846 MockAffectedFile('IsInBasePackageButImportsLog.java', [
847 'package org.chromium.base;',
848 'import android.util.Log;',
849 'private static final String TAG = "cr_Foo";',
850 'Log.d(TAG, "foo");',
852 MockAffectedFile('HasBothLog.java', [
853 'import org.chromium.base.Log;',
854 'some random stuff',
855 'private static final String TAG = "cr_Foo";',
856 'Log.d(TAG, "foo");',
857 'android.util.Log.d("TAG", "foo");',
859 MockAffectedFile('HasCorrectTag.java', [
860 'import org.chromium.base.Log;',
861 'some random stuff',
862 'private static final String TAG = "cr_Foo";',
863 'Log.d(TAG, "foo");',
865 MockAffectedFile('HasOldTag.java', [
866 'import org.chromium.base.Log;',
867 'some random stuff',
868 'private static final String TAG = "cr.Foo";',
869 'Log.d(TAG, "foo");',
871 MockAffectedFile('HasDottedTag.java', [
872 'import org.chromium.base.Log;',
873 'some random stuff',
874 'private static final String TAG = "cr_foo.bar";',
875 'Log.d(TAG, "foo");',
877 MockAffectedFile('HasNoTagDecl.java', [
878 'import org.chromium.base.Log;',
879 'some random stuff',
880 'Log.d(TAG, "foo");',
882 MockAffectedFile('HasIncorrectTagDecl.java', [
883 'import org.chromium.base.Log;',
884 'private static final String TAHG = "cr_Foo";',
885 'some random stuff',
886 'Log.d(TAG, "foo");',
888 MockAffectedFile('HasInlineTag.java', [
889 'import org.chromium.base.Log;',
890 'some random stuff',
891 'private static final String TAG = "cr_Foo";',
892 'Log.d("TAG", "foo");',
894 MockAffectedFile('HasUnprefixedTag.java', [
895 'import org.chromium.base.Log;',
896 'some random stuff',
897 'private static final String TAG = "rubbish";',
898 'Log.d(TAG, "foo");',
900 MockAffectedFile('HasTooLongTag.java', [
901 'import org.chromium.base.Log;',
902 'some random stuff',
903 'private static final String TAG = "21_charachers_long___";',
904 'Log.d(TAG, "foo");',
908 msgs = PRESUBMIT._CheckAndroidCrLogUsage(
909 mock_input_api, mock_output_api)
911 self.assertEqual(5, len(msgs),
912 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
914 # Declaration format
915 nb = len(msgs[0].items)
916 self.assertEqual(2, nb,
917 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
918 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
919 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
921 # Tag length
922 nb = len(msgs[1].items)
923 self.assertEqual(1, nb,
924 'Expected %d items, found %d: %s' % (1, nb, msgs[1].items))
925 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
927 # Tag must be a variable named TAG
928 nb = len(msgs[2].items)
929 self.assertEqual(1, nb,
930 'Expected %d items, found %d: %s' % (1, nb, msgs[2].items))
931 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
933 # Util Log usage
934 nb = len(msgs[3].items)
935 self.assertEqual(2, nb,
936 'Expected %d items, found %d: %s' % (2, nb, msgs[3].items))
937 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
938 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
940 # Tag must not contain
941 nb = len(msgs[4].items)
942 self.assertEqual(2, nb,
943 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
944 self.assertTrue('HasDottedTag.java' in msgs[4].items)
945 self.assertTrue('HasOldTag.java' in msgs[4].items)
948 if __name__ == '__main__':
949 unittest.main()