blob: 9bfb0453775b4e7047e1f09d4b65cce7c3c34af0 [file] [log] [blame]
Andrew Grieve3f9b9662022-02-02 19:07:551#!/usr/bin/env python3
Avi Drissman24976592022-09-12 15:24:312# Copyright 2012 The Chromium Authors
[email protected]2299dcf2012-11-15 19:56:243# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Andrew Grieve4deedb12022-02-03 21:34:506import io
Daniel Cheng4dcdb6b2017-04-13 08:30:177import os.path
[email protected]99171a92014-06-03 08:44:478import subprocess
[email protected]2299dcf2012-11-15 19:56:249import unittest
10
11import PRESUBMIT
Saagar Sanghavifceeaae2020-08-12 16:40:3612
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3913from PRESUBMIT_test_mocks import MockFile, MockAffectedFile
gayane3dff8c22014-12-04 17:09:5114from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
[email protected]2299dcf2012-11-15 19:56:2415
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3916
[email protected]99171a92014-06-03 08:44:4717_TEST_DATA_DIR = 'base/test/data/presubmit'
18
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3919
[email protected]b00342e7f2013-03-26 16:21:5420class VersionControlConflictsTest(unittest.TestCase):
[email protected]70ca77752012-11-20 03:45:0321 def testTypicalConflict(self):
22 lines = ['<<<<<<< HEAD',
23 ' base::ScopedTempDir temp_dir_;',
24 '=======',
25 ' ScopedTempDir temp_dir_;',
26 '>>>>>>> master']
27 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
28 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
29 self.assertEqual(3, len(errors))
30 self.assertTrue('1' in errors[0])
31 self.assertTrue('3' in errors[1])
32 self.assertTrue('5' in errors[2])
33
dbeam95c35a2f2015-06-02 01:40:2334 def testIgnoresReadmes(self):
35 lines = ['A First Level Header',
36 '====================',
37 '',
38 'A Second Level Header',
39 '---------------------']
40 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
41 MockInputApi(), MockFile('some/polymer/README.md', lines))
42 self.assertEqual(0, len(errors))
43
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3944
[email protected]b8079ae4a2012-12-05 19:56:4945class BadExtensionsTest(unittest.TestCase):
46 def testBadRejFile(self):
47 mock_input_api = MockInputApi()
48 mock_input_api.files = [
49 MockFile('some/path/foo.cc', ''),
50 MockFile('some/path/foo.cc.rej', ''),
51 MockFile('some/path2/bar.h.rej', ''),
52 ]
53
Saagar Sanghavifceeaae2020-08-12 16:40:3654 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
[email protected]b8079ae4a2012-12-05 19:56:4955 self.assertEqual(1, len(results))
56 self.assertEqual(2, len(results[0].items))
57 self.assertTrue('foo.cc.rej' in results[0].items[0])
58 self.assertTrue('bar.h.rej' in results[0].items[1])
59
60 def testBadOrigFile(self):
61 mock_input_api = MockInputApi()
62 mock_input_api.files = [
63 MockFile('other/path/qux.h.orig', ''),
64 MockFile('other/path/qux.h', ''),
65 MockFile('other/path/qux.cc', ''),
66 ]
67
Saagar Sanghavifceeaae2020-08-12 16:40:3668 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
[email protected]b8079ae4a2012-12-05 19:56:4969 self.assertEqual(1, len(results))
70 self.assertEqual(1, len(results[0].items))
71 self.assertTrue('qux.h.orig' in results[0].items[0])
72
73 def testGoodFiles(self):
74 mock_input_api = MockInputApi()
75 mock_input_api.files = [
76 MockFile('other/path/qux.h', ''),
77 MockFile('other/path/qux.cc', ''),
78 ]
Saagar Sanghavifceeaae2020-08-12 16:40:3679 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
[email protected]b8079ae4a2012-12-05 19:56:4980 self.assertEqual(0, len(results))
81
82
Lei Zhang1c12a22f2021-05-12 11:28:4583class CheckForSuperfluousStlIncludesInHeadersTest(unittest.TestCase):
84 def testGoodFiles(self):
85 mock_input_api = MockInputApi()
86 mock_input_api.files = [
87 # The check is not smart enough to figure out which definitions correspond
88 # to which header.
89 MockFile('other/path/foo.h',
90 ['#include <string>',
91 'std::vector']),
92 # The check is not smart enough to do IWYU.
93 MockFile('other/path/bar.h',
94 ['#include "base/check.h"',
95 'std::vector']),
96 MockFile('other/path/qux.h',
97 ['#include "base/stl_util.h"',
98 'foobar']),
Lei Zhang0643e342021-05-12 18:02:1299 MockFile('other/path/baz.h',
100 ['#include "set/vector.h"',
101 'bazzab']),
Lei Zhang1c12a22f2021-05-12 11:28:45102 # The check is only for header files.
103 MockFile('other/path/not_checked.cc',
104 ['#include <vector>',
105 'bazbaz']),
106 ]
107 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
108 mock_input_api, MockOutputApi())
109 self.assertEqual(0, len(results))
110
111 def testBadFiles(self):
112 mock_input_api = MockInputApi()
113 mock_input_api.files = [
114 MockFile('other/path/foo.h',
115 ['#include <vector>',
116 'vector']),
117 MockFile('other/path/bar.h',
118 ['#include <limits>',
119 '#include <set>',
120 'no_std_namespace']),
121 ]
122 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
123 mock_input_api, MockOutputApi())
124 self.assertEqual(1, len(results))
125 self.assertTrue('foo.h: Includes STL' in results[0].message)
126 self.assertTrue('bar.h: Includes STL' in results[0].message)
127
128
glidere61efad2015-02-18 17:39:43129class CheckSingletonInHeadersTest(unittest.TestCase):
130 def testSingletonInArbitraryHeader(self):
131 diff_singleton_h = ['base::subtle::AtomicWord '
olli.raula36aa8be2015-09-10 11:14:22132 'base::Singleton<Type, Traits, DifferentiatingType>::']
133 diff_foo_h = ['// base::Singleton<Foo> in comment.',
134 'friend class base::Singleton<Foo>']
oysteinec430ad42015-10-22 20:55:24135 diff_foo2_h = [' //Foo* bar = base::Singleton<Foo>::get();']
olli.raula36aa8be2015-09-10 11:14:22136 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
glidere61efad2015-02-18 17:39:43137 mock_input_api = MockInputApi()
138 mock_input_api.files = [MockAffectedFile('base/memory/singleton.h',
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39139 diff_singleton_h),
glidere61efad2015-02-18 17:39:43140 MockAffectedFile('foo.h', diff_foo_h),
oysteinec430ad42015-10-22 20:55:24141 MockAffectedFile('foo2.h', diff_foo2_h),
glidere61efad2015-02-18 17:39:43142 MockAffectedFile('bad.h', diff_bad_h)]
Saagar Sanghavifceeaae2020-08-12 16:40:36143 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
glidere61efad2015-02-18 17:39:43144 MockOutputApi())
145 self.assertEqual(1, len(warnings))
Sylvain Defresnea8b73d252018-02-28 15:45:54146 self.assertEqual(1, len(warnings[0].items))
glidere61efad2015-02-18 17:39:43147 self.assertEqual('error', warnings[0].type)
olli.raula36aa8be2015-09-10 11:14:22148 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
glidere61efad2015-02-18 17:39:43149
150 def testSingletonInCC(self):
olli.raula36aa8be2015-09-10 11:14:22151 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
glidere61efad2015-02-18 17:39:43152 mock_input_api = MockInputApi()
153 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
Saagar Sanghavifceeaae2020-08-12 16:40:36154 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
glidere61efad2015-02-18 17:39:43155 MockOutputApi())
156 self.assertEqual(0, len(warnings))
157
158
Xiaohan Wang42d96c22022-01-20 17:23:11159class DeprecatedOSMacroNamesTest(unittest.TestCase):
160 def testDeprecatedOSMacroNames(self):
161 lines = ['#if defined(OS_WIN)',
[email protected]b00342e7f2013-03-26 16:21:54162 ' #elif defined(OS_WINDOW)',
Xiaohan Wang42d96c22022-01-20 17:23:11163 ' # if defined(OS_MAC) || defined(OS_CHROME)']
164 errors = PRESUBMIT._CheckForDeprecatedOSMacrosInFile(
[email protected]b00342e7f2013-03-26 16:21:54165 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
Xiaohan Wang42d96c22022-01-20 17:23:11166 self.assertEqual(len(lines) + 1, len(errors))
167 self.assertTrue(':1: defined(OS_WIN) -> BUILDFLAG(IS_WIN)' in errors[0])
[email protected]b00342e7f2013-03-26 16:21:54168
169
lliabraa35bab3932014-10-01 12:16:44170class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
171 def testInvalidIfDefinedMacroNames(self):
172 lines = ['#if defined(TARGET_IPHONE_SIMULATOR)',
173 '#if !defined(TARGET_IPHONE_SIMULATOR)',
174 '#elif defined(TARGET_IPHONE_SIMULATOR)',
175 '#ifdef TARGET_IPHONE_SIMULATOR',
176 ' # ifdef TARGET_IPHONE_SIMULATOR',
177 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
178 '# else // defined(TARGET_IPHONE_SIMULATOR)',
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39179 '#endif // defined(TARGET_IPHONE_SIMULATOR)']
lliabraa35bab3932014-10-01 12:16:44180 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
181 MockInputApi(), MockFile('some/path/source.mm', lines))
182 self.assertEqual(len(lines), len(errors))
183
184 def testValidIfDefinedMacroNames(self):
185 lines = ['#if defined(FOO)',
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39186 '#ifdef BAR']
lliabraa35bab3932014-10-01 12:16:44187 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
188 MockInputApi(), MockFile('some/path/source.cc', lines))
189 self.assertEqual(0, len(errors))
190
191
Samuel Huang0db2ea22019-12-09 16:42:47192class CheckAddedDepsHaveTestApprovalsTest(unittest.TestCase):
Daniel Cheng4dcdb6b2017-04-13 08:30:17193
194 def calculate(self, old_include_rules, old_specific_include_rules,
195 new_include_rules, new_specific_include_rules):
196 return PRESUBMIT._CalculateAddedDeps(
197 os.path, 'include_rules = %r\nspecific_include_rules = %r' % (
198 old_include_rules, old_specific_include_rules),
199 'include_rules = %r\nspecific_include_rules = %r' % (
200 new_include_rules, new_specific_include_rules))
201
202 def testCalculateAddedDeps(self):
203 old_include_rules = [
204 '+base',
205 '-chrome',
206 '+content',
207 '-grit',
208 '-grit/",',
209 '+jni/fooblat.h',
210 '!sandbox',
[email protected]f32e2d1e2013-07-26 21:39:08211 ]
Daniel Cheng4dcdb6b2017-04-13 08:30:17212 old_specific_include_rules = {
213 'compositor\.*': {
214 '+cc',
215 },
216 }
217
218 new_include_rules = [
219 '-ash',
220 '+base',
221 '+chrome',
222 '+components',
223 '+content',
224 '+grit',
225 '+grit/generated_resources.h",',
226 '+grit/",',
227 '+jni/fooblat.h',
228 '+policy',
manzagop85e629e2017-05-09 22:11:48229 '+' + os.path.join('third_party', 'WebKit'),
Daniel Cheng4dcdb6b2017-04-13 08:30:17230 ]
231 new_specific_include_rules = {
232 'compositor\.*': {
233 '+cc',
234 },
235 'widget\.*': {
236 '+gpu',
237 },
238 }
239
[email protected]f32e2d1e2013-07-26 21:39:08240 expected = set([
manzagop85e629e2017-05-09 22:11:48241 os.path.join('chrome', 'DEPS'),
242 os.path.join('gpu', 'DEPS'),
243 os.path.join('components', 'DEPS'),
244 os.path.join('policy', 'DEPS'),
245 os.path.join('third_party', 'WebKit', 'DEPS'),
[email protected]f32e2d1e2013-07-26 21:39:08246 ])
Daniel Cheng4dcdb6b2017-04-13 08:30:17247 self.assertEqual(
248 expected,
249 self.calculate(old_include_rules, old_specific_include_rules,
250 new_include_rules, new_specific_include_rules))
251
252 def testCalculateAddedDepsIgnoresPermutations(self):
253 old_include_rules = [
254 '+base',
255 '+chrome',
256 ]
257 new_include_rules = [
258 '+chrome',
259 '+base',
260 ]
261 self.assertEqual(set(),
262 self.calculate(old_include_rules, {}, new_include_rules,
263 {}))
[email protected]f32e2d1e2013-07-26 21:39:08264
265
[email protected]99171a92014-06-03 08:44:47266class JSONParsingTest(unittest.TestCase):
267 def testSuccess(self):
268 input_api = MockInputApi()
269 filename = 'valid_json.json'
270 contents = ['// This is a comment.',
271 '{',
272 ' "key1": ["value1", "value2"],',
273 ' "key2": 3 // This is an inline comment.',
274 '}'
275 ]
276 input_api.files = [MockFile(filename, contents)]
277 self.assertEqual(None,
278 PRESUBMIT._GetJSONParseError(input_api, filename))
279
280 def testFailure(self):
281 input_api = MockInputApi()
282 test_data = [
283 ('invalid_json_1.json',
284 ['{ x }'],
Dirk Prankee3c9c62d2021-05-18 18:35:59285 'Expecting property name'),
[email protected]99171a92014-06-03 08:44:47286 ('invalid_json_2.json',
287 ['// Hello world!',
288 '{ "hello": "world }'],
[email protected]a3343272014-06-17 11:41:53289 'Unterminated string starting at:'),
[email protected]99171a92014-06-03 08:44:47290 ('invalid_json_3.json',
291 ['{ "a": "b", "c": "d", }'],
Dirk Prankee3c9c62d2021-05-18 18:35:59292 'Expecting property name'),
[email protected]99171a92014-06-03 08:44:47293 ('invalid_json_4.json',
294 ['{ "a": "b" "c": "d" }'],
Dirk Prankee3c9c62d2021-05-18 18:35:59295 "Expecting ',' delimiter:"),
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39296 ]
[email protected]99171a92014-06-03 08:44:47297
298 input_api.files = [MockFile(filename, contents)
299 for (filename, contents, _) in test_data]
300
301 for (filename, _, expected_error) in test_data:
302 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
[email protected]a3343272014-06-17 11:41:53303 self.assertTrue(expected_error in str(actual_error),
304 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47305
306 def testNoEatComments(self):
307 input_api = MockInputApi()
308 file_with_comments = 'file_with_comments.json'
309 contents_with_comments = ['// This is a comment.',
310 '{',
311 ' "key1": ["value1", "value2"],',
312 ' "key2": 3 // This is an inline comment.',
313 '}'
314 ]
315 file_without_comments = 'file_without_comments.json'
316 contents_without_comments = ['{',
317 ' "key1": ["value1", "value2"],',
318 ' "key2": 3',
319 '}'
320 ]
321 input_api.files = [MockFile(file_with_comments, contents_with_comments),
322 MockFile(file_without_comments,
323 contents_without_comments)]
324
Dirk Prankee3c9c62d2021-05-18 18:35:59325 self.assertNotEqual(None,
326 str(PRESUBMIT._GetJSONParseError(input_api,
327 file_with_comments,
328 eat_comments=False)))
[email protected]99171a92014-06-03 08:44:47329 self.assertEqual(None,
330 PRESUBMIT._GetJSONParseError(input_api,
331 file_without_comments,
332 eat_comments=False))
333
334
335class IDLParsingTest(unittest.TestCase):
336 def testSuccess(self):
337 input_api = MockInputApi()
338 filename = 'valid_idl_basics.idl'
339 contents = ['// Tests a valid IDL file.',
340 'namespace idl_basics {',
341 ' enum EnumType {',
342 ' name1,',
343 ' name2',
344 ' };',
345 '',
346 ' dictionary MyType1 {',
347 ' DOMString a;',
348 ' };',
349 '',
350 ' callback Callback1 = void();',
351 ' callback Callback2 = void(long x);',
352 ' callback Callback3 = void(MyType1 arg);',
353 ' callback Callback4 = void(EnumType type);',
354 '',
355 ' interface Functions {',
356 ' static void function1();',
357 ' static void function2(long x);',
358 ' static void function3(MyType1 arg);',
359 ' static void function4(Callback1 cb);',
360 ' static void function5(Callback2 cb);',
361 ' static void function6(Callback3 cb);',
362 ' static void function7(Callback4 cb);',
363 ' };',
364 '',
365 ' interface Events {',
366 ' static void onFoo1();',
367 ' static void onFoo2(long x);',
368 ' static void onFoo2(MyType1 arg);',
369 ' static void onFoo3(EnumType type);',
370 ' };',
371 '};'
372 ]
373 input_api.files = [MockFile(filename, contents)]
374 self.assertEqual(None,
375 PRESUBMIT._GetIDLParseError(input_api, filename))
376
377 def testFailure(self):
378 input_api = MockInputApi()
379 test_data = [
380 ('invalid_idl_1.idl',
381 ['//',
382 'namespace test {',
383 ' dictionary {',
384 ' DOMString s;',
385 ' };',
386 '};'],
387 'Unexpected "{" after keyword "dictionary".\n'),
388 # TODO(yoz): Disabled because it causes the IDL parser to hang.
389 # See crbug.com/363830.
390 # ('invalid_idl_2.idl',
391 # (['namespace test {',
392 # ' dictionary MissingSemicolon {',
393 # ' DOMString a',
394 # ' DOMString b;',
395 # ' };',
396 # '};'],
397 # 'Unexpected symbol DOMString after symbol a.'),
398 ('invalid_idl_3.idl',
399 ['//',
400 'namespace test {',
401 ' enum MissingComma {',
402 ' name1',
403 ' name2',
404 ' };',
405 '};'],
406 'Unexpected symbol name2 after symbol name1.'),
407 ('invalid_idl_4.idl',
408 ['//',
409 'namespace test {',
410 ' enum TrailingComma {',
411 ' name1,',
412 ' name2,',
413 ' };',
414 '};'],
415 'Trailing comma in block.'),
416 ('invalid_idl_5.idl',
417 ['//',
418 'namespace test {',
419 ' callback Callback1 = void(;',
420 '};'],
421 'Unexpected ";" after "(".'),
422 ('invalid_idl_6.idl',
423 ['//',
424 'namespace test {',
425 ' callback Callback1 = void(long );',
426 '};'],
427 'Unexpected ")" after symbol long.'),
428 ('invalid_idl_7.idl',
429 ['//',
430 'namespace test {',
431 ' interace Events {',
432 ' static void onFoo1();',
433 ' };',
434 '};'],
435 'Unexpected symbol Events after symbol interace.'),
436 ('invalid_idl_8.idl',
437 ['//',
438 'namespace test {',
439 ' interface NotEvent {',
440 ' static void onFoo1();',
441 ' };',
442 '};'],
443 'Did not process Interface Interface(NotEvent)'),
444 ('invalid_idl_9.idl',
445 ['//',
446 'namespace test {',
447 ' interface {',
448 ' static void function1();',
449 ' };',
450 '};'],
451 'Interface missing name.'),
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39452 ]
[email protected]99171a92014-06-03 08:44:47453
454 input_api.files = [MockFile(filename, contents)
455 for (filename, contents, _) in test_data]
456
457 for (filename, _, expected_error) in test_data:
458 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
459 self.assertTrue(expected_error in str(actual_error),
460 "'%s' not found in '%s'" % (expected_error, actual_error))
461
462
davileene0426252015-03-02 21:10:41463class UserMetricsActionTest(unittest.TestCase):
464 def testUserMetricsActionInActions(self):
465 input_api = MockInputApi()
466 file_with_user_action = 'file_with_user_action.cc'
467 contents_with_user_action = [
468 'base::UserMetricsAction("AboutChrome")'
469 ]
470
471 input_api.files = [MockFile(file_with_user_action,
472 contents_with_user_action)]
473
474 self.assertEqual(
Saagar Sanghavifceeaae2020-08-12 16:40:36475 [], PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi()))
davileene0426252015-03-02 21:10:41476
davileene0426252015-03-02 21:10:41477 def testUserMetricsActionNotAddedToActions(self):
478 input_api = MockInputApi()
479 file_with_user_action = 'file_with_user_action.cc'
480 contents_with_user_action = [
481 'base::UserMetricsAction("NotInActionsXml")'
482 ]
483
484 input_api.files = [MockFile(file_with_user_action,
485 contents_with_user_action)]
486
Saagar Sanghavifceeaae2020-08-12 16:40:36487 output = PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi())
davileene0426252015-03-02 21:10:41488 self.assertEqual(
489 ('File %s line %d: %s is missing in '
490 'tools/metrics/actions/actions.xml. Please run '
491 'tools/metrics/actions/extract_actions.py to update.'
492 % (file_with_user_action, 1, 'NotInActionsXml')),
493 output[0].message)
494
Alexei Svitkine64505a92021-03-11 22:00:54495 def testUserMetricsActionInTestFile(self):
496 input_api = MockInputApi()
497 file_with_user_action = 'file_with_user_action_unittest.cc'
498 contents_with_user_action = [
499 'base::UserMetricsAction("NotInActionsXml")'
500 ]
501
502 input_api.files = [MockFile(file_with_user_action,
503 contents_with_user_action)]
504
505 self.assertEqual(
506 [], PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi()))
507
davileene0426252015-03-02 21:10:41508
agrievef32bcc72016-04-04 14:57:40509class PydepsNeedsUpdatingTest(unittest.TestCase):
Andrew Grieve4deedb12022-02-03 21:34:50510 class MockPopen:
511 def __init__(self, stdout_func):
512 self._stdout_func = stdout_func
agrievef32bcc72016-04-04 14:57:40513
Andrew Grieve4deedb12022-02-03 21:34:50514 def wait(self):
515 self.stdout = io.StringIO(self._stdout_func())
516 return 0
517
518 class MockSubprocess:
agrievef32bcc72016-04-04 14:57:40519 CalledProcessError = subprocess.CalledProcessError
Andrew Grieve4deedb12022-02-03 21:34:50520 PIPE = 0
521
522 def __init__(self):
523 self._popen_func = None
524
525 def SetPopenCallback(self, func):
526 self._popen_func = func
527
528 def Popen(self, cmd, *args, **kwargs):
529 return PydepsNeedsUpdatingTest.MockPopen(lambda: self._popen_func(cmd))
agrievef32bcc72016-04-04 14:57:40530
Mohamed Heikal7cd4d8312020-06-16 16:49:40531 def _MockParseGclientArgs(self, is_android=True):
532 return lambda: {'checkout_android': 'true' if is_android else 'false' }
533
agrievef32bcc72016-04-04 14:57:40534 def setUp(self):
Mohamed Heikal7cd4d8312020-06-16 16:49:40535 mock_all_pydeps = ['A.pydeps', 'B.pydeps', 'D.pydeps']
agrievef32bcc72016-04-04 14:57:40536 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
537 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
Mohamed Heikal7cd4d8312020-06-16 16:49:40538 mock_android_pydeps = ['D.pydeps']
539 self.old_ANDROID_SPECIFIC_PYDEPS_FILES = (
540 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES)
541 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = mock_android_pydeps
542 self.old_ParseGclientArgs = PRESUBMIT._ParseGclientArgs
543 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs()
agrievef32bcc72016-04-04 14:57:40544 self.mock_input_api = MockInputApi()
545 self.mock_output_api = MockOutputApi()
546 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess()
547 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api, mock_all_pydeps)
548 self.checker._file_cache = {
Andrew Grieve5bb4cf702020-10-22 20:21:39549 'A.pydeps': '# Generated by:\n# CMD --output A.pydeps A\nA.py\nC.py\n',
550 'B.pydeps': '# Generated by:\n# CMD --output B.pydeps B\nB.py\nC.py\n',
551 'D.pydeps': '# Generated by:\n# CMD --output D.pydeps D\nD.py\n',
agrievef32bcc72016-04-04 14:57:40552 }
553
554 def tearDown(self):
555 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
Mohamed Heikal7cd4d8312020-06-16 16:49:40556 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = (
557 self.old_ANDROID_SPECIFIC_PYDEPS_FILES)
558 PRESUBMIT._ParseGclientArgs = self.old_ParseGclientArgs
agrievef32bcc72016-04-04 14:57:40559
560 def _RunCheck(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36561 return PRESUBMIT.CheckPydepsNeedsUpdating(self.mock_input_api,
agrievef32bcc72016-04-04 14:57:40562 self.mock_output_api,
563 checker_for_tests=self.checker)
564
565 def testAddedPydep(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36566 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30567 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13568 return []
569
agrievef32bcc72016-04-04 14:57:40570 self.mock_input_api.files = [
571 MockAffectedFile('new.pydeps', [], action='A'),
572 ]
573
Zhiling Huang45cabf32018-03-10 00:50:03574 self.mock_input_api.CreateMockFileInPath(
575 [x.LocalPath() for x in self.mock_input_api.AffectedFiles(
576 include_deletes=True)])
agrievef32bcc72016-04-04 14:57:40577 results = self._RunCheck()
578 self.assertEqual(1, len(results))
Andrew Grieve5bb4cf702020-10-22 20:21:39579 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40580
Zhiling Huang45cabf32018-03-10 00:50:03581 def testPydepNotInSrc(self):
582 self.mock_input_api.files = [
583 MockAffectedFile('new.pydeps', [], action='A'),
584 ]
585 self.mock_input_api.CreateMockFileInPath([])
586 results = self._RunCheck()
587 self.assertEqual(0, len(results))
588
agrievef32bcc72016-04-04 14:57:40589 def testRemovedPydep(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36590 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30591 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13592 return []
593
agrievef32bcc72016-04-04 14:57:40594 self.mock_input_api.files = [
595 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
596 ]
Zhiling Huang45cabf32018-03-10 00:50:03597 self.mock_input_api.CreateMockFileInPath(
598 [x.LocalPath() for x in self.mock_input_api.AffectedFiles(
599 include_deletes=True)])
agrievef32bcc72016-04-04 14:57:40600 results = self._RunCheck()
601 self.assertEqual(1, len(results))
Andrew Grieve5bb4cf702020-10-22 20:21:39602 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40603
604 def testRandomPyIgnored(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36605 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30606 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13607 return []
608
agrievef32bcc72016-04-04 14:57:40609 self.mock_input_api.files = [
610 MockAffectedFile('random.py', []),
611 ]
612
613 results = self._RunCheck()
614 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
615
616 def testRelevantPyNoChange(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36617 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30618 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13619 return []
620
agrievef32bcc72016-04-04 14:57:40621 self.mock_input_api.files = [
622 MockAffectedFile('A.py', []),
623 ]
624
Andrew Grieve4deedb12022-02-03 21:34:50625 def popen_callback(cmd):
Andrew Grieve5bb4cf702020-10-22 20:21:39626 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
agrievef32bcc72016-04-04 14:57:40627 return self.checker._file_cache['A.pydeps']
628
Andrew Grieve4deedb12022-02-03 21:34:50629 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
agrievef32bcc72016-04-04 14:57:40630
631 results = self._RunCheck()
632 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
633
634 def testRelevantPyOneChange(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36635 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30636 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13637 return []
638
agrievef32bcc72016-04-04 14:57:40639 self.mock_input_api.files = [
640 MockAffectedFile('A.py', []),
641 ]
642
Andrew Grieve4deedb12022-02-03 21:34:50643 def popen_callback(cmd):
Andrew Grieve5bb4cf702020-10-22 20:21:39644 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
agrievef32bcc72016-04-04 14:57:40645 return 'changed data'
646
Andrew Grieve4deedb12022-02-03 21:34:50647 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
agrievef32bcc72016-04-04 14:57:40648
649 results = self._RunCheck()
650 self.assertEqual(1, len(results))
Andrew Grieve4deedb12022-02-03 21:34:50651 # Check that --output "" is not included.
652 self.assertNotIn('""', str(results[0]))
Andrew Grieve5bb4cf702020-10-22 20:21:39653 self.assertIn('File is stale', str(results[0]))
agrievef32bcc72016-04-04 14:57:40654
655 def testRelevantPyTwoChanges(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36656 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30657 if not self.mock_input_api.platform.startswith('linux'):
pastarmovj89f7ee12016-09-20 14:58:13658 return []
659
agrievef32bcc72016-04-04 14:57:40660 self.mock_input_api.files = [
661 MockAffectedFile('C.py', []),
662 ]
663
Andrew Grieve4deedb12022-02-03 21:34:50664 def popen_callback(cmd):
agrievef32bcc72016-04-04 14:57:40665 return 'changed data'
666
Andrew Grieve4deedb12022-02-03 21:34:50667 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
agrievef32bcc72016-04-04 14:57:40668
669 results = self._RunCheck()
670 self.assertEqual(2, len(results))
Andrew Grieve5bb4cf702020-10-22 20:21:39671 self.assertIn('File is stale', str(results[0]))
672 self.assertIn('File is stale', str(results[1]))
agrievef32bcc72016-04-04 14:57:40673
Mohamed Heikal7cd4d8312020-06-16 16:49:40674 def testRelevantAndroidPyInNonAndroidCheckout(self):
Saagar Sanghavifceeaae2020-08-12 16:40:36675 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30676 if not self.mock_input_api.platform.startswith('linux'):
Mohamed Heikal7cd4d8312020-06-16 16:49:40677 return []
678
679 self.mock_input_api.files = [
680 MockAffectedFile('D.py', []),
681 ]
682
Andrew Grieve4deedb12022-02-03 21:34:50683 def popen_callback(cmd):
Andrew Grieve5bb4cf702020-10-22 20:21:39684 self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
Mohamed Heikal7cd4d8312020-06-16 16:49:40685 return 'changed data'
686
Andrew Grieve4deedb12022-02-03 21:34:50687 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Mohamed Heikal7cd4d8312020-06-16 16:49:40688 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(is_android=False)
689
690 results = self._RunCheck()
691 self.assertEqual(1, len(results))
Andrew Grieve5bb4cf702020-10-22 20:21:39692 self.assertIn('Android', str(results[0]))
693 self.assertIn('D.pydeps', str(results[0]))
694
695 def testGnPathsAndMissingOutputFlag(self):
696 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
Xiaohan Wangcef8b002022-01-20 21:34:30697 if not self.mock_input_api.platform.startswith('linux'):
Andrew Grieve5bb4cf702020-10-22 20:21:39698 return []
699
700 self.checker._file_cache = {
701 'A.pydeps': '# Generated by:\n# CMD --gn-paths A\n//A.py\n//C.py\n',
702 'B.pydeps': '# Generated by:\n# CMD --gn-paths B\n//B.py\n//C.py\n',
703 'D.pydeps': '# Generated by:\n# CMD --gn-paths D\n//D.py\n',
704 }
705
706 self.mock_input_api.files = [
707 MockAffectedFile('A.py', []),
708 ]
709
Andrew Grieve4deedb12022-02-03 21:34:50710 def popen_callback(cmd):
Andrew Grieve5bb4cf702020-10-22 20:21:39711 self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""', cmd)
712 return 'changed data'
713
Andrew Grieve4deedb12022-02-03 21:34:50714 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Andrew Grieve5bb4cf702020-10-22 20:21:39715
716 results = self._RunCheck()
717 self.assertEqual(1, len(results))
718 self.assertIn('File is stale', str(results[0]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40719
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39720
Daniel Bratell8ba52722018-03-02 16:06:14721class IncludeGuardTest(unittest.TestCase):
722 def testIncludeGuardChecks(self):
723 mock_input_api = MockInputApi()
724 mock_output_api = MockOutputApi()
725 mock_input_api.files = [
726 MockAffectedFile('content/browser/thing/foo.h', [
727 '// Comment',
728 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
729 '#define CONTENT_BROWSER_THING_FOO_H_',
730 'struct McBoatFace;',
731 '#endif // CONTENT_BROWSER_THING_FOO_H_',
732 ]),
733 MockAffectedFile('content/browser/thing/bar.h', [
734 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
735 '#define CONTENT_BROWSER_THING_BAR_H_',
736 'namespace content {',
737 '#endif // CONTENT_BROWSER_THING_BAR_H_',
738 '} // namespace content',
739 ]),
740 MockAffectedFile('content/browser/test1.h', [
741 'namespace content {',
742 '} // namespace content',
743 ]),
744 MockAffectedFile('content\\browser\\win.h', [
745 '#ifndef CONTENT_BROWSER_WIN_H_',
746 '#define CONTENT_BROWSER_WIN_H_',
747 'struct McBoatFace;',
748 '#endif // CONTENT_BROWSER_WIN_H_',
749 ]),
750 MockAffectedFile('content/browser/test2.h', [
751 '// Comment',
752 '#ifndef CONTENT_BROWSER_TEST2_H_',
753 'struct McBoatFace;',
754 '#endif // CONTENT_BROWSER_TEST2_H_',
755 ]),
756 MockAffectedFile('content/browser/internal.h', [
757 '// Comment',
758 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
759 '#define CONTENT_BROWSER_INTERNAL_H_',
760 '// Comment',
761 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
762 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
763 'namespace internal {',
764 '} // namespace internal',
765 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
766 'namespace content {',
767 '} // namespace content',
768 '#endif // CONTENT_BROWSER_THING_BAR_H_',
769 ]),
770 MockAffectedFile('content/browser/thing/foo.cc', [
771 '// This is a non-header.',
772 ]),
773 MockAffectedFile('content/browser/disabled.h', [
774 '// no-include-guard-because-multiply-included',
775 'struct McBoatFace;',
776 ]),
777 # New files don't allow misspelled include guards.
778 MockAffectedFile('content/browser/spleling.h', [
779 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
780 '#define CONTENT_BROWSER_SPLLEING_H_',
781 'struct McBoatFace;',
782 '#endif // CONTENT_BROWSER_SPLLEING_H_',
783 ]),
Olivier Robinbba137492018-07-30 11:31:34784 # New files don't allow + in include guards.
785 MockAffectedFile('content/browser/foo+bar.h', [
786 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
787 '#define CONTENT_BROWSER_FOO+BAR_H_',
788 'struct McBoatFace;',
789 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
790 ]),
Daniel Bratell8ba52722018-03-02 16:06:14791 # Old files allow misspelled include guards (for now).
792 MockAffectedFile('chrome/old.h', [
793 '// New contents',
794 '#ifndef CHROME_ODL_H_',
795 '#define CHROME_ODL_H_',
796 '#endif // CHROME_ODL_H_',
797 ], [
798 '// Old contents',
799 '#ifndef CHROME_ODL_H_',
800 '#define CHROME_ODL_H_',
801 '#endif // CHROME_ODL_H_',
802 ]),
803 # Using a Blink style include guard outside Blink is wrong.
804 MockAffectedFile('content/NotInBlink.h', [
805 '#ifndef NotInBlink_h',
806 '#define NotInBlink_h',
807 'struct McBoatFace;',
808 '#endif // NotInBlink_h',
809 ]),
Daniel Bratell39b5b062018-05-16 18:09:57810 # Using a Blink style include guard in Blink is no longer ok.
811 MockAffectedFile('third_party/blink/InBlink.h', [
Daniel Bratell8ba52722018-03-02 16:06:14812 '#ifndef InBlink_h',
813 '#define InBlink_h',
814 'struct McBoatFace;',
815 '#endif // InBlink_h',
816 ]),
817 # Using a bad include guard in Blink is not ok.
Daniel Bratell39b5b062018-05-16 18:09:57818 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
Daniel Bratell8ba52722018-03-02 16:06:14819 '#ifndef WrongInBlink_h',
820 '#define WrongInBlink_h',
821 'struct McBoatFace;',
822 '#endif // WrongInBlink_h',
823 ]),
Daniel Bratell39b5b062018-05-16 18:09:57824 # Using a bad include guard in Blink is not accepted even if
825 # it's an old file.
826 MockAffectedFile('third_party/blink/StillInBlink.h', [
Daniel Bratell8ba52722018-03-02 16:06:14827 '// New contents',
828 '#ifndef AcceptedInBlink_h',
829 '#define AcceptedInBlink_h',
830 'struct McBoatFace;',
831 '#endif // AcceptedInBlink_h',
832 ], [
833 '// Old contents',
834 '#ifndef AcceptedInBlink_h',
835 '#define AcceptedInBlink_h',
836 'struct McBoatFace;',
837 '#endif // AcceptedInBlink_h',
838 ]),
Daniel Bratell39b5b062018-05-16 18:09:57839 # Using a non-Chromium include guard in third_party
840 # (outside blink) is accepted.
841 MockAffectedFile('third_party/foo/some_file.h', [
842 '#ifndef REQUIRED_RPCNDR_H_',
843 '#define REQUIRED_RPCNDR_H_',
844 'struct SomeFileFoo;',
845 '#endif // REQUIRED_RPCNDR_H_',
846 ]),
Kinuko Yasuda0cdb3da2019-07-31 21:50:32847 # Not having proper include guard in *_message_generator.h
848 # for old IPC messages is allowed.
849 MockAffectedFile('content/common/content_message_generator.h', [
850 '#undef CONTENT_COMMON_FOO_MESSAGES_H_',
851 '#include "content/common/foo_messages.h"',
852 '#ifndef CONTENT_COMMON_FOO_MESSAGES_H_',
853 '#error "Failed to include content/common/foo_messages.h"',
854 '#endif',
855 ]),
Daniel Bratell8ba52722018-03-02 16:06:14856 ]
Saagar Sanghavifceeaae2020-08-12 16:40:36857 msgs = PRESUBMIT.CheckForIncludeGuards(
Daniel Bratell8ba52722018-03-02 16:06:14858 mock_input_api, mock_output_api)
Olivier Robinbba137492018-07-30 11:31:34859 expected_fail_count = 8
Daniel Bratell8ba52722018-03-02 16:06:14860 self.assertEqual(expected_fail_count, len(msgs),
861 'Expected %d items, found %d: %s'
862 % (expected_fail_count, len(msgs), msgs))
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39863 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
Daniel Bratell8ba52722018-03-02 16:06:14864 self.assertEqual(msgs[0].message,
865 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
866 'not covering the whole file')
867
Bruce Dawson32114b62022-04-11 16:45:49868 self.assertIn('content/browser/test1.h', msgs[1].message)
869 self.assertIn('Recommended name: CONTENT_BROWSER_TEST1_H_',
870 msgs[1].message)
Daniel Bratell8ba52722018-03-02 16:06:14871
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39872 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
Daniel Bratell8ba52722018-03-02 16:06:14873 self.assertEqual(msgs[2].message,
874 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
875 'include guard')
876
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39877 self.assertEqual(msgs[3].items, ['content/browser/spleling.h:1'])
Daniel Bratell8ba52722018-03-02 16:06:14878 self.assertEqual(msgs[3].message,
879 'Header using the wrong include guard name '
880 'CONTENT_BROWSER_SPLLEING_H_')
881
Bruce Dawson32114b62022-04-11 16:45:49882 self.assertIn('content/browser/foo+bar.h', msgs[4].message)
883 self.assertIn('Recommended name: CONTENT_BROWSER_FOO_BAR_H_',
884 msgs[4].message)
Olivier Robinbba137492018-07-30 11:31:34885
886 self.assertEqual(msgs[5].items, ['content/NotInBlink.h:1'])
887 self.assertEqual(msgs[5].message,
Daniel Bratell8ba52722018-03-02 16:06:14888 'Header using the wrong include guard name '
889 'NotInBlink_h')
890
Olivier Robinbba137492018-07-30 11:31:34891 self.assertEqual(msgs[6].items, ['third_party/blink/InBlink.h:1'])
892 self.assertEqual(msgs[6].message,
Daniel Bratell8ba52722018-03-02 16:06:14893 'Header using the wrong include guard name '
Daniel Bratell39b5b062018-05-16 18:09:57894 'InBlink_h')
895
Olivier Robinbba137492018-07-30 11:31:34896 self.assertEqual(msgs[7].items, ['third_party/blink/AlsoInBlink.h:1'])
897 self.assertEqual(msgs[7].message,
Daniel Bratell39b5b062018-05-16 18:09:57898 'Header using the wrong include guard name '
Daniel Bratell8ba52722018-03-02 16:06:14899 'WrongInBlink_h')
900
Chris Hall59f8d0c72020-05-01 07:31:19901class AccessibilityRelnotesFieldTest(unittest.TestCase):
902 def testRelnotesPresent(self):
903 mock_input_api = MockInputApi()
904 mock_output_api = MockOutputApi()
905
906 mock_input_api.files = [MockAffectedFile('ui/accessibility/foo.bar', [''])]
Akihiro Ota08108e542020-05-20 15:30:53907 mock_input_api.change.DescriptionText = lambda : 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:19908 mock_input_api.change.footers['AX-Relnotes'] = [
909 'Important user facing change']
910
Saagar Sanghavifceeaae2020-08-12 16:40:36911 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Chris Hall59f8d0c72020-05-01 07:31:19912 mock_input_api, mock_output_api)
913 self.assertEqual(0, len(msgs),
914 'Expected %d messages, found %d: %s'
915 % (0, len(msgs), msgs))
916
917 def testRelnotesMissingFromAccessibilityChange(self):
918 mock_input_api = MockInputApi()
919 mock_output_api = MockOutputApi()
920
921 mock_input_api.files = [
922 MockAffectedFile('some/file', ['']),
923 MockAffectedFile('ui/accessibility/foo.bar', ['']),
924 MockAffectedFile('some/other/file', [''])
925 ]
Akihiro Ota08108e542020-05-20 15:30:53926 mock_input_api.change.DescriptionText = lambda : 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:19927
Saagar Sanghavifceeaae2020-08-12 16:40:36928 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Chris Hall59f8d0c72020-05-01 07:31:19929 mock_input_api, mock_output_api)
930 self.assertEqual(1, len(msgs),
931 'Expected %d messages, found %d: %s'
932 % (1, len(msgs), msgs))
933 self.assertTrue("Missing 'AX-Relnotes:' field" in msgs[0].message,
934 'Missing AX-Relnotes field message not found in errors')
935
936 # The relnotes footer is not required for changes which do not touch any
937 # accessibility directories.
Gao Shenga79ebd42022-08-08 17:25:59938 def testIgnoresNonAccessibilityCode(self):
Chris Hall59f8d0c72020-05-01 07:31:19939 mock_input_api = MockInputApi()
940 mock_output_api = MockOutputApi()
941
942 mock_input_api.files = [
943 MockAffectedFile('some/file', ['']),
944 MockAffectedFile('some/other/file', [''])
945 ]
Akihiro Ota08108e542020-05-20 15:30:53946 mock_input_api.change.DescriptionText = lambda : 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:19947
Saagar Sanghavifceeaae2020-08-12 16:40:36948 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Chris Hall59f8d0c72020-05-01 07:31:19949 mock_input_api, mock_output_api)
950 self.assertEqual(0, len(msgs),
951 'Expected %d messages, found %d: %s'
952 % (0, len(msgs), msgs))
953
954 # Test that our presubmit correctly raises an error for a set of known paths.
955 def testExpectedPaths(self):
956 filesToTest = [
957 "chrome/browser/accessibility/foo.py",
Henrique Ferreirobb1bb4a2021-03-18 00:04:08958 "chrome/browser/ash/arc/accessibility/foo.cc",
Chris Hall59f8d0c72020-05-01 07:31:19959 "chrome/browser/ui/views/accessibility/foo.h",
960 "chrome/browser/extensions/api/automation/foo.h",
961 "chrome/browser/extensions/api/automation_internal/foo.cc",
962 "chrome/renderer/extensions/accessibility_foo.h",
963 "chrome/tests/data/accessibility/foo.html",
964 "content/browser/accessibility/foo.cc",
965 "content/renderer/accessibility/foo.h",
966 "content/tests/data/accessibility/foo.cc",
967 "extensions/renderer/api/automation/foo.h",
968 "ui/accessibility/foo/bar/baz.cc",
969 "ui/views/accessibility/foo/bar/baz.h",
970 ]
971
972 for testFile in filesToTest:
973 mock_input_api = MockInputApi()
974 mock_output_api = MockOutputApi()
975
976 mock_input_api.files = [
977 MockAffectedFile(testFile, [''])
978 ]
Akihiro Ota08108e542020-05-20 15:30:53979 mock_input_api.change.DescriptionText = lambda : 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:19980
Saagar Sanghavifceeaae2020-08-12 16:40:36981 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Chris Hall59f8d0c72020-05-01 07:31:19982 mock_input_api, mock_output_api)
983 self.assertEqual(1, len(msgs),
984 'Expected %d messages, found %d: %s, for file %s'
985 % (1, len(msgs), msgs, testFile))
986 self.assertTrue("Missing 'AX-Relnotes:' field" in msgs[0].message,
987 ('Missing AX-Relnotes field message not found in errors '
988 ' for file %s' % (testFile)))
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39989
Akihiro Ota08108e542020-05-20 15:30:53990 # Test that AX-Relnotes field can appear in the commit description (as long
991 # as it appears at the beginning of a line).
992 def testRelnotesInCommitDescription(self):
993 mock_input_api = MockInputApi()
994 mock_output_api = MockOutputApi()
995
996 mock_input_api.files = [
997 MockAffectedFile('ui/accessibility/foo.bar', ['']),
998 ]
999 mock_input_api.change.DescriptionText = lambda : ('Description:\n' +
1000 'AX-Relnotes: solves all accessibility issues forever')
1001
Saagar Sanghavifceeaae2020-08-12 16:40:361002 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Akihiro Ota08108e542020-05-20 15:30:531003 mock_input_api, mock_output_api)
1004 self.assertEqual(0, len(msgs),
1005 'Expected %d messages, found %d: %s'
1006 % (0, len(msgs), msgs))
1007
1008 # Test that we don't match AX-Relnotes if it appears in the middle of a line.
1009 def testRelnotesMustAppearAtBeginningOfLine(self):
1010 mock_input_api = MockInputApi()
1011 mock_output_api = MockOutputApi()
1012
1013 mock_input_api.files = [
1014 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1015 ]
1016 mock_input_api.change.DescriptionText = lambda : ('Description:\n' +
1017 'This change has no AX-Relnotes: we should print a warning')
1018
Saagar Sanghavifceeaae2020-08-12 16:40:361019 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Akihiro Ota08108e542020-05-20 15:30:531020 mock_input_api, mock_output_api)
1021 self.assertTrue("Missing 'AX-Relnotes:' field" in msgs[0].message,
1022 'Missing AX-Relnotes field message not found in errors')
1023
1024 # Tests that the AX-Relnotes field can be lowercase and use a '=' in place
1025 # of a ':'.
1026 def testRelnotesLowercaseWithEqualSign(self):
1027 mock_input_api = MockInputApi()
1028 mock_output_api = MockOutputApi()
1029
1030 mock_input_api.files = [
1031 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1032 ]
1033 mock_input_api.change.DescriptionText = lambda : ('Description:\n' +
Gao Shenga79ebd42022-08-08 17:25:591034 'ax-relnotes= this is a valid format for accessibility relnotes')
Akihiro Ota08108e542020-05-20 15:30:531035
Saagar Sanghavifceeaae2020-08-12 16:40:361036 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
Akihiro Ota08108e542020-05-20 15:30:531037 mock_input_api, mock_output_api)
1038 self.assertEqual(0, len(msgs),
1039 'Expected %d messages, found %d: %s'
1040 % (0, len(msgs), msgs))
1041
Mark Schillacie5a0be22022-01-19 00:38:391042class AccessibilityEventsTestsAreIncludedForAndroidTest(unittest.TestCase):
1043 # Test that no warning is raised when the Android file is also modified.
1044 def testAndroidChangeIncluded(self):
1045 mock_input_api = MockInputApi()
1046
1047 mock_input_api.files = [
1048 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1049 [''], action='A'),
1050 MockAffectedFile(
1051 'accessibility/WebContentsAccessibilityEventsTest.java',
1052 [''], action='M')
1053 ]
1054
1055 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1056 mock_input_api, MockOutputApi())
1057 self.assertEqual(0, len(msgs),
1058 'Expected %d messages, found %d: %s'
1059 % (0, len(msgs), msgs))
1060
1061 # Test that a warning is raised when the Android file is not modified.
1062 def testAndroidChangeMissing(self):
1063 mock_input_api = MockInputApi()
1064
1065 mock_input_api.files = [
1066 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1067 [''], action='A'),
1068 ]
1069
1070 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1071 mock_input_api, MockOutputApi())
1072 self.assertEqual(1, len(msgs),
1073 'Expected %d messages, found %d: %s'
1074 % (1, len(msgs), msgs))
1075
1076 # Test that Android change is not required when no html file is added/removed.
1077 def testIgnoreNonHtmlFiles(self):
1078 mock_input_api = MockInputApi()
1079
1080 mock_input_api.files = [
1081 MockAffectedFile('content/test/data/accessibility/event/foo.txt',
1082 [''], action='A'),
1083 MockAffectedFile('content/test/data/accessibility/event/foo.cc',
1084 [''], action='A'),
1085 MockAffectedFile('content/test/data/accessibility/event/foo.h',
1086 [''], action='A'),
1087 MockAffectedFile('content/test/data/accessibility/event/foo.py',
1088 [''], action='A')
1089 ]
1090
1091 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1092 mock_input_api, MockOutputApi())
1093 self.assertEqual(0, len(msgs),
1094 'Expected %d messages, found %d: %s'
1095 % (0, len(msgs), msgs))
1096
1097 # Test that Android change is not required for unrelated html files.
1098 def testIgnoreNonRelatedHtmlFiles(self):
1099 mock_input_api = MockInputApi()
1100
1101 mock_input_api.files = [
1102 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1103 [''], action='A'),
1104 MockAffectedFile('content/test/data/accessibility/html/foo.html',
1105 [''], action='A'),
1106 MockAffectedFile('chrome/tests/data/accessibility/foo.html',
1107 [''], action='A')
1108 ]
1109
1110 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1111 mock_input_api, MockOutputApi())
1112 self.assertEqual(0, len(msgs),
1113 'Expected %d messages, found %d: %s'
1114 % (0, len(msgs), msgs))
1115
1116 # Test that only modifying an html file will not trigger the warning.
1117 def testIgnoreModifiedFiles(self):
1118 mock_input_api = MockInputApi()
1119
1120 mock_input_api.files = [
1121 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1122 [''], action='M')
1123 ]
1124
1125 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1126 mock_input_api, MockOutputApi())
1127 self.assertEqual(0, len(msgs),
1128 'Expected %d messages, found %d: %s'
1129 % (0, len(msgs), msgs))
1130
1131 # Test that deleting an html file will trigger the warning.
1132 def testAndroidChangeMissingOnDeletedFile(self):
1133 mock_input_api = MockInputApi()
1134
1135 mock_input_api.files = [
1136 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1137 [], action='D')
1138 ]
1139
1140 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1141 mock_input_api, MockOutputApi())
1142 self.assertEqual(1, len(msgs),
1143 'Expected %d messages, found %d: %s'
1144 % (1, len(msgs), msgs))
1145
1146class AccessibilityTreeTestsAreIncludedForAndroidTest(unittest.TestCase):
1147 # Test that no warning is raised when the Android file is also modified.
1148 def testAndroidChangeIncluded(self):
1149 mock_input_api = MockInputApi()
1150
1151 mock_input_api.files = [
1152 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1153 [''], action='A'),
1154 MockAffectedFile(
Mark Schillaci6f568a52022-02-17 18:41:441155 'accessibility/WebContentsAccessibilityTreeTest.java',
Mark Schillacie5a0be22022-01-19 00:38:391156 [''], action='M')
1157 ]
1158
1159 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1160 mock_input_api, MockOutputApi())
1161 self.assertEqual(0, len(msgs),
1162 'Expected %d messages, found %d: %s'
1163 % (0, len(msgs), msgs))
1164
1165 # Test that no warning is raised when the Android file is also modified.
1166 def testAndroidChangeIncludedManyFiles(self):
1167 mock_input_api = MockInputApi()
1168
1169 mock_input_api.files = [
1170 MockAffectedFile('content/test/data/accessibility/accname/foo.html',
1171 [''], action='A'),
1172 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1173 [''], action='A'),
1174 MockAffectedFile('content/test/data/accessibility/css/foo.html',
1175 [''], action='A'),
1176 MockAffectedFile('content/test/data/accessibility/html/foo.html',
1177 [''], action='A'),
1178 MockAffectedFile(
Mark Schillaci6f568a52022-02-17 18:41:441179 'accessibility/WebContentsAccessibilityTreeTest.java',
Mark Schillacie5a0be22022-01-19 00:38:391180 [''], action='M')
1181 ]
1182
1183 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1184 mock_input_api, MockOutputApi())
1185 self.assertEqual(0, len(msgs),
1186 'Expected %d messages, found %d: %s'
1187 % (0, len(msgs), msgs))
1188
1189 # Test that a warning is raised when the Android file is not modified.
1190 def testAndroidChangeMissing(self):
1191 mock_input_api = MockInputApi()
1192
1193 mock_input_api.files = [
1194 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1195 [''], action='A'),
1196 ]
1197
1198 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1199 mock_input_api, MockOutputApi())
1200 self.assertEqual(1, len(msgs),
1201 'Expected %d messages, found %d: %s'
1202 % (1, len(msgs), msgs))
1203
1204 # Test that Android change is not required when no html file is added/removed.
1205 def testIgnoreNonHtmlFiles(self):
1206 mock_input_api = MockInputApi()
1207
1208 mock_input_api.files = [
1209 MockAffectedFile('content/test/data/accessibility/accname/foo.txt',
1210 [''], action='A'),
1211 MockAffectedFile('content/test/data/accessibility/aria/foo.cc',
1212 [''], action='A'),
1213 MockAffectedFile('content/test/data/accessibility/css/foo.h',
1214 [''], action='A'),
1215 MockAffectedFile('content/test/data/accessibility/tree/foo.py',
1216 [''], action='A')
1217 ]
1218
1219 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1220 mock_input_api, MockOutputApi())
1221 self.assertEqual(0, len(msgs),
1222 'Expected %d messages, found %d: %s'
1223 % (0, len(msgs), msgs))
1224
1225 # Test that Android change is not required for unrelated html files.
1226 def testIgnoreNonRelatedHtmlFiles(self):
1227 mock_input_api = MockInputApi()
1228
1229 mock_input_api.files = [
1230 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1231 [''], action='A'),
1232 ]
1233
1234 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1235 mock_input_api, MockOutputApi())
1236 self.assertEqual(0, len(msgs),
1237 'Expected %d messages, found %d: %s'
1238 % (0, len(msgs), msgs))
1239
1240 # Test that only modifying an html file will not trigger the warning.
1241 def testIgnoreModifiedFiles(self):
1242 mock_input_api = MockInputApi()
1243
1244 mock_input_api.files = [
1245 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1246 [''], action='M')
1247 ]
1248
1249 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1250 mock_input_api, MockOutputApi())
1251 self.assertEqual(0, len(msgs),
1252 'Expected %d messages, found %d: %s'
1253 % (0, len(msgs), msgs))
1254
1255 # Test that deleting an html file will trigger the warning.
1256 def testAndroidChangeMissingOnDeletedFile(self):
1257 mock_input_api = MockInputApi()
1258
1259 mock_input_api.files = [
1260 MockAffectedFile('content/test/data/accessibility/accname/foo.html',
1261 [], action='D')
1262 ]
1263
1264 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1265 mock_input_api, MockOutputApi())
1266 self.assertEqual(1, len(msgs),
1267 'Expected %d messages, found %d: %s'
1268 % (1, len(msgs), msgs))
1269
yolandyan45001472016-12-21 21:12:421270class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
1271 def testCheckAndroidTestAnnotationUsage(self):
1272 mock_input_api = MockInputApi()
1273 mock_output_api = MockOutputApi()
1274
1275 mock_input_api.files = [
1276 MockAffectedFile('LalaLand.java', [
1277 'random stuff'
1278 ]),
1279 MockAffectedFile('CorrectUsage.java', [
1280 'import android.support.test.filters.LargeTest;',
1281 'import android.support.test.filters.MediumTest;',
1282 'import android.support.test.filters.SmallTest;',
1283 ]),
1284 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1285 'import android.test.suitebuilder.annotation.LargeTest;',
1286 ]),
1287 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1288 'import android.test.suitebuilder.annotation.MediumTest;',
1289 ]),
1290 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1291 'import android.test.suitebuilder.annotation.SmallTest;',
1292 ]),
1293 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1294 'import android.test.suitebuilder.annotation.Smoke;',
1295 ])
1296 ]
1297 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1298 mock_input_api, mock_output_api)
1299 self.assertEqual(1, len(msgs),
1300 'Expected %d items, found %d: %s'
1301 % (1, len(msgs), msgs))
1302 self.assertEqual(4, len(msgs[0].items),
1303 'Expected %d items, found %d: %s'
1304 % (4, len(msgs[0].items), msgs[0].items))
1305 self.assertTrue('UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1306 'UsedDeprecatedLargeTestAnnotation not found in errors')
1307 self.assertTrue('UsedDeprecatedMediumTestAnnotation.java:1'
1308 in msgs[0].items,
1309 'UsedDeprecatedMediumTestAnnotation not found in errors')
1310 self.assertTrue('UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1311 'UsedDeprecatedSmallTestAnnotation not found in errors')
1312 self.assertTrue('UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1313 'UsedDeprecatedSmokeAnnotation not found in errors')
1314
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391315
Mohamed Heikal5e5b7922020-10-29 18:57:591316class CheckNoDownstreamDepsTest(unittest.TestCase):
1317 def testInvalidDepFromUpstream(self):
1318 mock_input_api = MockInputApi()
1319 mock_output_api = MockOutputApi()
1320
1321 mock_input_api.files = [
1322 MockAffectedFile('BUILD.gn', [
1323 'deps = [',
1324 ' "//clank/target:test",',
1325 ']'
1326 ]),
1327 MockAffectedFile('chrome/android/BUILD.gn', [
1328 'deps = [ "//clank/target:test" ]'
1329 ]),
1330 MockAffectedFile('chrome/chrome_java_deps.gni', [
1331 'java_deps = [',
1332 ' "//clank/target:test",',
1333 ']'
1334 ]),
1335 ]
1336 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1337 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
1338 mock_input_api, mock_output_api)
1339 self.assertEqual(1, len(msgs),
1340 'Expected %d items, found %d: %s'
1341 % (1, len(msgs), msgs))
1342 self.assertEqual(3, len(msgs[0].items),
1343 'Expected %d items, found %d: %s'
1344 % (3, len(msgs[0].items), msgs[0].items))
1345 self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
1346 'BUILD.gn not found in errors')
1347 self.assertTrue(
1348 any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
1349 'chrome/android/BUILD.gn:1 not found in errors')
1350 self.assertTrue(
1351 any('chrome/chrome_java_deps.gni:2' in item for item in msgs[0].items),
1352 'chrome/chrome_java_deps.gni:2 not found in errors')
1353
1354 def testAllowsComments(self):
1355 mock_input_api = MockInputApi()
1356 mock_output_api = MockOutputApi()
1357
1358 mock_input_api.files = [
1359 MockAffectedFile('BUILD.gn', [
1360 '# real implementation in //clank/target:test',
1361 ]),
1362 ]
1363 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1364 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
1365 mock_input_api, mock_output_api)
1366 self.assertEqual(0, len(msgs),
1367 'Expected %d items, found %d: %s'
1368 % (0, len(msgs), msgs))
1369
1370 def testOnlyChecksBuildFiles(self):
1371 mock_input_api = MockInputApi()
1372 mock_output_api = MockOutputApi()
1373
1374 mock_input_api.files = [
1375 MockAffectedFile('README.md', [
1376 'DEPS = [ "//clank/target:test" ]'
1377 ]),
1378 MockAffectedFile('chrome/android/java/file.java', [
1379 '//clank/ only function'
1380 ]),
1381 ]
1382 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1383 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
1384 mock_input_api, mock_output_api)
1385 self.assertEqual(0, len(msgs),
1386 'Expected %d items, found %d: %s'
1387 % (0, len(msgs), msgs))
1388
1389 def testValidDepFromDownstream(self):
1390 mock_input_api = MockInputApi()
1391 mock_output_api = MockOutputApi()
1392
1393 mock_input_api.files = [
1394 MockAffectedFile('BUILD.gn', [
1395 'DEPS = [',
1396 ' "//clank/target:test",',
1397 ']'
1398 ]),
1399 MockAffectedFile('java/BUILD.gn', [
1400 'DEPS = [ "//clank/target:test" ]'
1401 ]),
1402 ]
1403 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
1404 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(
1405 mock_input_api, mock_output_api)
1406 self.assertEqual(0, len(msgs),
1407 'Expected %d items, found %d: %s'
1408 % (0, len(msgs), msgs))
1409
Yoland Yanb92fa522017-08-28 17:37:061410class AndroidDeprecatedJUnitFrameworkTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:271411 def testCheckAndroidTestJUnitFramework(self):
Yoland Yanb92fa522017-08-28 17:37:061412 mock_input_api = MockInputApi()
1413 mock_output_api = MockOutputApi()
yolandyan45001472016-12-21 21:12:421414
Yoland Yanb92fa522017-08-28 17:37:061415 mock_input_api.files = [
1416 MockAffectedFile('LalaLand.java', [
1417 'random stuff'
1418 ]),
1419 MockAffectedFile('CorrectUsage.java', [
1420 'import org.junit.ABC',
1421 'import org.junit.XYZ;',
1422 ]),
1423 MockAffectedFile('UsedDeprecatedJUnit.java', [
1424 'import junit.framework.*;',
1425 ]),
1426 MockAffectedFile('UsedDeprecatedJUnitAssert.java', [
1427 'import junit.framework.Assert;',
1428 ]),
1429 ]
1430 msgs = PRESUBMIT._CheckAndroidTestJUnitFrameworkImport(
1431 mock_input_api, mock_output_api)
1432 self.assertEqual(1, len(msgs),
1433 'Expected %d items, found %d: %s'
1434 % (1, len(msgs), msgs))
1435 self.assertEqual(2, len(msgs[0].items),
1436 'Expected %d items, found %d: %s'
1437 % (2, len(msgs[0].items), msgs[0].items))
1438 self.assertTrue('UsedDeprecatedJUnit.java:1' in msgs[0].items,
1439 'UsedDeprecatedJUnit.java not found in errors')
1440 self.assertTrue('UsedDeprecatedJUnitAssert.java:1'
1441 in msgs[0].items,
1442 'UsedDeprecatedJUnitAssert not found in errors')
1443
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391444
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:271445class AndroidJUnitBaseClassTest(unittest.TestCase):
1446 def testCheckAndroidTestJUnitBaseClass(self):
Yoland Yanb92fa522017-08-28 17:37:061447 mock_input_api = MockInputApi()
1448 mock_output_api = MockOutputApi()
1449
1450 mock_input_api.files = [
1451 MockAffectedFile('LalaLand.java', [
1452 'random stuff'
1453 ]),
1454 MockAffectedFile('CorrectTest.java', [
1455 '@RunWith(ABC.class);'
1456 'public class CorrectTest {',
1457 '}',
1458 ]),
1459 MockAffectedFile('HistoricallyIncorrectTest.java', [
1460 'public class Test extends BaseCaseA {',
1461 '}',
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391462 ], old_contents=[
Yoland Yanb92fa522017-08-28 17:37:061463 'public class Test extends BaseCaseB {',
1464 '}',
1465 ]),
1466 MockAffectedFile('CorrectTestWithInterface.java', [
1467 '@RunWith(ABC.class);'
1468 'public class CorrectTest implement Interface {',
1469 '}',
1470 ]),
1471 MockAffectedFile('IncorrectTest.java', [
1472 'public class IncorrectTest extends TestCase {',
1473 '}',
1474 ]),
Vaclav Brozekf01ed502018-03-16 19:38:241475 MockAffectedFile('IncorrectWithInterfaceTest.java', [
Yoland Yanb92fa522017-08-28 17:37:061476 'public class Test implements X extends BaseClass {',
1477 '}',
1478 ]),
Vaclav Brozekf01ed502018-03-16 19:38:241479 MockAffectedFile('IncorrectMultiLineTest.java', [
Yoland Yanb92fa522017-08-28 17:37:061480 'public class Test implements X, Y, Z',
1481 ' extends TestBase {',
1482 '}',
1483 ]),
1484 ]
1485 msgs = PRESUBMIT._CheckAndroidTestJUnitInheritance(
1486 mock_input_api, mock_output_api)
1487 self.assertEqual(1, len(msgs),
1488 'Expected %d items, found %d: %s'
1489 % (1, len(msgs), msgs))
1490 self.assertEqual(3, len(msgs[0].items),
1491 'Expected %d items, found %d: %s'
1492 % (3, len(msgs[0].items), msgs[0].items))
1493 self.assertTrue('IncorrectTest.java:1' in msgs[0].items,
1494 'IncorrectTest not found in errors')
Vaclav Brozekf01ed502018-03-16 19:38:241495 self.assertTrue('IncorrectWithInterfaceTest.java:1'
Yoland Yanb92fa522017-08-28 17:37:061496 in msgs[0].items,
Vaclav Brozekf01ed502018-03-16 19:38:241497 'IncorrectWithInterfaceTest not found in errors')
1498 self.assertTrue('IncorrectMultiLineTest.java:2' in msgs[0].items,
1499 'IncorrectMultiLineTest not found in errors')
yolandyan45001472016-12-21 21:12:421500
Jinsong Fan91ebbbd2019-04-16 14:57:171501class AndroidDebuggableBuildTest(unittest.TestCase):
1502
1503 def testCheckAndroidDebuggableBuild(self):
1504 mock_input_api = MockInputApi()
1505 mock_output_api = MockOutputApi()
1506
1507 mock_input_api.files = [
1508 MockAffectedFile('RandomStuff.java', [
1509 'random stuff'
1510 ]),
1511 MockAffectedFile('CorrectUsage.java', [
1512 'import org.chromium.base.BuildInfo;',
1513 'some random stuff',
1514 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1515 ]),
1516 MockAffectedFile('JustCheckUserdebugBuild.java', [
1517 'import android.os.Build;',
1518 'some random stuff',
1519 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1520 ]),
1521 MockAffectedFile('JustCheckEngineeringBuild.java', [
1522 'import android.os.Build;',
1523 'some random stuff',
1524 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1525 ]),
1526 MockAffectedFile('UsedBuildType.java', [
1527 'import android.os.Build;',
1528 'some random stuff',
1529 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1530 '|| "eng".equals(Build.TYPE)',
1531 ]),
1532 MockAffectedFile('UsedExplicitBuildType.java', [
1533 'some random stuff',
1534 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1535 '|| "eng".equals(android.os.Build.TYPE)',
1536 ]),
1537 ]
1538
1539 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(
1540 mock_input_api, mock_output_api)
1541 self.assertEqual(1, len(msgs),
1542 'Expected %d items, found %d: %s'
1543 % (1, len(msgs), msgs))
1544 self.assertEqual(4, len(msgs[0].items),
1545 'Expected %d items, found %d: %s'
1546 % (4, len(msgs[0].items), msgs[0].items))
1547 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1548 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1549 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1550 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
1551
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391552
dgn4401aa52015-04-29 16:26:171553class LogUsageTest(unittest.TestCase):
1554
dgnaa68d5e2015-06-10 10:08:221555 def testCheckAndroidCrLogUsage(self):
1556 mock_input_api = MockInputApi()
1557 mock_output_api = MockOutputApi()
1558
1559 mock_input_api.files = [
1560 MockAffectedFile('RandomStuff.java', [
1561 'random stuff'
1562 ]),
dgn87d9fb62015-06-12 09:15:121563 MockAffectedFile('HasAndroidLog.java', [
1564 'import android.util.Log;',
1565 'some random stuff',
1566 'Log.d("TAG", "foo");',
1567 ]),
1568 MockAffectedFile('HasExplicitUtilLog.java', [
1569 'some random stuff',
1570 'android.util.Log.d("TAG", "foo");',
1571 ]),
1572 MockAffectedFile('IsInBasePackage.java', [
1573 'package org.chromium.base;',
dgn38736db2015-09-18 19:20:511574 'private static final String TAG = "cr_Foo";',
dgn87d9fb62015-06-12 09:15:121575 'Log.d(TAG, "foo");',
1576 ]),
1577 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1578 'package org.chromium.base;',
1579 'import android.util.Log;',
dgn38736db2015-09-18 19:20:511580 'private static final String TAG = "cr_Foo";',
dgn87d9fb62015-06-12 09:15:121581 'Log.d(TAG, "foo");',
1582 ]),
1583 MockAffectedFile('HasBothLog.java', [
1584 'import org.chromium.base.Log;',
1585 'some random stuff',
dgn38736db2015-09-18 19:20:511586 'private static final String TAG = "cr_Foo";',
dgn87d9fb62015-06-12 09:15:121587 'Log.d(TAG, "foo");',
1588 'android.util.Log.d("TAG", "foo");',
1589 ]),
dgnaa68d5e2015-06-10 10:08:221590 MockAffectedFile('HasCorrectTag.java', [
1591 'import org.chromium.base.Log;',
1592 'some random stuff',
dgn38736db2015-09-18 19:20:511593 'private static final String TAG = "cr_Foo";',
1594 'Log.d(TAG, "foo");',
1595 ]),
1596 MockAffectedFile('HasOldTag.java', [
1597 'import org.chromium.base.Log;',
1598 'some random stuff',
dgnaa68d5e2015-06-10 10:08:221599 'private static final String TAG = "cr.Foo";',
1600 'Log.d(TAG, "foo");',
1601 ]),
dgn38736db2015-09-18 19:20:511602 MockAffectedFile('HasDottedTag.java', [
dgnaa68d5e2015-06-10 10:08:221603 'import org.chromium.base.Log;',
1604 'some random stuff',
dgn38736db2015-09-18 19:20:511605 'private static final String TAG = "cr_foo.bar";',
dgnaa68d5e2015-06-10 10:08:221606 'Log.d(TAG, "foo");',
1607 ]),
Torne (Richard Coles)3bd7ad02019-10-22 21:20:461608 MockAffectedFile('HasDottedTagPublic.java', [
1609 'import org.chromium.base.Log;',
1610 'some random stuff',
1611 'public static final String TAG = "cr_foo.bar";',
1612 'Log.d(TAG, "foo");',
1613 ]),
dgnaa68d5e2015-06-10 10:08:221614 MockAffectedFile('HasNoTagDecl.java', [
1615 'import org.chromium.base.Log;',
1616 'some random stuff',
1617 'Log.d(TAG, "foo");',
1618 ]),
1619 MockAffectedFile('HasIncorrectTagDecl.java', [
1620 'import org.chromium.base.Log;',
dgn38736db2015-09-18 19:20:511621 'private static final String TAHG = "cr_Foo";',
dgnaa68d5e2015-06-10 10:08:221622 'some random stuff',
1623 'Log.d(TAG, "foo");',
1624 ]),
1625 MockAffectedFile('HasInlineTag.java', [
1626 'import org.chromium.base.Log;',
1627 'some random stuff',
dgn38736db2015-09-18 19:20:511628 'private static final String TAG = "cr_Foo";',
dgnaa68d5e2015-06-10 10:08:221629 'Log.d("TAG", "foo");',
1630 ]),
Tomasz Śniatowski3ae2f102020-03-23 15:35:551631 MockAffectedFile('HasInlineTagWithSpace.java', [
1632 'import org.chromium.base.Log;',
1633 'some random stuff',
1634 'private static final String TAG = "cr_Foo";',
1635 'Log.d("log message", "foo");',
1636 ]),
dgn38736db2015-09-18 19:20:511637 MockAffectedFile('HasUnprefixedTag.java', [
dgnaa68d5e2015-06-10 10:08:221638 'import org.chromium.base.Log;',
1639 'some random stuff',
1640 'private static final String TAG = "rubbish";',
1641 'Log.d(TAG, "foo");',
1642 ]),
1643 MockAffectedFile('HasTooLongTag.java', [
1644 'import org.chromium.base.Log;',
1645 'some random stuff',
Gao Shenga79ebd42022-08-08 17:25:591646 'private static final String TAG = "21_characters_long___";',
dgnaa68d5e2015-06-10 10:08:221647 'Log.d(TAG, "foo");',
1648 ]),
Tomasz Śniatowski3ae2f102020-03-23 15:35:551649 MockAffectedFile('HasTooLongTagWithNoLogCallsInDiff.java', [
1650 'import org.chromium.base.Log;',
1651 'some random stuff',
Gao Shenga79ebd42022-08-08 17:25:591652 'private static final String TAG = "21_characters_long___";',
Tomasz Śniatowski3ae2f102020-03-23 15:35:551653 ]),
dgnaa68d5e2015-06-10 10:08:221654 ]
1655
1656 msgs = PRESUBMIT._CheckAndroidCrLogUsage(
1657 mock_input_api, mock_output_api)
1658
dgn38736db2015-09-18 19:20:511659 self.assertEqual(5, len(msgs),
1660 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
dgnaa68d5e2015-06-10 10:08:221661
1662 # Declaration format
dgn38736db2015-09-18 19:20:511663 nb = len(msgs[0].items)
1664 self.assertEqual(2, nb,
1665 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
dgnaa68d5e2015-06-10 10:08:221666 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1667 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
dgnaa68d5e2015-06-10 10:08:221668
1669 # Tag length
dgn38736db2015-09-18 19:20:511670 nb = len(msgs[1].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551671 self.assertEqual(2, nb,
1672 'Expected %d items, found %d: %s' % (2, nb, msgs[1].items))
dgnaa68d5e2015-06-10 10:08:221673 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551674 self.assertTrue('HasTooLongTagWithNoLogCallsInDiff.java' in msgs[1].items)
dgnaa68d5e2015-06-10 10:08:221675
1676 # Tag must be a variable named TAG
dgn38736db2015-09-18 19:20:511677 nb = len(msgs[2].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551678 self.assertEqual(3, nb,
1679 'Expected %d items, found %d: %s' % (3, nb, msgs[2].items))
1680 self.assertTrue('HasBothLog.java:5' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221681 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551682 self.assertTrue('HasInlineTagWithSpace.java:4' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221683
dgn87d9fb62015-06-12 09:15:121684 # Util Log usage
dgn38736db2015-09-18 19:20:511685 nb = len(msgs[3].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551686 self.assertEqual(3, nb,
1687 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
dgn87d9fb62015-06-12 09:15:121688 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
Tomasz Śniatowski3ae2f102020-03-23 15:35:551689 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
dgn87d9fb62015-06-12 09:15:121690 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
dgnaa68d5e2015-06-10 10:08:221691
dgn38736db2015-09-18 19:20:511692 # Tag must not contain
1693 nb = len(msgs[4].items)
Torne (Richard Coles)3bd7ad02019-10-22 21:20:461694 self.assertEqual(3, nb,
dgn38736db2015-09-18 19:20:511695 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1696 self.assertTrue('HasDottedTag.java' in msgs[4].items)
Torne (Richard Coles)3bd7ad02019-10-22 21:20:461697 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511698 self.assertTrue('HasOldTag.java' in msgs[4].items)
1699
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391700
estadee17314a02017-01-12 16:22:161701class GoogleAnswerUrlFormatTest(unittest.TestCase):
1702
1703 def testCatchAnswerUrlId(self):
1704 input_api = MockInputApi()
1705 input_api.files = [
1706 MockFile('somewhere/file.cc',
1707 ['char* host = '
1708 ' "https://support.google.com/chrome/answer/123456";']),
1709 MockFile('somewhere_else/file.cc',
1710 ['char* host = '
1711 ' "https://support.google.com/chrome/a/answer/123456";']),
1712 ]
1713
Saagar Sanghavifceeaae2020-08-12 16:40:361714 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
estadee17314a02017-01-12 16:22:161715 input_api, MockOutputApi())
1716 self.assertEqual(1, len(warnings))
1717 self.assertEqual(2, len(warnings[0].items))
1718
1719 def testAllowAnswerUrlParam(self):
1720 input_api = MockInputApi()
1721 input_api.files = [
1722 MockFile('somewhere/file.cc',
1723 ['char* host = '
1724 ' "https://support.google.com/chrome/?p=cpn_crash_reports";']),
1725 ]
1726
Saagar Sanghavifceeaae2020-08-12 16:40:361727 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
estadee17314a02017-01-12 16:22:161728 input_api, MockOutputApi())
1729 self.assertEqual(0, len(warnings))
1730
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391731
reillyi38965732015-11-16 18:27:331732class HardcodedGoogleHostsTest(unittest.TestCase):
1733
1734 def testWarnOnAssignedLiterals(self):
1735 input_api = MockInputApi()
1736 input_api.files = [
1737 MockFile('content/file.cc',
1738 ['char* host = "https://www.google.com";']),
1739 MockFile('content/file.cc',
1740 ['char* host = "https://www.googleapis.com";']),
1741 MockFile('content/file.cc',
1742 ['char* host = "https://clients1.google.com";']),
1743 ]
1744
Saagar Sanghavifceeaae2020-08-12 16:40:361745 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
reillyi38965732015-11-16 18:27:331746 input_api, MockOutputApi())
1747 self.assertEqual(1, len(warnings))
1748 self.assertEqual(3, len(warnings[0].items))
1749
1750 def testAllowInComment(self):
1751 input_api = MockInputApi()
1752 input_api.files = [
1753 MockFile('content/file.cc',
1754 ['char* host = "https://www.aol.com"; // google.com'])
1755 ]
1756
Saagar Sanghavifceeaae2020-08-12 16:40:361757 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
reillyi38965732015-11-16 18:27:331758 input_api, MockOutputApi())
1759 self.assertEqual(0, len(warnings))
1760
dgn4401aa52015-04-29 16:26:171761
James Cook6b6597c2019-11-06 22:05:291762class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1763
1764 def testWarnsOnChromeOsDirectories(self):
Henrique Ferreiro2e1aa1092021-11-29 22:22:121765 files = [
James Cook6b6597c2019-11-06 22:05:291766 MockFile('ash/file.cc',
1767 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1768 MockFile('chrome/browser/chromeos/file.cc',
1769 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1770 MockFile('chromeos/file.cc',
1771 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1772 MockFile('components/arc/file.cc',
1773 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1774 MockFile('components/exo/file.cc',
1775 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1776 ]
Henrique Ferreiro2e1aa1092021-11-29 22:22:121777 input_api = MockInputApi()
1778 for file in files:
1779 input_api.files = [file]
1780 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1781 input_api, MockOutputApi())
1782 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291783
1784 def testDoesNotWarnOnSyncOsPref(self):
1785 input_api = MockInputApi()
1786 input_api.files = [
1787 MockFile('chromeos/file.cc',
1788 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1789 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361790 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
James Cook6b6597c2019-11-06 22:05:291791 input_api, MockOutputApi())
1792 self.assertEqual(0, len(warnings))
1793
Henrique Ferreiro2e1aa1092021-11-29 22:22:121794 def testDoesNotWarnOnOtherDirectories(self):
James Cook6b6597c2019-11-06 22:05:291795 input_api = MockInputApi()
1796 input_api.files = [
1797 MockFile('chrome/browser/ui/file.cc',
1798 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1799 MockFile('components/sync/file.cc',
1800 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1801 MockFile('content/browser/file.cc',
1802 ['PrefRegistrySyncable::SYNCABLE_PREF']),
Henrique Ferreiro2e1aa1092021-11-29 22:22:121803 MockFile('a/notchromeos/file.cc',
1804 ['PrefRegistrySyncable::SYNCABLE_PREF']),
James Cook6b6597c2019-11-06 22:05:291805 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361806 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
James Cook6b6597c2019-11-06 22:05:291807 input_api, MockOutputApi())
1808 self.assertEqual(0, len(warnings))
1809
1810 def testSeparateWarningForPriorityPrefs(self):
1811 input_api = MockInputApi()
1812 input_api.files = [
1813 MockFile('chromeos/file.cc',
1814 ['PrefRegistrySyncable::SYNCABLE_PREF',
1815 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF']),
1816 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361817 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
James Cook6b6597c2019-11-06 22:05:291818 input_api, MockOutputApi())
1819 self.assertEqual(2, len(warnings))
1820
1821
jbriance9e12f162016-11-25 07:57:501822class ForwardDeclarationTest(unittest.TestCase):
jbriance2c51e821a2016-12-12 08:24:311823 def testCheckHeadersOnlyOutsideThirdParty(self):
jbriance9e12f162016-11-25 07:57:501824 mock_input_api = MockInputApi()
1825 mock_input_api.files = [
1826 MockAffectedFile('somewhere/file.cc', [
1827 'class DummyClass;'
jbriance2c51e821a2016-12-12 08:24:311828 ]),
1829 MockAffectedFile('third_party/header.h', [
1830 'class DummyClass;'
jbriance9e12f162016-11-25 07:57:501831 ])
1832 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361833 warnings = PRESUBMIT.CheckUselessForwardDeclarations(mock_input_api,
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391834 MockOutputApi())
jbriance9e12f162016-11-25 07:57:501835 self.assertEqual(0, len(warnings))
1836
1837 def testNoNestedDeclaration(self):
1838 mock_input_api = MockInputApi()
1839 mock_input_api.files = [
1840 MockAffectedFile('somewhere/header.h', [
jbriance2c51e821a2016-12-12 08:24:311841 'class SomeClass {',
1842 ' protected:',
1843 ' class NotAMatch;',
jbriance9e12f162016-11-25 07:57:501844 '};'
1845 ])
1846 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361847 warnings = PRESUBMIT.CheckUselessForwardDeclarations(mock_input_api,
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391848 MockOutputApi())
jbriance9e12f162016-11-25 07:57:501849 self.assertEqual(0, len(warnings))
1850
1851 def testSubStrings(self):
1852 mock_input_api = MockInputApi()
1853 mock_input_api.files = [
1854 MockAffectedFile('somewhere/header.h', [
1855 'class NotUsefulClass;',
1856 'struct SomeStruct;',
1857 'UsefulClass *p1;',
1858 'SomeStructPtr *p2;'
1859 ])
1860 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361861 warnings = PRESUBMIT.CheckUselessForwardDeclarations(mock_input_api,
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391862 MockOutputApi())
jbriance9e12f162016-11-25 07:57:501863 self.assertEqual(2, len(warnings))
1864
1865 def testUselessForwardDeclaration(self):
1866 mock_input_api = MockInputApi()
1867 mock_input_api.files = [
1868 MockAffectedFile('somewhere/header.h', [
1869 'class DummyClass;',
1870 'struct DummyStruct;',
1871 'class UsefulClass;',
1872 'std::unique_ptr<UsefulClass> p;'
jbriance2c51e821a2016-12-12 08:24:311873 ])
jbriance9e12f162016-11-25 07:57:501874 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361875 warnings = PRESUBMIT.CheckUselessForwardDeclarations(mock_input_api,
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391876 MockOutputApi())
jbriance9e12f162016-11-25 07:57:501877 self.assertEqual(2, len(warnings))
1878
jbriance2c51e821a2016-12-12 08:24:311879 def testBlinkHeaders(self):
1880 mock_input_api = MockInputApi()
1881 mock_input_api.files = [
Kent Tamura32dbbcb2018-11-30 12:28:491882 MockAffectedFile('third_party/blink/header.h', [
jbriance2c51e821a2016-12-12 08:24:311883 'class DummyClass;',
1884 'struct DummyStruct;',
1885 ]),
Kent Tamura32dbbcb2018-11-30 12:28:491886 MockAffectedFile('third_party\\blink\\header.h', [
jbriance2c51e821a2016-12-12 08:24:311887 'class DummyClass;',
1888 'struct DummyStruct;',
1889 ])
1890 ]
Saagar Sanghavifceeaae2020-08-12 16:40:361891 warnings = PRESUBMIT.CheckUselessForwardDeclarations(mock_input_api,
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391892 MockOutputApi())
jbriance2c51e821a2016-12-12 08:24:311893 self.assertEqual(4, len(warnings))
1894
jbriance9e12f162016-11-25 07:57:501895
rlanday6802cf632017-05-30 17:48:361896class RelativeIncludesTest(unittest.TestCase):
1897 def testThirdPartyNotWebKitIgnored(self):
1898 mock_input_api = MockInputApi()
1899 mock_input_api.files = [
1900 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1901 MockAffectedFile('third_party/test/test.cpp', '#include "../header.h"'),
1902 ]
1903
1904 mock_output_api = MockOutputApi()
1905
Saagar Sanghavifceeaae2020-08-12 16:40:361906 errors = PRESUBMIT.CheckForRelativeIncludes(
rlanday6802cf632017-05-30 17:48:361907 mock_input_api, mock_output_api)
1908 self.assertEqual(0, len(errors))
1909
1910 def testNonCppFileIgnored(self):
1911 mock_input_api = MockInputApi()
1912 mock_input_api.files = [
1913 MockAffectedFile('test.py', '#include "../header.h"'),
1914 ]
1915
1916 mock_output_api = MockOutputApi()
1917
Saagar Sanghavifceeaae2020-08-12 16:40:361918 errors = PRESUBMIT.CheckForRelativeIncludes(
rlanday6802cf632017-05-30 17:48:361919 mock_input_api, mock_output_api)
1920 self.assertEqual(0, len(errors))
1921
1922 def testInnocuousChangesAllowed(self):
1923 mock_input_api = MockInputApi()
1924 mock_input_api.files = [
1925 MockAffectedFile('test.cpp', '#include "header.h"'),
1926 MockAffectedFile('test2.cpp', '../'),
1927 ]
1928
1929 mock_output_api = MockOutputApi()
1930
Saagar Sanghavifceeaae2020-08-12 16:40:361931 errors = PRESUBMIT.CheckForRelativeIncludes(
rlanday6802cf632017-05-30 17:48:361932 mock_input_api, mock_output_api)
1933 self.assertEqual(0, len(errors))
1934
1935 def testRelativeIncludeNonWebKitProducesError(self):
1936 mock_input_api = MockInputApi()
1937 mock_input_api.files = [
1938 MockAffectedFile('test.cpp', ['#include "../header.h"']),
1939 ]
1940
1941 mock_output_api = MockOutputApi()
1942
Saagar Sanghavifceeaae2020-08-12 16:40:361943 errors = PRESUBMIT.CheckForRelativeIncludes(
rlanday6802cf632017-05-30 17:48:361944 mock_input_api, mock_output_api)
1945 self.assertEqual(1, len(errors))
1946
1947 def testRelativeIncludeWebKitProducesError(self):
1948 mock_input_api = MockInputApi()
1949 mock_input_api.files = [
Kent Tamura32dbbcb2018-11-30 12:28:491950 MockAffectedFile('third_party/blink/test.cpp',
rlanday6802cf632017-05-30 17:48:361951 ['#include "../header.h']),
1952 ]
1953
1954 mock_output_api = MockOutputApi()
1955
Saagar Sanghavifceeaae2020-08-12 16:40:361956 errors = PRESUBMIT.CheckForRelativeIncludes(
rlanday6802cf632017-05-30 17:48:361957 mock_input_api, mock_output_api)
1958 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:241959
Daniel Cheng13ca61a882017-08-25 15:11:251960
Daniel Bratell65b033262019-04-23 08:17:061961class CCIncludeTest(unittest.TestCase):
1962 def testThirdPartyNotBlinkIgnored(self):
1963 mock_input_api = MockInputApi()
1964 mock_input_api.files = [
1965 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
1966 ]
1967
1968 mock_output_api = MockOutputApi()
1969
Saagar Sanghavifceeaae2020-08-12 16:40:361970 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:061971 mock_input_api, mock_output_api)
1972 self.assertEqual(0, len(errors))
1973
1974 def testPythonFileIgnored(self):
1975 mock_input_api = MockInputApi()
1976 mock_input_api.files = [
1977 MockAffectedFile('test.py', '#include "file.cc"'),
1978 ]
1979
1980 mock_output_api = MockOutputApi()
1981
Saagar Sanghavifceeaae2020-08-12 16:40:361982 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:061983 mock_input_api, mock_output_api)
1984 self.assertEqual(0, len(errors))
1985
1986 def testIncFilesAccepted(self):
1987 mock_input_api = MockInputApi()
1988 mock_input_api.files = [
1989 MockAffectedFile('test.py', '#include "file.inc"'),
1990 ]
1991
1992 mock_output_api = MockOutputApi()
1993
Saagar Sanghavifceeaae2020-08-12 16:40:361994 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:061995 mock_input_api, mock_output_api)
1996 self.assertEqual(0, len(errors))
1997
1998 def testInnocuousChangesAllowed(self):
1999 mock_input_api = MockInputApi()
2000 mock_input_api.files = [
2001 MockAffectedFile('test.cpp', '#include "header.h"'),
2002 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2003 ]
2004
2005 mock_output_api = MockOutputApi()
2006
Saagar Sanghavifceeaae2020-08-12 16:40:362007 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:062008 mock_input_api, mock_output_api)
2009 self.assertEqual(0, len(errors))
2010
2011 def testCcIncludeNonBlinkProducesError(self):
2012 mock_input_api = MockInputApi()
2013 mock_input_api.files = [
2014 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2015 ]
2016
2017 mock_output_api = MockOutputApi()
2018
Saagar Sanghavifceeaae2020-08-12 16:40:362019 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:062020 mock_input_api, mock_output_api)
2021 self.assertEqual(1, len(errors))
2022
2023 def testCppIncludeBlinkProducesError(self):
2024 mock_input_api = MockInputApi()
2025 mock_input_api.files = [
2026 MockAffectedFile('third_party/blink/test.cpp',
2027 ['#include "foo/file.cpp"']),
2028 ]
2029
2030 mock_output_api = MockOutputApi()
2031
Saagar Sanghavifceeaae2020-08-12 16:40:362032 errors = PRESUBMIT.CheckForCcIncludes(
Daniel Bratell65b033262019-04-23 08:17:062033 mock_input_api, mock_output_api)
2034 self.assertEqual(1, len(errors))
2035
2036
Andrew Grieve1b290e4a22020-11-24 20:07:012037class GnGlobForwardTest(unittest.TestCase):
2038 def testAddBareGlobs(self):
2039 mock_input_api = MockInputApi()
2040 mock_input_api.files = [
2041 MockAffectedFile('base/stuff.gni', [
2042 'forward_variables_from(invoker, "*")']),
2043 MockAffectedFile('base/BUILD.gn', [
2044 'forward_variables_from(invoker, "*")']),
2045 ]
2046 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api, MockOutputApi())
2047 self.assertEqual(1, len(warnings))
2048 msg = '\n'.join(warnings[0].items)
2049 self.assertIn('base/stuff.gni', msg)
2050 # Should not check .gn files. Local templates don't need to care about
2051 # visibility / testonly.
2052 self.assertNotIn('base/BUILD.gn', msg)
2053
2054 def testValidUses(self):
2055 mock_input_api = MockInputApi()
2056 mock_input_api.files = [
2057 MockAffectedFile('base/stuff.gni', [
2058 'forward_variables_from(invoker, "*", [])']),
2059 MockAffectedFile('base/stuff2.gni', [
2060 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)']),
2061 MockAffectedFile('base/stuff3.gni', [
2062 'forward_variables_from(invoker, [ "testonly" ])']),
2063 ]
2064 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api, MockOutputApi())
2065 self.assertEqual([], warnings)
2066
2067
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192068class NewHeaderWithoutGnChangeTest(unittest.TestCase):
2069 def testAddHeaderWithoutGn(self):
2070 mock_input_api = MockInputApi()
2071 mock_input_api.files = [
2072 MockAffectedFile('base/stuff.h', ''),
2073 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362074 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192075 mock_input_api, MockOutputApi())
2076 self.assertEqual(1, len(warnings))
2077 self.assertTrue('base/stuff.h' in warnings[0].items)
2078
2079 def testModifyHeader(self):
2080 mock_input_api = MockInputApi()
2081 mock_input_api.files = [
2082 MockAffectedFile('base/stuff.h', '', action='M'),
2083 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362084 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192085 mock_input_api, MockOutputApi())
2086 self.assertEqual(0, len(warnings))
2087
2088 def testDeleteHeader(self):
2089 mock_input_api = MockInputApi()
2090 mock_input_api.files = [
2091 MockAffectedFile('base/stuff.h', '', action='D'),
2092 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362093 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192094 mock_input_api, MockOutputApi())
2095 self.assertEqual(0, len(warnings))
2096
2097 def testAddHeaderWithGn(self):
2098 mock_input_api = MockInputApi()
2099 mock_input_api.files = [
2100 MockAffectedFile('base/stuff.h', ''),
2101 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2102 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362103 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192104 mock_input_api, MockOutputApi())
2105 self.assertEqual(0, len(warnings))
2106
2107 def testAddHeaderWithGni(self):
2108 mock_input_api = MockInputApi()
2109 mock_input_api.files = [
2110 MockAffectedFile('base/stuff.h', ''),
2111 MockAffectedFile('base/files.gni', 'stuff.h'),
2112 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362113 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192114 mock_input_api, MockOutputApi())
2115 self.assertEqual(0, len(warnings))
2116
2117 def testAddHeaderWithOther(self):
2118 mock_input_api = MockInputApi()
2119 mock_input_api.files = [
2120 MockAffectedFile('base/stuff.h', ''),
2121 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2122 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362123 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192124 mock_input_api, MockOutputApi())
2125 self.assertEqual(1, len(warnings))
2126
2127 def testAddHeaderWithWrongGn(self):
2128 mock_input_api = MockInputApi()
2129 mock_input_api.files = [
2130 MockAffectedFile('base/stuff.h', ''),
2131 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2132 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362133 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192134 mock_input_api, MockOutputApi())
2135 self.assertEqual(1, len(warnings))
2136
2137 def testAddHeadersWithGn(self):
2138 mock_input_api = MockInputApi()
2139 mock_input_api.files = [
2140 MockAffectedFile('base/stuff.h', ''),
2141 MockAffectedFile('base/another.h', ''),
2142 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2143 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362144 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192145 mock_input_api, MockOutputApi())
2146 self.assertEqual(0, len(warnings))
2147
2148 def testAddHeadersWithWrongGn(self):
2149 mock_input_api = MockInputApi()
2150 mock_input_api.files = [
2151 MockAffectedFile('base/stuff.h', ''),
2152 MockAffectedFile('base/another.h', ''),
2153 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2154 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362155 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192156 mock_input_api, MockOutputApi())
2157 self.assertEqual(1, len(warnings))
2158 self.assertFalse('base/stuff.h' in warnings[0].items)
2159 self.assertTrue('base/another.h' in warnings[0].items)
2160
2161 def testAddHeadersWithWrongGn2(self):
2162 mock_input_api = MockInputApi()
2163 mock_input_api.files = [
2164 MockAffectedFile('base/stuff.h', ''),
2165 MockAffectedFile('base/another.h', ''),
2166 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2167 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362168 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192169 mock_input_api, MockOutputApi())
2170 self.assertEqual(1, len(warnings))
2171 self.assertTrue('base/stuff.h' in warnings[0].items)
2172 self.assertTrue('base/another.h' in warnings[0].items)
2173
2174
Michael Giuffridad3bc8672018-10-25 22:48:022175class CorrectProductNameInMessagesTest(unittest.TestCase):
2176 def testProductNameInDesc(self):
2177 mock_input_api = MockInputApi()
2178 mock_input_api.files = [
2179 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2180 '<message name="Foo" desc="Welcome to Chrome">',
2181 ' Welcome to Chrome!',
2182 '</message>',
2183 ]),
2184 MockAffectedFile('chrome/app/chromium_strings.grd', [
2185 '<message name="Bar" desc="Welcome to Chrome">',
2186 ' Welcome to Chromium!',
2187 '</message>',
2188 ]),
2189 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362190 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
Michael Giuffridad3bc8672018-10-25 22:48:022191 mock_input_api, MockOutputApi())
2192 self.assertEqual(0, len(warnings))
2193
2194 def testChromeInChromium(self):
2195 mock_input_api = MockInputApi()
2196 mock_input_api.files = [
2197 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2198 '<message name="Foo" desc="Welcome to Chrome">',
2199 ' Welcome to Chrome!',
2200 '</message>',
2201 ]),
2202 MockAffectedFile('chrome/app/chromium_strings.grd', [
2203 '<message name="Bar" desc="Welcome to Chrome">',
2204 ' Welcome to Chrome!',
2205 '</message>',
2206 ]),
2207 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362208 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
Michael Giuffridad3bc8672018-10-25 22:48:022209 mock_input_api, MockOutputApi())
2210 self.assertEqual(1, len(warnings))
2211 self.assertTrue('chrome/app/chromium_strings.grd' in warnings[0].items[0])
2212
2213 def testChromiumInChrome(self):
2214 mock_input_api = MockInputApi()
2215 mock_input_api.files = [
2216 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2217 '<message name="Foo" desc="Welcome to Chrome">',
2218 ' Welcome to Chromium!',
2219 '</message>',
2220 ]),
2221 MockAffectedFile('chrome/app/chromium_strings.grd', [
2222 '<message name="Bar" desc="Welcome to Chrome">',
2223 ' Welcome to Chromium!',
2224 '</message>',
2225 ]),
2226 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362227 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
Michael Giuffridad3bc8672018-10-25 22:48:022228 mock_input_api, MockOutputApi())
2229 self.assertEqual(1, len(warnings))
2230 self.assertTrue(
2231 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
2232
2233 def testMultipleInstances(self):
2234 mock_input_api = MockInputApi()
2235 mock_input_api.files = [
2236 MockAffectedFile('chrome/app/chromium_strings.grd', [
2237 '<message name="Bar" desc="Welcome to Chrome">',
2238 ' Welcome to Chrome!',
2239 '</message>',
2240 '<message name="Baz" desc="A correct message">',
2241 ' Chromium is the software you are using.',
2242 '</message>',
2243 '<message name="Bat" desc="An incorrect message">',
2244 ' Google Chrome is the software you are using.',
2245 '</message>',
2246 ]),
2247 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362248 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
Michael Giuffridad3bc8672018-10-25 22:48:022249 mock_input_api, MockOutputApi())
2250 self.assertEqual(1, len(warnings))
2251 self.assertTrue(
2252 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2253 self.assertTrue(
2254 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2255
2256 def testMultipleWarnings(self):
2257 mock_input_api = MockInputApi()
2258 mock_input_api.files = [
2259 MockAffectedFile('chrome/app/chromium_strings.grd', [
2260 '<message name="Bar" desc="Welcome to Chrome">',
2261 ' Welcome to Chrome!',
2262 '</message>',
2263 '<message name="Baz" desc="A correct message">',
2264 ' Chromium is the software you are using.',
2265 '</message>',
2266 '<message name="Bat" desc="An incorrect message">',
2267 ' Google Chrome is the software you are using.',
2268 '</message>',
2269 ]),
2270 MockAffectedFile('components/components_google_chrome_strings.grd', [
2271 '<message name="Bar" desc="Welcome to Chrome">',
2272 ' Welcome to Chrome!',
2273 '</message>',
2274 '<message name="Baz" desc="A correct message">',
2275 ' Chromium is the software you are using.',
2276 '</message>',
2277 '<message name="Bat" desc="An incorrect message">',
2278 ' Google Chrome is the software you are using.',
2279 '</message>',
2280 ]),
2281 ]
Saagar Sanghavifceeaae2020-08-12 16:40:362282 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
Michael Giuffridad3bc8672018-10-25 22:48:022283 mock_input_api, MockOutputApi())
2284 self.assertEqual(2, len(warnings))
2285 self.assertTrue(
2286 'components/components_google_chrome_strings.grd:5'
2287 in warnings[0].items[0])
2288 self.assertTrue(
2289 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2290 self.assertTrue(
2291 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
2292
2293
Daniel Chenga37c03db2022-05-12 17:20:342294class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252295 def _createMockInputApi(self):
2296 mock_input_api = MockInputApi()
2297 def FakeRepositoryRoot():
2298 return mock_input_api.os_path.join('chromium', 'src')
2299 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2300 self._injectFakeOwnersClient(
2301 mock_input_api,
2302 ['[email protected]', '[email protected]'])
2303 return mock_input_api
2304
Daniel Chengd88244472022-05-16 09:08:472305 def _setupFakeChange(self, input_api):
2306 class FakeGerrit(object):
2307 def IsOwnersOverrideApproved(self, issue):
2308 return False
2309
2310 input_api.change.issue = 123
2311 input_api.gerrit = FakeGerrit()
2312
Daniel Chenga37c03db2022-05-12 17:20:342313 def _injectFakeOwnersClient(self, input_api, owners):
2314 class FakeOwnersClient(object):
2315 def ListOwners(self, f):
2316 return owners
2317
2318 input_api.owners_client = FakeOwnersClient()
2319
2320 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2321 def MockOwnerAndReviewers(input_api, email_regexp, approval_needed=False):
2322 return [owner, reviewers]
2323 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2324 MockOwnerAndReviewers
2325
2326
2327class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
2328 _test_cases = [
2329 ('*_messages.cc', 'scary_messages.cc'),
2330 ('*_messages*.h', 'scary_messages.h'),
2331 ('*_messages*.h', 'scary_messages_android.h'),
2332 ('*_param_traits*.*', 'scary_param_traits.h'),
2333 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2334 ('*.mojom', 'scary.mojom'),
2335 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2336 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2337 ('*_type_converter*.*', 'scary_type_converter.h'),
2338 ('*_type_converter*.*', 'scary_type_converter_nacl.h'),
2339 ('*.aidl', 'scary.aidl'),
2340 ]
2341
Daniel Cheng171dad8d2022-05-21 00:40:252342 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2343 mock_input_api = self._createMockInputApi()
2344 new_owners_file_path = mock_input_api.os_path.join(
2345 'services', 'goat', 'public', 'OWNERS')
2346 new_owners_file = [
2347 'per-file *.mojom=set noparent',
2348 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2349 ]
2350 def FakeReadFile(filename):
2351 self.assertEqual(
2352 mock_input_api.os_path.join('chromium', 'src', new_owners_file_path),
2353 filename)
2354 return '\n'.join(new_owners_file)
2355 mock_input_api.ReadFile = FakeReadFile
Daniel Cheng3008dc12022-05-13 04:02:112356 mock_input_api.files = [
Daniel Cheng171dad8d2022-05-21 00:40:252357 MockAffectedFile(
2358 new_owners_file_path, new_owners_file),
2359 MockAffectedFile(
2360 mock_input_api.os_path.join(
2361 'services', 'goat', 'public', 'goat.mojom'),
2362 ['// Scary contents.'])]
Daniel Chengd88244472022-05-16 09:08:472363 self._setupFakeChange(mock_input_api)
Daniel Cheng171dad8d2022-05-21 00:40:252364 self._injectFakeChangeOwnerAndReviewers(
2365 mock_input_api, '[email protected]', ['[email protected]'])
2366 mock_input_api.is_committing = True
2367 mock_input_api.dry_run = False
2368 mock_output_api = MockOutputApi()
2369 results = PRESUBMIT.CheckSecurityOwners(
2370 mock_input_api, mock_output_api)
2371 self.assertEqual(0, len(results))
2372
2373 def testMissingSecurityReviewerAtUpload(self):
2374 mock_input_api = self._createMockInputApi()
2375 new_owners_file_path = mock_input_api.os_path.join(
2376 'services', 'goat', 'public', 'OWNERS')
2377 new_owners_file = [
2378 'per-file *.mojom=set noparent',
2379 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2380 ]
2381 def FakeReadFile(filename):
2382 self.assertEqual(
2383 mock_input_api.os_path.join('chromium', 'src', new_owners_file_path),
2384 filename)
2385 return '\n'.join(new_owners_file)
2386 mock_input_api.ReadFile = FakeReadFile
2387 mock_input_api.files = [
2388 MockAffectedFile(
2389 new_owners_file_path, new_owners_file),
2390 MockAffectedFile(
2391 mock_input_api.os_path.join(
2392 'services', 'goat', 'public', 'goat.mojom'),
2393 ['// Scary contents.'])]
2394 self._setupFakeChange(mock_input_api)
Daniel Cheng3008dc12022-05-13 04:02:112395 self._injectFakeChangeOwnerAndReviewers(
2396 mock_input_api, '[email protected]', ['[email protected]'])
2397 mock_input_api.is_committing = False
2398 mock_input_api.dry_run = False
2399 mock_output_api = MockOutputApi()
2400 results = PRESUBMIT.CheckSecurityOwners(
2401 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252402 self.assertEqual(1, len(results))
Daniel Cheng681bc122022-05-19 02:23:442403 self.assertEqual('notify', results[0].type)
Daniel Cheng3008dc12022-05-13 04:02:112404 self.assertEqual(
Daniel Cheng171dad8d2022-05-21 00:40:252405 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2406 'following newly-added files:', results[0].message)
Daniel Cheng3008dc12022-05-13 04:02:112407
2408 def testMissingSecurityReviewerAtDryRunCommit(self):
Daniel Cheng171dad8d2022-05-21 00:40:252409 mock_input_api = self._createMockInputApi()
2410 new_owners_file_path = mock_input_api.os_path.join(
2411 'services', 'goat', 'public', 'OWNERS')
2412 new_owners_file = [
2413 'per-file *.mojom=set noparent',
2414 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2415 ]
2416 def FakeReadFile(filename):
2417 self.assertEqual(
2418 mock_input_api.os_path.join('chromium', 'src', new_owners_file_path),
2419 filename)
2420 return '\n'.join(new_owners_file)
2421 mock_input_api.ReadFile = FakeReadFile
Daniel Cheng3008dc12022-05-13 04:02:112422 mock_input_api.files = [
Daniel Cheng171dad8d2022-05-21 00:40:252423 MockAffectedFile(
2424 new_owners_file_path, new_owners_file),
2425 MockAffectedFile(
2426 mock_input_api.os_path.join(
2427 'services', 'goat', 'public', 'goat.mojom'),
2428 ['// Scary contents.'])]
Daniel Chengd88244472022-05-16 09:08:472429 self._setupFakeChange(mock_input_api)
Daniel Cheng3008dc12022-05-13 04:02:112430 self._injectFakeChangeOwnerAndReviewers(
2431 mock_input_api, '[email protected]', ['[email protected]'])
2432 mock_input_api.is_committing = True
2433 mock_input_api.dry_run = True
2434 mock_output_api = MockOutputApi()
2435 results = PRESUBMIT.CheckSecurityOwners(
2436 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252437 self.assertEqual(1, len(results))
Daniel Cheng3008dc12022-05-13 04:02:112438 self.assertEqual('error', results[0].type)
2439 self.assertEqual(
Daniel Cheng171dad8d2022-05-21 00:40:252440 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2441 'following newly-added files:', results[0].message)
Daniel Cheng3008dc12022-05-13 04:02:112442
Gao Shenga79ebd42022-08-08 17:25:592443 def testMissingSecurityApprovalAtRealCommit(self):
Daniel Cheng171dad8d2022-05-21 00:40:252444 mock_input_api = self._createMockInputApi()
2445 new_owners_file_path = mock_input_api.os_path.join(
2446 'services', 'goat', 'public', 'OWNERS')
2447 new_owners_file = [
2448 'per-file *.mojom=set noparent',
2449 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2450 ]
2451 def FakeReadFile(filename):
2452 self.assertEqual(
2453 mock_input_api.os_path.join('chromium', 'src', new_owners_file_path),
2454 filename)
2455 return '\n'.join(new_owners_file)
2456 mock_input_api.ReadFile = FakeReadFile
Daniel Cheng3008dc12022-05-13 04:02:112457 mock_input_api.files = [
Daniel Cheng171dad8d2022-05-21 00:40:252458 MockAffectedFile(
2459 new_owners_file_path, new_owners_file),
2460 MockAffectedFile(
2461 mock_input_api.os_path.join(
2462 'services', 'goat', 'public', 'goat.mojom'),
2463 ['// Scary contents.'])]
Daniel Chengd88244472022-05-16 09:08:472464 self._setupFakeChange(mock_input_api)
Daniel Cheng3008dc12022-05-13 04:02:112465 self._injectFakeChangeOwnerAndReviewers(
2466 mock_input_api, '[email protected]', ['[email protected]'])
2467 mock_input_api.is_committing = True
2468 mock_input_api.dry_run = False
2469 mock_output_api = MockOutputApi()
2470 results = PRESUBMIT.CheckSecurityOwners(
2471 mock_input_api, mock_output_api)
Daniel Cheng3008dc12022-05-13 04:02:112472 self.assertEqual('error', results[0].type)
2473 self.assertEqual(
Daniel Cheng171dad8d2022-05-21 00:40:252474 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2475 'following newly-added files:', results[0].message)
Daniel Chenga37c03db2022-05-12 17:20:342476
2477 def testIpcChangeNeedsSecurityOwner(self):
Daniel Cheng3008dc12022-05-13 04:02:112478 for is_committing in [True, False]:
2479 for pattern, filename in self._test_cases:
2480 with self.subTest(
2481 line=f'is_committing={is_committing}, filename={filename}'):
Daniel Cheng171dad8d2022-05-21 00:40:252482 mock_input_api = self._createMockInputApi()
Daniel Cheng3008dc12022-05-13 04:02:112483 mock_input_api.files = [
Daniel Cheng171dad8d2022-05-21 00:40:252484 MockAffectedFile(
2485 mock_input_api.os_path.join(
2486 'services', 'goat', 'public', filename),
2487 ['// Scary contents.'])]
Daniel Chengd88244472022-05-16 09:08:472488 self._setupFakeChange(mock_input_api)
Daniel Cheng3008dc12022-05-13 04:02:112489 self._injectFakeChangeOwnerAndReviewers(
2490 mock_input_api, '[email protected]', ['[email protected]'])
2491 mock_input_api.is_committing = is_committing
2492 mock_input_api.dry_run = False
2493 mock_output_api = MockOutputApi()
2494 results = PRESUBMIT.CheckSecurityOwners(
2495 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252496 self.assertEqual(1, len(results))
2497 self.assertEqual('error', results[0].type)
2498 self.assertTrue(results[0].message.replace('\\', '/').startswith(
2499 'Found missing OWNERS lines for security-sensitive files. '
2500 'Please add the following lines to services/goat/public/OWNERS:'))
Daniel Cheng3008dc12022-05-13 04:02:112501 self.assertEqual(['[email protected]'],
2502 mock_output_api.more_cc)
Daniel Chenga37c03db2022-05-12 17:20:342503
2504
Ken Rockot9f668262018-12-21 18:56:362505 def testServiceManifestChangeNeedsSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252506 mock_input_api = self._createMockInputApi()
Ken Rockot9f668262018-12-21 18:56:362507 mock_input_api.files = [
Daniel Cheng171dad8d2022-05-21 00:40:252508 MockAffectedFile(
2509 mock_input_api.os_path.join(
2510 'services', 'goat', 'public', 'cpp', 'manifest.cc'),
2511 [
2512 '#include "services/goat/public/cpp/manifest.h"',
2513 'const service_manager::Manifest& GetManifest() {}',
2514 ])]
Daniel Chengd88244472022-05-16 09:08:472515 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342516 self._injectFakeChangeOwnerAndReviewers(
2517 mock_input_api, '[email protected]', ['[email protected]'])
Ken Rockot9f668262018-12-21 18:56:362518 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362519 errors = PRESUBMIT.CheckSecurityOwners(
Ken Rockot9f668262018-12-21 18:56:362520 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252521 self.assertEqual(1, len(errors))
2522 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2523 'Found missing OWNERS lines for security-sensitive files. '
2524 'Please add the following lines to services/goat/public/cpp/OWNERS:'))
Daniel Chenga37c03db2022-05-12 17:20:342525 self.assertEqual(['[email protected]'], mock_output_api.more_cc)
Ken Rockot9f668262018-12-21 18:56:362526
2527 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252528 mock_input_api = self._createMockInputApi()
Daniel Chenga37c03db2022-05-12 17:20:342529 self._injectFakeChangeOwnerAndReviewers(
2530 mock_input_api, '[email protected]', ['[email protected]'])
Ken Rockot9f668262018-12-21 18:56:362531 mock_input_api.files = [
2532 MockAffectedFile('some/non/service/thing/foo_manifest.cc',
2533 [
2534 'const char kNoEnforcement[] = "not a manifest!";',
2535 ])]
2536 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362537 errors = PRESUBMIT.CheckSecurityOwners(
Wez17c66962020-04-29 15:26:032538 mock_input_api, mock_output_api)
2539 self.assertEqual([], errors)
Daniel Chenga37c03db2022-05-12 17:20:342540 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032541
2542
Daniel Chenga37c03db2022-05-12 17:20:342543class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032544 def testFidlChangeNeedsSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252545 mock_input_api = self._createMockInputApi()
Wez17c66962020-04-29 15:26:032546 mock_input_api.files = [
2547 MockAffectedFile('potentially/scary/ipc.fidl',
2548 [
2549 'library test.fidl'
2550 ])]
Daniel Chengd88244472022-05-16 09:08:472551 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342552 self._injectFakeChangeOwnerAndReviewers(
2553 mock_input_api, '[email protected]', ['[email protected]'])
Wez17c66962020-04-29 15:26:032554 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362555 errors = PRESUBMIT.CheckSecurityOwners(
Wez17c66962020-04-29 15:26:032556 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252557 self.assertEqual(1, len(errors))
2558 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2559 'Found missing OWNERS lines for security-sensitive files. '
2560 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032561
2562 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252563 mock_input_api = self._createMockInputApi()
Wez17c66962020-04-29 15:26:032564 mock_input_api.files = [
2565 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2566 [
2567 '{ "that is no": "manifest!" }'
2568 ])]
Daniel Chengd88244472022-05-16 09:08:472569 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342570 self._injectFakeChangeOwnerAndReviewers(
2571 mock_input_api, '[email protected]', ['[email protected]'])
Wez17c66962020-04-29 15:26:032572 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362573 errors = PRESUBMIT.CheckSecurityOwners(
Wez17c66962020-04-29 15:26:032574 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252575 self.assertEqual(1, len(errors))
2576 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2577 'Found missing OWNERS lines for security-sensitive files. '
2578 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032579
2580 def testComponentManifestV2NeedsSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252581 mock_input_api = self._createMockInputApi()
Wez17c66962020-04-29 15:26:032582 mock_input_api.files = [
2583 MockAffectedFile('potentially/scary/v2_manifest.cml',
2584 [
2585 '{ "that is no": "manifest!" }'
2586 ])]
Daniel Chengd88244472022-05-16 09:08:472587 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342588 self._injectFakeChangeOwnerAndReviewers(
2589 mock_input_api, '[email protected]', ['[email protected]'])
Daniel Chengd88244472022-05-16 09:08:472590 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362591 errors = PRESUBMIT.CheckSecurityOwners(
Wez17c66962020-04-29 15:26:032592 mock_input_api, mock_output_api)
Daniel Cheng171dad8d2022-05-21 00:40:252593 self.assertEqual(1, len(errors))
2594 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2595 'Found missing OWNERS lines for security-sensitive files. '
2596 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032597
Joshua Peraza1ca6d392020-12-08 00:14:092598 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2599 mock_input_api = MockInputApi()
Daniel Chenga37c03db2022-05-12 17:20:342600 self._injectFakeChangeOwnerAndReviewers(
2601 mock_input_api, '[email protected]', ['[email protected]'])
Joshua Peraza1ca6d392020-12-08 00:14:092602 mock_input_api.files = [
2603 MockAffectedFile('third_party/crashpad/test/tests.cmx',
2604 [
2605 'const char kNoEnforcement[] = "Security?!? Pah!";',
2606 ])]
2607 mock_output_api = MockOutputApi()
2608 errors = PRESUBMIT.CheckSecurityOwners(
2609 mock_input_api, mock_output_api)
2610 self.assertEqual([], errors)
2611
Wez17c66962020-04-29 15:26:032612 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2613 mock_input_api = MockInputApi()
Daniel Chenga37c03db2022-05-12 17:20:342614 self._injectFakeChangeOwnerAndReviewers(
2615 mock_input_api, '[email protected]', ['[email protected]'])
Wez17c66962020-04-29 15:26:032616 mock_input_api.files = [
2617 MockAffectedFile('some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc',
2618 [
2619 'const char kNoEnforcement[] = "Security?!? Pah!";',
2620 ])]
2621 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362622 errors = PRESUBMIT.CheckSecurityOwners(
Ken Rockot9f668262018-12-21 18:56:362623 mock_input_api, mock_output_api)
2624 self.assertEqual([], errors)
2625
Daniel Cheng13ca61a882017-08-25 15:11:252626
Daniel Chenga37c03db2022-05-12 17:20:342627class SecurityChangeTest(_SecurityOwnersTestCase):
Alex Goughbc964dd2020-06-15 17:52:372628 def testDiffGetServiceSandboxType(self):
Robert Sesek2c905332020-05-06 23:17:132629 mock_input_api = MockInputApi()
2630 mock_input_api.files = [
2631 MockAffectedFile(
2632 'services/goat/teleporter_host.cc',
2633 [
Alex Goughbc964dd2020-06-15 17:52:372634 'template <>',
2635 'inline content::SandboxType',
2636 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2637 '#if defined(OS_WIN)',
2638 ' return SandboxType::kGoaty;',
2639 '#else',
2640 ' return SandboxType::kNoSandbox;',
2641 '#endif // !defined(OS_WIN)',
2642 '}'
Robert Sesek2c905332020-05-06 23:17:132643 ]
2644 ),
2645 ]
2646 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2647 mock_input_api)
2648 self.assertEqual({
2649 'services/goat/teleporter_host.cc': set([
Alex Goughbc964dd2020-06-15 17:52:372650 'content::GetServiceSandboxType<>()'
Robert Sesek2c905332020-05-06 23:17:132651 ])},
2652 files_to_functions)
2653
2654 def testDiffRemovingLine(self):
2655 mock_input_api = MockInputApi()
2656 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2657 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
2658+++ new 2020-05-04 14:08:32.000000000 -0400
2659@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372660 template <>
2661 inline content::SandboxType
2662-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2663 #if defined(OS_WIN)
2664 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132665"""
2666 mock_input_api.files = [mock_file]
2667 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2668 mock_input_api)
2669 self.assertEqual({
2670 'services/goat/teleporter_host.cc': set([
Alex Goughbc964dd2020-06-15 17:52:372671 'content::GetServiceSandboxType<>()'
Robert Sesek2c905332020-05-06 23:17:132672 ])},
2673 files_to_functions)
2674
2675 def testChangeOwnersMissing(self):
Daniel Cheng171dad8d2022-05-21 00:40:252676 mock_input_api = self._createMockInputApi()
Daniel Chengd88244472022-05-16 09:08:472677 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342678 self._injectFakeChangeOwnerAndReviewers(
2679 mock_input_api, '[email protected]', ['[email protected]'])
Robert Sesek2c905332020-05-06 23:17:132680 mock_input_api.is_committing = False
2681 mock_input_api.files = [
Alex Goughbc964dd2020-06-15 17:52:372682 MockAffectedFile('file.cc', ['GetServiceSandboxType<Goat>(Sandbox)'])
Robert Sesek2c905332020-05-06 23:17:132683 ]
2684 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362685 result = PRESUBMIT.CheckSecurityChanges(mock_input_api, mock_output_api)
Dirk Prankee3c9c62d2021-05-18 18:35:592686 self.assertEqual(1, len(result))
2687 self.assertEqual(result[0].type, 'notify')
2688 self.assertEqual(result[0].message,
Daniel Chenga37c03db2022-05-12 17:20:342689 'The following files change calls to security-sensitive functions\n' \
Robert Sesek2c905332020-05-06 23:17:132690 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2691 ' file.cc\n'
Alex Goughbc964dd2020-06-15 17:52:372692 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132693
2694 def testChangeOwnersMissingAtCommit(self):
Daniel Cheng171dad8d2022-05-21 00:40:252695 mock_input_api = self._createMockInputApi()
Daniel Chengd88244472022-05-16 09:08:472696 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342697 self._injectFakeChangeOwnerAndReviewers(
2698 mock_input_api, '[email protected]', ['[email protected]'])
Robert Sesek2c905332020-05-06 23:17:132699 mock_input_api.is_committing = True
Daniel Cheng3008dc12022-05-13 04:02:112700 mock_input_api.dry_run = False
Robert Sesek2c905332020-05-06 23:17:132701 mock_input_api.files = [
Alex Goughbc964dd2020-06-15 17:52:372702 MockAffectedFile('file.cc', ['GetServiceSandboxType<mojom::Goat>()'])
Robert Sesek2c905332020-05-06 23:17:132703 ]
2704 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362705 result = PRESUBMIT.CheckSecurityChanges(mock_input_api, mock_output_api)
Dirk Prankee3c9c62d2021-05-18 18:35:592706 self.assertEqual(1, len(result))
2707 self.assertEqual(result[0].type, 'error')
2708 self.assertEqual(result[0].message,
Daniel Chenga37c03db2022-05-12 17:20:342709 'The following files change calls to security-sensitive functions\n' \
Robert Sesek2c905332020-05-06 23:17:132710 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2711 ' file.cc\n'
Alex Goughbc964dd2020-06-15 17:52:372712 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132713
2714 def testChangeOwnersPresent(self):
Daniel Cheng171dad8d2022-05-21 00:40:252715 mock_input_api = self._createMockInputApi()
Daniel Chenga37c03db2022-05-12 17:20:342716 self._injectFakeChangeOwnerAndReviewers(
2717 mock_input_api, '[email protected]',
2718 ['[email protected]', '[email protected]'])
Robert Sesek2c905332020-05-06 23:17:132719 mock_input_api.files = [
2720 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2721 ]
2722 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362723 result = PRESUBMIT.CheckSecurityChanges(mock_input_api, mock_output_api)
Dirk Prankee3c9c62d2021-05-18 18:35:592724 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132725
2726 def testChangeOwnerIsSecurityOwner(self):
Daniel Cheng171dad8d2022-05-21 00:40:252727 mock_input_api = self._createMockInputApi()
Daniel Chengd88244472022-05-16 09:08:472728 self._setupFakeChange(mock_input_api)
Daniel Chenga37c03db2022-05-12 17:20:342729 self._injectFakeChangeOwnerAndReviewers(
2730 mock_input_api, '[email protected]', ['[email protected]'])
Robert Sesek2c905332020-05-06 23:17:132731 mock_input_api.files = [
Alex Goughbc964dd2020-06-15 17:52:372732 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
Robert Sesek2c905332020-05-06 23:17:132733 ]
2734 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:362735 result = PRESUBMIT.CheckSecurityChanges(mock_input_api, mock_output_api)
Dirk Prankee3c9c62d2021-05-18 18:35:592736 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132737
2738
Mario Sanchez Prada2472cab2019-09-18 10:58:312739class BannedTypeCheckTest(unittest.TestCase):
Sylvain Defresnea8b73d252018-02-28 15:45:542740
Peter Kasting94a56c42019-10-25 21:54:042741 def testBannedCppFunctions(self):
2742 input_api = MockInputApi()
2743 input_api.files = [
2744 MockFile('some/cpp/problematic/file.cc',
2745 ['using namespace std;']),
Oksana Zhuravlovac8222d22019-12-19 19:21:162746 MockFile('third_party/blink/problematic/file.cc',
2747 ['GetInterfaceProvider()']),
Peter Kasting94a56c42019-10-25 21:54:042748 MockFile('some/cpp/ok/file.cc',
2749 ['using std::string;']),
Allen Bauer53b43fb12020-03-12 17:21:472750 MockFile('some/cpp/problematic/file2.cc',
2751 ['set_owned_by_client()']),
danakjd18e8892020-12-17 17:42:012752 MockFile('some/cpp/nocheck/file.cc',
2753 ['using namespace std; // nocheck']),
2754 MockFile('some/cpp/comment/file.cc',
2755 [' // A comment about `using namespace std;`']),
Peter Kasting94a56c42019-10-25 21:54:042756 ]
2757
Saagar Sanghavifceeaae2020-08-12 16:40:362758 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Oksana Zhuravlovac8222d22019-12-19 19:21:162759
2760 # warnings are results[0], errors are results[1]
2761 self.assertEqual(2, len(results))
2762 self.assertTrue('some/cpp/problematic/file.cc' in results[1].message)
2763 self.assertTrue(
2764 'third_party/blink/problematic/file.cc' in results[0].message)
2765 self.assertTrue('some/cpp/ok/file.cc' not in results[1].message)
Allen Bauer53b43fb12020-03-12 17:21:472766 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
danakjd18e8892020-12-17 17:42:012767 self.assertFalse('some/cpp/nocheck/file.cc' in results[0].message)
2768 self.assertFalse('some/cpp/nocheck/file.cc' in results[1].message)
2769 self.assertFalse('some/cpp/comment/file.cc' in results[0].message)
2770 self.assertFalse('some/cpp/comment/file.cc' in results[1].message)
Peter Kasting94a56c42019-10-25 21:54:042771
Peter K. Lee6c03ccff2019-07-15 14:40:052772 def testBannedIosObjcFunctions(self):
Sylvain Defresnea8b73d252018-02-28 15:45:542773 input_api = MockInputApi()
2774 input_api.files = [
2775 MockFile('some/ios/file.mm',
2776 ['TEST(SomeClassTest, SomeInteraction) {',
2777 '}']),
2778 MockFile('some/mac/file.mm',
2779 ['TEST(SomeClassTest, SomeInteraction) {',
2780 '}']),
2781 MockFile('another/ios_file.mm',
2782 ['class SomeTest : public testing::Test {};']),
Peter K. Lee6c03ccff2019-07-15 14:40:052783 MockFile('some/ios/file_egtest.mm',
2784 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
2785 MockFile('some/ios/file_unittest.mm',
2786 ['TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }']),
Sylvain Defresnea8b73d252018-02-28 15:45:542787 ]
2788
Saagar Sanghavifceeaae2020-08-12 16:40:362789 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542790 self.assertEqual(1, len(errors))
2791 self.assertTrue('some/ios/file.mm' in errors[0].message)
2792 self.assertTrue('another/ios_file.mm' in errors[0].message)
2793 self.assertTrue('some/mac/file.mm' not in errors[0].message)
Peter K. Lee6c03ccff2019-07-15 14:40:052794 self.assertTrue('some/ios/file_egtest.mm' in errors[0].message)
2795 self.assertTrue('some/ios/file_unittest.mm' not in errors[0].message)
Sylvain Defresnea8b73d252018-02-28 15:45:542796
Carlos Knippschildab192b8c2019-04-08 20:02:382797 def testBannedMojoFunctions(self):
2798 input_api = MockInputApi()
2799 input_api.files = [
Oksana Zhuravlovafd247772019-05-16 16:57:292800 MockFile('some/cpp/problematic/file2.cc',
2801 ['mojo::ConvertTo<>']),
Oksana Zhuravlovafd247772019-05-16 16:57:292802 MockFile('third_party/blink/ok/file3.cc',
2803 ['mojo::ConvertTo<>']),
2804 MockFile('content/renderer/ok/file3.cc',
2805 ['mojo::ConvertTo<>']),
Carlos Knippschildab192b8c2019-04-08 20:02:382806 ]
2807
Saagar Sanghavifceeaae2020-08-12 16:40:362808 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Oksana Zhuravlova1d3b59de2019-05-17 00:08:222809
2810 # warnings are results[0], errors are results[1]
Robert Sesek351d2d52021-02-02 01:47:072811 self.assertEqual(1, len(results))
Oksana Zhuravlova1d3b59de2019-05-17 00:08:222812 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
Oksana Zhuravlova1d3b59de2019-05-17 00:08:222813 self.assertTrue('third_party/blink/ok/file3.cc' not in results[0].message)
2814 self.assertTrue('content/renderer/ok/file3.cc' not in results[0].message)
Carlos Knippschildab192b8c2019-04-08 20:02:382815
Daniel Cheng92c15e32022-03-16 17:48:222816 def testBannedMojomPatterns(self):
2817 input_api = MockInputApi()
2818 input_api.files = [
2819 MockFile('bad.mojom',
2820 ['struct Bad {',
2821 ' handle<shared_buffer> buffer;',
2822 '};']),
2823 MockFile('good.mojom',
2824 ['struct Good {',
2825 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
2826 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
2827 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;',
2828 '};']),
2829 ]
2830
2831 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
2832
2833 # warnings are results[0], errors are results[1]
2834 self.assertEqual(1, len(results))
2835 self.assertTrue('bad.mojom' in results[0].message)
2836 self.assertTrue('good.mojom' not in results[0].message)
2837
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:272838class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:242839 def testTruePositives(self):
2840 mock_input_api = MockInputApi()
2841 mock_input_api.files = [
2842 MockFile('some/path/foo.cc', ['foo_for_testing();']),
2843 MockFile('some/path/foo.mm', ['FooForTesting();']),
2844 MockFile('some/path/foo.cxx', ['FooForTests();']),
2845 MockFile('some/path/foo.cpp', ['foo_for_test();']),
2846 ]
2847
Saagar Sanghavifceeaae2020-08-12 16:40:362848 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
Vaclav Brozekf01ed502018-03-16 19:38:242849 mock_input_api, MockOutputApi())
2850 self.assertEqual(1, len(results))
2851 self.assertEqual(4, len(results[0].items))
2852 self.assertTrue('foo.cc' in results[0].items[0])
2853 self.assertTrue('foo.mm' in results[0].items[1])
2854 self.assertTrue('foo.cxx' in results[0].items[2])
2855 self.assertTrue('foo.cpp' in results[0].items[3])
2856
2857 def testFalsePositives(self):
2858 mock_input_api = MockInputApi()
2859 mock_input_api.files = [
2860 MockFile('some/path/foo.h', ['foo_for_testing();']),
2861 MockFile('some/path/foo.mm', ['FooForTesting() {']),
2862 MockFile('some/path/foo.cc', ['::FooForTests();']),
2863 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
2864 ]
2865
Saagar Sanghavifceeaae2020-08-12 16:40:362866 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
Vaclav Brozekf01ed502018-03-16 19:38:242867 mock_input_api, MockOutputApi())
2868 self.assertEqual(0, len(results))
2869
James Cook1b4dc132021-03-09 22:45:132870 def testAllowedFiles(self):
2871 mock_input_api = MockInputApi()
2872 mock_input_api.files = [
2873 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
2874 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
2875 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
2876 ]
2877
2878 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
2879 mock_input_api, MockOutputApi())
2880 self.assertEqual(0, len(results))
2881
Vaclav Brozekf01ed502018-03-16 19:38:242882
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:272883class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:232884 def testTruePositives(self):
2885 mock_input_api = MockInputApi()
2886 mock_input_api.files = [
2887 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
2888 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:392889 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
Vaclav Brozek7dbc28c2018-03-27 08:35:232890 MockFile('dir/java/src/mult.java', [
2891 'int x = SomethingLongHere()',
2892 ' * SomethingLongHereForTesting();'
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:392893 ])
Vaclav Brozek7dbc28c2018-03-27 08:35:232894 ]
2895
Saagar Sanghavifceeaae2020-08-12 16:40:362896 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
Vaclav Brozek7dbc28c2018-03-27 08:35:232897 mock_input_api, MockOutputApi())
2898 self.assertEqual(1, len(results))
2899 self.assertEqual(4, len(results[0].items))
2900 self.assertTrue('foo.java' in results[0].items[0])
2901 self.assertTrue('bar.java' in results[0].items[1])
2902 self.assertTrue('baz.java' in results[0].items[2])
2903 self.assertTrue('mult.java' in results[0].items[3])
2904
2905 def testFalsePositives(self):
2906 mock_input_api = MockInputApi()
2907 mock_input_api.files = [
2908 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
2909 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
2910 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
2911 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
Sky Malice9e6d6032020-10-15 22:49:552912 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
2913 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
2914 MockFile('dir/java/src/bar5.java', [
2915 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
2916 ]),
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:392917 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
2918 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
Vaclav Brozek7dbc28c2018-03-27 08:35:232919 MockFile('dir/junit/src/javadoc.java', [
2920 '/** Use FooForTest(); to obtain foo in tests.'
2921 ' */'
2922 ]),
2923 MockFile('dir/junit/src/javadoc2.java', [
2924 '/** ',
2925 ' * Use FooForTest(); to obtain foo in tests.'
2926 ' */'
2927 ]),
2928 ]
2929
Saagar Sanghavifceeaae2020-08-12 16:40:362930 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
Vaclav Brozek7dbc28c2018-03-27 08:35:232931 mock_input_api, MockOutputApi())
2932 self.assertEqual(0, len(results))
2933
2934
Mohamed Heikald048240a2019-11-12 16:57:372935class NewImagesWarningTest(unittest.TestCase):
2936 def testTruePositives(self):
2937 mock_input_api = MockInputApi()
2938 mock_input_api.files = [
2939 MockFile('dir/android/res/drawable/foo.png', []),
2940 MockFile('dir/android/res/drawable-v21/bar.svg', []),
2941 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
2942 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
2943 ]
2944
2945 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api, MockOutputApi())
2946 self.assertEqual(1, len(results))
2947 self.assertEqual(4, len(results[0].items))
2948 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
2949 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
2950 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
2951 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
2952
2953 def testFalsePositives(self):
2954 mock_input_api = MockInputApi()
2955 mock_input_api.files = [
2956 MockFile('dir/pngs/README.md', []),
2957 MockFile('java/test/res/drawable/foo.png', []),
2958 MockFile('third_party/blink/foo.png', []),
2959 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
2960 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
2961 ]
2962
2963 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api, MockOutputApi())
2964 self.assertEqual(0, len(results))
2965
Evan Stade7cd4a2c2022-08-04 23:37:252966class ProductIconsTest(unittest.TestCase):
2967 def test(self):
2968 mock_input_api = MockInputApi()
2969 mock_input_api.files = [
2970 MockFile('components/vector_icons/google_jetpack.icon', []),
2971 MockFile('components/vector_icons/generic_jetpack.icon', []),
2972 ]
2973
2974 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(mock_input_api, MockOutputApi())
2975 self.assertEqual(1, len(results))
2976 self.assertEqual(1, len(results[0].items))
2977 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:372978
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:272979class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:052980 def testTruePositivesNullptr(self):
2981 mock_input_api = MockInputApi()
2982 mock_input_api.files = [
Vaclav Brozekc2fecf42018-04-06 16:40:162983 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
2984 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
Vaclav Brozek851d9602018-04-04 16:13:052985 ]
2986
Saagar Sanghavifceeaae2020-08-12 16:40:362987 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api, MockOutputApi())
Vaclav Brozek851d9602018-04-04 16:13:052988 self.assertEqual(1, len(results))
Vaclav Brozekc2fecf42018-04-06 16:40:162989 self.assertTrue('nullptr' in results[0].message)
Vaclav Brozek851d9602018-04-04 16:13:052990 self.assertEqual(2, len(results[0].items))
2991 self.assertTrue('baz.cc' in results[0].items[0])
2992 self.assertTrue('baz-p.cc' in results[0].items[1])
2993
2994 def testTruePositivesConstructor(self):
Vaclav Brozek52e18bf2018-04-03 07:05:242995 mock_input_api = MockInputApi()
2996 mock_input_api.files = [
Vaclav Brozekc2fecf42018-04-06 16:40:162997 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
2998 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
2999 MockFile('dir/mult.cc', [
Vaclav Brozek95face62018-04-04 14:15:113000 'return',
3001 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3002 ]),
Vaclav Brozekc2fecf42018-04-06 16:40:163003 MockFile('dir/mult2.cc', [
Vaclav Brozek95face62018-04-04 14:15:113004 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3005 ' std::unique_ptr<T>(foo);'
3006 ]),
Vaclav Brozekc2fecf42018-04-06 16:40:163007 MockFile('dir/mult3.cc', [
Vaclav Brozek95face62018-04-04 14:15:113008 'bar = std::unique_ptr<T>(',
3009 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3010 ]),
Vaclav Brozekb7fadb692018-08-30 06:39:533011 MockFile('dir/multi_arg.cc', [
3012 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));']),
Vaclav Brozek52e18bf2018-04-03 07:05:243013 ]
3014
Saagar Sanghavifceeaae2020-08-12 16:40:363015 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api, MockOutputApi())
Vaclav Brozek851d9602018-04-04 16:13:053016 self.assertEqual(1, len(results))
Vaclav Brozekc2fecf42018-04-06 16:40:163017 self.assertTrue('std::make_unique' in results[0].message)
Vaclav Brozekb7fadb692018-08-30 06:39:533018 self.assertEqual(6, len(results[0].items))
Vaclav Brozek851d9602018-04-04 16:13:053019 self.assertTrue('foo.cc' in results[0].items[0])
3020 self.assertTrue('bar.mm' in results[0].items[1])
3021 self.assertTrue('mult.cc' in results[0].items[2])
3022 self.assertTrue('mult2.cc' in results[0].items[3])
3023 self.assertTrue('mult3.cc' in results[0].items[4])
Vaclav Brozekb7fadb692018-08-30 06:39:533024 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozek52e18bf2018-04-03 07:05:243025
3026 def testFalsePositives(self):
3027 mock_input_api = MockInputApi()
3028 mock_input_api.files = [
Vaclav Brozekc2fecf42018-04-06 16:40:163029 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3030 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3031 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3032 MockFile('dir/baz.cc', [
Vaclav Brozek52e18bf2018-04-03 07:05:243033 'std::unique_ptr<T> result = std::make_unique<T>();'
3034 ]),
Vaclav Brozeka54c528b2018-04-06 19:23:553035 MockFile('dir/baz2.cc', [
3036 'std::unique_ptr<T> result = std::make_unique<T>('
3037 ]),
3038 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3039 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
Vaclav Brozekb7fadb692018-08-30 06:39:533040
3041 # Two-argument invocation of std::unique_ptr is exempt because there is
3042 # no equivalent using std::make_unique.
3043 MockFile('dir/multi_arg.cc', [
3044 'auto p = std::unique_ptr<T, D>(new T(), D());']),
Vaclav Brozek52e18bf2018-04-03 07:05:243045 ]
3046
Saagar Sanghavifceeaae2020-08-12 16:40:363047 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api, MockOutputApi())
Vaclav Brozek52e18bf2018-04-03 07:05:243048 self.assertEqual(0, len(results))
3049
Danil Chapovalov3518f362018-08-11 16:13:433050class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
3051 def testBlocksDirectIncludes(self):
3052 mock_input_api = MockInputApi()
3053 mock_input_api.files = [
3054 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3055 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3056 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3057 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3058 ]
Aleksey Khoroshilov9b28c032022-06-03 16:35:323059 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
Dirk Prankee3c9c62d2021-05-18 18:35:593060 self.assertEqual(1, len(results))
3061 self.assertEqual(4, len(results[0].items))
Danil Chapovalov3518f362018-08-11 16:13:433062 self.assertTrue('StrCat' in results[0].message)
3063 self.assertTrue('foo_win.cc' in results[0].items[0])
3064 self.assertTrue('bar.h' in results[0].items[1])
3065 self.assertTrue('baz.h' in results[0].items[2])
3066 self.assertTrue('jumbo.h' in results[0].items[3])
3067
3068 def testAllowsToIncludeWrapper(self):
3069 mock_input_api = MockInputApi()
3070 mock_input_api.files = [
3071 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3072 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3073 ]
Aleksey Khoroshilov9b28c032022-06-03 16:35:323074 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
Dirk Prankee3c9c62d2021-05-18 18:35:593075 self.assertEqual(0, len(results))
Danil Chapovalov3518f362018-08-11 16:13:433076
3077 def testAllowsToCreateWrapper(self):
3078 mock_input_api = MockInputApi()
3079 mock_input_api.files = [
3080 MockFile('base/win/shlwapi.h', [
3081 '#include <shlwapi.h>',
3082 '#include "base/win/windows_defines.inc"']),
3083 ]
Aleksey Khoroshilov9b28c032022-06-03 16:35:323084 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
3085 self.assertEqual(0, len(results))
3086
3087 def testIgnoresNonImplAndHeaders(self):
3088 mock_input_api = MockInputApi()
3089 mock_input_api.files = [
3090 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3091 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3092 ]
3093 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api, MockOutputApi())
Dirk Prankee3c9c62d2021-05-18 18:35:593094 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243095
Mustafa Emre Acer51f2f742020-03-09 19:41:123096
Rainhard Findlingfc31844c52020-05-15 09:58:263097class StringTest(unittest.TestCase):
3098 """Tests ICU syntax check and translation screenshots check."""
3099
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143100 # An empty grd file.
3101 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
3102 <grit latest_public_release="1" current_release="1">
3103 <release seq="1">
3104 <messages></messages>
3105 </release>
3106 </grit>
3107 """.splitlines()
3108 # A grd file with a single message.
3109 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
3110 <grit latest_public_release="1" current_release="1">
3111 <release seq="1">
3112 <messages>
3113 <message name="IDS_TEST1">
3114 Test string 1
3115 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483116 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3117 translateable="false">
3118 Non translateable message 1, should be ignored
3119 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393120 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343121 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393122 Accessibility label 1, should be ignored
3123 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143124 </messages>
3125 </release>
3126 </grit>
3127 """.splitlines()
3128 # A grd file with two messages.
3129 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
3130 <grit latest_public_release="1" current_release="1">
3131 <release seq="1">
3132 <messages>
3133 <message name="IDS_TEST1">
3134 Test string 1
3135 </message>
3136 <message name="IDS_TEST2">
3137 Test string 2
3138 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483139 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3140 translateable="false">
3141 Non translateable message 2, should be ignored
3142 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143143 </messages>
3144 </release>
3145 </grit>
3146 """.splitlines()
Rainhard Findlingfc31844c52020-05-15 09:58:263147 # A grd file with one ICU syntax message without syntax errors.
3148 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
3149 <grit latest_public_release="1" current_release="1">
3150 <release seq="1">
3151 <messages>
3152 <message name="IDS_TEST1">
3153 {NUM, plural,
3154 =1 {Test text for numeric one}
3155 other {Test text for plural with {NUM} as number}}
3156 </message>
3157 </messages>
3158 </release>
3159 </grit>
3160 """.splitlines()
3161 # A grd file with one ICU syntax message without syntax errors.
3162 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
3163 <grit latest_public_release="1" current_release="1">
3164 <release seq="1">
3165 <messages>
3166 <message name="IDS_TEST1">
3167 {NUM, plural,
3168 =1 {Different test text for numeric one}
3169 other {Different test text for plural with {NUM} as number}}
3170 </message>
3171 </messages>
3172 </release>
3173 </grit>
3174 """.splitlines()
3175 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3176 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
3177 <grit latest_public_release="1" current_release="1">
3178 <release seq="1">
3179 <messages>
3180 <message name="IDS_TEST1">
3181 {NUM, plural
3182 =1 {Test text for numeric one}
3183 other {Test text for plural with {NUM} as number}}
3184 </message>
3185 </messages>
3186 </release>
3187 </grit>
3188 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143189
meacerff8a9b62019-12-10 19:43:583190 OLD_GRDP_CONTENTS = (
3191 '<?xml version="1.0" encoding="utf-8"?>',
3192 '<grit-part>',
3193 '</grit-part>'
3194 )
3195
3196 NEW_GRDP_CONTENTS1 = (
3197 '<?xml version="1.0" encoding="utf-8"?>',
3198 '<grit-part>',
3199 '<message name="IDS_PART_TEST1">',
3200 'Part string 1',
3201 '</message>',
3202 '</grit-part>')
3203
3204 NEW_GRDP_CONTENTS2 = (
3205 '<?xml version="1.0" encoding="utf-8"?>',
3206 '<grit-part>',
3207 '<message name="IDS_PART_TEST1">',
3208 'Part string 1',
3209 '</message>',
3210 '<message name="IDS_PART_TEST2">',
3211 'Part string 2',
3212 '</message>',
3213 '</grit-part>')
3214
Rainhard Findlingd8d04372020-08-13 13:30:093215 NEW_GRDP_CONTENTS3 = (
3216 '<?xml version="1.0" encoding="utf-8"?>',
3217 '<grit-part>',
3218 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
3219 'Part string 1',
3220 '</message>',
3221 '</grit-part>')
3222
3223 NEW_GRDP_CONTENTS4 = (
3224 '<?xml version="1.0" encoding="utf-8"?>',
3225 '<grit-part>',
3226 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
3227 'Part string 1',
3228 '</message>',
3229 '</grit-part>')
3230
Rainhard Findling1a3e71e2020-09-21 07:33:353231 NEW_GRDP_CONTENTS5 = (
3232 '<?xml version="1.0" encoding="utf-8"?>',
3233 '<grit-part>',
3234 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
3235 'Part string 1',
3236 '</message>',
3237 '</grit-part>')
3238
3239 NEW_GRDP_CONTENTS6 = (
3240 '<?xml version="1.0" encoding="utf-8"?>',
3241 '<grit-part>',
3242 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
3243 'Part string 1',
3244 '</message>',
3245 '</grit-part>')
3246
Rainhard Findlingfc31844c52020-05-15 09:58:263247 # A grdp file with one ICU syntax message without syntax errors.
3248 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3249 '<?xml version="1.0" encoding="utf-8"?>',
3250 '<grit-part>',
3251 '<message name="IDS_PART_TEST1">',
3252 '{NUM, plural,',
3253 '=1 {Test text for numeric one}',
3254 'other {Test text for plural with {NUM} as number}}',
3255 '</message>',
3256 '</grit-part>')
3257 # A grdp file with one ICU syntax message without syntax errors.
3258 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3259 '<?xml version="1.0" encoding="utf-8"?>',
3260 '<grit-part>',
3261 '<message name="IDS_PART_TEST1">',
3262 '{NUM, plural,',
3263 '=1 {Different test text for numeric one}',
3264 'other {Different test text for plural with {NUM} as number}}',
3265 '</message>',
3266 '</grit-part>')
3267
3268 # A grdp file with one ICU syntax message with syntax errors (superfluent
3269 # whitespace).
3270 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3271 '<?xml version="1.0" encoding="utf-8"?>',
3272 '<grit-part>',
3273 '<message name="IDS_PART_TEST1">',
3274 '{NUM, plural,',
3275 '= 1 {Test text for numeric one}',
3276 'other {Test text for plural with {NUM} as number}}',
3277 '</message>',
3278 '</grit-part>')
3279
Mustafa Emre Acerc8a012d2018-07-31 00:00:393280 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3281 'changelist. Run '
3282 'tools/translate/upload_screenshots.py to '
3283 'upload them instead:')
3284 GENERATE_SIGNATURES_MESSAGE = ('You are adding or modifying UI strings.\n'
3285 'To ensure the best translations, take '
3286 'screenshots of the relevant UI '
3287 '(https://g.co/chrome/translation) and add '
3288 'these files to your changelist:')
3289 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3290 'files. Remove:')
Rainhard Findlingfc31844c52020-05-15 09:58:263291 ICU_SYNTAX_ERROR_MESSAGE = ('ICU syntax errors were found in the following '
3292 'strings (problems or feedback? Contact '
3293 '[email protected]):')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143294
3295 def makeInputApi(self, files):
3296 input_api = MockInputApi()
3297 input_api.files = files
meacere7be7532019-10-02 17:41:033298 # Override os_path.exists because the presubmit uses the actual
3299 # os.path.exists.
3300 input_api.CreateMockFileInPath(
3301 [x.LocalPath() for x in input_api.AffectedFiles(include_deletes=True)])
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143302 return input_api
3303
meacerff8a9b62019-12-10 19:43:583304 """ CL modified and added messages, but didn't add any screenshots."""
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143305 def testNoScreenshots(self):
meacerff8a9b62019-12-10 19:43:583306 # No new strings (file contents same). Should not warn.
3307 input_api = self.makeInputApi([
3308 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS1,
3309 self.NEW_GRD_CONTENTS1, action='M'),
3310 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS1,
3311 self.NEW_GRDP_CONTENTS1, action='M')])
Gao Shenga79ebd42022-08-08 17:25:593312 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
meacerff8a9b62019-12-10 19:43:583313 self.assertEqual(0, len(warnings))
3314
3315 # Add two new strings. Should have two warnings.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143316 input_api = self.makeInputApi([
3317 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
meacerff8a9b62019-12-10 19:43:583318 self.NEW_GRD_CONTENTS1, action='M'),
3319 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS2,
3320 self.NEW_GRDP_CONTENTS1, action='M')])
Gao Shenga79ebd42022-08-08 17:25:593321 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143322 self.assertEqual(1, len(warnings))
3323 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
Mustafa Emre Acerc6ed2682020-07-07 07:24:003324 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acerea3e57a2018-12-17 23:51:013325 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583326 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3327 os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3328 warnings[0].items)
Mustafa Emre Acer36eaad52019-11-12 23:03:343329
meacerff8a9b62019-12-10 19:43:583330 # Add four new strings. Should have four warnings.
Mustafa Emre Acerad8fb082019-11-19 04:24:213331 input_api = self.makeInputApi([
3332 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS2,
meacerff8a9b62019-12-10 19:43:583333 self.OLD_GRD_CONTENTS, action='M'),
3334 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS2,
3335 self.OLD_GRDP_CONTENTS, action='M')])
Gao Shenga79ebd42022-08-08 17:25:593336 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acerad8fb082019-11-19 04:24:213337 self.assertEqual(1, len(warnings))
Mustafa Emre Acerc6ed2682020-07-07 07:24:003338 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acerad8fb082019-11-19 04:24:213339 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[0].message)
meacerff8a9b62019-12-10 19:43:583340 self.assertEqual([
3341 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3342 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3343 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3344 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3345 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213346
Rainhard Findlingd8d04372020-08-13 13:30:093347 def testModifiedMessageDescription(self):
3348 # CL modified a message description for a message that does not yet have a
Rainhard Findling1a3e71e2020-09-21 07:33:353349 # screenshot. Should not warn.
Rainhard Findlingd8d04372020-08-13 13:30:093350 input_api = self.makeInputApi([
3351 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS3,
3352 self.NEW_GRDP_CONTENTS4, action='M')])
3353 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Rainhard Findling1a3e71e2020-09-21 07:33:353354 self.assertEqual(0, len(warnings))
Rainhard Findlingd8d04372020-08-13 13:30:093355
3356 # CL modified a message description for a message that already has a
3357 # screenshot. Should not warn.
3358 input_api = self.makeInputApi([
3359 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS3,
3360 self.NEW_GRDP_CONTENTS4, action='M'),
3361 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3362 'binary', action='A')])
3363 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3364 self.assertEqual(0, len(warnings))
3365
Rainhard Findling1a3e71e2020-09-21 07:33:353366 def testModifiedMessageMeaning(self):
3367 # CL modified a message meaning for a message that does not yet have a
3368 # screenshot. Should warn.
3369 input_api = self.makeInputApi([
3370 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS5,
3371 self.NEW_GRDP_CONTENTS6, action='M')])
3372 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3373 self.assertEqual(1, len(warnings))
3374
3375 # CL modified a message meaning for a message that already has a
3376 # screenshot. Should not warn.
3377 input_api = self.makeInputApi([
3378 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS5,
3379 self.NEW_GRDP_CONTENTS6, action='M'),
3380 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3381 'binary', action='A')])
3382 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3383 self.assertEqual(0, len(warnings))
3384
meacerff8a9b62019-12-10 19:43:583385 def testPngAddedSha1NotAdded(self):
3386 # CL added one new message in a grd file and added the png file associated
3387 # with it, but did not add the corresponding sha1 file. This should warn
3388 # twice:
3389 # - Once for the added png file (because we don't want developers to upload
3390 # actual images)
3391 # - Once for the missing .sha1 file
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143392 input_api = self.makeInputApi([
Mustafa Emre Acerea3e57a2018-12-17 23:51:013393 MockAffectedFile(
3394 'test.grd',
3395 self.NEW_GRD_CONTENTS1,
3396 self.OLD_GRD_CONTENTS,
3397 action='M'),
3398 MockAffectedFile(
3399 os.path.join('test_grd', 'IDS_TEST1.png'), 'binary', action='A')
3400 ])
Gao Shenga79ebd42022-08-08 17:25:593401 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143402 self.assertEqual(2, len(warnings))
Mustafa Emre Acerc6ed2682020-07-07 07:24:003403 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143404 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
Mustafa Emre Acerea3e57a2018-12-17 23:51:013405 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3406 warnings[0].items)
Mustafa Emre Acerc6ed2682020-07-07 07:24:003407 self.assertEqual('error', warnings[1].type)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143408 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
Mustafa Emre Acerea3e57a2018-12-17 23:51:013409 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3410 warnings[1].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143411
meacerff8a9b62019-12-10 19:43:583412 # CL added two messages (one in grd, one in grdp) and added the png files
3413 # associated with the messages, but did not add the corresponding sha1
3414 # files. This should warn twice:
3415 # - Once for the added png files (because we don't want developers to upload
3416 # actual images)
3417 # - Once for the missing .sha1 files
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143418 input_api = self.makeInputApi([
meacerff8a9b62019-12-10 19:43:583419 # Modified files:
Mustafa Emre Acer36eaad52019-11-12 23:03:343420 MockAffectedFile(
3421 'test.grd',
meacerff8a9b62019-12-10 19:43:583422 self.NEW_GRD_CONTENTS1,
Mustafa Emre Acer36eaad52019-11-12 23:03:343423 self.OLD_GRD_CONTENTS,
meacer2308d0742019-11-12 18:15:423424 action='M'),
Mustafa Emre Acer12e7fee2019-11-18 18:49:553425 MockAffectedFile(
meacerff8a9b62019-12-10 19:43:583426 'part.grdp',
3427 self.NEW_GRDP_CONTENTS1,
3428 self.OLD_GRDP_CONTENTS,
3429 action='M'),
3430 # Added files:
3431 MockAffectedFile(
3432 os.path.join('test_grd', 'IDS_TEST1.png'), 'binary', action='A'),
3433 MockAffectedFile(
3434 os.path.join('part_grdp', 'IDS_PART_TEST1.png'), 'binary',
3435 action='A')
Mustafa Emre Acerad8fb082019-11-19 04:24:213436 ])
Gao Shenga79ebd42022-08-08 17:25:593437 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acerad8fb082019-11-19 04:24:213438 self.assertEqual(2, len(warnings))
Mustafa Emre Acerc6ed2682020-07-07 07:24:003439 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acerad8fb082019-11-19 04:24:213440 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
meacerff8a9b62019-12-10 19:43:583441 self.assertEqual([os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3442 os.path.join('test_grd', 'IDS_TEST1.png')],
Mustafa Emre Acerad8fb082019-11-19 04:24:213443 warnings[0].items)
Mustafa Emre Acerc6ed2682020-07-07 07:24:003444 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acerad8fb082019-11-19 04:24:213445 self.assertEqual(self.GENERATE_SIGNATURES_MESSAGE, warnings[1].message)
meacerff8a9b62019-12-10 19:43:583446 self.assertEqual([os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3447 os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3448 warnings[1].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213449
3450 def testScreenshotsWithSha1(self):
meacerff8a9b62019-12-10 19:43:583451 # CL added four messages (two each in a grd and grdp) and their
3452 # corresponding .sha1 files. No warnings.
Mustafa Emre Acerad8fb082019-11-19 04:24:213453 input_api = self.makeInputApi([
meacerff8a9b62019-12-10 19:43:583454 # Modified files:
Mustafa Emre Acerad8fb082019-11-19 04:24:213455 MockAffectedFile(
3456 'test.grd',
3457 self.NEW_GRD_CONTENTS2,
3458 self.OLD_GRD_CONTENTS,
Mustafa Emre Acer12e7fee2019-11-18 18:49:553459 action='M'),
meacerff8a9b62019-12-10 19:43:583460 MockAffectedFile(
3461 'part.grdp',
3462 self.NEW_GRDP_CONTENTS2,
3463 self.OLD_GRDP_CONTENTS,
3464 action='M'),
3465 # Added files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013466 MockFile(
3467 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3468 'binary',
3469 action='A'),
3470 MockFile(
3471 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3472 'binary',
meacerff8a9b62019-12-10 19:43:583473 action='A'),
3474 MockFile(
3475 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3476 'binary',
3477 action='A'),
3478 MockFile(
3479 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3480 'binary',
3481 action='A'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013482 ])
Gao Shenga79ebd42022-08-08 17:25:593483 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143484 self.assertEqual([], warnings)
3485
3486 def testScreenshotsRemovedWithSha1(self):
meacerff8a9b62019-12-10 19:43:583487 # Replace new contents with old contents in grd and grp files, removing
3488 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3489 # Should warn to remove the sha1 files associated with these strings.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143490 input_api = self.makeInputApi([
meacerff8a9b62019-12-10 19:43:583491 # Modified files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013492 MockAffectedFile(
3493 'test.grd',
meacerff8a9b62019-12-10 19:43:583494 self.OLD_GRD_CONTENTS, # new_contents
3495 self.NEW_GRD_CONTENTS2, # old_contents
Mustafa Emre Acerea3e57a2018-12-17 23:51:013496 action='M'),
meacerff8a9b62019-12-10 19:43:583497 MockAffectedFile(
3498 'part.grdp',
3499 self.OLD_GRDP_CONTENTS, # new_contents
3500 self.NEW_GRDP_CONTENTS2, # old_contents
3501 action='M'),
3502 # Unmodified files:
3503 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ''),
3504 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'), 'binary', ''),
3505 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3506 'binary', ''),
3507 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3508 'binary', '')
Mustafa Emre Acerea3e57a2018-12-17 23:51:013509 ])
Gao Shenga79ebd42022-08-08 17:25:593510 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143511 self.assertEqual(1, len(warnings))
Mustafa Emre Acerc6ed2682020-07-07 07:24:003512 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143513 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
Mustafa Emre Acerea3e57a2018-12-17 23:51:013514 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583515 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3516 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013517 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3518 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3519 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143520
meacerff8a9b62019-12-10 19:43:583521 # Same as above, but this time one of the .sha1 files is also removed.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143522 input_api = self.makeInputApi([
meacerff8a9b62019-12-10 19:43:583523 # Modified files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013524 MockAffectedFile(
3525 'test.grd',
meacerff8a9b62019-12-10 19:43:583526 self.OLD_GRD_CONTENTS, # new_contents
3527 self.NEW_GRD_CONTENTS2, # old_contents
Mustafa Emre Acerea3e57a2018-12-17 23:51:013528 action='M'),
meacerff8a9b62019-12-10 19:43:583529 MockAffectedFile(
3530 'part.grdp',
3531 self.OLD_GRDP_CONTENTS, # new_contents
3532 self.NEW_GRDP_CONTENTS2, # old_contents
3533 action='M'),
3534 # Unmodified files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013535 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ''),
meacerff8a9b62019-12-10 19:43:583536 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3537 'binary', ''),
3538 # Deleted files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013539 MockAffectedFile(
3540 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3541 '',
3542 'old_contents',
meacerff8a9b62019-12-10 19:43:583543 action='D'),
3544 MockAffectedFile(
3545 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3546 '',
3547 'old_contents',
Mustafa Emre Acerea3e57a2018-12-17 23:51:013548 action='D')
3549 ])
Gao Shenga79ebd42022-08-08 17:25:593550 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143551 self.assertEqual(1, len(warnings))
Mustafa Emre Acerc6ed2682020-07-07 07:24:003552 self.assertEqual('error', warnings[0].type)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143553 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
meacerff8a9b62019-12-10 19:43:583554 self.assertEqual([os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3555 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3556 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143557
meacerff8a9b62019-12-10 19:43:583558 # Remove all sha1 files. There should be no warnings.
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143559 input_api = self.makeInputApi([
meacerff8a9b62019-12-10 19:43:583560 # Modified files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013561 MockAffectedFile(
3562 'test.grd',
3563 self.OLD_GRD_CONTENTS,
3564 self.NEW_GRD_CONTENTS2,
3565 action='M'),
meacerff8a9b62019-12-10 19:43:583566 MockAffectedFile(
3567 'part.grdp',
3568 self.OLD_GRDP_CONTENTS,
3569 self.NEW_GRDP_CONTENTS2,
3570 action='M'),
3571 # Deleted files:
Mustafa Emre Acerea3e57a2018-12-17 23:51:013572 MockFile(
3573 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3574 'binary',
3575 action='D'),
3576 MockFile(
3577 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3578 'binary',
meacerff8a9b62019-12-10 19:43:583579 action='D'),
3580 MockFile(
3581 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3582 'binary',
3583 action='D'),
3584 MockFile(
3585 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3586 'binary',
Mustafa Emre Acerea3e57a2018-12-17 23:51:013587 action='D')
3588 ])
Gao Shenga79ebd42022-08-08 17:25:593589 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143590 self.assertEqual([], warnings)
3591
Rainhard Findlingfc31844c52020-05-15 09:58:263592 def testIcuSyntax(self):
3593 # Add valid ICU syntax string. Should not raise an error.
3594 input_api = self.makeInputApi([
3595 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
3596 self.NEW_GRD_CONTENTS1, action='M'),
3597 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
3598 self.NEW_GRDP_CONTENTS1, action='M')])
Saagar Sanghavifceeaae2020-08-12 16:40:363599 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Rainhard Findlingfc31844c52020-05-15 09:58:263600 # We expect no ICU syntax errors.
3601 icu_errors = [e for e in results
3602 if e.message == self.ICU_SYNTAX_ERROR_MESSAGE]
3603 self.assertEqual(0, len(icu_errors))
3604
3605 # Valid changes in ICU syntax. Should not raise an error.
3606 input_api = self.makeInputApi([
3607 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
3608 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1, action='M'),
3609 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
3610 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1, action='M')])
Saagar Sanghavifceeaae2020-08-12 16:40:363611 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Rainhard Findlingfc31844c52020-05-15 09:58:263612 # We expect no ICU syntax errors.
3613 icu_errors = [e for e in results
3614 if e.message == self.ICU_SYNTAX_ERROR_MESSAGE]
3615 self.assertEqual(0, len(icu_errors))
3616
3617 # Add invalid ICU syntax strings. Should raise two errors.
3618 input_api = self.makeInputApi([
3619 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
3620 self.NEW_GRD_CONTENTS1, action='M'),
3621 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
3622 self.NEW_GRD_CONTENTS1, action='M')])
Saagar Sanghavifceeaae2020-08-12 16:40:363623 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Rainhard Findlingfc31844c52020-05-15 09:58:263624 # We expect 2 ICU syntax errors.
3625 icu_errors = [e for e in results
3626 if e.message == self.ICU_SYNTAX_ERROR_MESSAGE]
3627 self.assertEqual(1, len(icu_errors))
3628 self.assertEqual([
3629 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
3630 'ICU syntax.',
3631 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
3632 ], icu_errors[0].items)
3633
3634 # Change two strings to have ICU syntax errors. Should raise two errors.
3635 input_api = self.makeInputApi([
3636 MockAffectedFile('test.grd', self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
3637 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1, action='M'),
3638 MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
3639 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1, action='M')])
Saagar Sanghavifceeaae2020-08-12 16:40:363640 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
Rainhard Findlingfc31844c52020-05-15 09:58:263641 # We expect 2 ICU syntax errors.
3642 icu_errors = [e for e in results
3643 if e.message == self.ICU_SYNTAX_ERROR_MESSAGE]
3644 self.assertEqual(1, len(icu_errors))
3645 self.assertEqual([
3646 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
3647 'ICU syntax.',
3648 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
3649 ], icu_errors[0].items)
3650
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143651
Mustafa Emre Acer51f2f742020-03-09 19:41:123652class TranslationExpectationsTest(unittest.TestCase):
3653 ERROR_MESSAGE_FORMAT = (
3654 "Failed to get a list of translatable grd files. "
3655 "This happens when:\n"
3656 " - One of the modified grd or grdp files cannot be parsed or\n"
3657 " - %s is not updated.\n"
3658 "Stack:\n"
3659 )
3660 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
3661 # This lists all .grd files under REPO_ROOT.
3662 EXPECTATIONS = os.path.join(REPO_ROOT,
3663 "translation_expectations.pyl")
3664 # This lists all .grd files under REPO_ROOT except unlisted.grd.
3665 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
3666 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
3667
3668 # Tests that the presubmit doesn't return when no grd or grdp files are
3669 # modified.
3670 def testExpectationsNoModifiedGrd(self):
3671 input_api = MockInputApi()
3672 input_api.files = [
3673 MockAffectedFile('not_used.txt', 'not used', 'not used', action='M')
3674 ]
3675 # Fake list of all grd files in the repo. This list is missing all grd/grdps
3676 # under tools/translation/testdata. This is OK because the presubmit won't
3677 # run in the first place since there are no modified grd/grps in input_api.
3678 grd_files = ['doesnt_exist_doesnt_matter.grd']
Saagar Sanghavifceeaae2020-08-12 16:40:363679 warnings = PRESUBMIT.CheckTranslationExpectations(
Mustafa Emre Acer51f2f742020-03-09 19:41:123680 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
3681 grd_files)
3682 self.assertEqual(0, len(warnings))
3683
3684
3685 # Tests that the list of files passed to the presubmit matches the list of
3686 # files in the expectations.
3687 def testExpectationsSuccess(self):
3688 # Mock input file list needs a grd or grdp file in order to run the
3689 # presubmit. The file itself doesn't matter.
3690 input_api = MockInputApi()
3691 input_api.files = [
3692 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
3693 ]
3694 # List of all grd files in the repo.
3695 grd_files = ['test.grd', 'unlisted.grd', 'not_translated.grd',
3696 'internal.grd']
Saagar Sanghavifceeaae2020-08-12 16:40:363697 warnings = PRESUBMIT.CheckTranslationExpectations(
Mustafa Emre Acer51f2f742020-03-09 19:41:123698 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
3699 grd_files)
3700 self.assertEqual(0, len(warnings))
3701
3702 # Tests that the presubmit warns when a file is listed in expectations, but
3703 # does not actually exist.
3704 def testExpectationsMissingFile(self):
3705 # Mock input file list needs a grd or grdp file in order to run the
3706 # presubmit.
3707 input_api = MockInputApi()
3708 input_api.files = [
3709 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
3710 ]
3711 # unlisted.grd is listed under tools/translation/testdata but is not
3712 # included in translation expectations.
3713 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
Saagar Sanghavifceeaae2020-08-12 16:40:363714 warnings = PRESUBMIT.CheckTranslationExpectations(
Mustafa Emre Acer51f2f742020-03-09 19:41:123715 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
3716 grd_files)
3717 self.assertEqual(1, len(warnings))
3718 self.assertTrue(warnings[0].message.startswith(
3719 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
3720 self.assertTrue(
3721 ("test.grd is listed in the translation expectations, "
3722 "but this grd file does not exist")
3723 in warnings[0].message)
3724
3725 # Tests that the presubmit warns when a file is not listed in expectations but
3726 # does actually exist.
3727 def testExpectationsUnlistedFile(self):
3728 # Mock input file list needs a grd or grdp file in order to run the
3729 # presubmit.
3730 input_api = MockInputApi()
3731 input_api.files = [
3732 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
3733 ]
3734 # unlisted.grd is listed under tools/translation/testdata but is not
3735 # included in translation expectations.
3736 grd_files = ['test.grd', 'unlisted.grd', 'not_translated.grd',
3737 'internal.grd']
Saagar Sanghavifceeaae2020-08-12 16:40:363738 warnings = PRESUBMIT.CheckTranslationExpectations(
Mustafa Emre Acer51f2f742020-03-09 19:41:123739 input_api, MockOutputApi(), self.REPO_ROOT,
3740 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
3741 self.assertEqual(1, len(warnings))
3742 self.assertTrue(warnings[0].message.startswith(
3743 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
3744 self.assertTrue(
3745 ("unlisted.grd appears to be translatable "
3746 "(because it contains <file> or <message> elements), "
3747 "but is not listed in the translation expectations.")
3748 in warnings[0].message)
3749
3750 # Tests that the presubmit warns twice:
3751 # - for a non-existing file listed in expectations
3752 # - for an existing file not listed in expectations
3753 def testMultipleWarnings(self):
3754 # Mock input file list needs a grd or grdp file in order to run the
3755 # presubmit.
3756 input_api = MockInputApi()
3757 input_api.files = [
3758 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
3759 ]
3760 # unlisted.grd is listed under tools/translation/testdata but is not
3761 # included in translation expectations.
3762 # test.grd is not listed under tools/translation/testdata but is included
3763 # in translation expectations.
3764 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
Saagar Sanghavifceeaae2020-08-12 16:40:363765 warnings = PRESUBMIT.CheckTranslationExpectations(
Mustafa Emre Acer51f2f742020-03-09 19:41:123766 input_api, MockOutputApi(), self.REPO_ROOT,
3767 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
3768 self.assertEqual(1, len(warnings))
3769 self.assertTrue(warnings[0].message.startswith(
3770 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
3771 self.assertTrue(
3772 ("unlisted.grd appears to be translatable "
3773 "(because it contains <file> or <message> elements), "
3774 "but is not listed in the translation expectations.")
3775 in warnings[0].message)
3776 self.assertTrue(
3777 ("test.grd is listed in the translation expectations, "
3778 "but this grd file does not exist")
3779 in warnings[0].message)
3780
3781
Dominic Battre033531052018-09-24 15:45:343782class DISABLETypoInTest(unittest.TestCase):
3783
3784 def testPositive(self):
3785 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
3786 # where the desire is to disable a test.
3787 tests = [
3788 # Disabled on one platform:
3789 '#if defined(OS_WIN)\n'
3790 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
3791 '#else\n'
3792 '#define MAYBE_FoobarTest FoobarTest\n'
3793 '#endif\n',
3794 # Disabled on one platform spread cross lines:
3795 '#if defined(OS_WIN)\n'
3796 '#define MAYBE_FoobarTest \\\n'
3797 ' DISABLE_FoobarTest\n'
3798 '#else\n'
3799 '#define MAYBE_FoobarTest FoobarTest\n'
3800 '#endif\n',
3801 # Disabled on all platforms:
3802 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
3803 # Disabled on all platforms but multiple lines
3804 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
3805 ]
3806
3807 for test in tests:
3808 mock_input_api = MockInputApi()
3809 mock_input_api.files = [
3810 MockFile('some/path/foo_unittest.cc', test.splitlines()),
3811 ]
3812
Saagar Sanghavifceeaae2020-08-12 16:40:363813 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
Dominic Battre033531052018-09-24 15:45:343814 MockOutputApi())
3815 self.assertEqual(
3816 1,
3817 len(results),
3818 msg=('expected len(results) == 1 but got %d in test: %s' %
3819 (len(results), test)))
3820 self.assertTrue(
3821 'foo_unittest.cc' in results[0].message,
3822 msg=('expected foo_unittest.cc in message but got %s in test %s' %
3823 (results[0].message, test)))
3824
Gao Shenga79ebd42022-08-08 17:25:593825 def testIgnoreNotTestFiles(self):
Dominic Battre033531052018-09-24 15:45:343826 mock_input_api = MockInputApi()
3827 mock_input_api.files = [
3828 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
3829 ]
3830
Saagar Sanghavifceeaae2020-08-12 16:40:363831 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
Dominic Battre033531052018-09-24 15:45:343832 MockOutputApi())
3833 self.assertEqual(0, len(results))
3834
Gao Shenga79ebd42022-08-08 17:25:593835 def testIgnoreDeletedFiles(self):
Katie Df13948e2018-09-25 07:33:443836 mock_input_api = MockInputApi()
3837 mock_input_api.files = [
3838 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)', action='D'),
3839 ]
3840
Saagar Sanghavifceeaae2020-08-12 16:40:363841 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
Katie Df13948e2018-09-25 07:33:443842 MockOutputApi())
3843 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:343844
Nina Satragnof7660532021-09-20 18:03:353845class ForgettingMAYBEInTests(unittest.TestCase):
3846 def testPositive(self):
3847 test = (
3848 '#if defined(HAS_ENERGY)\n'
3849 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
3850 '#else\n'
3851 '#define MAYBE_CastExplosion CastExplosion\n'
3852 '#endif\n'
3853 'TEST_F(ArchWizard, CastExplosion) {\n'
3854 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
3855 '#define MAYBE_ArchPriest ArchPriest\n'
3856 '#else\n'
3857 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
3858 '#endif\n'
3859 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
3860 '#if !defined(CRUSADER_IN_PARTY)\n'
3861 '#define MAYBE_Crusader \\\n'
3862 ' DISABLED_Crusader \n'
3863 '#else\n'
3864 '#define MAYBE_Crusader \\\n'
3865 ' Crusader\n'
3866 '#endif\n'
3867 ' TEST_F(\n'
3868 ' Crusader,\n'
3869 ' CastTaunt) { }\n'
3870 '#if defined(LEARNED_BASIC_SKILLS)\n'
3871 '#define MAYBE_CastSteal \\\n'
3872 ' DISABLED_CastSteal \n'
3873 '#else\n'
3874 '#define MAYBE_CastSteal \\\n'
3875 ' CastSteal\n'
3876 '#endif\n'
3877 ' TEST_F(\n'
3878 ' ThiefClass,\n'
3879 ' CastSteal) { }\n'
3880 )
3881 mock_input_api = MockInputApi()
3882 mock_input_api.files = [
3883 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
3884 ]
3885 results = PRESUBMIT.CheckForgettingMAYBEInTests(mock_input_api,
3886 MockOutputApi())
3887 self.assertEqual(4, len(results))
3888 self.assertTrue('CastExplosion' in results[0].message)
3889 self.assertTrue('fantasyworld/classes_unittest.cc:2' in results[0].message)
3890 self.assertTrue('ArchPriest' in results[1].message)
3891 self.assertTrue('fantasyworld/classes_unittest.cc:8' in results[1].message)
3892 self.assertTrue('Crusader' in results[2].message)
3893 self.assertTrue('fantasyworld/classes_unittest.cc:14' in results[2].message)
3894 self.assertTrue('CastSteal' in results[3].message)
3895 self.assertTrue('fantasyworld/classes_unittest.cc:24' in results[3].message)
3896
3897 def testNegative(self):
3898 test = (
3899 '#if defined(HAS_ENERGY)\n'
3900 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
3901 '#else\n'
3902 '#define MAYBE_CastExplosion CastExplosion\n'
3903 '#endif\n'
3904 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
3905 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
3906 '#define MAYBE_ArchPriest ArchPriest\n'
3907 '#else\n'
3908 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
3909 '#endif\n'
3910 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
3911 '#if !defined(CRUSADER_IN_PARTY)\n'
3912 '#define MAYBE_Crusader \\\n'
3913 ' DISABLED_Crusader \n'
3914 '#else\n'
3915 '#define MAYBE_Crusader \\\n'
3916 ' Crusader\n'
3917 '#endif\n'
3918 ' TEST_F(\n'
3919 ' MAYBE_Crusader,\n'
3920 ' CastTaunt) { }\n'
3921 '#if defined(LEARNED_BASIC_SKILLS)\n'
3922 '#define MAYBE_CastSteal \\\n'
3923 ' DISABLED_CastSteal \n'
3924 '#else\n'
3925 '#define MAYBE_CastSteal \\\n'
3926 ' CastSteal\n'
3927 '#endif\n'
3928 ' TEST_F(\n'
3929 ' ThiefClass,\n'
3930 ' MAYBE_CastSteal) { }\n'
3931 )
3932
3933 mock_input_api = MockInputApi()
3934 mock_input_api.files = [
3935 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
3936 ]
3937 results = PRESUBMIT.CheckForgettingMAYBEInTests(mock_input_api,
3938 MockOutputApi())
3939 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:513940
Max Morozb47503b2019-08-08 21:03:273941class CheckFuzzTargetsTest(unittest.TestCase):
3942
3943 def _check(self, files):
3944 mock_input_api = MockInputApi()
3945 mock_input_api.files = []
3946 for fname, contents in files.items():
3947 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
Saagar Sanghavifceeaae2020-08-12 16:40:363948 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api, MockOutputApi())
Max Morozb47503b2019-08-08 21:03:273949
3950 def testLibFuzzerSourcesIgnored(self):
3951 results = self._check({
3952 "third_party/lib/Fuzzer/FuzzerDriver.cpp": "LLVMFuzzerInitialize",
3953 })
3954 self.assertEqual(results, [])
3955
3956 def testNonCodeFilesIgnored(self):
3957 results = self._check({
3958 "README.md": "LLVMFuzzerInitialize",
3959 })
3960 self.assertEqual(results, [])
3961
3962 def testNoErrorHeaderPresent(self):
3963 results = self._check({
3964 "fuzzer.cc": (
3965 "#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
3966 "LLVMFuzzerInitialize"
3967 )
3968 })
3969 self.assertEqual(results, [])
3970
3971 def testErrorMissingHeader(self):
3972 results = self._check({
3973 "fuzzer.cc": "LLVMFuzzerInitialize"
3974 })
3975 self.assertEqual(len(results), 1)
3976 self.assertEqual(results[0].items, ['fuzzer.cc'])
3977
3978
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263979class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:403980 def testSetNoParentTopLevelAllowed(self):
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:263981 mock_input_api = MockInputApi()
3982 mock_input_api.files = [
3983 MockAffectedFile('goat/OWNERS',
3984 [
3985 'set noparent',
3986 '[email protected]',
John Abd-El-Malekdfd1edc2021-02-24 22:22:403987 ])
3988 ]
3989 mock_output_api = MockOutputApi()
3990 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
3991 self.assertEqual([], errors)
3992
3993 def testSetNoParentMissing(self):
3994 mock_input_api = MockInputApi()
3995 mock_input_api.files = [
3996 MockAffectedFile('services/goat/OWNERS',
3997 [
3998 'set noparent',
3999 '[email protected]',
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264000 'per-file *.json=set noparent',
4001 'per-file *[email protected]',
4002 ])
4003 ]
4004 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:364005 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264006 self.assertEqual(1, len(errors))
4007 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4008 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4009
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264010 def testSetNoParentWithCorrectRule(self):
4011 mock_input_api = MockInputApi()
4012 mock_input_api.files = [
John Abd-El-Malekdfd1edc2021-02-24 22:22:404013 MockAffectedFile('services/goat/OWNERS',
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264014 [
4015 'set noparent',
4016 'file://ipc/SECURITY_OWNERS',
4017 'per-file *.json=set noparent',
4018 'per-file *.json=file://ipc/SECURITY_OWNERS',
4019 ])
4020 ]
4021 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:364022 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264023 self.assertEqual([], errors)
4024
4025
Ken Rockotc31f4832020-05-29 18:58:514026class MojomStabilityCheckTest(unittest.TestCase):
4027 def runTestWithAffectedFiles(self, affected_files):
4028 mock_input_api = MockInputApi()
4029 mock_input_api.files = affected_files
4030 mock_output_api = MockOutputApi()
Saagar Sanghavifceeaae2020-08-12 16:40:364031 return PRESUBMIT.CheckStableMojomChanges(
Ken Rockotc31f4832020-05-29 18:58:514032 mock_input_api, mock_output_api)
4033
4034 def testSafeChangePasses(self):
4035 errors = self.runTestWithAffectedFiles([
4036 MockAffectedFile('foo/foo.mojom',
4037 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4038 old_contents=['[Stable] struct S {};'])
4039 ])
4040 self.assertEqual([], errors)
4041
4042 def testBadChangeFails(self):
4043 errors = self.runTestWithAffectedFiles([
4044 MockAffectedFile('foo/foo.mojom',
4045 ['[Stable] struct S { int32 x; };'],
4046 old_contents=['[Stable] struct S {};'])
4047 ])
4048 self.assertEqual(1, len(errors))
4049 self.assertTrue('not backward-compatible' in errors[0].message)
4050
Ken Rockotad7901f942020-06-04 20:17:094051 def testDeletedFile(self):
4052 """Regression test for https://crbug.com/1091407."""
4053 errors = self.runTestWithAffectedFiles([
4054 MockAffectedFile('a.mojom', [], old_contents=['struct S {};'],
4055 action='D'),
4056 MockAffectedFile('b.mojom',
4057 ['struct S {}; struct T { S s; };'],
4058 old_contents=['import "a.mojom"; struct T { S s; };'])
4059 ])
4060 self.assertEqual([], errors)
4061
Jose Magana2b456f22021-03-09 23:26:404062class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4063
4064 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
4065
4066 # Each positive test is also a naive negative test for the other cases.
4067
4068 def testWarningNMF(self):
4069 mock_input_api = MockInputApi()
4070 mock_input_api.files = [
4071 MockAffectedFile(
4072 'foo.NMF',
4073 ['"program"', '"Z":"content"', 'B'],
4074 ['"program"', 'B'],
4075 scm_diff='\n'.join([
4076 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4077 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4078 '@@ -1,2 +1,3 @@',
4079 ' "program"',
4080 '+"Z":"content"',
4081 ' B']),
4082 action='M')
4083 ]
4084 mock_output_api = MockOutputApi()
4085 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(mock_input_api,
Gao Shenga79ebd42022-08-08 17:25:594086 mock_output_api)
Jose Magana2b456f22021-03-09 23:26:404087 self.assertEqual(1, len(errors))
4088 self.assertTrue( self.ERROR_MSG_PIECE in errors[0].message)
4089 self.assertTrue( 'foo.NMF' in errors[0].message)
4090
4091 def testWarningManifest(self):
4092 mock_input_api = MockInputApi()
4093 mock_input_api.files = [
4094 MockAffectedFile(
4095 'manifest.json',
4096 ['"app":', '"Z":"content"', 'B'],
4097 ['"app":"', 'B'],
4098 scm_diff='\n'.join([
4099 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4100 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4101 '@@ -1,2 +1,3 @@',
4102 ' "app"',
4103 '+"Z":"content"',
4104 ' B']),
4105 action='M')
4106 ]
4107 mock_output_api = MockOutputApi()
4108 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(mock_input_api,
Gao Shenga79ebd42022-08-08 17:25:594109 mock_output_api)
Jose Magana2b456f22021-03-09 23:26:404110 self.assertEqual(1, len(errors))
4111 self.assertTrue( self.ERROR_MSG_PIECE in errors[0].message)
4112 self.assertTrue( 'manifest.json' in errors[0].message)
4113
4114 def testOKWarningManifestWithoutApp(self):
4115 mock_input_api = MockInputApi()
4116 mock_input_api.files = [
4117 MockAffectedFile(
4118 'manifest.json',
4119 ['"name":', '"Z":"content"', 'B'],
4120 ['"name":"', 'B'],
4121 scm_diff='\n'.join([
4122 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4123 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4124 '@@ -1,2 +1,3 @@',
4125 ' "app"',
4126 '+"Z":"content"',
4127 ' B']),
4128 action='M')
4129 ]
4130 mock_output_api = MockOutputApi()
4131 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(mock_input_api,
Gao Shenga79ebd42022-08-08 17:25:594132 mock_output_api)
Jose Magana2b456f22021-03-09 23:26:404133 self.assertEqual(0, len(errors))
4134
4135 def testWarningPPAPI(self):
4136 mock_input_api = MockInputApi()
4137 mock_input_api.files = [
4138 MockAffectedFile(
4139 'foo.hpp',
4140 ['A', '#include <ppapi.h>', 'B'],
4141 ['A', 'B'],
4142 scm_diff='\n'.join([
4143 '--- foo.hpp.old 2020-12-02 20:40:54.430676385 +0100',
4144 '+++ foo.hpp.new 2020-12-02 20:41:02.086700197 +0100',
4145 '@@ -1,2 +1,3 @@',
4146 ' A',
4147 '+#include <ppapi.h>',
4148 ' B']),
4149 action='M')
4150 ]
4151 mock_output_api = MockOutputApi()
4152 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(mock_input_api,
Gao Shenga79ebd42022-08-08 17:25:594153 mock_output_api)
Jose Magana2b456f22021-03-09 23:26:404154 self.assertEqual(1, len(errors))
4155 self.assertTrue( self.ERROR_MSG_PIECE in errors[0].message)
4156 self.assertTrue( 'foo.hpp' in errors[0].message)
4157
4158 def testNoWarningPPAPI(self):
4159 mock_input_api = MockInputApi()
4160 mock_input_api.files = [
4161 MockAffectedFile(
4162 'foo.txt',
4163 ['A', 'Peppapig', 'B'],
4164 ['A', 'B'],
4165 scm_diff='\n'.join([
4166 '--- foo.txt.old 2020-12-02 20:40:54.430676385 +0100',
4167 '+++ foo.txt.new 2020-12-02 20:41:02.086700197 +0100',
4168 '@@ -1,2 +1,3 @@',
4169 ' A',
4170 '+Peppapig',
4171 ' B']),
4172 action='M')
4173 ]
4174 mock_output_api = MockOutputApi()
4175 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(mock_input_api,
Gao Shenga79ebd42022-08-08 17:25:594176 mock_output_api)
Jose Magana2b456f22021-03-09 23:26:404177 self.assertEqual(0, len(errors))
4178
Dominic Battre645d42342020-12-04 16:14:104179class CheckDeprecationOfPreferencesTest(unittest.TestCase):
4180 # Test that a warning is generated if a preference registration is removed
4181 # from a random file.
4182 def testWarning(self):
4183 mock_input_api = MockInputApi()
4184 mock_input_api.files = [
4185 MockAffectedFile(
4186 'foo.cc',
4187 ['A', 'B'],
4188 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4189 scm_diff='\n'.join([
4190 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4191 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4192 '@@ -1,3 +1,2 @@',
4193 ' A',
4194 '-prefs->RegisterStringPref("foo", "default");',
4195 ' B']),
4196 action='M')
4197 ]
4198 mock_output_api = MockOutputApi()
4199 errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
4200 mock_output_api)
4201 self.assertEqual(1, len(errors))
4202 self.assertTrue(
4203 'Discovered possible removal of preference registrations' in
4204 errors[0].message)
4205
4206 # Test that a warning is inhibited if the preference registration was moved
4207 # to the deprecation functions in browser prefs.
4208 def testNoWarningForMigration(self):
4209 mock_input_api = MockInputApi()
4210 mock_input_api.files = [
4211 # RegisterStringPref was removed from foo.cc.
4212 MockAffectedFile(
4213 'foo.cc',
4214 ['A', 'B'],
4215 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4216 scm_diff='\n'.join([
4217 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4218 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4219 '@@ -1,3 +1,2 @@',
4220 ' A',
4221 '-prefs->RegisterStringPref("foo", "default");',
4222 ' B']),
4223 action='M'),
4224 # But the preference was properly migrated.
4225 MockAffectedFile(
4226 'chrome/browser/prefs/browser_prefs.cc',
4227 [
4228 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4229 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4230 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4231 'prefs->RegisterStringPref("foo", "default");',
4232 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4233 ],
4234 [
4235 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4236 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4237 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4238 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4239 ],
4240 scm_diff='\n'.join([
4241 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4242 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4243 '@@ -2,3 +2,4 @@',
4244 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4245 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4246 '+prefs->RegisterStringPref("foo", "default");',
4247 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS']),
4248 action='M'),
4249 ]
4250 mock_output_api = MockOutputApi()
4251 errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
4252 mock_output_api)
4253 self.assertEqual(0, len(errors))
4254
4255 # Test that a warning is NOT inhibited if the preference registration was
4256 # moved to a place outside of the migration functions in browser_prefs.cc
4257 def testWarningForImproperMigration(self):
4258 mock_input_api = MockInputApi()
4259 mock_input_api.files = [
4260 # RegisterStringPref was removed from foo.cc.
4261 MockAffectedFile(
4262 'foo.cc',
4263 ['A', 'B'],
4264 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4265 scm_diff='\n'.join([
4266 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4267 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4268 '@@ -1,3 +1,2 @@',
4269 ' A',
4270 '-prefs->RegisterStringPref("foo", "default");',
4271 ' B']),
4272 action='M'),
4273 # The registration call was moved to a place in browser_prefs.cc that
4274 # is outside the migration functions.
4275 MockAffectedFile(
4276 'chrome/browser/prefs/browser_prefs.cc',
4277 [
4278 'prefs->RegisterStringPref("foo", "default");',
4279 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4280 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4281 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4282 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4283 ],
4284 [
4285 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4286 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4287 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4288 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4289 ],
4290 scm_diff='\n'.join([
4291 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4292 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4293 '@@ -1,2 +1,3 @@',
4294 '+prefs->RegisterStringPref("foo", "default");',
4295 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4296 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS']),
4297 action='M'),
4298 ]
4299 mock_output_api = MockOutputApi()
4300 errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
4301 mock_output_api)
4302 self.assertEqual(1, len(errors))
4303 self.assertTrue(
4304 'Discovered possible removal of preference registrations' in
4305 errors[0].message)
4306
Gao Shenga79ebd42022-08-08 17:25:594307 # Check that the presubmit fails if a marker line in browser_prefs.cc is
Dominic Battre645d42342020-12-04 16:14:104308 # deleted.
4309 def testDeletedMarkerRaisesError(self):
4310 mock_input_api = MockInputApi()
4311 mock_input_api.files = [
4312 MockAffectedFile('chrome/browser/prefs/browser_prefs.cc',
4313 [
4314 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4315 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4316 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4317 # The following line is deleted for this test
4318 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4319 ])
4320 ]
4321 mock_output_api = MockOutputApi()
4322 errors = PRESUBMIT.CheckDeprecationOfPreferences(mock_input_api,
4323 mock_output_api)
4324 self.assertEqual(1, len(errors))
4325 self.assertEqual(
4326 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4327 errors[0].message)
4328
Kevin McNee967dd2d22021-11-15 16:09:294329class MPArchApiUsage(unittest.TestCase):
Kevin McNee4eeec792022-02-14 20:02:044330 def _assert_notify(
Kevin McNee29c0e8232022-08-05 15:36:094331 self, expected_uses, expect_fyi, msg, local_path, new_contents):
Kevin McNee967dd2d22021-11-15 16:09:294332 mock_input_api = MockInputApi()
4333 mock_output_api = MockOutputApi()
4334 mock_input_api.files = [
4335 MockFile(local_path, new_contents),
4336 ]
Kevin McNee4eeec792022-02-14 20:02:044337 result = PRESUBMIT.CheckMPArchApiUsage(mock_input_api, mock_output_api)
Kevin McNee29c0e8232022-08-05 15:36:094338
4339 watchlist_email = ('[email protected]'
4340 if expect_fyi else '[email protected]')
Kevin McNee967dd2d22021-11-15 16:09:294341 self.assertEqual(
Kevin McNee29c0e8232022-08-05 15:36:094342 bool(expected_uses or expect_fyi),
4343 watchlist_email in mock_output_api.more_cc,
Kevin McNee967dd2d22021-11-15 16:09:294344 msg)
Kevin McNee4eeec792022-02-14 20:02:044345 if expected_uses:
4346 self.assertEqual(1, len(result), msg)
4347 self.assertEqual(result[0].type, 'notify', msg)
4348 self.assertEqual(sorted(result[0].items), sorted(expected_uses), msg)
Kevin McNee29c0e8232022-08-05 15:36:094349 else:
4350 self.assertEqual(0, len(result), msg)
Kevin McNee967dd2d22021-11-15 16:09:294351
4352 def testNotify(self):
4353 self._assert_notify(
Kevin McNee4eeec792022-02-14 20:02:044354 ['IsInMainFrame'],
Kevin McNee29c0e8232022-08-05 15:36:094355 False,
Kevin McNee967dd2d22021-11-15 16:09:294356 'Introduce IsInMainFrame',
4357 'chrome/my_feature.cc',
4358 ['void DoSomething(content::NavigationHandle* navigation_handle) {',
4359 ' if (navigation_handle->IsInMainFrame())',
4360 ' all_of_our_page_state.reset();',
4361 '}',
4362 ])
4363 self._assert_notify(
Kevin McNee4eeec792022-02-14 20:02:044364 ['FromRenderFrameHost'],
Kevin McNee29c0e8232022-08-05 15:36:094365 False,
Kevin McNee967dd2d22021-11-15 16:09:294366 'Introduce WC::FromRenderFrameHost',
4367 'chrome/my_feature.cc',
4368 ['void DoSomething(content::RenderFrameHost* rfh) {',
4369 ' auto* wc = content::WebContents::FromRenderFrameHost(rfh);',
4370 ' ChangeTabState(wc);',
4371 '}',
4372 ])
4373
Kevin McNee29c0e8232022-08-05 15:36:094374 def testFyi(self):
4375 self._assert_notify(
4376 [],
4377 True,
4378 'Introduce WCO and WCUD',
4379 'chrome/my_feature.h',
4380 ['class MyFeature',
4381 ' : public content::WebContentsObserver,',
4382 ' public content::WebContentsUserData<MyFeature> {};',
4383 ])
4384 self._assert_notify(
4385 [],
4386 True,
4387 'Introduce WCO override',
4388 'chrome/my_feature.h',
4389 ['void DidFinishNavigation(',
4390 ' content::NavigationHandle* navigation_handle) override;',
4391 ])
4392
Kevin McNee967dd2d22021-11-15 16:09:294393 def testNoNotify(self):
4394 self._assert_notify(
Kevin McNee4eeec792022-02-14 20:02:044395 [],
Kevin McNee29c0e8232022-08-05 15:36:094396 False,
Kevin McNee967dd2d22021-11-15 16:09:294397 'No API usage',
4398 'chrome/my_feature.cc',
4399 ['void DoSomething() {',
4400 ' // TODO: Something',
4401 '}',
4402 ])
4403 # Something under a top level directory we're not concerned about happens
4404 # to share a name with a content API.
4405 self._assert_notify(
Kevin McNee4eeec792022-02-14 20:02:044406 [],
Kevin McNee29c0e8232022-08-05 15:36:094407 False,
Kevin McNee967dd2d22021-11-15 16:09:294408 'Uninteresting top level directory',
4409 'third_party/my_dep/my_code.cc',
4410 ['bool HasParent(Node* node) {',
4411 ' return node->GetParent();',
4412 '}',
4413 ])
4414 # We're not concerned with usage in test code.
4415 self._assert_notify(
Kevin McNee4eeec792022-02-14 20:02:044416 [],
Kevin McNee29c0e8232022-08-05 15:36:094417 False,
Kevin McNee967dd2d22021-11-15 16:09:294418 'Usage in test code',
4419 'chrome/my_feature_unittest.cc',
4420 ['TEST_F(MyFeatureTest, DoesSomething) {',
Kevin McNee29c0e8232022-08-05 15:36:094421 ' EXPECT_TRUE(rfh()->GetMainFrame());',
Kevin McNee967dd2d22021-11-15 16:09:294422 '}',
4423 ])
4424
Dominic Battre645d42342020-12-04 16:14:104425
Henrique Ferreiro2a4b55942021-11-29 23:45:364426class AssertAshOnlyCodeTest(unittest.TestCase):
4427 def testErrorsOnlyOnAshDirectories(self):
4428 files_in_ash = [
4429 MockFile('ash/BUILD.gn', []),
4430 MockFile('chrome/browser/ash/BUILD.gn', []),
4431 ]
4432 other_files = [
4433 MockFile('chrome/browser/BUILD.gn', []),
4434 MockFile('chrome/browser/BUILD.gn', ['assert(is_chromeos_ash)']),
4435 ]
4436 input_api = MockInputApi()
4437 input_api.files = files_in_ash
4438 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4439 self.assertEqual(2, len(errors))
4440
4441 input_api.files = other_files
4442 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4443 self.assertEqual(0, len(errors))
4444
4445 def testDoesNotErrorOnNonGNFiles(self):
4446 input_api = MockInputApi()
4447 input_api.files = [
4448 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4449 MockFile('chrome/browser/ash/test.cc',
4450 ['assert(is_chromeos_ash)']),
4451 ]
4452 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4453 self.assertEqual(0, len(errors))
4454
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214455 def testDeletedFile(self):
4456 input_api = MockInputApi()
4457 input_api.files = [
4458 MockFile('ash/BUILD.gn', []),
4459 MockFile('ash/foo/BUILD.gn', [], action='D'),
4460 ]
4461 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4462 self.assertEqual(1, len(errors))
4463
Henrique Ferreiro2a4b55942021-11-29 23:45:364464 def testDoesNotErrorWithAssertion(self):
4465 input_api = MockInputApi()
4466 input_api.files = [
4467 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4468 MockFile('chrome/browser/ash/BUILD.gn',
4469 ['assert(is_chromeos_ash)']),
4470 MockFile('chrome/browser/ash/BUILD.gn',
4471 ['assert(is_chromeos_ash, "test")']),
4472 ]
4473 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4474 self.assertEqual(0, len(errors))
4475
4476
Lukasz Anforowicz7016d05e2021-11-30 03:56:274477class CheckRawPtrUsageTest(unittest.TestCase):
4478 def testAllowedCases(self):
4479 mock_input_api = MockInputApi()
4480 mock_input_api.files = [
4481 # Browser-side files are allowed.
4482 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4483 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4484 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4485 MockAffectedFile('test13/blink/public/common/foo.cc', ['raw_ptr<int>']),
4486 MockAffectedFile('test14/blink/public/platform/foo.cc',
4487 ['raw_ptr<int>']),
4488
4489 # Non-C++ files are allowed.
4490 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
4491
4492 # Mentions in a comment are allowed.
4493 MockAffectedFile('test30/renderer/foo.cc', ['//raw_ptr<int>']),
4494 ]
4495 mock_output_api = MockOutputApi()
4496 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4497 self.assertFalse(errors)
4498
4499 def testDisallowedCases(self):
4500 mock_input_api = MockInputApi()
4501 mock_input_api.files = [
4502 MockAffectedFile('test1/renderer/foo.h', ['raw_ptr<int>']),
4503 MockAffectedFile('test2/renderer/foo.cc', ['raw_ptr<int>']),
4504 MockAffectedFile('test3/blink/public/web/foo.cc', ['raw_ptr<int>']),
4505 ]
4506 mock_output_api = MockOutputApi()
4507 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4508 self.assertEqual(len(mock_input_api.files), len(errors))
4509 for error in errors:
4510 self.assertTrue(
4511 'raw_ptr<T> should not be used in Renderer-only code' in
4512 error.message)
4513
4514
Henrique Ferreirof9819f2e32021-11-30 13:31:564515class AssertPythonShebangTest(unittest.TestCase):
4516 def testError(self):
4517 input_api = MockInputApi()
4518 input_api.files = [
4519 MockFile('ash/test.py', ['#!/usr/bin/python']),
4520 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
4521 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:274522 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:564523 ]
4524 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
4525 self.assertEqual(3, len(errors))
4526
4527 def testNonError(self):
4528 input_api = MockInputApi()
4529 input_api.files = [
4530 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
4531 MockFile('third_party/blink/web_tests/external/test.py',
4532 ['#!/usr/bin/python2']),
4533 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
4534 ]
4535 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
4536 self.assertEqual(0, len(errors))
4537
Kalvin Lee4a3b79de2022-05-26 16:00:164538class VerifyDcheckParentheses(unittest.TestCase):
4539 def testPermissibleUsage(self):
4540 input_api = MockInputApi()
4541 input_api.files = [
4542 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
4543 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
4544
4545 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
4546 # own thing at their own risk.
4547 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
4548 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
4549 MockFile('okay6.cc', ['BUILDFLAG(PA_DCHECK_IS_ON)']),
4550 ]
4551 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api, MockOutputApi())
4552 self.assertEqual(0, len(errors))
4553
4554 def testMissingParentheses(self):
4555 input_api = MockInputApi()
4556 input_api.files = [
4557 MockFile('bad1.cc', ['DCHECK_IS_ON']),
4558 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
4559 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
4560 ]
4561 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api, MockOutputApi())
4562 self.assertEqual(3, len(errors))
4563 for error in errors:
4564 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:564565
James Shen81cc0e22022-06-15 21:10:454566class CheckBatchAnnotation(unittest.TestCase):
4567 """Test the CheckBatchAnnotation presubmit check."""
4568
4569 def testTruePositives(self):
4570 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
4571"""
4572 mock_input = MockInputApi()
4573 mock_input.files = [
4574 MockFile('path/OneTest.java', ['public class OneTest']),
4575 MockFile('path/TwoTest.java', ['public class TwoTest']),
ckitagawae8fd23b2022-06-17 15:29:384576 MockFile('path/ThreeTest.java',
4577 ['@Batch(Batch.PER_CLASS)',
4578 'import org.chromium.base.test.BaseRobolectricTestRunner;',
4579 'public class Three {']),
4580 MockFile('path/FourTest.java',
4581 ['@DoNotBatch(reason = "dummy reason 1")',
4582 'import org.chromium.base.test.BaseRobolectricTestRunner;',
4583 'public class Four {']),
James Shen81cc0e22022-06-15 21:10:454584 ]
4585 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
ckitagawae8fd23b2022-06-17 15:29:384586 self.assertEqual(2, len(errors))
James Shen81cc0e22022-06-15 21:10:454587 self.assertEqual(2, len(errors[0].items))
4588 self.assertIn('OneTest.java', errors[0].items[0])
4589 self.assertIn('TwoTest.java', errors[0].items[1])
ckitagawae8fd23b2022-06-17 15:29:384590 self.assertEqual(2, len(errors[1].items))
4591 self.assertIn('ThreeTest.java', errors[1].items[0])
4592 self.assertIn('FourTest.java', errors[1].items[1])
4593
James Shen81cc0e22022-06-15 21:10:454594
4595 def testAnnotationsPresent(self):
4596 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
4597 mock_input = MockInputApi()
4598 mock_input.files = [
4599 MockFile('path/OneTest.java',
4600 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
4601 MockFile('path/TwoTest.java',
4602 ['@DoNotBatch(reason = "dummy reasons.")', 'public class Two {'
4603 ]),
4604 MockFile('path/ThreeTest.java',
4605 ['@Batch(Batch.PER_CLASS)',
4606 'public class Three extends BaseTestA {'],
4607 ['@Batch(Batch.PER_CLASS)',
4608 'public class Three extends BaseTestB {']),
4609 MockFile('path/FourTest.java',
4610 ['@DoNotBatch(reason = "dummy reason 1")',
4611 'public class Four extends BaseTestA {'],
4612 ['@DoNotBatch(reason = "dummy reason 2")',
4613 'public class Four extends BaseTestB {']),
4614 MockFile('path/FiveTest.java',
4615 ['import androidx.test.uiautomator.UiDevice;',
4616 'public class Five extends BaseTestA {'],
4617 ['import androidx.test.uiautomator.UiDevice;',
4618 'public class Five extends BaseTestB {']),
4619 MockFile('path/SixTest.java',
4620 ['import org.chromium.base.test.BaseRobolectricTestRunner;',
4621 'public class Six extends BaseTestA {'],
4622 ['import org.chromium.base.test.BaseRobolectricTestRunner;',
4623 'public class Six extends BaseTestB {']),
4624 MockFile('path/SevenTest.java',
4625 ['import org.robolectric.annotation.Config;',
4626 'public class Seven extends BaseTestA {'],
4627 ['import org.robolectric.annotation.Config;',
4628 'public class Seven extends BaseTestB {']),
4629 MockFile(
4630 'path/OtherClass.java',
4631 ['public class OtherClass {'],
4632 ),
4633 MockFile('path/PRESUBMIT.py',
4634 ['@Batch(Batch.PER_CLASS)',
4635 '@DoNotBatch(reason = "dummy reason)']),
4636 ]
4637 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
4638 self.assertEqual(0, len(errors))
4639
4640
[email protected]2299dcf2012-11-15 19:56:244641if __name__ == '__main__':
4642 unittest.main()