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.
11 from PRESUBMIT_test_mocks import MockFile, MockAffectedFile
12 from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
15 _TEST_DATA_DIR = 'base/test/data/presubmit'
18 class VersionControlConflictsTest(unittest.TestCase):
19 def testTypicalConflict(self):
20 lines = ['<<<<<<< HEAD',
21 ' base::ScopedTempDir temp_dir_;',
23 ' ScopedTempDir temp_dir_;',
25 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
26 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
27 self.assertEqual(3, len(errors))
28 self.assertTrue('1' in errors[0])
29 self.assertTrue('3' in errors[1])
30 self.assertTrue('5' in errors[2])
32 def testIgnoresReadmes(self):
33 lines = ['A First Level Header',
34 '====================',
36 'A Second Level Header',
37 '---------------------']
38 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
39 MockInputApi(), MockFile('some/polymer/README.md', lines))
40 self.assertEqual(0, len(errors))
43 class UmaHistogramChangeMatchedOrNotTest(unittest.TestCase):
44 def testTypicalCorrectlyMatchedChange(self):
45 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
47 'RecordHistogram.recordBooleanHistogram("Bla.Foo.Dummy", true)']
48 diff_xml = ['<histogram name="Bla.Foo.Dummy"> </histogram>']
49 mock_input_api = MockInputApi()
50 mock_input_api.files = [
51 MockFile('some/path/foo.cc', diff_cc),
52 MockFile('some/path/foo.java', diff_java),
53 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
55 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
57 self.assertEqual(0, len(warnings))
59 def testTypicalNotMatchedChange(self):
60 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
62 'RecordHistogram.recordBooleanHistogram("Bla.Foo.Dummy", true)']
63 mock_input_api = MockInputApi()
64 mock_input_api.files = [
65 MockFile('some/path/foo.cc', diff_cc),
66 MockFile('some/path/foo.java', diff_java),
68 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
70 self.assertEqual(1, len(warnings))
71 self.assertEqual('warning', warnings[0].type)
72 self.assertTrue('foo.cc' in warnings[0].items[0])
73 self.assertTrue('foo.java' in warnings[0].items[1])
75 def testTypicalNotMatchedChangeViaSuffixes(self):
76 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
78 'RecordHistogram.recordBooleanHistogram("Bla.Foo.Dummy", true)']
79 diff_xml = ['<histogram_suffixes name="SuperHistogram">',
80 ' <suffix name="Dummy"/>',
81 ' <affected-histogram name="Snafu.Dummy"/>',
83 mock_input_api = MockInputApi()
84 mock_input_api.files = [
85 MockFile('some/path/foo.cc', diff_cc),
86 MockFile('some/path/foo.java', diff_java),
87 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
89 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
91 self.assertEqual(1, len(warnings))
92 self.assertEqual('warning', warnings[0].type)
93 self.assertTrue('foo.cc' in warnings[0].items[0])
94 self.assertTrue('foo.java' in warnings[0].items[1])
96 def testTypicalCorrectlyMatchedChangeViaSuffixes(self):
97 diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)']
99 'RecordHistogram.recordBooleanHistogram("Bla.Foo.Dummy", true)']
100 diff_xml = ['<histogram_suffixes name="SuperHistogram">',
101 ' <suffix name="Dummy"/>',
102 ' <affected-histogram name="Bla.Foo"/>',
104 mock_input_api = MockInputApi()
105 mock_input_api.files = [
106 MockFile('some/path/foo.cc', diff_cc),
107 MockFile('some/path/foo.java', diff_java),
108 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
110 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
112 self.assertEqual(0, len(warnings))
114 def testTypicalCorrectlyMatchedChangeViaSuffixesWithSeparator(self):
115 diff_cc = ['UMA_HISTOGRAM_BOOL("Snafu_Dummy", true)']
116 diff_java = ['RecordHistogram.recordBooleanHistogram("Snafu_Dummy", true)']
117 diff_xml = ['<histogram_suffixes name="SuperHistogram" separator="_">',
118 ' <suffix name="Dummy"/>',
119 ' <affected-histogram name="Snafu"/>',
121 mock_input_api = MockInputApi()
122 mock_input_api.files = [
123 MockFile('some/path/foo.cc', diff_cc),
124 MockFile('some/path/foo.java', diff_java),
125 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
127 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
129 self.assertEqual(0, len(warnings))
131 def testCorrectlyMatchedChangeViaSuffixesWithLineWrapping(self):
133 'UMA_HISTOGRAM_BOOL("LongHistogramNameNeedsLineWrapping.Dummy", true)']
134 diff_java = ['RecordHistogram.recordBooleanHistogram(' +
135 '"LongHistogramNameNeedsLineWrapping.Dummy", true)']
136 diff_xml = ['<histogram_suffixes',
137 ' name="LongHistogramNameNeedsLineWrapping"',
139 ' <suffix name="Dummy"/>',
140 ' <affected-histogram',
141 ' name="LongHistogramNameNeedsLineWrapping"/>',
143 mock_input_api = MockInputApi()
144 mock_input_api.files = [
145 MockFile('some/path/foo.cc', diff_cc),
146 MockFile('some/path/foo.java', diff_java),
147 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
149 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
151 self.assertEqual(0, len(warnings))
153 def testNameMatch(self):
154 # Check that the detected histogram name is "Dummy" and not, e.g.,
155 # "Dummy\", true); // The \"correct"
156 diff_cc = ['UMA_HISTOGRAM_BOOL("Dummy", true); // The "correct" histogram']
158 'RecordHistogram.recordBooleanHistogram("Dummy", true);' +
159 ' // The "correct" histogram']
160 diff_xml = ['<histogram name="Dummy"> </histogram>']
161 mock_input_api = MockInputApi()
162 mock_input_api.files = [
163 MockFile('some/path/foo.cc', diff_cc),
164 MockFile('some/path/foo.java', diff_java),
165 MockFile('tools/metrics/histograms/histograms.xml', diff_xml),
167 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
169 self.assertEqual(0, len(warnings))
171 def testSimilarMacroNames(self):
172 diff_cc = ['PUMA_HISTOGRAM_COOL("Mountain Lion", 42)']
174 'FakeRecordHistogram.recordFakeHistogram("Mountain Lion", 42)']
175 mock_input_api = MockInputApi()
176 mock_input_api.files = [
177 MockFile('some/path/foo.cc', diff_cc),
178 MockFile('some/path/foo.java', diff_java),
180 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
182 self.assertEqual(0, len(warnings))
184 def testMultiLine(self):
185 diff_cc = ['UMA_HISTOGRAM_BOOLEAN(', ' "Multi.Line", true)']
186 diff_cc2 = ['UMA_HISTOGRAM_BOOLEAN(', ' "Multi.Line"', ' , true)']
188 'RecordHistogram.recordBooleanHistogram(',
189 ' "Multi.Line", true);',
191 mock_input_api = MockInputApi()
192 mock_input_api.files = [
193 MockFile('some/path/foo.cc', diff_cc),
194 MockFile('some/path/foo2.cc', diff_cc2),
195 MockFile('some/path/foo.java', diff_java),
197 warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api,
199 self.assertEqual(1, len(warnings))
200 self.assertEqual('warning', warnings[0].type)
201 self.assertTrue('foo.cc' in warnings[0].items[0])
202 self.assertTrue('foo2.cc' in warnings[0].items[1])
205 class BadExtensionsTest(unittest.TestCase):
206 def testBadRejFile(self):
207 mock_input_api = MockInputApi()
208 mock_input_api.files = [
209 MockFile('some/path/foo.cc', ''),
210 MockFile('some/path/foo.cc.rej', ''),
211 MockFile('some/path2/bar.h.rej', ''),
214 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
215 self.assertEqual(1, len(results))
216 self.assertEqual(2, len(results[0].items))
217 self.assertTrue('foo.cc.rej' in results[0].items[0])
218 self.assertTrue('bar.h.rej' in results[0].items[1])
220 def testBadOrigFile(self):
221 mock_input_api = MockInputApi()
222 mock_input_api.files = [
223 MockFile('other/path/qux.h.orig', ''),
224 MockFile('other/path/qux.h', ''),
225 MockFile('other/path/qux.cc', ''),
228 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
229 self.assertEqual(1, len(results))
230 self.assertEqual(1, len(results[0].items))
231 self.assertTrue('qux.h.orig' in results[0].items[0])
233 def testGoodFiles(self):
234 mock_input_api = MockInputApi()
235 mock_input_api.files = [
236 MockFile('other/path/qux.h', ''),
237 MockFile('other/path/qux.cc', ''),
239 results = PRESUBMIT._CheckPatchFiles(mock_input_api, MockOutputApi())
240 self.assertEqual(0, len(results))
243 class CheckSingletonInHeadersTest(unittest.TestCase):
244 def testSingletonInArbitraryHeader(self):
245 diff_singleton_h = ['base::subtle::AtomicWord '
246 'base::Singleton<Type, Traits, DifferentiatingType>::']
247 diff_foo_h = ['// base::Singleton<Foo> in comment.',
248 'friend class base::Singleton<Foo>']
249 diff_foo2_h = [' //Foo* bar = base::Singleton<Foo>::get();']
250 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
251 mock_input_api = MockInputApi()
252 mock_input_api.files = [MockAffectedFile('base/memory/singleton.h',
254 MockAffectedFile('foo.h', diff_foo_h),
255 MockAffectedFile('foo2.h', diff_foo2_h),
256 MockAffectedFile('bad.h', diff_bad_h)]
257 warnings = PRESUBMIT._CheckSingletonInHeaders(mock_input_api,
259 self.assertEqual(1, len(warnings))
260 self.assertEqual(1, len(warnings[0].items))
261 self.assertEqual('error', warnings[0].type)
262 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
264 def testSingletonInCC(self):
265 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
266 mock_input_api = MockInputApi()
267 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
268 warnings = PRESUBMIT._CheckSingletonInHeaders(mock_input_api,
270 self.assertEqual(0, len(warnings))
273 class InvalidOSMacroNamesTest(unittest.TestCase):
274 def testInvalidOSMacroNames(self):
275 lines = ['#if defined(OS_WINDOWS)',
276 ' #elif defined(OS_WINDOW)',
277 ' # if defined(OS_MACOSX) || defined(OS_CHROME)',
278 '# else // defined(OS_MAC)',
279 '#endif // defined(OS_MACOS)']
280 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
281 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
282 self.assertEqual(len(lines), len(errors))
283 self.assertTrue(':1 OS_WINDOWS' in errors[0])
284 self.assertTrue('(did you mean OS_WIN?)' in errors[0])
286 def testValidOSMacroNames(self):
287 lines = ['#if defined(%s)' % m for m in PRESUBMIT._VALID_OS_MACROS]
288 errors = PRESUBMIT._CheckForInvalidOSMacrosInFile(
289 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
290 self.assertEqual(0, len(errors))
293 class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
294 def testInvalidIfDefinedMacroNames(self):
295 lines = ['#if defined(TARGET_IPHONE_SIMULATOR)',
296 '#if !defined(TARGET_IPHONE_SIMULATOR)',
297 '#elif defined(TARGET_IPHONE_SIMULATOR)',
298 '#ifdef TARGET_IPHONE_SIMULATOR',
299 ' # ifdef TARGET_IPHONE_SIMULATOR',
300 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
301 '# else // defined(TARGET_IPHONE_SIMULATOR)',
302 '#endif // defined(TARGET_IPHONE_SIMULATOR)']
303 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
304 MockInputApi(), MockFile('some/path/source.mm', lines))
305 self.assertEqual(len(lines), len(errors))
307 def testValidIfDefinedMacroNames(self):
308 lines = ['#if defined(FOO)',
310 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
311 MockInputApi(), MockFile('some/path/source.cc', lines))
312 self.assertEqual(0, len(errors))
315 class CheckAddedDepsHaveTetsApprovalsTest(unittest.TestCase):
317 def calculate(self, old_include_rules, old_specific_include_rules,
318 new_include_rules, new_specific_include_rules):
319 return PRESUBMIT._CalculateAddedDeps(
320 os.path, 'include_rules = %r\nspecific_include_rules = %r' % (
321 old_include_rules, old_specific_include_rules),
322 'include_rules = %r\nspecific_include_rules = %r' % (
323 new_include_rules, new_specific_include_rules))
325 def testCalculateAddedDeps(self):
326 old_include_rules = [
335 old_specific_include_rules = {
341 new_include_rules = [
348 '+grit/generated_resources.h",',
352 '+' + os.path.join('third_party', 'WebKit'),
354 new_specific_include_rules = {
364 os.path.join('chrome', 'DEPS'),
365 os.path.join('gpu', 'DEPS'),
366 os.path.join('components', 'DEPS'),
367 os.path.join('policy', 'DEPS'),
368 os.path.join('third_party', 'WebKit', 'DEPS'),
372 self.calculate(old_include_rules, old_specific_include_rules,
373 new_include_rules, new_specific_include_rules))
375 def testCalculateAddedDepsIgnoresPermutations(self):
376 old_include_rules = [
380 new_include_rules = [
384 self.assertEqual(set(),
385 self.calculate(old_include_rules, {}, new_include_rules,
389 class JSONParsingTest(unittest.TestCase):
390 def testSuccess(self):
391 input_api = MockInputApi()
392 filename = 'valid_json.json'
393 contents = ['// This is a comment.',
395 ' "key1": ["value1", "value2"],',
396 ' "key2": 3 // This is an inline comment.',
399 input_api.files = [MockFile(filename, contents)]
400 self.assertEqual(None,
401 PRESUBMIT._GetJSONParseError(input_api, filename))
403 def testFailure(self):
404 input_api = MockInputApi()
406 ('invalid_json_1.json',
408 'Expecting property name:'),
409 ('invalid_json_2.json',
411 '{ "hello": "world }'],
412 'Unterminated string starting at:'),
413 ('invalid_json_3.json',
414 ['{ "a": "b", "c": "d", }'],
415 'Expecting property name:'),
416 ('invalid_json_4.json',
417 ['{ "a": "b" "c": "d" }'],
418 'Expecting , delimiter:'),
421 input_api.files = [MockFile(filename, contents)
422 for (filename, contents, _) in test_data]
424 for (filename, _, expected_error) in test_data:
425 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
426 self.assertTrue(expected_error in str(actual_error),
427 "'%s' not found in '%s'" % (expected_error, actual_error))
429 def testNoEatComments(self):
430 input_api = MockInputApi()
431 file_with_comments = 'file_with_comments.json'
432 contents_with_comments = ['// This is a comment.',
434 ' "key1": ["value1", "value2"],',
435 ' "key2": 3 // This is an inline comment.',
438 file_without_comments = 'file_without_comments.json'
439 contents_without_comments = ['{',
440 ' "key1": ["value1", "value2"],',
444 input_api.files = [MockFile(file_with_comments, contents_with_comments),
445 MockFile(file_without_comments,
446 contents_without_comments)]
448 self.assertEqual('No JSON object could be decoded',
449 str(PRESUBMIT._GetJSONParseError(input_api,
451 eat_comments=False)))
452 self.assertEqual(None,
453 PRESUBMIT._GetJSONParseError(input_api,
454 file_without_comments,
458 class IDLParsingTest(unittest.TestCase):
459 def testSuccess(self):
460 input_api = MockInputApi()
461 filename = 'valid_idl_basics.idl'
462 contents = ['// Tests a valid IDL file.',
463 'namespace idl_basics {',
469 ' dictionary MyType1 {',
473 ' callback Callback1 = void();',
474 ' callback Callback2 = void(long x);',
475 ' callback Callback3 = void(MyType1 arg);',
476 ' callback Callback4 = void(EnumType type);',
478 ' interface Functions {',
479 ' static void function1();',
480 ' static void function2(long x);',
481 ' static void function3(MyType1 arg);',
482 ' static void function4(Callback1 cb);',
483 ' static void function5(Callback2 cb);',
484 ' static void function6(Callback3 cb);',
485 ' static void function7(Callback4 cb);',
488 ' interface Events {',
489 ' static void onFoo1();',
490 ' static void onFoo2(long x);',
491 ' static void onFoo2(MyType1 arg);',
492 ' static void onFoo3(EnumType type);',
496 input_api.files = [MockFile(filename, contents)]
497 self.assertEqual(None,
498 PRESUBMIT._GetIDLParseError(input_api, filename))
500 def testFailure(self):
501 input_api = MockInputApi()
503 ('invalid_idl_1.idl',
510 'Unexpected "{" after keyword "dictionary".\n'),
511 # TODO(yoz): Disabled because it causes the IDL parser to hang.
512 # See crbug.com/363830.
513 # ('invalid_idl_2.idl',
514 # (['namespace test {',
515 # ' dictionary MissingSemicolon {',
520 # 'Unexpected symbol DOMString after symbol a.'),
521 ('invalid_idl_3.idl',
524 ' enum MissingComma {',
529 'Unexpected symbol name2 after symbol name1.'),
530 ('invalid_idl_4.idl',
533 ' enum TrailingComma {',
538 'Trailing comma in block.'),
539 ('invalid_idl_5.idl',
542 ' callback Callback1 = void(;',
544 'Unexpected ";" after "(".'),
545 ('invalid_idl_6.idl',
548 ' callback Callback1 = void(long );',
550 'Unexpected ")" after symbol long.'),
551 ('invalid_idl_7.idl',
554 ' interace Events {',
555 ' static void onFoo1();',
558 'Unexpected symbol Events after symbol interace.'),
559 ('invalid_idl_8.idl',
562 ' interface NotEvent {',
563 ' static void onFoo1();',
566 'Did not process Interface Interface(NotEvent)'),
567 ('invalid_idl_9.idl',
571 ' static void function1();',
574 'Interface missing name.'),
577 input_api.files = [MockFile(filename, contents)
578 for (filename, contents, _) in test_data]
580 for (filename, _, expected_error) in test_data:
581 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
582 self.assertTrue(expected_error in str(actual_error),
583 "'%s' not found in '%s'" % (expected_error, actual_error))
586 class TryServerMasterTest(unittest.TestCase):
587 def testTryServerMasters(self):
589 'master.tryserver.chromium.android': [
590 'android_archive_rel_ng',
591 'android_arm64_dbg_recipe',
593 'android_clang_dbg_recipe',
594 'android_compile_dbg',
595 'android_compile_x64_dbg',
596 'android_compile_x86_dbg',
598 'android_cronet_tester'
599 'android_swarming_rel',
600 'cast_shell_android',
601 'linux_android_dbg_ng',
602 'linux_android_rel_ng',
604 'master.tryserver.chromium.mac': [
607 'ios_rel_device_ninja',
610 'mac_chromium_compile_dbg',
611 'mac_chromium_compile_rel',
615 'mac_nacl_sdk_build',
620 'master.tryserver.chromium.linux': [
621 'chromium_presubmit',
622 'linux_arm_cross_compile',
624 'linux_chromeos_asan',
625 'linux_chromeos_browser_asan',
626 'linux_chromeos_valgrind',
627 'linux_chromium_chromeos_dbg',
628 'linux_chromium_chromeos_rel',
629 'linux_chromium_compile_dbg',
630 'linux_chromium_compile_rel',
631 'linux_chromium_dbg',
632 'linux_chromium_gn_dbg',
633 'linux_chromium_gn_rel',
634 'linux_chromium_rel',
635 'linux_chromium_trusty32_dbg',
636 'linux_chromium_trusty32_rel',
637 'linux_chromium_trusty_dbg',
638 'linux_chromium_trusty_rel',
644 'linux_layout_rel_32',
646 'linux_nacl_sdk_bionic',
647 'linux_nacl_sdk_bionic_build',
648 'linux_nacl_sdk_build',
650 'linux_rel_naclmore',
651 'linux_rel_precise32',
653 'tools_build_presubmit',
655 'master.tryserver.chromium.win': [
659 'win_chromium_compile_dbg',
660 'win_chromium_compile_rel',
664 'win_chromium_x64_dbg',
665 'win_chromium_x64_rel',
667 'win_nacl_sdk_build',
671 for master, bots in bots.iteritems():
673 self.assertEqual(master, PRESUBMIT.GetTryServerMasterForBot(bot),
674 'bot=%s: expected %s, computed %s' % (
675 bot, master, PRESUBMIT.GetTryServerMasterForBot(bot)))
678 class UserMetricsActionTest(unittest.TestCase):
679 def testUserMetricsActionInActions(self):
680 input_api = MockInputApi()
681 file_with_user_action = 'file_with_user_action.cc'
682 contents_with_user_action = [
683 'base::UserMetricsAction("AboutChrome")'
686 input_api.files = [MockFile(file_with_user_action,
687 contents_with_user_action)]
690 [], PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi()))
692 def testUserMetricsActionNotAddedToActions(self):
693 input_api = MockInputApi()
694 file_with_user_action = 'file_with_user_action.cc'
695 contents_with_user_action = [
696 'base::UserMetricsAction("NotInActionsXml")'
699 input_api.files = [MockFile(file_with_user_action,
700 contents_with_user_action)]
702 output = PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi())
704 ('File %s line %d: %s is missing in '
705 'tools/metrics/actions/actions.xml. Please run '
706 'tools/metrics/actions/extract_actions.py to update.'
707 % (file_with_user_action, 1, 'NotInActionsXml')),
711 class PydepsNeedsUpdatingTest(unittest.TestCase):
713 class MockSubprocess(object):
714 CalledProcessError = subprocess.CalledProcessError
717 mock_all_pydeps = ['A.pydeps', 'B.pydeps']
718 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
719 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
720 self.mock_input_api = MockInputApi()
721 self.mock_output_api = MockOutputApi()
722 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess()
723 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api, mock_all_pydeps)
724 self.checker._file_cache = {
725 'A.pydeps': '# Generated by:\n# CMD A\nA.py\nC.py\n',
726 'B.pydeps': '# Generated by:\n# CMD B\nB.py\nC.py\n',
730 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
733 return PRESUBMIT._CheckPydepsNeedsUpdating(self.mock_input_api,
734 self.mock_output_api,
735 checker_for_tests=self.checker)
737 def testAddedPydep(self):
738 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
739 if self.mock_input_api.platform != 'linux2':
742 self.mock_input_api.files = [
743 MockAffectedFile('new.pydeps', [], action='A'),
746 self.mock_input_api.CreateMockFileInPath(
747 [x.LocalPath() for x in self.mock_input_api.AffectedFiles(
748 include_deletes=True)])
749 results = self._RunCheck()
750 self.assertEqual(1, len(results))
751 self.assertTrue('PYDEPS_FILES' in str(results[0]))
753 def testPydepNotInSrc(self):
754 self.mock_input_api.files = [
755 MockAffectedFile('new.pydeps', [], action='A'),
757 self.mock_input_api.CreateMockFileInPath([])
758 results = self._RunCheck()
759 self.assertEqual(0, len(results))
761 def testRemovedPydep(self):
762 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
763 if self.mock_input_api.platform != 'linux2':
766 self.mock_input_api.files = [
767 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
769 self.mock_input_api.CreateMockFileInPath(
770 [x.LocalPath() for x in self.mock_input_api.AffectedFiles(
771 include_deletes=True)])
772 results = self._RunCheck()
773 self.assertEqual(1, len(results))
774 self.assertTrue('PYDEPS_FILES' in str(results[0]))
776 def testRandomPyIgnored(self):
777 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
778 if self.mock_input_api.platform != 'linux2':
781 self.mock_input_api.files = [
782 MockAffectedFile('random.py', []),
785 results = self._RunCheck()
786 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
788 def testRelevantPyNoChange(self):
789 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
790 if self.mock_input_api.platform != 'linux2':
793 self.mock_input_api.files = [
794 MockAffectedFile('A.py', []),
797 def mock_check_output(cmd, shell=False, env=None):
798 self.assertEqual('CMD A --output ""', cmd)
799 return self.checker._file_cache['A.pydeps']
801 self.mock_input_api.subprocess.check_output = mock_check_output
803 results = self._RunCheck()
804 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
806 def testRelevantPyOneChange(self):
807 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
808 if self.mock_input_api.platform != 'linux2':
811 self.mock_input_api.files = [
812 MockAffectedFile('A.py', []),
815 def mock_check_output(cmd, shell=False, env=None):
816 self.assertEqual('CMD A --output ""', cmd)
817 return 'changed data'
819 self.mock_input_api.subprocess.check_output = mock_check_output
821 results = self._RunCheck()
822 self.assertEqual(1, len(results))
823 self.assertTrue('File is stale' in str(results[0]))
825 def testRelevantPyTwoChanges(self):
826 # PRESUBMIT._CheckPydepsNeedsUpdating is only implemented for Android.
827 if self.mock_input_api.platform != 'linux2':
830 self.mock_input_api.files = [
831 MockAffectedFile('C.py', []),
834 def mock_check_output(cmd, shell=False, env=None):
835 return 'changed data'
837 self.mock_input_api.subprocess.check_output = mock_check_output
839 results = self._RunCheck()
840 self.assertEqual(2, len(results))
841 self.assertTrue('File is stale' in str(results[0]))
842 self.assertTrue('File is stale' in str(results[1]))
845 class IncludeGuardTest(unittest.TestCase):
846 def testIncludeGuardChecks(self):
847 mock_input_api = MockInputApi()
848 mock_output_api = MockOutputApi()
849 mock_input_api.files = [
850 MockAffectedFile('content/browser/thing/foo.h', [
852 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
853 '#define CONTENT_BROWSER_THING_FOO_H_',
854 'struct McBoatFace;',
855 '#endif // CONTENT_BROWSER_THING_FOO_H_',
857 MockAffectedFile('content/browser/thing/bar.h', [
858 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
859 '#define CONTENT_BROWSER_THING_BAR_H_',
860 'namespace content {',
861 '#endif // CONTENT_BROWSER_THING_BAR_H_',
862 '} // namespace content',
864 MockAffectedFile('content/browser/test1.h', [
865 'namespace content {',
866 '} // namespace content',
868 MockAffectedFile('content\\browser\\win.h', [
869 '#ifndef CONTENT_BROWSER_WIN_H_',
870 '#define CONTENT_BROWSER_WIN_H_',
871 'struct McBoatFace;',
872 '#endif // CONTENT_BROWSER_WIN_H_',
874 MockAffectedFile('content/browser/test2.h', [
876 '#ifndef CONTENT_BROWSER_TEST2_H_',
877 'struct McBoatFace;',
878 '#endif // CONTENT_BROWSER_TEST2_H_',
880 MockAffectedFile('content/browser/internal.h', [
882 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
883 '#define CONTENT_BROWSER_INTERNAL_H_',
885 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
886 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
887 'namespace internal {',
888 '} // namespace internal',
889 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
890 'namespace content {',
891 '} // namespace content',
892 '#endif // CONTENT_BROWSER_THING_BAR_H_',
894 MockAffectedFile('content/browser/thing/foo.cc', [
895 '// This is a non-header.',
897 MockAffectedFile('content/browser/disabled.h', [
898 '// no-include-guard-because-multiply-included',
899 'struct McBoatFace;',
901 # New files don't allow misspelled include guards.
902 MockAffectedFile('content/browser/spleling.h', [
903 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
904 '#define CONTENT_BROWSER_SPLLEING_H_',
905 'struct McBoatFace;',
906 '#endif // CONTENT_BROWSER_SPLLEING_H_',
908 # New files don't allow + in include guards.
909 MockAffectedFile('content/browser/foo+bar.h', [
910 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
911 '#define CONTENT_BROWSER_FOO+BAR_H_',
912 'struct McBoatFace;',
913 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
915 # Old files allow misspelled include guards (for now).
916 MockAffectedFile('chrome/old.h', [
918 '#ifndef CHROME_ODL_H_',
919 '#define CHROME_ODL_H_',
920 '#endif // CHROME_ODL_H_',
923 '#ifndef CHROME_ODL_H_',
924 '#define CHROME_ODL_H_',
925 '#endif // CHROME_ODL_H_',
927 # Using a Blink style include guard outside Blink is wrong.
928 MockAffectedFile('content/NotInBlink.h', [
929 '#ifndef NotInBlink_h',
930 '#define NotInBlink_h',
931 'struct McBoatFace;',
932 '#endif // NotInBlink_h',
934 # Using a Blink style include guard in Blink is no longer ok.
935 MockAffectedFile('third_party/blink/InBlink.h', [
938 'struct McBoatFace;',
939 '#endif // InBlink_h',
941 # Using a bad include guard in Blink is not ok.
942 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
943 '#ifndef WrongInBlink_h',
944 '#define WrongInBlink_h',
945 'struct McBoatFace;',
946 '#endif // WrongInBlink_h',
948 # Using a bad include guard in Blink is not accepted even if
950 MockAffectedFile('third_party/blink/StillInBlink.h', [
952 '#ifndef AcceptedInBlink_h',
953 '#define AcceptedInBlink_h',
954 'struct McBoatFace;',
955 '#endif // AcceptedInBlink_h',
958 '#ifndef AcceptedInBlink_h',
959 '#define AcceptedInBlink_h',
960 'struct McBoatFace;',
961 '#endif // AcceptedInBlink_h',
963 # Using a non-Chromium include guard in third_party
964 # (outside blink) is accepted.
965 MockAffectedFile('third_party/foo/some_file.h', [
966 '#ifndef REQUIRED_RPCNDR_H_',
967 '#define REQUIRED_RPCNDR_H_',
968 'struct SomeFileFoo;',
969 '#endif // REQUIRED_RPCNDR_H_',
972 msgs = PRESUBMIT._CheckForIncludeGuards(
973 mock_input_api, mock_output_api)
974 expected_fail_count = 8
975 self.assertEqual(expected_fail_count, len(msgs),
976 'Expected %d items, found %d: %s'
977 % (expected_fail_count, len(msgs), msgs))
978 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
979 self.assertEqual(msgs[0].message,
980 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
981 'not covering the whole file')
983 self.assertEqual(msgs[1].items, ['content/browser/test1.h'])
984 self.assertEqual(msgs[1].message,
985 'Missing include guard CONTENT_BROWSER_TEST1_H_')
987 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
988 self.assertEqual(msgs[2].message,
989 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
992 self.assertEqual(msgs[3].items, ['content/browser/spleling.h:1'])
993 self.assertEqual(msgs[3].message,
994 'Header using the wrong include guard name '
995 'CONTENT_BROWSER_SPLLEING_H_')
997 self.assertEqual(msgs[4].items, ['content/browser/foo+bar.h'])
998 self.assertEqual(msgs[4].message,
999 'Missing include guard CONTENT_BROWSER_FOO_BAR_H_')
1001 self.assertEqual(msgs[5].items, ['content/NotInBlink.h:1'])
1002 self.assertEqual(msgs[5].message,
1003 'Header using the wrong include guard name '
1006 self.assertEqual(msgs[6].items, ['third_party/blink/InBlink.h:1'])
1007 self.assertEqual(msgs[6].message,
1008 'Header using the wrong include guard name '
1011 self.assertEqual(msgs[7].items, ['third_party/blink/AlsoInBlink.h:1'])
1012 self.assertEqual(msgs[7].message,
1013 'Header using the wrong include guard name '
1017 class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
1018 def testCheckAndroidTestAnnotationUsage(self):
1019 mock_input_api = MockInputApi()
1020 mock_output_api = MockOutputApi()
1022 mock_input_api.files = [
1023 MockAffectedFile('LalaLand.java', [
1026 MockAffectedFile('CorrectUsage.java', [
1027 'import android.support.test.filters.LargeTest;',
1028 'import android.support.test.filters.MediumTest;',
1029 'import android.support.test.filters.SmallTest;',
1031 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1032 'import android.test.suitebuilder.annotation.LargeTest;',
1034 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1035 'import android.test.suitebuilder.annotation.MediumTest;',
1037 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1038 'import android.test.suitebuilder.annotation.SmallTest;',
1040 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1041 'import android.test.suitebuilder.annotation.Smoke;',
1044 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1045 mock_input_api, mock_output_api)
1046 self.assertEqual(1, len(msgs),
1047 'Expected %d items, found %d: %s'
1048 % (1, len(msgs), msgs))
1049 self.assertEqual(4, len(msgs[0].items),
1050 'Expected %d items, found %d: %s'
1051 % (4, len(msgs[0].items), msgs[0].items))
1052 self.assertTrue('UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1053 'UsedDeprecatedLargeTestAnnotation not found in errors')
1054 self.assertTrue('UsedDeprecatedMediumTestAnnotation.java:1'
1056 'UsedDeprecatedMediumTestAnnotation not found in errors')
1057 self.assertTrue('UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1058 'UsedDeprecatedSmallTestAnnotation not found in errors')
1059 self.assertTrue('UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1060 'UsedDeprecatedSmokeAnnotation not found in errors')
1063 class AndroidDeprecatedJUnitFrameworkTest(unittest.TestCase):
1064 def testCheckAndroidTestJUnitFramework(self):
1065 mock_input_api = MockInputApi()
1066 mock_output_api = MockOutputApi()
1068 mock_input_api.files = [
1069 MockAffectedFile('LalaLand.java', [
1072 MockAffectedFile('CorrectUsage.java', [
1073 'import org.junit.ABC',
1074 'import org.junit.XYZ;',
1076 MockAffectedFile('UsedDeprecatedJUnit.java', [
1077 'import junit.framework.*;',
1079 MockAffectedFile('UsedDeprecatedJUnitAssert.java', [
1080 'import junit.framework.Assert;',
1083 msgs = PRESUBMIT._CheckAndroidTestJUnitFrameworkImport(
1084 mock_input_api, mock_output_api)
1085 self.assertEqual(1, len(msgs),
1086 'Expected %d items, found %d: %s'
1087 % (1, len(msgs), msgs))
1088 self.assertEqual(2, len(msgs[0].items),
1089 'Expected %d items, found %d: %s'
1090 % (2, len(msgs[0].items), msgs[0].items))
1091 self.assertTrue('UsedDeprecatedJUnit.java:1' in msgs[0].items,
1092 'UsedDeprecatedJUnit.java not found in errors')
1093 self.assertTrue('UsedDeprecatedJUnitAssert.java:1'
1095 'UsedDeprecatedJUnitAssert not found in errors')
1098 class AndroidJUnitBaseClassTest(unittest.TestCase):
1099 def testCheckAndroidTestJUnitBaseClass(self):
1100 mock_input_api = MockInputApi()
1101 mock_output_api = MockOutputApi()
1103 mock_input_api.files = [
1104 MockAffectedFile('LalaLand.java', [
1107 MockAffectedFile('CorrectTest.java', [
1108 '@RunWith(ABC.class);'
1109 'public class CorrectTest {',
1112 MockAffectedFile('HistoricallyIncorrectTest.java', [
1113 'public class Test extends BaseCaseA {',
1116 'public class Test extends BaseCaseB {',
1119 MockAffectedFile('CorrectTestWithInterface.java', [
1120 '@RunWith(ABC.class);'
1121 'public class CorrectTest implement Interface {',
1124 MockAffectedFile('IncorrectTest.java', [
1125 'public class IncorrectTest extends TestCase {',
1128 MockAffectedFile('IncorrectWithInterfaceTest.java', [
1129 'public class Test implements X extends BaseClass {',
1132 MockAffectedFile('IncorrectMultiLineTest.java', [
1133 'public class Test implements X, Y, Z',
1134 ' extends TestBase {',
1138 msgs = PRESUBMIT._CheckAndroidTestJUnitInheritance(
1139 mock_input_api, mock_output_api)
1140 self.assertEqual(1, len(msgs),
1141 'Expected %d items, found %d: %s'
1142 % (1, len(msgs), msgs))
1143 self.assertEqual(3, len(msgs[0].items),
1144 'Expected %d items, found %d: %s'
1145 % (3, len(msgs[0].items), msgs[0].items))
1146 self.assertTrue('IncorrectTest.java:1' in msgs[0].items,
1147 'IncorrectTest not found in errors')
1148 self.assertTrue('IncorrectWithInterfaceTest.java:1'
1150 'IncorrectWithInterfaceTest not found in errors')
1151 self.assertTrue('IncorrectMultiLineTest.java:2' in msgs[0].items,
1152 'IncorrectMultiLineTest not found in errors')
1154 class AndroidDebuggableBuildTest(unittest.TestCase):
1156 def testCheckAndroidDebuggableBuild(self):
1157 mock_input_api = MockInputApi()
1158 mock_output_api = MockOutputApi()
1160 mock_input_api.files = [
1161 MockAffectedFile('RandomStuff.java', [
1164 MockAffectedFile('CorrectUsage.java', [
1165 'import org.chromium.base.BuildInfo;',
1166 'some random stuff',
1167 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1169 MockAffectedFile('JustCheckUserdebugBuild.java', [
1170 'import android.os.Build;',
1171 'some random stuff',
1172 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1174 MockAffectedFile('JustCheckEngineeringBuild.java', [
1175 'import android.os.Build;',
1176 'some random stuff',
1177 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1179 MockAffectedFile('UsedBuildType.java', [
1180 'import android.os.Build;',
1181 'some random stuff',
1182 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1183 '|| "eng".equals(Build.TYPE)',
1185 MockAffectedFile('UsedExplicitBuildType.java', [
1186 'some random stuff',
1187 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1188 '|| "eng".equals(android.os.Build.TYPE)',
1192 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(
1193 mock_input_api, mock_output_api)
1194 self.assertEqual(1, len(msgs),
1195 'Expected %d items, found %d: %s'
1196 % (1, len(msgs), msgs))
1197 self.assertEqual(4, len(msgs[0].items),
1198 'Expected %d items, found %d: %s'
1199 % (4, len(msgs[0].items), msgs[0].items))
1200 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1201 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1202 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1203 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
1206 class LogUsageTest(unittest.TestCase):
1208 def testCheckAndroidCrLogUsage(self):
1209 mock_input_api = MockInputApi()
1210 mock_output_api = MockOutputApi()
1212 mock_input_api.files = [
1213 MockAffectedFile('RandomStuff.java', [
1216 MockAffectedFile('HasAndroidLog.java', [
1217 'import android.util.Log;',
1218 'some random stuff',
1219 'Log.d("TAG", "foo");',
1221 MockAffectedFile('HasExplicitUtilLog.java', [
1222 'some random stuff',
1223 'android.util.Log.d("TAG", "foo");',
1225 MockAffectedFile('IsInBasePackage.java', [
1226 'package org.chromium.base;',
1227 'private static final String TAG = "cr_Foo";',
1228 'Log.d(TAG, "foo");',
1230 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1231 'package org.chromium.base;',
1232 'import android.util.Log;',
1233 'private static final String TAG = "cr_Foo";',
1234 'Log.d(TAG, "foo");',
1236 MockAffectedFile('HasBothLog.java', [
1237 'import org.chromium.base.Log;',
1238 'some random stuff',
1239 'private static final String TAG = "cr_Foo";',
1240 'Log.d(TAG, "foo");',
1241 'android.util.Log.d("TAG", "foo");',
1243 MockAffectedFile('HasCorrectTag.java', [
1244 'import org.chromium.base.Log;',
1245 'some random stuff',
1246 'private static final String TAG = "cr_Foo";',
1247 'Log.d(TAG, "foo");',
1249 MockAffectedFile('HasOldTag.java', [
1250 'import org.chromium.base.Log;',
1251 'some random stuff',
1252 'private static final String TAG = "cr.Foo";',
1253 'Log.d(TAG, "foo");',
1255 MockAffectedFile('HasDottedTag.java', [
1256 'import org.chromium.base.Log;',
1257 'some random stuff',
1258 'private static final String TAG = "cr_foo.bar";',
1259 'Log.d(TAG, "foo");',
1261 MockAffectedFile('HasNoTagDecl.java', [
1262 'import org.chromium.base.Log;',
1263 'some random stuff',
1264 'Log.d(TAG, "foo");',
1266 MockAffectedFile('HasIncorrectTagDecl.java', [
1267 'import org.chromium.base.Log;',
1268 'private static final String TAHG = "cr_Foo";',
1269 'some random stuff',
1270 'Log.d(TAG, "foo");',
1272 MockAffectedFile('HasInlineTag.java', [
1273 'import org.chromium.base.Log;',
1274 'some random stuff',
1275 'private static final String TAG = "cr_Foo";',
1276 'Log.d("TAG", "foo");',
1278 MockAffectedFile('HasUnprefixedTag.java', [
1279 'import org.chromium.base.Log;',
1280 'some random stuff',
1281 'private static final String TAG = "rubbish";',
1282 'Log.d(TAG, "foo");',
1284 MockAffectedFile('HasTooLongTag.java', [
1285 'import org.chromium.base.Log;',
1286 'some random stuff',
1287 'private static final String TAG = "21_charachers_long___";',
1288 'Log.d(TAG, "foo");',
1292 msgs = PRESUBMIT._CheckAndroidCrLogUsage(
1293 mock_input_api, mock_output_api)
1295 self.assertEqual(5, len(msgs),
1296 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
1298 # Declaration format
1299 nb = len(msgs[0].items)
1300 self.assertEqual(2, nb,
1301 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
1302 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1303 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
1306 nb = len(msgs[1].items)
1307 self.assertEqual(1, nb,
1308 'Expected %d items, found %d: %s' % (1, nb, msgs[1].items))
1309 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
1311 # Tag must be a variable named TAG
1312 nb = len(msgs[2].items)
1313 self.assertEqual(1, nb,
1314 'Expected %d items, found %d: %s' % (1, nb, msgs[2].items))
1315 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
1318 nb = len(msgs[3].items)
1319 self.assertEqual(2, nb,
1320 'Expected %d items, found %d: %s' % (2, nb, msgs[3].items))
1321 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1322 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
1324 # Tag must not contain
1325 nb = len(msgs[4].items)
1326 self.assertEqual(2, nb,
1327 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1328 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1329 self.assertTrue('HasOldTag.java' in msgs[4].items)
1332 class GoogleAnswerUrlFormatTest(unittest.TestCase):
1334 def testCatchAnswerUrlId(self):
1335 input_api = MockInputApi()
1337 MockFile('somewhere/file.cc',
1339 ' "https://support.google.com/chrome/answer/123456";']),
1340 MockFile('somewhere_else/file.cc',
1342 ' "https://support.google.com/chrome/a/answer/123456";']),
1345 warnings = PRESUBMIT._CheckGoogleSupportAnswerUrl(
1346 input_api, MockOutputApi())
1347 self.assertEqual(1, len(warnings))
1348 self.assertEqual(2, len(warnings[0].items))
1350 def testAllowAnswerUrlParam(self):
1351 input_api = MockInputApi()
1353 MockFile('somewhere/file.cc',
1355 ' "https://support.google.com/chrome/?p=cpn_crash_reports";']),
1358 warnings = PRESUBMIT._CheckGoogleSupportAnswerUrl(
1359 input_api, MockOutputApi())
1360 self.assertEqual(0, len(warnings))
1363 class HardcodedGoogleHostsTest(unittest.TestCase):
1365 def testWarnOnAssignedLiterals(self):
1366 input_api = MockInputApi()
1368 MockFile('content/file.cc',
1369 ['char* host = "https://www.google.com";']),
1370 MockFile('content/file.cc',
1371 ['char* host = "https://www.googleapis.com";']),
1372 MockFile('content/file.cc',
1373 ['char* host = "https://clients1.google.com";']),
1376 warnings = PRESUBMIT._CheckHardcodedGoogleHostsInLowerLayers(
1377 input_api, MockOutputApi())
1378 self.assertEqual(1, len(warnings))
1379 self.assertEqual(3, len(warnings[0].items))
1381 def testAllowInComment(self):
1382 input_api = MockInputApi()
1384 MockFile('content/file.cc',
1385 ['char* host = "https://www.aol.com"; // google.com'])
1388 warnings = PRESUBMIT._CheckHardcodedGoogleHostsInLowerLayers(
1389 input_api, MockOutputApi())
1390 self.assertEqual(0, len(warnings))
1393 class ForwardDeclarationTest(unittest.TestCase):
1394 def testCheckHeadersOnlyOutsideThirdParty(self):
1395 mock_input_api = MockInputApi()
1396 mock_input_api.files = [
1397 MockAffectedFile('somewhere/file.cc', [
1400 MockAffectedFile('third_party/header.h', [
1404 warnings = PRESUBMIT._CheckUselessForwardDeclarations(mock_input_api,
1406 self.assertEqual(0, len(warnings))
1408 def testNoNestedDeclaration(self):
1409 mock_input_api = MockInputApi()
1410 mock_input_api.files = [
1411 MockAffectedFile('somewhere/header.h', [
1412 'class SomeClass {',
1414 ' class NotAMatch;',
1418 warnings = PRESUBMIT._CheckUselessForwardDeclarations(mock_input_api,
1420 self.assertEqual(0, len(warnings))
1422 def testSubStrings(self):
1423 mock_input_api = MockInputApi()
1424 mock_input_api.files = [
1425 MockAffectedFile('somewhere/header.h', [
1426 'class NotUsefulClass;',
1427 'struct SomeStruct;',
1429 'SomeStructPtr *p2;'
1432 warnings = PRESUBMIT._CheckUselessForwardDeclarations(mock_input_api,
1434 self.assertEqual(2, len(warnings))
1436 def testUselessForwardDeclaration(self):
1437 mock_input_api = MockInputApi()
1438 mock_input_api.files = [
1439 MockAffectedFile('somewhere/header.h', [
1440 'class DummyClass;',
1441 'struct DummyStruct;',
1442 'class UsefulClass;',
1443 'std::unique_ptr<UsefulClass> p;'
1446 warnings = PRESUBMIT._CheckUselessForwardDeclarations(mock_input_api,
1448 self.assertEqual(2, len(warnings))
1450 def testBlinkHeaders(self):
1451 mock_input_api = MockInputApi()
1452 mock_input_api.files = [
1453 MockAffectedFile('third_party/blink/header.h', [
1454 'class DummyClass;',
1455 'struct DummyStruct;',
1457 MockAffectedFile('third_party\\blink\\header.h', [
1458 'class DummyClass;',
1459 'struct DummyStruct;',
1462 warnings = PRESUBMIT._CheckUselessForwardDeclarations(mock_input_api,
1464 self.assertEqual(4, len(warnings))
1467 class RelativeIncludesTest(unittest.TestCase):
1468 def testThirdPartyNotWebKitIgnored(self):
1469 mock_input_api = MockInputApi()
1470 mock_input_api.files = [
1471 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1472 MockAffectedFile('third_party/test/test.cpp', '#include "../header.h"'),
1475 mock_output_api = MockOutputApi()
1477 errors = PRESUBMIT._CheckForRelativeIncludes(
1478 mock_input_api, mock_output_api)
1479 self.assertEqual(0, len(errors))
1481 def testNonCppFileIgnored(self):
1482 mock_input_api = MockInputApi()
1483 mock_input_api.files = [
1484 MockAffectedFile('test.py', '#include "../header.h"'),
1487 mock_output_api = MockOutputApi()
1489 errors = PRESUBMIT._CheckForRelativeIncludes(
1490 mock_input_api, mock_output_api)
1491 self.assertEqual(0, len(errors))
1493 def testInnocuousChangesAllowed(self):
1494 mock_input_api = MockInputApi()
1495 mock_input_api.files = [
1496 MockAffectedFile('test.cpp', '#include "header.h"'),
1497 MockAffectedFile('test2.cpp', '../'),
1500 mock_output_api = MockOutputApi()
1502 errors = PRESUBMIT._CheckForRelativeIncludes(
1503 mock_input_api, mock_output_api)
1504 self.assertEqual(0, len(errors))
1506 def testRelativeIncludeNonWebKitProducesError(self):
1507 mock_input_api = MockInputApi()
1508 mock_input_api.files = [
1509 MockAffectedFile('test.cpp', ['#include "../header.h"']),
1512 mock_output_api = MockOutputApi()
1514 errors = PRESUBMIT._CheckForRelativeIncludes(
1515 mock_input_api, mock_output_api)
1516 self.assertEqual(1, len(errors))
1518 def testRelativeIncludeWebKitProducesError(self):
1519 mock_input_api = MockInputApi()
1520 mock_input_api.files = [
1521 MockAffectedFile('third_party/blink/test.cpp',
1522 ['#include "../header.h']),
1525 mock_output_api = MockOutputApi()
1527 errors = PRESUBMIT._CheckForRelativeIncludes(
1528 mock_input_api, mock_output_api)
1529 self.assertEqual(1, len(errors))
1532 class CCIncludeTest(unittest.TestCase):
1533 def testThirdPartyNotBlinkIgnored(self):
1534 mock_input_api = MockInputApi()
1535 mock_input_api.files = [
1536 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
1539 mock_output_api = MockOutputApi()
1541 errors = PRESUBMIT._CheckForCcIncludes(
1542 mock_input_api, mock_output_api)
1543 self.assertEqual(0, len(errors))
1545 def testPythonFileIgnored(self):
1546 mock_input_api = MockInputApi()
1547 mock_input_api.files = [
1548 MockAffectedFile('test.py', '#include "file.cc"'),
1551 mock_output_api = MockOutputApi()
1553 errors = PRESUBMIT._CheckForCcIncludes(
1554 mock_input_api, mock_output_api)
1555 self.assertEqual(0, len(errors))
1557 def testIncFilesAccepted(self):
1558 mock_input_api = MockInputApi()
1559 mock_input_api.files = [
1560 MockAffectedFile('test.py', '#include "file.inc"'),
1563 mock_output_api = MockOutputApi()
1565 errors = PRESUBMIT._CheckForCcIncludes(
1566 mock_input_api, mock_output_api)
1567 self.assertEqual(0, len(errors))
1569 def testInnocuousChangesAllowed(self):
1570 mock_input_api = MockInputApi()
1571 mock_input_api.files = [
1572 MockAffectedFile('test.cpp', '#include "header.h"'),
1573 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
1576 mock_output_api = MockOutputApi()
1578 errors = PRESUBMIT._CheckForCcIncludes(
1579 mock_input_api, mock_output_api)
1580 self.assertEqual(0, len(errors))
1582 def testCcIncludeNonBlinkProducesError(self):
1583 mock_input_api = MockInputApi()
1584 mock_input_api.files = [
1585 MockAffectedFile('test.cpp', ['#include "file.cc"']),
1588 mock_output_api = MockOutputApi()
1590 errors = PRESUBMIT._CheckForCcIncludes(
1591 mock_input_api, mock_output_api)
1592 self.assertEqual(1, len(errors))
1594 def testCppIncludeBlinkProducesError(self):
1595 mock_input_api = MockInputApi()
1596 mock_input_api.files = [
1597 MockAffectedFile('third_party/blink/test.cpp',
1598 ['#include "foo/file.cpp"']),
1601 mock_output_api = MockOutputApi()
1603 errors = PRESUBMIT._CheckForCcIncludes(
1604 mock_input_api, mock_output_api)
1605 self.assertEqual(1, len(errors))
1608 class NewHeaderWithoutGnChangeTest(unittest.TestCase):
1609 def testAddHeaderWithoutGn(self):
1610 mock_input_api = MockInputApi()
1611 mock_input_api.files = [
1612 MockAffectedFile('base/stuff.h', ''),
1614 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1615 mock_input_api, MockOutputApi())
1616 self.assertEqual(1, len(warnings))
1617 self.assertTrue('base/stuff.h' in warnings[0].items)
1619 def testModifyHeader(self):
1620 mock_input_api = MockInputApi()
1621 mock_input_api.files = [
1622 MockAffectedFile('base/stuff.h', '', action='M'),
1624 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1625 mock_input_api, MockOutputApi())
1626 self.assertEqual(0, len(warnings))
1628 def testDeleteHeader(self):
1629 mock_input_api = MockInputApi()
1630 mock_input_api.files = [
1631 MockAffectedFile('base/stuff.h', '', action='D'),
1633 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1634 mock_input_api, MockOutputApi())
1635 self.assertEqual(0, len(warnings))
1637 def testAddHeaderWithGn(self):
1638 mock_input_api = MockInputApi()
1639 mock_input_api.files = [
1640 MockAffectedFile('base/stuff.h', ''),
1641 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
1643 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1644 mock_input_api, MockOutputApi())
1645 self.assertEqual(0, len(warnings))
1647 def testAddHeaderWithGni(self):
1648 mock_input_api = MockInputApi()
1649 mock_input_api.files = [
1650 MockAffectedFile('base/stuff.h', ''),
1651 MockAffectedFile('base/files.gni', 'stuff.h'),
1653 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1654 mock_input_api, MockOutputApi())
1655 self.assertEqual(0, len(warnings))
1657 def testAddHeaderWithOther(self):
1658 mock_input_api = MockInputApi()
1659 mock_input_api.files = [
1660 MockAffectedFile('base/stuff.h', ''),
1661 MockAffectedFile('base/stuff.cc', 'stuff.h'),
1663 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1664 mock_input_api, MockOutputApi())
1665 self.assertEqual(1, len(warnings))
1667 def testAddHeaderWithWrongGn(self):
1668 mock_input_api = MockInputApi()
1669 mock_input_api.files = [
1670 MockAffectedFile('base/stuff.h', ''),
1671 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
1673 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1674 mock_input_api, MockOutputApi())
1675 self.assertEqual(1, len(warnings))
1677 def testAddHeadersWithGn(self):
1678 mock_input_api = MockInputApi()
1679 mock_input_api.files = [
1680 MockAffectedFile('base/stuff.h', ''),
1681 MockAffectedFile('base/another.h', ''),
1682 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
1684 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1685 mock_input_api, MockOutputApi())
1686 self.assertEqual(0, len(warnings))
1688 def testAddHeadersWithWrongGn(self):
1689 mock_input_api = MockInputApi()
1690 mock_input_api.files = [
1691 MockAffectedFile('base/stuff.h', ''),
1692 MockAffectedFile('base/another.h', ''),
1693 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
1695 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1696 mock_input_api, MockOutputApi())
1697 self.assertEqual(1, len(warnings))
1698 self.assertFalse('base/stuff.h' in warnings[0].items)
1699 self.assertTrue('base/another.h' in warnings[0].items)
1701 def testAddHeadersWithWrongGn2(self):
1702 mock_input_api = MockInputApi()
1703 mock_input_api.files = [
1704 MockAffectedFile('base/stuff.h', ''),
1705 MockAffectedFile('base/another.h', ''),
1706 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
1708 warnings = PRESUBMIT._CheckNewHeaderWithoutGnChange(
1709 mock_input_api, MockOutputApi())
1710 self.assertEqual(1, len(warnings))
1711 self.assertTrue('base/stuff.h' in warnings[0].items)
1712 self.assertTrue('base/another.h' in warnings[0].items)
1715 class CorrectProductNameInMessagesTest(unittest.TestCase):
1716 def testProductNameInDesc(self):
1717 mock_input_api = MockInputApi()
1718 mock_input_api.files = [
1719 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
1720 '<message name="Foo" desc="Welcome to Chrome">',
1721 ' Welcome to Chrome!',
1724 MockAffectedFile('chrome/app/chromium_strings.grd', [
1725 '<message name="Bar" desc="Welcome to Chrome">',
1726 ' Welcome to Chromium!',
1730 warnings = PRESUBMIT._CheckCorrectProductNameInMessages(
1731 mock_input_api, MockOutputApi())
1732 self.assertEqual(0, len(warnings))
1734 def testChromeInChromium(self):
1735 mock_input_api = MockInputApi()
1736 mock_input_api.files = [
1737 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
1738 '<message name="Foo" desc="Welcome to Chrome">',
1739 ' Welcome to Chrome!',
1742 MockAffectedFile('chrome/app/chromium_strings.grd', [
1743 '<message name="Bar" desc="Welcome to Chrome">',
1744 ' Welcome to Chrome!',
1748 warnings = PRESUBMIT._CheckCorrectProductNameInMessages(
1749 mock_input_api, MockOutputApi())
1750 self.assertEqual(1, len(warnings))
1751 self.assertTrue('chrome/app/chromium_strings.grd' in warnings[0].items[0])
1753 def testChromiumInChrome(self):
1754 mock_input_api = MockInputApi()
1755 mock_input_api.files = [
1756 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
1757 '<message name="Foo" desc="Welcome to Chrome">',
1758 ' Welcome to Chromium!',
1761 MockAffectedFile('chrome/app/chromium_strings.grd', [
1762 '<message name="Bar" desc="Welcome to Chrome">',
1763 ' Welcome to Chromium!',
1767 warnings = PRESUBMIT._CheckCorrectProductNameInMessages(
1768 mock_input_api, MockOutputApi())
1769 self.assertEqual(1, len(warnings))
1771 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
1773 def testMultipleInstances(self):
1774 mock_input_api = MockInputApi()
1775 mock_input_api.files = [
1776 MockAffectedFile('chrome/app/chromium_strings.grd', [
1777 '<message name="Bar" desc="Welcome to Chrome">',
1778 ' Welcome to Chrome!',
1780 '<message name="Baz" desc="A correct message">',
1781 ' Chromium is the software you are using.',
1783 '<message name="Bat" desc="An incorrect message">',
1784 ' Google Chrome is the software you are using.',
1788 warnings = PRESUBMIT._CheckCorrectProductNameInMessages(
1789 mock_input_api, MockOutputApi())
1790 self.assertEqual(1, len(warnings))
1792 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
1794 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
1796 def testMultipleWarnings(self):
1797 mock_input_api = MockInputApi()
1798 mock_input_api.files = [
1799 MockAffectedFile('chrome/app/chromium_strings.grd', [
1800 '<message name="Bar" desc="Welcome to Chrome">',
1801 ' Welcome to Chrome!',
1803 '<message name="Baz" desc="A correct message">',
1804 ' Chromium is the software you are using.',
1806 '<message name="Bat" desc="An incorrect message">',
1807 ' Google Chrome is the software you are using.',
1810 MockAffectedFile('components/components_google_chrome_strings.grd', [
1811 '<message name="Bar" desc="Welcome to Chrome">',
1812 ' Welcome to Chrome!',
1814 '<message name="Baz" desc="A correct message">',
1815 ' Chromium is the software you are using.',
1817 '<message name="Bat" desc="An incorrect message">',
1818 ' Google Chrome is the software you are using.',
1822 warnings = PRESUBMIT._CheckCorrectProductNameInMessages(
1823 mock_input_api, MockOutputApi())
1824 self.assertEqual(2, len(warnings))
1826 'components/components_google_chrome_strings.grd:5'
1827 in warnings[0].items[0])
1829 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
1831 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
1834 class ServiceManifestOwnerTest(unittest.TestCase):
1835 def testServiceManifestJsonChangeNeedsSecurityOwner(self):
1836 mock_input_api = MockInputApi()
1837 mock_input_api.files = [
1838 MockAffectedFile('services/goat/manifest.json',
1841 ' "name": "teleporter",',
1842 ' "display_name": "Goat Teleporter",'
1843 ' "interface_provider_specs": {',
1848 mock_output_api = MockOutputApi()
1849 errors = PRESUBMIT._CheckIpcOwners(
1850 mock_input_api, mock_output_api)
1851 self.assertEqual(1, len(errors))
1853 'Found OWNERS files that need to be updated for IPC security review ' +
1854 'coverage.\nPlease update the OWNERS files below:', errors[0].message)
1856 # No warning if already covered by an OWNERS rule.
1858 def testNonManifestJsonChangesDoNotRequireSecurityOwner(self):
1859 mock_input_api = MockInputApi()
1860 mock_input_api.files = [
1861 MockAffectedFile('services/goat/species.json',
1869 mock_output_api = MockOutputApi()
1870 errors = PRESUBMIT._CheckIpcOwners(
1871 mock_input_api, mock_output_api)
1872 self.assertEqual([], errors)
1874 def testServiceManifestChangeNeedsSecurityOwner(self):
1875 mock_input_api = MockInputApi()
1876 mock_input_api.files = [
1877 MockAffectedFile('services/goat/public/cpp/manifest.cc',
1879 '#include "services/goat/public/cpp/manifest.h"',
1880 'const service_manager::Manifest& GetManifest() {}',
1882 mock_output_api = MockOutputApi()
1883 errors = PRESUBMIT._CheckIpcOwners(
1884 mock_input_api, mock_output_api)
1885 self.assertEqual(1, len(errors))
1887 'Found OWNERS files that need to be updated for IPC security review ' +
1888 'coverage.\nPlease update the OWNERS files below:', errors[0].message)
1890 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
1891 mock_input_api = MockInputApi()
1892 mock_input_api.files = [
1893 MockAffectedFile('some/non/service/thing/foo_manifest.cc',
1895 'const char kNoEnforcement[] = "not a manifest!";',
1897 mock_output_api = MockOutputApi()
1898 errors = PRESUBMIT._CheckIpcOwners(
1899 mock_input_api, mock_output_api)
1900 self.assertEqual([], errors)
1903 class BannedFunctionCheckTest(unittest.TestCase):
1905 def testBannedIosObcjFunctions(self):
1906 input_api = MockInputApi()
1908 MockFile('some/ios/file.mm',
1909 ['TEST(SomeClassTest, SomeInteraction) {',
1911 MockFile('some/mac/file.mm',
1912 ['TEST(SomeClassTest, SomeInteraction) {',
1914 MockFile('another/ios_file.mm',
1915 ['class SomeTest : public testing::Test {};']),
1918 errors = PRESUBMIT._CheckNoBannedFunctions(input_api, MockOutputApi())
1919 self.assertEqual(1, len(errors))
1920 self.assertTrue('some/ios/file.mm' in errors[0].message)
1921 self.assertTrue('another/ios_file.mm' in errors[0].message)
1922 self.assertTrue('some/mac/file.mm' not in errors[0].message)
1924 def testBannedMojoFunctions(self):
1925 input_api = MockInputApi()
1927 MockFile('some/cpp/problematic/file.cc',
1928 ['mojo::DataPipe();']),
1929 MockFile('some/cpp/problematic/file2.cc',
1930 ['mojo::ConvertTo<>']),
1931 MockFile('some/cpp/ok/file.cc',
1932 ['CreateDataPipe();']),
1933 MockFile('some/cpp/ok/file2.cc',
1934 ['mojo::DataPipeDrainer();']),
1935 MockFile('third_party/blink/ok/file3.cc',
1936 ['mojo::ConvertTo<>']),
1937 MockFile('content/renderer/ok/file3.cc',
1938 ['mojo::ConvertTo<>']),
1941 results = PRESUBMIT._CheckNoBannedFunctions(input_api, MockOutputApi())
1943 # warnings are results[0], errors are results[1]
1944 self.assertEqual(2, len(results))
1945 self.assertTrue('some/cpp/problematic/file.cc' in results[1].message)
1946 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
1947 self.assertTrue('some/cpp/ok/file.cc' not in results[1].message)
1948 self.assertTrue('some/cpp/ok/file2.cc' not in results[1].message)
1949 self.assertTrue('third_party/blink/ok/file3.cc' not in results[0].message)
1950 self.assertTrue('content/renderer/ok/file3.cc' not in results[0].message)
1953 class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
1954 def testTruePositives(self):
1955 mock_input_api = MockInputApi()
1956 mock_input_api.files = [
1957 MockFile('some/path/foo.cc', ['foo_for_testing();']),
1958 MockFile('some/path/foo.mm', ['FooForTesting();']),
1959 MockFile('some/path/foo.cxx', ['FooForTests();']),
1960 MockFile('some/path/foo.cpp', ['foo_for_test();']),
1963 results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctions(
1964 mock_input_api, MockOutputApi())
1965 self.assertEqual(1, len(results))
1966 self.assertEqual(4, len(results[0].items))
1967 self.assertTrue('foo.cc' in results[0].items[0])
1968 self.assertTrue('foo.mm' in results[0].items[1])
1969 self.assertTrue('foo.cxx' in results[0].items[2])
1970 self.assertTrue('foo.cpp' in results[0].items[3])
1972 def testFalsePositives(self):
1973 mock_input_api = MockInputApi()
1974 mock_input_api.files = [
1975 MockFile('some/path/foo.h', ['foo_for_testing();']),
1976 MockFile('some/path/foo.mm', ['FooForTesting() {']),
1977 MockFile('some/path/foo.cc', ['::FooForTests();']),
1978 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
1981 results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctions(
1982 mock_input_api, MockOutputApi())
1983 self.assertEqual(0, len(results))
1986 class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
1987 def testTruePositives(self):
1988 mock_input_api = MockInputApi()
1989 mock_input_api.files = [
1990 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
1991 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
1992 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
1993 MockFile('dir/java/src/mult.java', [
1994 'int x = SomethingLongHere()',
1995 ' * SomethingLongHereForTesting();'
1999 results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctionsJava(
2000 mock_input_api, MockOutputApi())
2001 self.assertEqual(1, len(results))
2002 self.assertEqual(4, len(results[0].items))
2003 self.assertTrue('foo.java' in results[0].items[0])
2004 self.assertTrue('bar.java' in results[0].items[1])
2005 self.assertTrue('baz.java' in results[0].items[2])
2006 self.assertTrue('mult.java' in results[0].items[3])
2008 def testFalsePositives(self):
2009 mock_input_api = MockInputApi()
2010 mock_input_api.files = [
2011 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
2012 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
2013 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
2014 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
2015 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
2016 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
2017 MockFile('dir/junit/src/javadoc.java', [
2018 '/** Use FooForTest(); to obtain foo in tests.'
2021 MockFile('dir/junit/src/javadoc2.java', [
2023 ' * Use FooForTest(); to obtain foo in tests.'
2028 results = PRESUBMIT._CheckNoProductionCodeUsingTestOnlyFunctionsJava(
2029 mock_input_api, MockOutputApi())
2030 self.assertEqual(0, len(results))
2033 class CheckUniquePtrTest(unittest.TestCase):
2034 def testTruePositivesNullptr(self):
2035 mock_input_api = MockInputApi()
2036 mock_input_api.files = [
2037 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
2038 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
2041 results = PRESUBMIT._CheckUniquePtr(mock_input_api, MockOutputApi())
2042 self.assertEqual(1, len(results))
2043 self.assertTrue('nullptr' in results[0].message)
2044 self.assertEqual(2, len(results[0].items))
2045 self.assertTrue('baz.cc' in results[0].items[0])
2046 self.assertTrue('baz-p.cc' in results[0].items[1])
2048 def testTruePositivesConstructor(self):
2049 mock_input_api = MockInputApi()
2050 mock_input_api.files = [
2051 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
2052 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
2053 MockFile('dir/mult.cc', [
2055 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
2057 MockFile('dir/mult2.cc', [
2058 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
2059 ' std::unique_ptr<T>(foo);'
2061 MockFile('dir/mult3.cc', [
2062 'bar = std::unique_ptr<T>(',
2063 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
2065 MockFile('dir/multi_arg.cc', [
2066 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));']),
2069 results = PRESUBMIT._CheckUniquePtr(mock_input_api, MockOutputApi())
2070 self.assertEqual(1, len(results))
2071 self.assertTrue('std::make_unique' in results[0].message)
2072 self.assertEqual(6, len(results[0].items))
2073 self.assertTrue('foo.cc' in results[0].items[0])
2074 self.assertTrue('bar.mm' in results[0].items[1])
2075 self.assertTrue('mult.cc' in results[0].items[2])
2076 self.assertTrue('mult2.cc' in results[0].items[3])
2077 self.assertTrue('mult3.cc' in results[0].items[4])
2078 self.assertTrue('multi_arg.cc' in results[0].items[5])
2080 def testFalsePositives(self):
2081 mock_input_api = MockInputApi()
2082 mock_input_api.files = [
2083 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
2084 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
2085 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
2086 MockFile('dir/baz.cc', [
2087 'std::unique_ptr<T> result = std::make_unique<T>();'
2089 MockFile('dir/baz2.cc', [
2090 'std::unique_ptr<T> result = std::make_unique<T>('
2092 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
2093 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
2095 # Two-argument invocation of std::unique_ptr is exempt because there is
2096 # no equivalent using std::make_unique.
2097 MockFile('dir/multi_arg.cc', [
2098 'auto p = std::unique_ptr<T, D>(new T(), D());']),
2101 results = PRESUBMIT._CheckUniquePtr(mock_input_api, MockOutputApi())
2102 self.assertEqual(0, len(results))
2104 class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
2105 def testBlocksDirectIncludes(self):
2106 mock_input_api = MockInputApi()
2107 mock_input_api.files = [
2108 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
2109 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
2110 MockFile('dir/baz.h', ['#include <atlbase.h>']),
2111 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
2113 results = PRESUBMIT._CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
2114 self.assertEquals(1, len(results))
2115 self.assertEquals(4, len(results[0].items))
2116 self.assertTrue('StrCat' in results[0].message)
2117 self.assertTrue('foo_win.cc' in results[0].items[0])
2118 self.assertTrue('bar.h' in results[0].items[1])
2119 self.assertTrue('baz.h' in results[0].items[2])
2120 self.assertTrue('jumbo.h' in results[0].items[3])
2122 def testAllowsToIncludeWrapper(self):
2123 mock_input_api = MockInputApi()
2124 mock_input_api.files = [
2125 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
2126 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
2128 results = PRESUBMIT._CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
2129 self.assertEquals(0, len(results))
2131 def testAllowsToCreateWrapper(self):
2132 mock_input_api = MockInputApi()
2133 mock_input_api.files = [
2134 MockFile('base/win/shlwapi.h', [
2135 '#include <shlwapi.h>',
2136 '#include "base/win/windows_defines.inc"']),
2138 results = PRESUBMIT._CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
2139 self.assertEquals(0, len(results))
2141 class TranslationScreenshotsTest(unittest.TestCase):
2142 # An empty grd file.
2143 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
2144 <grit latest_public_release="1" current_release="1">
2146 <messages></messages>
2150 # A grd file with a single message.
2151 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
2152 <grit latest_public_release="1" current_release="1">
2155 <message name="IDS_TEST1">
2162 # A grd file with two messages.
2163 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
2164 <grit latest_public_release="1" current_release="1">
2167 <message name="IDS_TEST1">
2170 <message name="IDS_TEST2">
2178 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
2180 'tools/translate/upload_screenshots.py to '
2181 'upload them instead:')
2182 GENERATE_SIGNATURES_MESSAGE = ('You are adding or modifying UI strings.\n'
2183 'To ensure the best translations, take '
2184 'screenshots of the relevant UI '
2185 '(https://g.co/chrome/translation) and add '
2186 'these files to your changelist:')
2187 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
2190 def makeInputApi(self, files):
2191 input_api = MockInputApi()
2192 input_api.files = files
2195 def testNoScreenshots(self):
2196 # CL modified and added messages, but didn't add any screenshots.
2197 input_api = self.makeInputApi([
2198 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
2199 self.OLD_GRD_CONTENTS, action='M')])
2200 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2202 self.assertEqual(1, len(warnings))
2203 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
2205 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
2206 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
2207 ], warnings[0].items)
2209 input_api = self.makeInputApi([
2210 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
2211 self.NEW_GRD_CONTENTS1, action='M')])
2212 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2214 self.assertEqual(1, len(warnings))
2215 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
2216 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
2220 def testUnnecessaryScreenshots(self):
2221 # CL added a single message and added the png file, but not the sha1 file.
2222 input_api = self.makeInputApi([
2225 self.NEW_GRD_CONTENTS1,
2226 self.OLD_GRD_CONTENTS,
2229 os.path.join('test_grd', 'IDS_TEST1.png'), 'binary', action='A')
2231 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2233 self.assertEqual(2, len(warnings))
2234 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
2235 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
2237 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
2238 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
2241 # CL added two messages, one has a png. Expect two messages:
2242 # - One for the unnecessary png.
2243 # - Another one for missing .sha1 files.
2244 input_api = self.makeInputApi([
2247 self.NEW_GRD_CONTENTS2,
2248 self.OLD_GRD_CONTENTS,
2251 os.path.join('test_grd', 'IDS_TEST1.png'), 'binary', action='A')
2253 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2255 self.assertEqual(2, len(warnings))
2256 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
2257 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
2259 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
2261 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
2262 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
2263 ], warnings[1].items)
2265 def testScreenshotsWithSha1(self):
2266 # CL added two messages and their corresponding .sha1 files. No warnings.
2267 input_api = self.makeInputApi([
2270 self.NEW_GRD_CONTENTS2,
2271 self.OLD_GRD_CONTENTS,
2274 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
2278 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
2282 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2284 self.assertEqual([], warnings)
2286 def testScreenshotsRemovedWithSha1(self):
2287 # Swap old contents with new contents, remove IDS_TEST1 and IDS_TEST2. The
2288 # sha1 files associated with the messages should also be removed by the CL.
2289 input_api = self.makeInputApi([
2292 self.OLD_GRD_CONTENTS,
2293 self.NEW_GRD_CONTENTS2,
2295 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ""),
2296 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'), 'binary', "")
2298 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2300 self.assertEqual(1, len(warnings))
2301 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
2303 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
2304 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
2305 ], warnings[0].items)
2307 # Same as above, but this time one of the .sha1 files is removed.
2308 input_api = self.makeInputApi([
2311 self.OLD_GRD_CONTENTS,
2312 self.NEW_GRD_CONTENTS2,
2314 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ''),
2316 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
2321 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2323 self.assertEqual(1, len(warnings))
2324 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
2325 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
2328 # Remove both sha1 files. No presubmit warnings.
2329 input_api = self.makeInputApi([
2332 self.OLD_GRD_CONTENTS,
2333 self.NEW_GRD_CONTENTS2,
2336 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
2340 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
2344 warnings = PRESUBMIT._CheckTranslationScreenshots(input_api,
2346 self.assertEqual([], warnings)
2349 class DISABLETypoInTest(unittest.TestCase):
2351 def testPositive(self):
2352 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
2353 # where the desire is to disable a test.
2355 # Disabled on one platform:
2356 '#if defined(OS_WIN)\n'
2357 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
2359 '#define MAYBE_FoobarTest FoobarTest\n'
2361 # Disabled on one platform spread cross lines:
2362 '#if defined(OS_WIN)\n'
2363 '#define MAYBE_FoobarTest \\\n'
2364 ' DISABLE_FoobarTest\n'
2366 '#define MAYBE_FoobarTest FoobarTest\n'
2368 # Disabled on all platforms:
2369 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
2370 # Disabled on all platforms but multiple lines
2371 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
2375 mock_input_api = MockInputApi()
2376 mock_input_api.files = [
2377 MockFile('some/path/foo_unittest.cc', test.splitlines()),
2380 results = PRESUBMIT._CheckNoDISABLETypoInTests(mock_input_api,
2385 msg=('expected len(results) == 1 but got %d in test: %s' %
2386 (len(results), test)))
2388 'foo_unittest.cc' in results[0].message,
2389 msg=('expected foo_unittest.cc in message but got %s in test %s' %
2390 (results[0].message, test)))
2392 def testIngoreNotTestFiles(self):
2393 mock_input_api = MockInputApi()
2394 mock_input_api.files = [
2395 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
2398 results = PRESUBMIT._CheckNoDISABLETypoInTests(mock_input_api,
2400 self.assertEqual(0, len(results))
2402 def testIngoreDeletedFiles(self):
2403 mock_input_api = MockInputApi()
2404 mock_input_api.files = [
2405 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)', action='D'),
2408 results = PRESUBMIT._CheckNoDISABLETypoInTests(mock_input_api,
2410 self.assertEqual(0, len(results))
2413 class BuildtoolsRevisionsAreInSyncTest(unittest.TestCase):
2414 # TODO(crbug.com/941824): We need to make sure the entries in
2415 # //buildtools/DEPS are kept in sync with the entries in //DEPS
2416 # so that users of //buildtools in other projects get the same tooling
2417 # Chromium gets. If we ever fix the referenced bug and add 'includedeps'
2418 # support to gclient, we can eliminate the duplication and delete
2419 # these tests for the corresponding presubmit check.
2421 def _check(self, files):
2422 mock_input_api = MockInputApi()
2423 mock_input_api.files = []
2424 for fname, contents in files.items():
2425 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
2426 return PRESUBMIT._CheckBuildtoolsRevisionsAreInSync(mock_input_api,
2429 def testOneFileChangedButNotTheOther(self):
2430 results = self._check({
2431 "DEPS": "'libunwind_revision': 'onerev'",
2433 self.assertNotEqual(results, [])
2435 def testNeitherFileChanged(self):
2436 results = self._check({
2437 "OWNERS": "foobar@example.com",
2439 self.assertEqual(results, [])
2441 def testBothFilesChangedAndMatch(self):
2442 results = self._check({
2443 "DEPS": "'libunwind_revision': 'onerev'",
2444 "buildtools/DEPS": "'libunwind_revision': 'onerev'",
2446 self.assertEqual(results, [])
2448 def testBothFilesWereChangedAndDontMatch(self):
2449 results = self._check({
2450 "DEPS": "'libunwind_revision': 'onerev'",
2451 "buildtools/DEPS": "'libunwind_revision': 'anotherrev'",
2453 self.assertNotEqual(results, [])
2456 if __name__ == '__main__':