blob: d8eda3613f2d6b71a219496aeee33492eb525728 [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
Min Qinbc44383c2023-02-22 17:25:269import textwrap
[email protected]2299dcf2012-11-15 19:56:2410import unittest
11
12import PRESUBMIT
Saagar Sanghavifceeaae2020-08-12 16:40:3613
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3914from PRESUBMIT_test_mocks import MockFile, MockAffectedFile
gayane3dff8c22014-12-04 17:09:5115from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
[email protected]2299dcf2012-11-15 19:56:2416
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3917
[email protected]99171a92014-06-03 08:44:4718_TEST_DATA_DIR = 'base/test/data/presubmit'
19
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3920
[email protected]b00342e7f2013-03-26 16:21:5421class VersionControlConflictsTest(unittest.TestCase):
[email protected]70ca77752012-11-20 03:45:0322
Daniel Cheng566634ff2024-06-29 14:56:5323 def testTypicalConflict(self):
24 lines = [
25 '<<<<<<< HEAD', ' base::ScopedTempDir temp_dir_;', '=======',
26 ' ScopedTempDir temp_dir_;', '>>>>>>> master'
27 ]
28 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
29 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
30 self.assertEqual(3, len(errors))
31 self.assertTrue('1' in errors[0])
32 self.assertTrue('3' in errors[1])
33 self.assertTrue('5' in errors[2])
34
35 def testIgnoresReadmes(self):
36 lines = [
37 'A First Level Header', '====================', '',
38 'A Second Level Header', '---------------------'
39 ]
40 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
41 MockInputApi(), MockFile('some/polymer/README.md', lines))
42 self.assertEqual(0, len(errors))
dbeam95c35a2f2015-06-02 01:40:2343
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3944
[email protected]b8079ae4a2012-12-05 19:56:4945class BadExtensionsTest(unittest.TestCase):
[email protected]b8079ae4a2012-12-05 19:56:4946
Daniel Cheng566634ff2024-06-29 14:56:5347 def testBadRejFile(self):
48 mock_input_api = MockInputApi()
49 mock_input_api.files = [
50 MockFile('some/path/foo.cc', ''),
51 MockFile('some/path/foo.cc.rej', ''),
52 MockFile('some/path2/bar.h.rej', ''),
53 ]
[email protected]b8079ae4a2012-12-05 19:56:4954
Daniel Cheng566634ff2024-06-29 14:56:5355 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
56 self.assertEqual(1, len(results))
57 self.assertEqual(2, len(results[0].items))
58 self.assertTrue('foo.cc.rej' in results[0].items[0])
59 self.assertTrue('bar.h.rej' in results[0].items[1])
[email protected]b8079ae4a2012-12-05 19:56:4960
Daniel Cheng566634ff2024-06-29 14:56:5361 def testBadOrigFile(self):
62 mock_input_api = MockInputApi()
63 mock_input_api.files = [
64 MockFile('other/path/qux.h.orig', ''),
65 MockFile('other/path/qux.h', ''),
66 MockFile('other/path/qux.cc', ''),
67 ]
[email protected]b8079ae4a2012-12-05 19:56:4968
Daniel Cheng566634ff2024-06-29 14:56:5369 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
70 self.assertEqual(1, len(results))
71 self.assertEqual(1, len(results[0].items))
72 self.assertTrue('qux.h.orig' in results[0].items[0])
73
74 def testGoodFiles(self):
75 mock_input_api = MockInputApi()
76 mock_input_api.files = [
77 MockFile('other/path/qux.h', ''),
78 MockFile('other/path/qux.cc', ''),
79 ]
80 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
81 self.assertEqual(0, len(results))
[email protected]b8079ae4a2012-12-05 19:56:4982
83
Lei Zhang1c12a22f2021-05-12 11:28:4584class CheckForSuperfluousStlIncludesInHeadersTest(unittest.TestCase):
Lei Zhang1c12a22f2021-05-12 11:28:4585
Daniel Cheng566634ff2024-06-29 14:56:5386 def testGoodFiles(self):
87 mock_input_api = MockInputApi()
88 mock_input_api.files = [
89 # The check is not smart enough to figure out which definitions correspond
90 # to which header.
91 MockFile('other/path/foo.h', ['#include <string>', 'std::vector']),
92 # The check is not smart enough to do IWYU.
93 MockFile('other/path/bar.h',
94 ['#include "base/check.h"', 'std::vector']),
95 MockFile('other/path/qux.h',
96 ['#include "base/stl_util.h"', 'foobar']),
97 MockFile('other/path/baz.h',
98 ['#include "set/vector.h"', 'bazzab']),
99 # The check is only for header files.
100 MockFile('other/path/not_checked.cc',
101 ['#include <vector>', 'bazbaz']),
102 ]
103 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
104 mock_input_api, MockOutputApi())
105 self.assertEqual(0, len(results))
106
107 def testBadFiles(self):
108 mock_input_api = MockInputApi()
109 mock_input_api.files = [
110 MockFile('other/path/foo.h', ['#include <vector>', 'vector']),
111 MockFile(
112 'other/path/bar.h',
113 ['#include <limits>', '#include <set>', 'no_std_namespace']),
114 ]
115 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
116 mock_input_api, MockOutputApi())
117 self.assertEqual(1, len(results))
118 self.assertTrue('foo.h: Includes STL' in results[0].message)
119 self.assertTrue('bar.h: Includes STL' in results[0].message)
Lei Zhang1c12a22f2021-05-12 11:28:45120
121
glidere61efad2015-02-18 17:39:43122class CheckSingletonInHeadersTest(unittest.TestCase):
glidere61efad2015-02-18 17:39:43123
Daniel Cheng566634ff2024-06-29 14:56:53124 def testSingletonInArbitraryHeader(self):
125 diff_singleton_h = [
126 'base::subtle::AtomicWord '
127 'base::Singleton<Type, Traits, DifferentiatingType>::'
128 ]
129 diff_foo_h = [
130 '// base::Singleton<Foo> in comment.',
131 'friend class base::Singleton<Foo>'
132 ]
133 diff_foo2_h = [' //Foo* bar = base::Singleton<Foo>::get();']
134 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
135 mock_input_api = MockInputApi()
136 mock_input_api.files = [
137 MockAffectedFile('base/memory/singleton.h', diff_singleton_h),
138 MockAffectedFile('foo.h', diff_foo_h),
139 MockAffectedFile('foo2.h', diff_foo2_h),
140 MockAffectedFile('bad.h', diff_bad_h)
141 ]
142 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
143 MockOutputApi())
144 self.assertEqual(1, len(warnings))
145 self.assertEqual(1, len(warnings[0].items))
146 self.assertEqual('error', warnings[0].type)
147 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
148
149 def testSingletonInCC(self):
150 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
151 mock_input_api = MockInputApi()
152 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
153 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
154 MockOutputApi())
155 self.assertEqual(0, len(warnings))
glidere61efad2015-02-18 17:39:43156
157
Xiaohan Wang42d96c22022-01-20 17:23:11158class DeprecatedOSMacroNamesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:53159
160 def testDeprecatedOSMacroNames(self):
161 lines = [
162 '#if defined(OS_WIN)', ' #elif defined(OS_WINDOW)',
163 ' # if defined(OS_MAC) || defined(OS_CHROME)'
164 ]
165 errors = PRESUBMIT._CheckForDeprecatedOSMacrosInFile(
166 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
167 self.assertEqual(len(lines) + 1, len(errors))
168 self.assertTrue(
169 ':1: defined(OS_WIN) -> BUILDFLAG(IS_WIN)' in errors[0])
[email protected]b00342e7f2013-03-26 16:21:54170
171
lliabraa35bab3932014-10-01 12:16:44172class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
lliabraa35bab3932014-10-01 12:16:44173
Daniel Cheng566634ff2024-06-29 14:56:53174 def testInvalidIfDefinedMacroNames(self):
175 lines = [
176 '#if defined(TARGET_IPHONE_SIMULATOR)',
177 '#if !defined(TARGET_IPHONE_SIMULATOR)',
178 '#elif defined(TARGET_IPHONE_SIMULATOR)',
179 '#ifdef TARGET_IPHONE_SIMULATOR',
180 ' # ifdef TARGET_IPHONE_SIMULATOR',
181 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
182 '# else // defined(TARGET_IPHONE_SIMULATOR)',
183 '#endif // defined(TARGET_IPHONE_SIMULATOR)'
184 ]
185 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
186 MockInputApi(), MockFile('some/path/source.mm', lines))
187 self.assertEqual(len(lines), len(errors))
188
189 def testValidIfDefinedMacroNames(self):
190 lines = [
191 '#if defined(FOO)', '#ifdef BAR', '#if TARGET_IPHONE_SIMULATOR'
192 ]
193 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
194 MockInputApi(), MockFile('some/path/source.cc', lines))
195 self.assertEqual(0, len(errors))
lliabraa35bab3932014-10-01 12:16:44196
197
Andrew Williamsc9f69b482023-07-10 16:07:36198class CheckNoUNIT_TESTInSourceFilesTest(unittest.TestCase):
Andrew Williamsc9f69b482023-07-10 16:07:36199
Daniel Cheng566634ff2024-06-29 14:56:53200 def testUnitTestMacros(self):
201 lines = [
202 '#if defined(UNIT_TEST)', '#if defined UNIT_TEST',
203 '#if !defined(UNIT_TEST)', '#elif defined(UNIT_TEST)',
204 '#ifdef UNIT_TEST', ' # ifdef UNIT_TEST', '#ifndef UNIT_TEST',
205 '# if defined(VALID) || defined(UNIT_TEST)',
206 '# if defined(UNIT_TEST) && defined(VALID)',
207 '# else // defined(UNIT_TEST)', '#endif // defined(UNIT_TEST)'
208 ]
209 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
210 MockInputApi(), MockFile('some/path/source.cc', lines))
211 self.assertEqual(len(lines), len(errors))
212
213 def testNotUnitTestMacros(self):
214 lines = [
215 '// Comment about "#if defined(UNIT_TEST)"',
216 '/* Comment about #if defined(UNIT_TEST)" */',
217 '#ifndef UNIT_TEST_H', '#define UNIT_TEST_H',
218 '#ifndef TEST_UNIT_TEST', '#define TEST_UNIT_TEST',
219 '#if defined(_UNIT_TEST)', '#if defined(UNIT_TEST_)',
220 '#ifdef _UNIT_TEST', '#ifdef UNIT_TEST_', '#ifndef _UNIT_TEST',
221 '#ifndef UNIT_TEST_'
222 ]
223 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
224 MockInputApi(), MockFile('some/path/source.cc', lines))
225 self.assertEqual(0, len(errors))
Andrew Williamsc9f69b482023-07-10 16:07:36226
Rasika Navarangec2d33d22024-05-23 15:19:02227
228class CheckEachPerfettoTestDataFileHasDepsEntry(unittest.TestCase):
229
Daniel Cheng566634ff2024-06-29 14:56:53230 def testNewSha256FileNoDEPS(self):
231 input_api = MockInputApi()
232 input_api.files = [
233 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', []),
234 ]
235 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
236 input_api, MockOutputApi())
237 self.assertEqual(
238 ('You must update the DEPS file when you update a .sha256 file '
239 'in base/tracing/test/data_sha256'), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02240
Daniel Cheng566634ff2024-06-29 14:56:53241 def testNewSha256FileSuccess(self):
242 input_api = MockInputApi()
243 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02244 'src/base/tracing/test/data': {
245 'bucket': 'perfetto',
246 'objects': [
247 {
248 'object_name': 'test_data/new.pftrace-a1b2c3f4',
249 'sha256sum': 'a1b2c3f4',
250 'size_bytes': 1,
251 'generation': 1,
252 'output_file': 'new.pftrace'
253 },
254 ],
255 'dep_type': 'gcs'
256 },
257 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53258 input_api.files = [
259 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
260 ['a1b2c3f4']),
261 MockFile('DEPS', new_deps,
262 ["deps={'src/base/tracing/test/data':{}}"]),
263 ]
264 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
265 input_api, MockOutputApi())
266 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02267
Daniel Cheng566634ff2024-06-29 14:56:53268 def testNewSha256FileWrongSha256(self):
269 input_api = MockInputApi()
270 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02271 'src/base/tracing/test/data': {
272 'bucket': 'perfetto',
273 'objects': [
274 {
275 'object_name': 'test_data/new.pftrace-a1b2c3f4',
276 'sha256sum': 'wrong_hash',
277 'size_bytes': 1,
278 'generation': 1,
279 'output_file': 'new.pftrace'
280 },
281 ],
282 'dep_type': 'gcs'
283 },
284 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53285 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
286 ['a1b2c3f4'])
287 input_api.files = [
288 f,
289 MockFile('DEPS', new_deps,
290 ["deps={'src/base/tracing/test/data':{}}"]),
291 ]
292 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
293 input_api, MockOutputApi())
294 self.assertEqual(
295 ('No corresponding DEPS entry found for %s. '
296 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
297 'to generate the DEPS entry.' % (f.LocalPath(), f.LocalPath())),
298 results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02299
Daniel Cheng566634ff2024-06-29 14:56:53300 def testDeleteSha256File(self):
301 input_api = MockInputApi()
302 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02303 'src/base/tracing/test/data': {
304 'bucket': 'perfetto',
305 'objects': [
306 {
307 'object_name': 'test_data/new.pftrace-a1b2c3f4',
308 'sha256sum': 'a1b2c3f4',
309 'size_bytes': 1,
310 'generation': 1,
311 'output_file': 'new.pftrace'
312 },
313 ],
314 'dep_type': 'gcs'
315 },
316 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53317 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
318 ['a1b2c3f4'],
319 action='D')
320 input_api.files = [
321 f,
322 MockFile('DEPS', old_deps, old_deps),
323 ]
324 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
325 input_api, MockOutputApi())
326 self.assertEqual((
327 'You deleted %s so you must also remove the corresponding DEPS entry.'
328 % f.LocalPath()), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02329
Daniel Cheng566634ff2024-06-29 14:56:53330 def testDeleteSha256Success(self):
331 input_api = MockInputApi()
332 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02333 'src/base/tracing/test/data': {
334 'bucket': 'perfetto',
335 'objects': [],
336 'dep_type': 'gcs'
337 },
338 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53339 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02340 'src/base/tracing/test/data': {
341 'bucket': 'perfetto',
342 'objects': [
343 {
344 'object_name': 'test_data/new.pftrace-a1b2c3f4',
345 'sha256sum': 'a1b2c3f4',
346 'size_bytes': 1,
347 'generation': 1,
348 'output_file': 'new.pftrace'
349 },
350 ],
351 'dep_type': 'gcs'
352 },
353 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53354 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
355 ['a1b2c3f4'],
356 action='D')
357 input_api.files = [
358 f,
359 MockFile('DEPS', new_deps, old_deps),
360 ]
361 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
362 input_api, MockOutputApi())
363 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02364
365
Samuel Huang0db2ea22019-12-09 16:42:47366class CheckAddedDepsHaveTestApprovalsTest(unittest.TestCase):
Daniel Cheng4dcdb6b2017-04-13 08:30:17367
Andrew Grieve713b89b2024-10-15 20:20:08368 def setUp(self):
369 self.input_api = input_api = MockInputApi()
370 input_api.environ = {}
371 input_api.owners_client = self.FakeOwnersClient()
372 input_api.gerrit = self.fakeGerrit()
373 input_api.change.issue = 123
374 self.mockOwnersAndReviewers("owner", set(["reviewer"]))
375 self.mockListSubmodules([])
376
Daniel Cheng566634ff2024-06-29 14:56:53377 def calculate(self, old_include_rules, old_specific_include_rules,
378 new_include_rules, new_specific_include_rules):
379 return PRESUBMIT._CalculateAddedDeps(
380 os.path, 'include_rules = %r\nspecific_include_rules = %r' %
381 (old_include_rules, old_specific_include_rules),
382 'include_rules = %r\nspecific_include_rules = %r' %
383 (new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17384
Daniel Cheng566634ff2024-06-29 14:56:53385 def testCalculateAddedDeps(self):
386 old_include_rules = [
387 '+base',
388 '-chrome',
389 '+content',
390 '-grit',
391 '-grit/",',
392 '+jni/fooblat.h',
393 '!sandbox',
394 ]
395 old_specific_include_rules = {
396 'compositor\.*': {
397 '+cc',
398 },
399 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17400
Daniel Cheng566634ff2024-06-29 14:56:53401 new_include_rules = [
402 '-ash',
403 '+base',
404 '+chrome',
405 '+components',
406 '+content',
407 '+grit',
408 '+grit/generated_resources.h",',
409 '+grit/",',
410 '+jni/fooblat.h',
411 '+policy',
412 '+' + os.path.join('third_party', 'WebKit'),
413 ]
414 new_specific_include_rules = {
415 'compositor\.*': {
416 '+cc',
417 },
418 'widget\.*': {
419 '+gpu',
420 },
421 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17422
Daniel Cheng566634ff2024-06-29 14:56:53423 expected = set([
424 os.path.join('chrome', 'DEPS'),
425 os.path.join('gpu', 'DEPS'),
426 os.path.join('components', 'DEPS'),
427 os.path.join('policy', 'DEPS'),
428 os.path.join('third_party', 'WebKit', 'DEPS'),
429 ])
430 self.assertEqual(
431 expected,
432 self.calculate(old_include_rules, old_specific_include_rules,
433 new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17434
Daniel Cheng566634ff2024-06-29 14:56:53435 def testCalculateAddedDepsIgnoresPermutations(self):
436 old_include_rules = [
437 '+base',
438 '+chrome',
439 ]
440 new_include_rules = [
441 '+chrome',
442 '+base',
443 ]
444 self.assertEqual(
445 set(), self.calculate(old_include_rules, {}, new_include_rules,
446 {}))
[email protected]f32e2d1e2013-07-26 21:39:08447
Andrew Grieveb77ac762024-11-29 15:01:48448 def testFindAddedDepsThatRequireReview(self):
449 caring = ['new_usages_require_review = True']
450 self.input_api.InitFiles([
451 MockAffectedFile('cares/DEPS', caring),
452 MockAffectedFile('cares/inherits/DEPS', []),
453 MockAffectedFile('willynilly/DEPS', []),
454 MockAffectedFile('willynilly/butactually/DEPS', caring),
455 ])
456
457 expected = {
458 'cares': True,
459 'cares/sub/sub': True,
460 'cares/inherits': True,
461 'cares/inherits/sub': True,
462 'willynilly': False,
463 'willynilly/butactually': True,
464 'willynilly/butactually/sub': True,
465 }
466 results = PRESUBMIT._FindAddedDepsThatRequireReview(
467 self.input_api, set(expected))
468 actual = {k: k in results for k in expected}
469 self.assertEqual(expected, actual)
470
Daniel Cheng566634ff2024-06-29 14:56:53471 class FakeOwnersClient(object):
472 APPROVED = "APPROVED"
473 PENDING = "PENDING"
474 returns = {}
Scott Leebf6a0942024-06-26 22:59:39475
Daniel Cheng566634ff2024-06-29 14:56:53476 def ListOwners(self, *args, **kwargs):
477 return self.returns.get(self.ListOwners.__name__, "")
Scott Leebf6a0942024-06-26 22:59:39478
Daniel Cheng566634ff2024-06-29 14:56:53479 def mockListOwners(self, owners):
480 self.returns[self.ListOwners.__name__] = owners
Scott Leebf6a0942024-06-26 22:59:39481
Daniel Cheng566634ff2024-06-29 14:56:53482 def GetFilesApprovalStatus(self, *args, **kwargs):
483 return self.returns.get(self.GetFilesApprovalStatus.__name__, {})
Scott Leebf6a0942024-06-26 22:59:39484
Daniel Cheng566634ff2024-06-29 14:56:53485 def mockGetFilesApprovalStatus(self, status):
486 self.returns[self.GetFilesApprovalStatus.__name__] = status
Scott Leebf6a0942024-06-26 22:59:39487
Daniel Cheng566634ff2024-06-29 14:56:53488 def SuggestOwners(self, *args, **kwargs):
489 return ["eng1", "eng2", "eng3"]
Scott Leebf6a0942024-06-26 22:59:39490
Daniel Cheng566634ff2024-06-29 14:56:53491 class fakeGerrit(object):
Scott Leebf6a0942024-06-26 22:59:39492
Daniel Cheng566634ff2024-06-29 14:56:53493 def IsOwnersOverrideApproved(self, issue):
494 return False
Scott Leebf6a0942024-06-26 22:59:39495
Daniel Cheng566634ff2024-06-29 14:56:53496 def mockOwnersAndReviewers(self, owner, reviewers):
Scott Leebf6a0942024-06-26 22:59:39497
Daniel Cheng566634ff2024-06-29 14:56:53498 def mock(*args, **kwargs):
499 return [owner, reviewers]
Scott Leebf6a0942024-06-26 22:59:39500
Daniel Cheng566634ff2024-06-29 14:56:53501 self.input_api.canned_checks.GetCodereviewOwnerAndReviewers = mock
Scott Leebf6a0942024-06-26 22:59:39502
Daniel Cheng566634ff2024-06-29 14:56:53503 def mockListSubmodules(self, paths):
Scott Leebf6a0942024-06-26 22:59:39504
Daniel Cheng566634ff2024-06-29 14:56:53505 def mock(*args, **kwargs):
506 return paths
Scott Leebf6a0942024-06-26 22:59:39507
Daniel Cheng566634ff2024-06-29 14:56:53508 self.input_api.ListSubmodules = mock
509
510 def testApprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08511 self.input_api.InitFiles([
512 MockAffectedFile('pdf/DEPS', ['include_rules=["+v8/123"]']),
Andrew Grieveb77ac762024-11-29 15:01:48513 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Andrew Grieve713b89b2024-10-15 20:20:08514 ])
Daniel Cheng566634ff2024-06-29 14:56:53515
516 # mark the additional dep as approved.
517 os_path = self.input_api.os_path
518 self.input_api.owners_client.mockGetFilesApprovalStatus(
519 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.APPROVED})
520 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
521 self.input_api, MockOutputApi())
522 # Then, the check should pass.
523 self.assertEqual([], results)
524
525 def testUnapprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08526 self.input_api.InitFiles([
527 MockAffectedFile('pdf/DEPS', ['include_rules=["+v8/123"]']),
Andrew Grieveb77ac762024-11-29 15:01:48528 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Andrew Grieve713b89b2024-10-15 20:20:08529 ])
Daniel Cheng566634ff2024-06-29 14:56:53530
531 # pending.
532 os_path = self.input_api.os_path
533 self.input_api.owners_client.mockGetFilesApprovalStatus(
534 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.PENDING})
535 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
536 self.input_api, MockOutputApi())
537 # the check should fail
538 self.assertIn('You need LGTM', results[0].message)
539 self.assertIn('+v8/123', results[0].message)
540
541 # unless the added dep is from a submodule.
542 self.mockListSubmodules(['v8'])
543 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
544 self.input_api, MockOutputApi())
545 self.assertEqual([], results)
Scott Leebf6a0942024-06-26 22:59:39546
[email protected]f32e2d1e2013-07-26 21:39:08547
[email protected]99171a92014-06-03 08:44:47548class JSONParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47549
Daniel Cheng566634ff2024-06-29 14:56:53550 def testSuccess(self):
551 input_api = MockInputApi()
552 filename = 'valid_json.json'
553 contents = [
554 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
555 ' "key2": 3 // This is an inline comment.', '}'
556 ]
557 input_api.files = [MockFile(filename, contents)]
558 self.assertEqual(None,
559 PRESUBMIT._GetJSONParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47560
Daniel Cheng566634ff2024-06-29 14:56:53561 def testFailure(self):
562 input_api = MockInputApi()
563 test_data = [
564 ('invalid_json_1.json', ['{ x }'], 'Expecting property name'),
565 ('invalid_json_2.json', ['// Hello world!', '{ "hello": "world }'],
566 'Unterminated string starting at:'),
567 ('invalid_json_3.json', ['{ "a": "b", "c": "d", }'],
568 'Expecting property name'),
569 ('invalid_json_4.json', ['{ "a": "b" "c": "d" }'],
570 "Expecting ',' delimiter:"),
571 ]
[email protected]99171a92014-06-03 08:44:47572
Daniel Cheng566634ff2024-06-29 14:56:53573 input_api.files = [
574 MockFile(filename, contents)
575 for (filename, contents, _) in test_data
576 ]
[email protected]99171a92014-06-03 08:44:47577
Daniel Cheng566634ff2024-06-29 14:56:53578 for (filename, _, expected_error) in test_data:
579 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
580 self.assertTrue(
581 expected_error in str(actual_error),
582 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47583
Daniel Cheng566634ff2024-06-29 14:56:53584 def testNoEatComments(self):
585 input_api = MockInputApi()
586 file_with_comments = 'file_with_comments.json'
587 contents_with_comments = [
588 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
589 ' "key2": 3 // This is an inline comment.', '}'
590 ]
591 file_without_comments = 'file_without_comments.json'
592 contents_without_comments = [
593 '{', ' "key1": ["value1", "value2"],', ' "key2": 3', '}'
594 ]
595 input_api.files = [
596 MockFile(file_with_comments, contents_with_comments),
597 MockFile(file_without_comments, contents_without_comments)
598 ]
599
600 self.assertNotEqual(
601 None,
602 str(
603 PRESUBMIT._GetJSONParseError(input_api,
604 file_with_comments,
605 eat_comments=False)))
606 self.assertEqual(
607 None,
608 PRESUBMIT._GetJSONParseError(input_api,
609 file_without_comments,
610 eat_comments=False))
[email protected]99171a92014-06-03 08:44:47611
612
613class IDLParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47614
Daniel Cheng566634ff2024-06-29 14:56:53615 def testSuccess(self):
616 input_api = MockInputApi()
617 filename = 'valid_idl_basics.idl'
618 contents = [
619 '// Tests a valid IDL file.', 'namespace idl_basics {',
620 ' enum EnumType {', ' name1,', ' name2', ' };', '',
621 ' dictionary MyType1 {', ' DOMString a;', ' };', '',
622 ' callback Callback1 = void();',
623 ' callback Callback2 = void(long x);',
624 ' callback Callback3 = void(MyType1 arg);',
625 ' callback Callback4 = void(EnumType type);', '',
626 ' interface Functions {', ' static void function1();',
627 ' static void function2(long x);',
628 ' static void function3(MyType1 arg);',
629 ' static void function4(Callback1 cb);',
630 ' static void function5(Callback2 cb);',
631 ' static void function6(Callback3 cb);',
632 ' static void function7(Callback4 cb);', ' };', '',
633 ' interface Events {', ' static void onFoo1();',
634 ' static void onFoo2(long x);',
635 ' static void onFoo2(MyType1 arg);',
636 ' static void onFoo3(EnumType type);', ' };', '};'
637 ]
638 input_api.files = [MockFile(filename, contents)]
639 self.assertEqual(None,
640 PRESUBMIT._GetIDLParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47641
Daniel Cheng566634ff2024-06-29 14:56:53642 def testFailure(self):
643 input_api = MockInputApi()
644 test_data = [
645 ('invalid_idl_1.idl', [
646 '//', 'namespace test {', ' dictionary {', ' DOMString s;',
647 ' };', '};'
648 ], 'Unexpected "{" after keyword "dictionary".\n'),
649 # TODO(yoz): Disabled because it causes the IDL parser to hang.
650 # See crbug.com/363830.
651 # ('invalid_idl_2.idl',
652 # (['namespace test {',
653 # ' dictionary MissingSemicolon {',
654 # ' DOMString a',
655 # ' DOMString b;',
656 # ' };',
657 # '};'],
658 # 'Unexpected symbol DOMString after symbol a.'),
659 ('invalid_idl_3.idl', [
660 '//', 'namespace test {', ' enum MissingComma {', ' name1',
661 ' name2', ' };', '};'
662 ], 'Unexpected symbol name2 after symbol name1.'),
663 ('invalid_idl_4.idl', [
664 '//', 'namespace test {', ' enum TrailingComma {',
665 ' name1,', ' name2,', ' };', '};'
666 ], 'Trailing comma in block.'),
667 ('invalid_idl_5.idl',
668 ['//', 'namespace test {', ' callback Callback1 = void(;',
669 '};'], 'Unexpected ";" after "(".'),
670 ('invalid_idl_6.idl', [
671 '//', 'namespace test {',
672 ' callback Callback1 = void(long );', '};'
673 ], 'Unexpected ")" after symbol long.'),
674 ('invalid_idl_7.idl', [
675 '//', 'namespace test {', ' interace Events {',
676 ' static void onFoo1();', ' };', '};'
677 ], 'Unexpected symbol Events after symbol interace.'),
678 ('invalid_idl_8.idl', [
679 '//', 'namespace test {', ' interface NotEvent {',
680 ' static void onFoo1();', ' };', '};'
681 ], 'Did not process Interface Interface(NotEvent)'),
682 ('invalid_idl_9.idl', [
683 '//', 'namespace test {', ' interface {',
684 ' static void function1();', ' };', '};'
685 ], 'Interface missing name.'),
686 ]
[email protected]99171a92014-06-03 08:44:47687
Daniel Cheng566634ff2024-06-29 14:56:53688 input_api.files = [
689 MockFile(filename, contents)
690 for (filename, contents, _) in test_data
691 ]
692
693 for (filename, _, expected_error) in test_data:
694 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
695 self.assertTrue(
696 expected_error in str(actual_error),
697 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47698
699
davileene0426252015-03-02 21:10:41700class UserMetricsActionTest(unittest.TestCase):
davileene0426252015-03-02 21:10:41701
Daniel Cheng566634ff2024-06-29 14:56:53702 def testUserMetricsActionInActions(self):
703 input_api = MockInputApi()
704 file_with_user_action = 'file_with_user_action.cc'
705 contents_with_user_action = ['base::UserMetricsAction("AboutChrome")']
davileene0426252015-03-02 21:10:41706
Daniel Cheng566634ff2024-06-29 14:56:53707 input_api.files = [
708 MockFile(file_with_user_action, contents_with_user_action)
709 ]
davileene0426252015-03-02 21:10:41710
Daniel Cheng566634ff2024-06-29 14:56:53711 self.assertEqual([],
712 PRESUBMIT.CheckUserActionUpdate(
713 input_api, MockOutputApi()))
davileene0426252015-03-02 21:10:41714
Daniel Cheng566634ff2024-06-29 14:56:53715 def testUserMetricsActionNotAddedToActions(self):
716 input_api = MockInputApi()
717 file_with_user_action = 'file_with_user_action.cc'
718 contents_with_user_action = [
719 'base::UserMetricsAction("NotInActionsXml")'
720 ]
davileene0426252015-03-02 21:10:41721
Daniel Cheng566634ff2024-06-29 14:56:53722 input_api.files = [
723 MockFile(file_with_user_action, contents_with_user_action)
724 ]
davileene0426252015-03-02 21:10:41725
Daniel Cheng566634ff2024-06-29 14:56:53726 output = PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi())
727 self.assertEqual(
728 ('File %s line %d: %s is missing in '
729 'tools/metrics/actions/actions.xml. Please run '
730 'tools/metrics/actions/extract_actions.py to update.' %
731 (file_with_user_action, 1, 'NotInActionsXml')), output[0].message)
Alexei Svitkine64505a92021-03-11 22:00:54732
Daniel Cheng566634ff2024-06-29 14:56:53733 def testUserMetricsActionInTestFile(self):
734 input_api = MockInputApi()
735 file_with_user_action = 'file_with_user_action_unittest.cc'
736 contents_with_user_action = [
737 'base::UserMetricsAction("NotInActionsXml")'
738 ]
Alexei Svitkine64505a92021-03-11 22:00:54739
Daniel Cheng566634ff2024-06-29 14:56:53740 input_api.files = [
741 MockFile(file_with_user_action, contents_with_user_action)
742 ]
743
744 self.assertEqual([],
745 PRESUBMIT.CheckUserActionUpdate(
746 input_api, MockOutputApi()))
Alexei Svitkine64505a92021-03-11 22:00:54747
davileene0426252015-03-02 21:10:41748
agrievef32bcc72016-04-04 14:57:40749class PydepsNeedsUpdatingTest(unittest.TestCase):
750
Daniel Cheng566634ff2024-06-29 14:56:53751 class MockPopen:
Andrew Grieve4deedb12022-02-03 21:34:50752
Daniel Cheng566634ff2024-06-29 14:56:53753 def __init__(self, stdout):
754 self.stdout = io.StringIO(stdout)
Andrew Grieve4deedb12022-02-03 21:34:50755
Daniel Cheng566634ff2024-06-29 14:56:53756 def wait(self):
757 return 0
Andrew Grieve4deedb12022-02-03 21:34:50758
Daniel Cheng566634ff2024-06-29 14:56:53759 class MockSubprocess:
760 CalledProcessError = subprocess.CalledProcessError
761 PIPE = 0
Andrew Grieve4deedb12022-02-03 21:34:50762
Daniel Cheng566634ff2024-06-29 14:56:53763 def __init__(self):
764 self._popen_func = None
agrievef32bcc72016-04-04 14:57:40765
Daniel Cheng566634ff2024-06-29 14:56:53766 def SetPopenCallback(self, func):
767 self._popen_func = func
Mohamed Heikal7cd4d8312020-06-16 16:49:40768
Daniel Cheng566634ff2024-06-29 14:56:53769 def Popen(self, cmd, *args, **kwargs):
770 return PydepsNeedsUpdatingTest.MockPopen(self._popen_func(cmd))
agrievef32bcc72016-04-04 14:57:40771
Daniel Cheng566634ff2024-06-29 14:56:53772 def _MockParseGclientArgs(self, is_android=True):
773 return lambda: {'checkout_android': 'true' if is_android else 'false'}
agrievef32bcc72016-04-04 14:57:40774
Daniel Cheng566634ff2024-06-29 14:56:53775 def setUp(self):
776 mock_all_pydeps = ['A.pydeps', 'B.pydeps', 'D.pydeps']
777 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
778 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
779 mock_android_pydeps = ['D.pydeps']
780 self.old_ANDROID_SPECIFIC_PYDEPS_FILES = (
781 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES)
782 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = mock_android_pydeps
783 self.old_ParseGclientArgs = PRESUBMIT._ParseGclientArgs
784 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs()
785 self.mock_input_api = MockInputApi()
786 self.mock_output_api = MockOutputApi()
787 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess(
788 )
789 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api,
790 mock_all_pydeps)
791 self.checker._file_cache = {
792 'A.pydeps':
793 '# Generated by:\n# CMD --output A.pydeps A\nA.py\nC.py\n',
794 'B.pydeps':
795 '# Generated by:\n# CMD --output B.pydeps B\nB.py\nC.py\n',
796 'D.pydeps': '# Generated by:\n# CMD --output D.pydeps D\nD.py\n',
797 }
agrievef32bcc72016-04-04 14:57:40798
Daniel Cheng566634ff2024-06-29 14:56:53799 def tearDown(self):
800 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
801 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = (
802 self.old_ANDROID_SPECIFIC_PYDEPS_FILES)
803 PRESUBMIT._ParseGclientArgs = self.old_ParseGclientArgs
pastarmovj89f7ee12016-09-20 14:58:13804
Daniel Cheng566634ff2024-06-29 14:56:53805 def _RunCheck(self):
806 return PRESUBMIT.CheckPydepsNeedsUpdating(
807 self.mock_input_api,
808 self.mock_output_api,
809 checker_for_tests=self.checker)
agrievef32bcc72016-04-04 14:57:40810
Daniel Cheng566634ff2024-06-29 14:56:53811 def testAddedPydep(self):
812 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
813 if not self.mock_input_api.platform.startswith('linux'):
814 return []
agrievef32bcc72016-04-04 14:57:40815
Andrew Grieve713b89b2024-10-15 20:20:08816 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53817 MockAffectedFile('new.pydeps', [], action='A'),
Sophey Dong58cf9bbd2024-10-09 00:08:10818 ])
Andrew Grieve713b89b2024-10-15 20:20:08819
Daniel Cheng566634ff2024-06-29 14:56:53820 results = self._RunCheck()
821 self.assertEqual(1, len(results))
822 self.assertIn('PYDEPS_FILES', str(results[0]))
pastarmovj89f7ee12016-09-20 14:58:13823
Daniel Cheng566634ff2024-06-29 14:56:53824 def testPydepNotInSrc(self):
Andrew Grieve713b89b2024-10-15 20:20:08825 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53826 MockAffectedFile('new.pydeps', [], action='A'),
Andrew Grieve713b89b2024-10-15 20:20:08827 ])
828 self.mock_input_api.os_path.exists = lambda x: False
Daniel Cheng566634ff2024-06-29 14:56:53829 results = self._RunCheck()
830 self.assertEqual(0, len(results))
agrievef32bcc72016-04-04 14:57:40831
Daniel Cheng566634ff2024-06-29 14:56:53832 def testRemovedPydep(self):
833 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
834 if not self.mock_input_api.platform.startswith('linux'):
835 return []
pastarmovj89f7ee12016-09-20 14:58:13836
Andrew Grieve713b89b2024-10-15 20:20:08837 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53838 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
Daniel Cheng566634ff2024-06-29 14:56:53839 ])
840 results = self._RunCheck()
841 self.assertEqual(1, len(results))
842 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40843
Daniel Cheng566634ff2024-06-29 14:56:53844 def testRandomPyIgnored(self):
845 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
846 if not self.mock_input_api.platform.startswith('linux'):
847 return []
agrievef32bcc72016-04-04 14:57:40848
Daniel Cheng566634ff2024-06-29 14:56:53849 self.mock_input_api.files = [
850 MockAffectedFile('random.py', []),
851 ]
pastarmovj89f7ee12016-09-20 14:58:13852
Daniel Cheng566634ff2024-06-29 14:56:53853 results = self._RunCheck()
854 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40855
Daniel Cheng566634ff2024-06-29 14:56:53856 def testRelevantPyNoChange(self):
857 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
858 if not self.mock_input_api.platform.startswith('linux'):
859 return []
agrievef32bcc72016-04-04 14:57:40860
Daniel Cheng566634ff2024-06-29 14:56:53861 self.mock_input_api.files = [
862 MockAffectedFile('A.py', []),
863 ]
agrievef32bcc72016-04-04 14:57:40864
Daniel Cheng566634ff2024-06-29 14:56:53865 def popen_callback(cmd):
866 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
867 return self.checker._file_cache['A.pydeps']
agrievef32bcc72016-04-04 14:57:40868
Daniel Cheng566634ff2024-06-29 14:56:53869 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13870
Daniel Cheng566634ff2024-06-29 14:56:53871 results = self._RunCheck()
872 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40873
Daniel Cheng566634ff2024-06-29 14:56:53874 def testRelevantPyOneChange(self):
875 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
876 if not self.mock_input_api.platform.startswith('linux'):
877 return []
agrievef32bcc72016-04-04 14:57:40878
Daniel Cheng566634ff2024-06-29 14:56:53879 self.mock_input_api.files = [
880 MockAffectedFile('A.py', []),
881 ]
agrievef32bcc72016-04-04 14:57:40882
Daniel Cheng566634ff2024-06-29 14:56:53883 def popen_callback(cmd):
884 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
885 return 'changed data'
agrievef32bcc72016-04-04 14:57:40886
Daniel Cheng566634ff2024-06-29 14:56:53887 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13888
Daniel Cheng566634ff2024-06-29 14:56:53889 results = self._RunCheck()
890 self.assertEqual(1, len(results))
891 # Check that --output "" is not included.
892 self.assertNotIn('""', str(results[0]))
893 self.assertIn('File is stale', str(results[0]))
agrievef32bcc72016-04-04 14:57:40894
Daniel Cheng566634ff2024-06-29 14:56:53895 def testRelevantPyTwoChanges(self):
896 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
897 if not self.mock_input_api.platform.startswith('linux'):
898 return []
agrievef32bcc72016-04-04 14:57:40899
Daniel Cheng566634ff2024-06-29 14:56:53900 self.mock_input_api.files = [
901 MockAffectedFile('C.py', []),
902 ]
agrievef32bcc72016-04-04 14:57:40903
Daniel Cheng566634ff2024-06-29 14:56:53904 def popen_callback(cmd):
905 return 'changed data'
agrievef32bcc72016-04-04 14:57:40906
Daniel Cheng566634ff2024-06-29 14:56:53907 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Mohamed Heikal7cd4d8312020-06-16 16:49:40908
Daniel Cheng566634ff2024-06-29 14:56:53909 results = self._RunCheck()
910 self.assertEqual(2, len(results))
911 self.assertIn('File is stale', str(results[0]))
912 self.assertIn('File is stale', str(results[1]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40913
Daniel Cheng566634ff2024-06-29 14:56:53914 def testRelevantAndroidPyInNonAndroidCheckout(self):
915 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
916 if not self.mock_input_api.platform.startswith('linux'):
917 return []
Mohamed Heikal7cd4d8312020-06-16 16:49:40918
Daniel Cheng566634ff2024-06-29 14:56:53919 self.mock_input_api.files = [
920 MockAffectedFile('D.py', []),
921 ]
Mohamed Heikal7cd4d8312020-06-16 16:49:40922
Daniel Cheng566634ff2024-06-29 14:56:53923 def popen_callback(cmd):
924 self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
925 return 'changed data'
Andrew Grieve5bb4cf702020-10-22 20:21:39926
Daniel Cheng566634ff2024-06-29 14:56:53927 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
928 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(
929 is_android=False)
Andrew Grieve5bb4cf702020-10-22 20:21:39930
Daniel Cheng566634ff2024-06-29 14:56:53931 results = self._RunCheck()
932 self.assertEqual(1, len(results))
933 self.assertIn('Android', str(results[0]))
934 self.assertIn('D.pydeps', str(results[0]))
Andrew Grieve5bb4cf702020-10-22 20:21:39935
Daniel Cheng566634ff2024-06-29 14:56:53936 def testGnPathsAndMissingOutputFlag(self):
937 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
938 if not self.mock_input_api.platform.startswith('linux'):
939 return []
Andrew Grieve5bb4cf702020-10-22 20:21:39940
Daniel Cheng566634ff2024-06-29 14:56:53941 self.checker._file_cache = {
942 'A.pydeps':
943 '# Generated by:\n# CMD --gn-paths A\n//A.py\n//C.py\n',
944 'B.pydeps':
945 '# Generated by:\n# CMD --gn-paths B\n//B.py\n//C.py\n',
946 'D.pydeps': '# Generated by:\n# CMD --gn-paths D\n//D.py\n',
947 }
Andrew Grieve5bb4cf702020-10-22 20:21:39948
Daniel Cheng566634ff2024-06-29 14:56:53949 self.mock_input_api.files = [
950 MockAffectedFile('A.py', []),
951 ]
Andrew Grieve5bb4cf702020-10-22 20:21:39952
Daniel Cheng566634ff2024-06-29 14:56:53953 def popen_callback(cmd):
954 self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""',
955 cmd)
956 return 'changed data'
957
958 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
959
960 results = self._RunCheck()
961 self.assertEqual(1, len(results))
962 self.assertIn('File is stale', str(results[0]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40963
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39964
Daniel Bratell8ba52722018-03-02 16:06:14965class IncludeGuardTest(unittest.TestCase):
Daniel Bratell8ba52722018-03-02 16:06:14966
Daniel Cheng566634ff2024-06-29 14:56:53967 def testIncludeGuardChecks(self):
968 mock_input_api = MockInputApi()
969 mock_output_api = MockOutputApi()
970 mock_input_api.files = [
971 MockAffectedFile('content/browser/thing/foo.h', [
972 '// Comment',
973 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
974 '#define CONTENT_BROWSER_THING_FOO_H_',
975 'struct McBoatFace;',
976 '#endif // CONTENT_BROWSER_THING_FOO_H_',
977 ]),
978 MockAffectedFile('content/browser/thing/bar.h', [
979 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
980 '#define CONTENT_BROWSER_THING_BAR_H_',
981 'namespace content {',
982 '#endif // CONTENT_BROWSER_THING_BAR_H_',
983 '} // namespace content',
984 ]),
985 MockAffectedFile('content/browser/test1.h', [
986 'namespace content {',
987 '} // namespace content',
988 ]),
989 MockAffectedFile('content\\browser\\win.h', [
990 '#ifndef CONTENT_BROWSER_WIN_H_',
991 '#define CONTENT_BROWSER_WIN_H_',
992 'struct McBoatFace;',
993 '#endif // CONTENT_BROWSER_WIN_H_',
994 ]),
995 MockAffectedFile('content/browser/test2.h', [
996 '// Comment',
997 '#ifndef CONTENT_BROWSER_TEST2_H_',
998 'struct McBoatFace;',
999 '#endif // CONTENT_BROWSER_TEST2_H_',
1000 ]),
1001 MockAffectedFile('content/browser/internal.h', [
1002 '// Comment',
1003 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
1004 '#define CONTENT_BROWSER_INTERNAL_H_',
1005 '// Comment',
1006 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1007 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1008 'namespace internal {',
1009 '} // namespace internal',
1010 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
1011 'namespace content {',
1012 '} // namespace content',
1013 '#endif // CONTENT_BROWSER_THING_BAR_H_',
1014 ]),
1015 MockAffectedFile('content/browser/thing/foo.cc', [
1016 '// This is a non-header.',
1017 ]),
1018 MockAffectedFile('content/browser/disabled.h', [
1019 '// no-include-guard-because-multiply-included',
1020 'struct McBoatFace;',
1021 ]),
1022 # New files don't allow misspelled include guards.
1023 MockAffectedFile('content/browser/spleling.h', [
1024 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
1025 '#define CONTENT_BROWSER_SPLLEING_H_',
1026 'struct McBoatFace;',
1027 '#endif // CONTENT_BROWSER_SPLLEING_H_',
1028 ]),
1029 # New files don't allow + in include guards.
1030 MockAffectedFile('content/browser/foo+bar.h', [
1031 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
1032 '#define CONTENT_BROWSER_FOO+BAR_H_',
1033 'struct McBoatFace;',
1034 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
1035 ]),
1036 # Old files allow misspelled include guards (for now).
1037 MockAffectedFile('chrome/old.h', [
1038 '// New contents',
1039 '#ifndef CHROME_ODL_H_',
1040 '#define CHROME_ODL_H_',
1041 '#endif // CHROME_ODL_H_',
1042 ], [
1043 '// Old contents',
1044 '#ifndef CHROME_ODL_H_',
1045 '#define CHROME_ODL_H_',
1046 '#endif // CHROME_ODL_H_',
1047 ],
1048 action='M'),
1049 # Using a Blink style include guard outside Blink is wrong.
1050 MockAffectedFile('content/NotInBlink.h', [
1051 '#ifndef NotInBlink_h',
1052 '#define NotInBlink_h',
1053 'struct McBoatFace;',
1054 '#endif // NotInBlink_h',
1055 ]),
1056 # Using a Blink style include guard in Blink is no longer ok.
1057 MockAffectedFile('third_party/blink/InBlink.h', [
1058 '#ifndef InBlink_h',
1059 '#define InBlink_h',
1060 'struct McBoatFace;',
1061 '#endif // InBlink_h',
1062 ]),
1063 # Using a bad include guard in Blink is not ok.
1064 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
1065 '#ifndef WrongInBlink_h',
1066 '#define WrongInBlink_h',
1067 'struct McBoatFace;',
1068 '#endif // WrongInBlink_h',
1069 ]),
1070 # Using a bad include guard in Blink is not supposed to be accepted even
1071 # if it's an old file. However the current presubmit has accepted this
1072 # for a while.
1073 MockAffectedFile('third_party/blink/StillInBlink.h', [
1074 '// New contents',
1075 '#ifndef AcceptedInBlink_h',
1076 '#define AcceptedInBlink_h',
1077 'struct McBoatFace;',
1078 '#endif // AcceptedInBlink_h',
1079 ], [
1080 '// Old contents',
1081 '#ifndef AcceptedInBlink_h',
1082 '#define AcceptedInBlink_h',
1083 'struct McBoatFace;',
1084 '#endif // AcceptedInBlink_h',
1085 ],
1086 action='M'),
1087 # Using a non-Chromium include guard in third_party
1088 # (outside blink) is accepted.
1089 MockAffectedFile('third_party/foo/some_file.h', [
1090 '#ifndef REQUIRED_RPCNDR_H_',
1091 '#define REQUIRED_RPCNDR_H_',
1092 'struct SomeFileFoo;',
1093 '#endif // REQUIRED_RPCNDR_H_',
1094 ]),
1095 # Not having proper include guard in *_message_generator.h
1096 # for old IPC messages is allowed.
1097 MockAffectedFile('content/common/content_message_generator.h', [
1098 '#undef CONTENT_COMMON_FOO_MESSAGES_H_',
1099 '#include "content/common/foo_messages.h"',
1100 '#ifndef CONTENT_COMMON_FOO_MESSAGES_H_',
1101 '#error "Failed to include content/common/foo_messages.h"',
1102 '#endif',
1103 ]),
1104 MockAffectedFile('chrome/renderer/thing/qux.h', [
1105 '// Comment',
1106 '#ifndef CHROME_RENDERER_THING_QUX_H_',
1107 '#define CHROME_RENDERER_THING_QUX_H_',
1108 'struct Boaty;',
1109 '#endif',
1110 ]),
1111 ]
1112 msgs = PRESUBMIT.CheckForIncludeGuards(mock_input_api, mock_output_api)
1113 expected_fail_count = 10
1114 self.assertEqual(
1115 expected_fail_count, len(msgs), 'Expected %d items, found %d: %s' %
1116 (expected_fail_count, len(msgs), msgs))
1117 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
1118 self.assertEqual(
1119 msgs[0].message, 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
1120 'not covering the whole file')
Daniel Bratell8ba52722018-03-02 16:06:141121
Daniel Cheng566634ff2024-06-29 14:56:531122 self.assertIn('content/browser/test1.h', msgs[1].message)
1123 self.assertIn('Recommended name: CONTENT_BROWSER_TEST1_H_',
1124 msgs[1].message)
Daniel Bratell8ba52722018-03-02 16:06:141125
Daniel Cheng566634ff2024-06-29 14:56:531126 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
1127 self.assertEqual(
1128 msgs[2].message, 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
1129 'include guard')
Lei Zhangd84f9512024-05-28 19:43:301130
Daniel Cheng566634ff2024-06-29 14:56:531131 self.assertIn('content/browser/internal.h', msgs[3].message)
1132 self.assertIn(
1133 'Recommended #endif comment: // CONTENT_BROWSER_INTERNAL_H_',
1134 msgs[3].message)
Daniel Bratell8ba52722018-03-02 16:06:141135
Daniel Cheng566634ff2024-06-29 14:56:531136 self.assertEqual(msgs[4].items, ['content/browser/spleling.h:1'])
1137 self.assertEqual(
1138 msgs[4].message, 'Header using the wrong include guard name '
1139 'CONTENT_BROWSER_SPLLEING_H_')
Olivier Robinbba137492018-07-30 11:31:341140
Daniel Cheng566634ff2024-06-29 14:56:531141 self.assertIn('content/browser/foo+bar.h', msgs[5].message)
1142 self.assertIn('Recommended name: CONTENT_BROWSER_FOO_BAR_H_',
1143 msgs[5].message)
Daniel Bratell8ba52722018-03-02 16:06:141144
Daniel Cheng566634ff2024-06-29 14:56:531145 self.assertEqual(msgs[6].items, ['content/NotInBlink.h:1'])
1146 self.assertEqual(
1147 msgs[6].message, 'Header using the wrong include guard name '
1148 'NotInBlink_h')
Daniel Bratell39b5b062018-05-16 18:09:571149
Daniel Cheng566634ff2024-06-29 14:56:531150 self.assertEqual(msgs[7].items, ['third_party/blink/InBlink.h:1'])
1151 self.assertEqual(
1152 msgs[7].message, 'Header using the wrong include guard name '
1153 'InBlink_h')
Daniel Bratell8ba52722018-03-02 16:06:141154
Daniel Cheng566634ff2024-06-29 14:56:531155 self.assertEqual(msgs[8].items, ['third_party/blink/AlsoInBlink.h:1'])
1156 self.assertEqual(
1157 msgs[8].message, 'Header using the wrong include guard name '
1158 'WrongInBlink_h')
1159
1160 self.assertIn('chrome/renderer/thing/qux.h', msgs[9].message)
1161 self.assertIn(
1162 'Recommended #endif comment: // CHROME_RENDERER_THING_QUX_H_',
1163 msgs[9].message)
Lei Zhangd84f9512024-05-28 19:43:301164
1165
Chris Hall59f8d0c72020-05-01 07:31:191166class AccessibilityRelnotesFieldTest(unittest.TestCase):
Chris Hall59f8d0c72020-05-01 07:31:191167
Daniel Cheng566634ff2024-06-29 14:56:531168 def testRelnotesPresent(self):
1169 mock_input_api = MockInputApi()
1170 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191171
Daniel Cheng566634ff2024-06-29 14:56:531172 mock_input_api.files = [
1173 MockAffectedFile('ui/accessibility/foo.bar', [''])
1174 ]
1175 mock_input_api.change.DescriptionText = lambda: 'Commit description'
1176 mock_input_api.change.footers['AX-Relnotes'] = [
1177 'Important user facing change'
1178 ]
Chris Hall59f8d0c72020-05-01 07:31:191179
Daniel Cheng566634ff2024-06-29 14:56:531180 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1181 mock_input_api, mock_output_api)
1182 self.assertEqual(
1183 0, len(msgs),
1184 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191185
Daniel Cheng566634ff2024-06-29 14:56:531186 def testRelnotesMissingFromAccessibilityChange(self):
1187 mock_input_api = MockInputApi()
1188 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191189
Daniel Cheng566634ff2024-06-29 14:56:531190 mock_input_api.files = [
1191 MockAffectedFile('some/file', ['']),
1192 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1193 MockAffectedFile('some/other/file', [''])
1194 ]
1195 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191196
Daniel Cheng566634ff2024-06-29 14:56:531197 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1198 mock_input_api, mock_output_api)
1199 self.assertEqual(
1200 1, len(msgs),
1201 'Expected %d messages, found %d: %s' % (1, len(msgs), msgs))
1202 self.assertTrue(
1203 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1204 'Missing AX-Relnotes field message not found in errors')
Chris Hall59f8d0c72020-05-01 07:31:191205
Daniel Cheng566634ff2024-06-29 14:56:531206 # The relnotes footer is not required for changes which do not touch any
1207 # accessibility directories.
1208 def testIgnoresNonAccessibilityCode(self):
1209 mock_input_api = MockInputApi()
1210 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191211
Daniel Cheng566634ff2024-06-29 14:56:531212 mock_input_api.files = [
1213 MockAffectedFile('some/file', ['']),
1214 MockAffectedFile('some/other/file', [''])
1215 ]
1216 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191217
Daniel Cheng566634ff2024-06-29 14:56:531218 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1219 mock_input_api, mock_output_api)
1220 self.assertEqual(
1221 0, len(msgs),
1222 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191223
Daniel Cheng566634ff2024-06-29 14:56:531224 # Test that our presubmit correctly raises an error for a set of known paths.
1225 def testExpectedPaths(self):
1226 filesToTest = [
1227 "chrome/browser/accessibility/foo.py",
1228 "chrome/browser/ash/arc/accessibility/foo.cc",
1229 "chrome/browser/ui/views/accessibility/foo.h",
1230 "chrome/browser/extensions/api/automation/foo.h",
1231 "chrome/browser/extensions/api/automation_internal/foo.cc",
1232 "chrome/renderer/extensions/accessibility_foo.h",
1233 "chrome/tests/data/accessibility/foo.html",
1234 "content/browser/accessibility/foo.cc",
1235 "content/renderer/accessibility/foo.h",
1236 "content/tests/data/accessibility/foo.cc",
1237 "extensions/renderer/api/automation/foo.h",
1238 "ui/accessibility/foo/bar/baz.cc",
1239 "ui/views/accessibility/foo/bar/baz.h",
1240 ]
Chris Hall59f8d0c72020-05-01 07:31:191241
Daniel Cheng566634ff2024-06-29 14:56:531242 for testFile in filesToTest:
1243 mock_input_api = MockInputApi()
1244 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191245
Daniel Cheng566634ff2024-06-29 14:56:531246 mock_input_api.files = [MockAffectedFile(testFile, [''])]
1247 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391248
Daniel Cheng566634ff2024-06-29 14:56:531249 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1250 mock_input_api, mock_output_api)
1251 self.assertEqual(
1252 1, len(msgs),
1253 'Expected %d messages, found %d: %s, for file %s' %
1254 (1, len(msgs), msgs, testFile))
1255 self.assertTrue(
1256 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1257 ('Missing AX-Relnotes field message not found in errors '
1258 ' for file %s' % (testFile)))
Akihiro Ota08108e542020-05-20 15:30:531259
Daniel Cheng566634ff2024-06-29 14:56:531260 # Test that AX-Relnotes field can appear in the commit description (as long
1261 # as it appears at the beginning of a line).
1262 def testRelnotesInCommitDescription(self):
1263 mock_input_api = MockInputApi()
1264 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531265
Daniel Cheng566634ff2024-06-29 14:56:531266 mock_input_api.files = [
1267 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1268 ]
1269 mock_input_api.change.DescriptionText = lambda: (
1270 'Description:\n' +
1271 'AX-Relnotes: solves all accessibility issues forever')
Akihiro Ota08108e542020-05-20 15:30:531272
Daniel Cheng566634ff2024-06-29 14:56:531273 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1274 mock_input_api, mock_output_api)
1275 self.assertEqual(
1276 0, len(msgs),
1277 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Akihiro Ota08108e542020-05-20 15:30:531278
Daniel Cheng566634ff2024-06-29 14:56:531279 # Test that we don't match AX-Relnotes if it appears in the middle of a line.
1280 def testRelnotesMustAppearAtBeginningOfLine(self):
1281 mock_input_api = MockInputApi()
1282 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531283
Daniel Cheng566634ff2024-06-29 14:56:531284 mock_input_api.files = [
1285 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1286 ]
1287 mock_input_api.change.DescriptionText = lambda: (
1288 'Description:\n' +
1289 'This change has no AX-Relnotes: we should print a warning')
Akihiro Ota08108e542020-05-20 15:30:531290
Daniel Cheng566634ff2024-06-29 14:56:531291 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1292 mock_input_api, mock_output_api)
1293 self.assertTrue(
1294 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1295 'Missing AX-Relnotes field message not found in errors')
Akihiro Ota08108e542020-05-20 15:30:531296
Daniel Cheng566634ff2024-06-29 14:56:531297 # Tests that the AX-Relnotes field can be lowercase and use a '=' in place
1298 # of a ':'.
1299 def testRelnotesLowercaseWithEqualSign(self):
1300 mock_input_api = MockInputApi()
1301 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531302
Daniel Cheng566634ff2024-06-29 14:56:531303 mock_input_api.files = [
1304 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1305 ]
1306 mock_input_api.change.DescriptionText = lambda: (
1307 'Description:\n' +
1308 'ax-relnotes= this is a valid format for accessibility relnotes')
1309
1310 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1311 mock_input_api, mock_output_api)
1312 self.assertEqual(
1313 0, len(msgs),
1314 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1315
Akihiro Ota08108e542020-05-20 15:30:531316
Mark Schillaci44c90b42024-11-22 20:44:381317class AccessibilityAriaElementAttributeGettersTest(unittest.TestCase):
1318
1319 # Test warning is surfaced for various possible uses of bad methods.
1320 def testMatchingLines(self):
1321 mock_input_api = MockInputApi()
1322 mock_input_api.files = [
1323 MockFile(
1324 "third_party/blink/renderer/core/accessibility/ax_object.h",
1325 [
1326 "->getAttribute(html_names::kAriaCheckedAttr)",
1327 "node->hasAttribute(html_names::kRoleAttr)",
1328 "->FastHasAttribute(html_names::kAriaLabelAttr)",
1329 " .FastGetAttribute(html_names::kAriaCurrentAttr);",
1330
1331 ],
1332 action='M'
1333 ),
1334 MockFile(
1335 "third_party/blink/renderer/core/accessibility/ax_table.cc",
1336 [
1337 "bool result = node->hasAttribute(html_names::kFooAttr);",
1338 "foo->getAttribute(html_names::kAriaInvalidValueAttr)",
1339 "foo->GetAriaCurrentState(html_names::kAriaCurrentStateAttr)",
1340 ],
1341 action='M'
1342 ),
1343 ]
1344
1345 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1346 self.assertEqual(1, len(results))
1347 self.assertEqual(5, len(results[0].items))
1348 self.assertIn("ax_object.h:1", results[0].items[0])
1349 self.assertIn("ax_object.h:2", results[0].items[1])
1350 self.assertIn("ax_object.h:3", results[0].items[2])
1351 self.assertIn("ax_object.h:4", results[0].items[3])
1352 self.assertIn("ax_table.cc:2", results[0].items[4])
1353 self.assertIn("Please use ARIA-specific attribute access", results[0].message)
1354
1355 # Test no warnings for files that are not accessibility related.
1356 def testNonMatchingFiles(self):
1357 mock_input_api = MockInputApi()
1358 mock_input_api.files = [
1359 MockFile(
1360 "content/browser/foobar/foo.cc",
1361 ["->getAttribute(html_names::kAriaCheckedAttr)"],
1362 action='M'),
1363 MockFile(
1364 "third_party/blink/renderer/core/foo.cc",
1365 ["node->hasAttribute(html_names::kRoleAttr)"],
1366 action='M'),
1367 ]
1368 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1369 self.assertEqual(0, len(results))
1370
1371 # Test no warning when methods are used with different attribute params.
1372 def testNoBadParam(self):
1373 mock_input_api = MockInputApi()
1374 mock_input_api.files = [
1375 MockFile(
1376 "third_party/blink/renderer/core/accessibility/ax_object.h",
1377 [
1378 "->getAttribute(html_names::kCheckedAttr)",
1379 "->hasAttribute(html_names::kIdAttr)",
1380 ],
1381 action='M'
1382 )
1383 ]
1384
1385 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1386 self.assertEqual(0, len(results))
1387
1388 # Test no warning when attribute params are used for different methods.
1389 def testNoMethod(self):
1390 mock_input_api = MockInputApi()
1391 mock_input_api.files = [
1392 MockFile(
1393 "third_party/blink/renderer/core/accessibility/ax_object.cc",
1394 [
1395 "foo(html_names::kAriaCheckedAttr)",
1396 "bar(html_names::kRoleAttr)"
1397 ],
1398 action='M'
1399 )
1400 ]
1401
1402 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1403 self.assertEqual(0, len(results))
1404
1405
yolandyan45001472016-12-21 21:12:421406class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
yolandyan45001472016-12-21 21:12:421407
Daniel Cheng566634ff2024-06-29 14:56:531408 def testCheckAndroidTestAnnotationUsage(self):
1409 mock_input_api = MockInputApi()
1410 mock_output_api = MockOutputApi()
1411
1412 mock_input_api.files = [
1413 MockAffectedFile('LalaLand.java', ['random stuff']),
1414 MockAffectedFile('CorrectUsage.java', [
1415 'import androidx.test.filters.LargeTest;',
1416 'import androidx.test.filters.MediumTest;',
1417 'import androidx.test.filters.SmallTest;',
1418 ]),
1419 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1420 'import android.test.suitebuilder.annotation.LargeTest;',
1421 ]),
1422 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1423 'import android.test.suitebuilder.annotation.MediumTest;',
1424 ]),
1425 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1426 'import android.test.suitebuilder.annotation.SmallTest;',
1427 ]),
1428 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1429 'import android.test.suitebuilder.annotation.Smoke;',
1430 ])
1431 ]
1432 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1433 mock_input_api, mock_output_api)
1434 self.assertEqual(
1435 1, len(msgs),
1436 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1437 self.assertEqual(
1438 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1439 (4, len(msgs[0].items), msgs[0].items))
1440 self.assertTrue(
1441 'UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1442 'UsedDeprecatedLargeTestAnnotation not found in errors')
1443 self.assertTrue(
1444 'UsedDeprecatedMediumTestAnnotation.java:1' in msgs[0].items,
1445 'UsedDeprecatedMediumTestAnnotation not found in errors')
1446 self.assertTrue(
1447 'UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1448 'UsedDeprecatedSmallTestAnnotation not found in errors')
1449 self.assertTrue(
1450 'UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1451 'UsedDeprecatedSmokeAnnotation not found in errors')
1452
yolandyan45001472016-12-21 21:12:421453
Min Qinbc44383c2023-02-22 17:25:261454class AndroidBannedImportTest(unittest.TestCase):
Min Qinbc44383c2023-02-22 17:25:261455
Daniel Cheng566634ff2024-06-29 14:56:531456 def testCheckAndroidNoBannedImports(self):
1457 mock_input_api = MockInputApi()
1458 mock_output_api = MockOutputApi()
1459
1460 test_files = [
1461 MockAffectedFile('RandomStufff.java', ['random stuff']),
1462 MockAffectedFile('NoBannedImports.java', [
1463 'import androidx.test.filters.LargeTest;',
1464 'import androidx.test.filters.MediumTest;',
1465 'import androidx.test.filters.SmallTest;',
1466 ]),
1467 MockAffectedFile('BannedUri.java', [
1468 'import java.net.URI;',
1469 ]),
1470 MockAffectedFile('BannedTargetApi.java', [
1471 'import android.annotation.TargetApi;',
1472 ]),
Daniel Cheng566634ff2024-06-29 14:56:531473 MockAffectedFile('BannedActivityTestRule.java', [
1474 'import androidx.test.rule.ActivityTestRule;',
1475 ]),
1476 MockAffectedFile('BannedVectorDrawableCompat.java', [
1477 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
1478 ])
1479 ]
1480 msgs = []
1481 for file in test_files:
1482 mock_input_api.files = [file]
1483 msgs.append(
1484 PRESUBMIT._CheckAndroidNoBannedImports(mock_input_api,
1485 mock_output_api))
1486 self.assertEqual(0, len(msgs[0]))
1487 self.assertEqual(0, len(msgs[1]))
1488 self.assertTrue(msgs[2][0].message.startswith(
1489 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261490 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531491 BannedUri.java:1:""")))
1492 self.assertTrue(msgs[3][0].message.startswith(
1493 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261494 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531495 BannedTargetApi.java:1:""")))
1496 self.assertTrue(msgs[4][0].message.startswith(
1497 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261498 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531499 BannedActivityTestRule.java:1:""")))
Theo Cristea1d9a90a2024-11-14 13:31:301500 self.assertTrue(msgs[5][0].message.startswith(
Daniel Cheng566634ff2024-06-29 14:56:531501 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261502 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531503 BannedVectorDrawableCompat.java:1:""")))
1504
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391505
Mohamed Heikal5e5b7922020-10-29 18:57:591506class CheckNoDownstreamDepsTest(unittest.TestCase):
Mohamed Heikal5e5b7922020-10-29 18:57:591507
Daniel Cheng566634ff2024-06-29 14:56:531508 def testInvalidDepFromUpstream(self):
1509 mock_input_api = MockInputApi()
1510 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591511
Daniel Cheng566634ff2024-06-29 14:56:531512 mock_input_api.files = [
1513 MockAffectedFile('BUILD.gn',
1514 ['deps = [', ' "//clank/target:test",', ']']),
1515 MockAffectedFile('chrome/android/BUILD.gn',
1516 ['deps = [ "//clank/target:test" ]']),
1517 MockAffectedFile(
1518 'chrome/chrome_java_deps.gni',
1519 ['java_deps = [', ' "//clank/target:test",', ']']),
1520 ]
1521 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1522 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1523 mock_output_api)
1524 self.assertEqual(
1525 1, len(msgs),
1526 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1527 self.assertEqual(
1528 3, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1529 (3, len(msgs[0].items), msgs[0].items))
1530 self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
1531 'BUILD.gn not found in errors')
1532 self.assertTrue(
1533 any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
1534 'chrome/android/BUILD.gn:1 not found in errors')
1535 self.assertTrue(
1536 any('chrome/chrome_java_deps.gni:2' in item
1537 for item in msgs[0].items),
1538 'chrome/chrome_java_deps.gni:2 not found in errors')
Mohamed Heikal5e5b7922020-10-29 18:57:591539
Daniel Cheng566634ff2024-06-29 14:56:531540 def testAllowsComments(self):
1541 mock_input_api = MockInputApi()
1542 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591543
Daniel Cheng566634ff2024-06-29 14:56:531544 mock_input_api.files = [
1545 MockAffectedFile('BUILD.gn', [
1546 '# real implementation in //clank/target:test',
1547 ]),
1548 ]
1549 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1550 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1551 mock_output_api)
1552 self.assertEqual(
1553 0, len(msgs),
1554 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591555
Daniel Cheng566634ff2024-06-29 14:56:531556 def testOnlyChecksBuildFiles(self):
1557 mock_input_api = MockInputApi()
1558 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591559
Daniel Cheng566634ff2024-06-29 14:56:531560 mock_input_api.files = [
1561 MockAffectedFile('README.md',
1562 ['DEPS = [ "//clank/target:test" ]']),
1563 MockAffectedFile('chrome/android/java/file.java',
1564 ['//clank/ only function']),
1565 ]
1566 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1567 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1568 mock_output_api)
1569 self.assertEqual(
1570 0, len(msgs),
1571 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591572
Daniel Cheng566634ff2024-06-29 14:56:531573 def testValidDepFromDownstream(self):
1574 mock_input_api = MockInputApi()
1575 mock_output_api = MockOutputApi()
1576
1577 mock_input_api.files = [
1578 MockAffectedFile('BUILD.gn',
1579 ['DEPS = [', ' "//clank/target:test",', ']']),
1580 MockAffectedFile('java/BUILD.gn',
1581 ['DEPS = [ "//clank/target:test" ]']),
1582 ]
1583 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
1584 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1585 mock_output_api)
1586 self.assertEqual(
1587 0, len(msgs),
1588 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591589
yolandyan45001472016-12-21 21:12:421590
Jinsong Fan91ebbbd2019-04-16 14:57:171591class AndroidDebuggableBuildTest(unittest.TestCase):
1592
Daniel Cheng566634ff2024-06-29 14:56:531593 def testCheckAndroidDebuggableBuild(self):
1594 mock_input_api = MockInputApi()
1595 mock_output_api = MockOutputApi()
Jinsong Fan91ebbbd2019-04-16 14:57:171596
Daniel Cheng566634ff2024-06-29 14:56:531597 mock_input_api.files = [
1598 MockAffectedFile('RandomStuff.java', ['random stuff']),
1599 MockAffectedFile('CorrectUsage.java', [
1600 'import org.chromium.base.BuildInfo;',
1601 'some random stuff',
1602 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1603 ]),
1604 MockAffectedFile('JustCheckUserdebugBuild.java', [
1605 'import android.os.Build;',
1606 'some random stuff',
1607 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1608 ]),
1609 MockAffectedFile('JustCheckEngineeringBuild.java', [
1610 'import android.os.Build;',
1611 'some random stuff',
1612 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1613 ]),
1614 MockAffectedFile('UsedBuildType.java', [
1615 'import android.os.Build;',
1616 'some random stuff',
1617 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1618 '|| "eng".equals(Build.TYPE)',
1619 ]),
1620 MockAffectedFile('UsedExplicitBuildType.java', [
1621 'some random stuff',
1622 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1623 '|| "eng".equals(android.os.Build.TYPE)',
1624 ]),
1625 ]
Jinsong Fan91ebbbd2019-04-16 14:57:171626
Daniel Cheng566634ff2024-06-29 14:56:531627 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(mock_input_api,
1628 mock_output_api)
1629 self.assertEqual(
1630 1, len(msgs),
1631 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1632 self.assertEqual(
1633 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1634 (4, len(msgs[0].items), msgs[0].items))
1635 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1636 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1637 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1638 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
Jinsong Fan91ebbbd2019-04-16 14:57:171639
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391640
dgn4401aa52015-04-29 16:26:171641class LogUsageTest(unittest.TestCase):
1642
Daniel Cheng566634ff2024-06-29 14:56:531643 def testCheckAndroidCrLogUsage(self):
1644 mock_input_api = MockInputApi()
1645 mock_output_api = MockOutputApi()
dgnaa68d5e2015-06-10 10:08:221646
Daniel Cheng566634ff2024-06-29 14:56:531647 mock_input_api.files = [
1648 MockAffectedFile('RandomStuff.java', ['random stuff']),
1649 MockAffectedFile('HasAndroidLog.java', [
1650 'import android.util.Log;',
1651 'some random stuff',
1652 'Log.d("TAG", "foo");',
1653 ]),
1654 MockAffectedFile('HasExplicitUtilLog.java', [
1655 'some random stuff',
1656 'android.util.Log.d("TAG", "foo");',
1657 ]),
1658 MockAffectedFile('IsInBasePackage.java', [
1659 'package org.chromium.base;',
1660 'private static final String TAG = "cr_Foo";',
1661 'Log.d(TAG, "foo");',
1662 ]),
1663 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1664 'package org.chromium.base;',
1665 'import android.util.Log;',
1666 'private static final String TAG = "cr_Foo";',
1667 'Log.d(TAG, "foo");',
1668 ]),
1669 MockAffectedFile('HasBothLog.java', [
1670 'import org.chromium.base.Log;',
1671 'some random stuff',
1672 'private static final String TAG = "cr_Foo";',
1673 'Log.d(TAG, "foo");',
1674 'android.util.Log.d("TAG", "foo");',
1675 ]),
1676 MockAffectedFile('HasCorrectTag.java', [
1677 'import org.chromium.base.Log;',
1678 'some random stuff',
1679 'private static final String TAG = "cr_Foo";',
1680 'Log.d(TAG, "foo");',
1681 ]),
1682 MockAffectedFile('HasOldTag.java', [
1683 'import org.chromium.base.Log;',
1684 'some random stuff',
1685 'private static final String TAG = "cr.Foo";',
1686 'Log.d(TAG, "foo");',
1687 ]),
1688 MockAffectedFile('HasDottedTag.java', [
1689 'import org.chromium.base.Log;',
1690 'some random stuff',
1691 'private static final String TAG = "cr_foo.bar";',
1692 'Log.d(TAG, "foo");',
1693 ]),
1694 MockAffectedFile('HasDottedTagPublic.java', [
1695 'import org.chromium.base.Log;',
1696 'some random stuff',
1697 'public static final String TAG = "cr_foo.bar";',
1698 'Log.d(TAG, "foo");',
1699 ]),
1700 MockAffectedFile('HasNoTagDecl.java', [
1701 'import org.chromium.base.Log;',
1702 'some random stuff',
1703 'Log.d(TAG, "foo");',
1704 ]),
1705 MockAffectedFile('HasIncorrectTagDecl.java', [
1706 'import org.chromium.base.Log;',
1707 'private static final String TAHG = "cr_Foo";',
1708 'some random stuff',
1709 'Log.d(TAG, "foo");',
1710 ]),
1711 MockAffectedFile('HasInlineTag.java', [
1712 'import org.chromium.base.Log;',
1713 'some random stuff',
1714 'private static final String TAG = "cr_Foo";',
1715 'Log.d("TAG", "foo");',
1716 ]),
1717 MockAffectedFile('HasInlineTagWithSpace.java', [
1718 'import org.chromium.base.Log;',
1719 'some random stuff',
1720 'private static final String TAG = "cr_Foo";',
1721 'Log.d("log message", "foo");',
1722 ]),
1723 MockAffectedFile('HasUnprefixedTag.java', [
1724 'import org.chromium.base.Log;',
1725 'some random stuff',
1726 'private static final String TAG = "rubbish";',
1727 'Log.d(TAG, "foo");',
1728 ]),
1729 MockAffectedFile('HasTooLongTag.java', [
1730 'import org.chromium.base.Log;',
1731 'some random stuff',
1732 'private static final String TAG = "21_characters_long___";',
1733 'Log.d(TAG, "foo");',
1734 ]),
1735 MockAffectedFile('HasTooLongTagWithNoLogCallsInDiff.java', [
1736 'import org.chromium.base.Log;',
1737 'some random stuff',
1738 'private static final String TAG = "21_characters_long___";',
1739 ]),
1740 ]
dgnaa68d5e2015-06-10 10:08:221741
Daniel Cheng566634ff2024-06-29 14:56:531742 msgs = PRESUBMIT._CheckAndroidCrLogUsage(mock_input_api,
1743 mock_output_api)
dgnaa68d5e2015-06-10 10:08:221744
Daniel Cheng566634ff2024-06-29 14:56:531745 self.assertEqual(
1746 5, len(msgs),
1747 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
dgnaa68d5e2015-06-10 10:08:221748
Daniel Cheng566634ff2024-06-29 14:56:531749 # Declaration format
1750 nb = len(msgs[0].items)
1751 self.assertEqual(
1752 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
1753 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1754 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
dgnaa68d5e2015-06-10 10:08:221755
Daniel Cheng566634ff2024-06-29 14:56:531756 # Tag length
1757 nb = len(msgs[1].items)
1758 self.assertEqual(
1759 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[1].items))
1760 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
1761 self.assertTrue(
1762 'HasTooLongTagWithNoLogCallsInDiff.java' in msgs[1].items)
Geoff Huang77e3d6f2023-12-25 06:27:381763
Daniel Cheng566634ff2024-06-29 14:56:531764 # Tag must be a variable named TAG
1765 nb = len(msgs[2].items)
1766 self.assertEqual(
1767 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[2].items))
1768 self.assertTrue('HasBothLog.java:5' in msgs[2].items)
1769 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
1770 self.assertTrue('HasInlineTagWithSpace.java:4' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221771
Daniel Cheng566634ff2024-06-29 14:56:531772 # Util Log usage
1773 nb = len(msgs[3].items)
1774 self.assertEqual(
1775 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1776 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1777 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
1778 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381779
Daniel Cheng566634ff2024-06-29 14:56:531780 # Tag must not contain
1781 nb = len(msgs[4].items)
1782 self.assertEqual(
1783 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1784 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1785 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1786 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511787
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391788
estadee17314a02017-01-12 16:22:161789class GoogleAnswerUrlFormatTest(unittest.TestCase):
1790
Daniel Cheng566634ff2024-06-29 14:56:531791 def testCatchAnswerUrlId(self):
1792 input_api = MockInputApi()
1793 input_api.files = [
1794 MockFile('somewhere/file.cc', [
1795 'char* host = '
1796 ' "https://support.google.com/chrome/answer/123456";'
1797 ]),
1798 MockFile('somewhere_else/file.cc', [
1799 'char* host = '
1800 ' "https://support.google.com/chrome/a/answer/123456";'
1801 ]),
1802 ]
estadee17314a02017-01-12 16:22:161803
Daniel Cheng566634ff2024-06-29 14:56:531804 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1805 input_api, MockOutputApi())
1806 self.assertEqual(1, len(warnings))
1807 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161808
Daniel Cheng566634ff2024-06-29 14:56:531809 def testAllowAnswerUrlParam(self):
1810 input_api = MockInputApi()
1811 input_api.files = [
1812 MockFile('somewhere/file.cc', [
1813 'char* host = '
1814 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1815 ]),
1816 ]
estadee17314a02017-01-12 16:22:161817
Daniel Cheng566634ff2024-06-29 14:56:531818 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1819 input_api, MockOutputApi())
1820 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161821
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391822
reillyi38965732015-11-16 18:27:331823class HardcodedGoogleHostsTest(unittest.TestCase):
1824
Daniel Cheng566634ff2024-06-29 14:56:531825 def testWarnOnAssignedLiterals(self):
1826 input_api = MockInputApi()
1827 input_api.files = [
1828 MockFile('content/file.cc',
1829 ['char* host = "https://www.google.com";']),
1830 MockFile('content/file.cc',
1831 ['char* host = "https://www.googleapis.com";']),
1832 MockFile('content/file.cc',
1833 ['char* host = "https://clients1.google.com";']),
1834 ]
reillyi38965732015-11-16 18:27:331835
Daniel Cheng566634ff2024-06-29 14:56:531836 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1837 input_api, MockOutputApi())
1838 self.assertEqual(1, len(warnings))
1839 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331840
Daniel Cheng566634ff2024-06-29 14:56:531841 def testAllowInComment(self):
1842 input_api = MockInputApi()
1843 input_api.files = [
1844 MockFile('content/file.cc',
1845 ['char* host = "https://www.aol.com"; // google.com'])
1846 ]
reillyi38965732015-11-16 18:27:331847
Daniel Cheng566634ff2024-06-29 14:56:531848 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1849 input_api, MockOutputApi())
1850 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331851
dgn4401aa52015-04-29 16:26:171852
James Cook6b6597c2019-11-06 22:05:291853class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1854
Daniel Cheng566634ff2024-06-29 14:56:531855 def testWarnsOnChromeOsDirectories(self):
1856 files = [
1857 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1858 MockFile('chrome/browser/chromeos/file.cc',
1859 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1860 MockFile('chromeos/file.cc',
1861 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1862 MockFile('components/arc/file.cc',
1863 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1864 MockFile('components/exo/file.cc',
1865 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1866 ]
1867 input_api = MockInputApi()
1868 for file in files:
1869 input_api.files = [file]
1870 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1871 input_api, MockOutputApi())
1872 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291873
Daniel Cheng566634ff2024-06-29 14:56:531874 def testDoesNotWarnOnSyncOsPref(self):
1875 input_api = MockInputApi()
1876 input_api.files = [
1877 MockFile('chromeos/file.cc',
1878 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1879 ]
1880 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1881 input_api, MockOutputApi())
1882 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291883
Daniel Cheng566634ff2024-06-29 14:56:531884 def testDoesNotWarnOnOtherDirectories(self):
1885 input_api = MockInputApi()
1886 input_api.files = [
1887 MockFile('chrome/browser/ui/file.cc',
1888 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1889 MockFile('components/sync/file.cc',
1890 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1891 MockFile('content/browser/file.cc',
1892 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1893 MockFile('a/notchromeos/file.cc',
1894 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1895 ]
1896 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1897 input_api, MockOutputApi())
1898 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291899
Daniel Cheng566634ff2024-06-29 14:56:531900 def testSeparateWarningForPriorityPrefs(self):
1901 input_api = MockInputApi()
1902 input_api.files = [
1903 MockFile('chromeos/file.cc', [
1904 'PrefRegistrySyncable::SYNCABLE_PREF',
1905 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
1906 ]),
1907 ]
1908 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1909 input_api, MockOutputApi())
1910 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:291911
1912
jbriance9e12f162016-11-25 07:57:501913class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:501914
Daniel Cheng566634ff2024-06-29 14:56:531915 def testCheckHeadersOnlyOutsideThirdParty(self):
1916 mock_input_api = MockInputApi()
1917 mock_input_api.files = [
1918 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
1919 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
1920 ]
1921 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1922 mock_input_api, MockOutputApi())
1923 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501924
Daniel Cheng566634ff2024-06-29 14:56:531925 def testNoNestedDeclaration(self):
1926 mock_input_api = MockInputApi()
1927 mock_input_api.files = [
1928 MockAffectedFile('somewhere/header.h', [
1929 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
1930 ])
1931 ]
1932 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1933 mock_input_api, MockOutputApi())
1934 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501935
Daniel Cheng566634ff2024-06-29 14:56:531936 def testSubStrings(self):
1937 mock_input_api = MockInputApi()
1938 mock_input_api.files = [
1939 MockAffectedFile('somewhere/header.h', [
1940 'class NotUsefulClass;', 'struct SomeStruct;',
1941 'UsefulClass *p1;', 'SomeStructPtr *p2;'
1942 ])
1943 ]
1944 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1945 mock_input_api, MockOutputApi())
1946 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:501947
Daniel Cheng566634ff2024-06-29 14:56:531948 def testUselessForwardDeclaration(self):
1949 mock_input_api = MockInputApi()
1950 mock_input_api.files = [
1951 MockAffectedFile('somewhere/header.h', [
1952 'class DummyClass;', 'struct DummyStruct;',
1953 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
1954 ])
1955 ]
1956 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1957 mock_input_api, MockOutputApi())
1958 self.assertEqual(2, len(warnings))
1959
1960 def testBlinkHeaders(self):
1961 mock_input_api = MockInputApi()
1962 mock_input_api.files = [
1963 MockAffectedFile('third_party/blink/header.h', [
1964 'class DummyClass;',
1965 'struct DummyStruct;',
1966 ]),
1967 MockAffectedFile('third_party\\blink\\header.h', [
1968 'class DummyClass;',
1969 'struct DummyStruct;',
1970 ])
1971 ]
1972 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1973 mock_input_api, MockOutputApi())
1974 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:311975
jbriance9e12f162016-11-25 07:57:501976
rlanday6802cf632017-05-30 17:48:361977class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:361978
Daniel Cheng566634ff2024-06-29 14:56:531979 def testThirdPartyNotWebKitIgnored(self):
1980 mock_input_api = MockInputApi()
1981 mock_input_api.files = [
1982 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1983 MockAffectedFile('third_party/test/test.cpp',
1984 '#include "../header.h"'),
1985 ]
rlanday6802cf632017-05-30 17:48:361986
Daniel Cheng566634ff2024-06-29 14:56:531987 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:361988
Daniel Cheng566634ff2024-06-29 14:56:531989 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
1990 mock_output_api)
1991 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:361992
Daniel Cheng566634ff2024-06-29 14:56:531993 def testNonCppFileIgnored(self):
1994 mock_input_api = MockInputApi()
1995 mock_input_api.files = [
1996 MockAffectedFile('test.py', '#include "../header.h"'),
1997 ]
rlanday6802cf632017-05-30 17:48:361998
Daniel Cheng566634ff2024-06-29 14:56:531999 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362000
Daniel Cheng566634ff2024-06-29 14:56:532001 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2002 mock_output_api)
2003 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362004
Daniel Cheng566634ff2024-06-29 14:56:532005 def testInnocuousChangesAllowed(self):
2006 mock_input_api = MockInputApi()
2007 mock_input_api.files = [
2008 MockAffectedFile('test.cpp', '#include "header.h"'),
2009 MockAffectedFile('test2.cpp', '../'),
2010 ]
rlanday6802cf632017-05-30 17:48:362011
Daniel Cheng566634ff2024-06-29 14:56:532012 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362013
Daniel Cheng566634ff2024-06-29 14:56:532014 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2015 mock_output_api)
2016 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362017
Daniel Cheng566634ff2024-06-29 14:56:532018 def testRelativeIncludeNonWebKitProducesError(self):
2019 mock_input_api = MockInputApi()
2020 mock_input_api.files = [
2021 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2022 ]
rlanday6802cf632017-05-30 17:48:362023
Daniel Cheng566634ff2024-06-29 14:56:532024 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362025
Daniel Cheng566634ff2024-06-29 14:56:532026 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2027 mock_output_api)
2028 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362029
Daniel Cheng566634ff2024-06-29 14:56:532030 def testRelativeIncludeWebKitProducesError(self):
2031 mock_input_api = MockInputApi()
2032 mock_input_api.files = [
2033 MockAffectedFile('third_party/blink/test.cpp',
2034 ['#include "../header.h']),
2035 ]
rlanday6802cf632017-05-30 17:48:362036
Daniel Cheng566634ff2024-06-29 14:56:532037 mock_output_api = MockOutputApi()
2038
2039 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2040 mock_output_api)
2041 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242042
Daniel Cheng13ca61a882017-08-25 15:11:252043
Daniel Bratell65b033262019-04-23 08:17:062044class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062045
Daniel Cheng566634ff2024-06-29 14:56:532046 def testThirdPartyNotBlinkIgnored(self):
2047 mock_input_api = MockInputApi()
2048 mock_input_api.files = [
2049 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2050 ]
Daniel Bratell65b033262019-04-23 08:17:062051
Daniel Cheng566634ff2024-06-29 14:56:532052 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062053
Daniel Cheng566634ff2024-06-29 14:56:532054 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2055 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062056
Daniel Cheng566634ff2024-06-29 14:56:532057 def testPythonFileIgnored(self):
2058 mock_input_api = MockInputApi()
2059 mock_input_api.files = [
2060 MockAffectedFile('test.py', '#include "file.cc"'),
2061 ]
Daniel Bratell65b033262019-04-23 08:17:062062
Daniel Cheng566634ff2024-06-29 14:56:532063 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062064
Daniel Cheng566634ff2024-06-29 14:56:532065 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2066 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062067
Daniel Cheng566634ff2024-06-29 14:56:532068 def testIncFilesAccepted(self):
2069 mock_input_api = MockInputApi()
2070 mock_input_api.files = [
2071 MockAffectedFile('test.py', '#include "file.inc"'),
2072 ]
Daniel Bratell65b033262019-04-23 08:17:062073
Daniel Cheng566634ff2024-06-29 14:56:532074 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062075
Daniel Cheng566634ff2024-06-29 14:56:532076 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2077 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062078
Daniel Cheng566634ff2024-06-29 14:56:532079 def testInnocuousChangesAllowed(self):
2080 mock_input_api = MockInputApi()
2081 mock_input_api.files = [
2082 MockAffectedFile('test.cpp', '#include "header.h"'),
2083 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2084 ]
Daniel Bratell65b033262019-04-23 08:17:062085
Daniel Cheng566634ff2024-06-29 14:56:532086 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062087
Daniel Cheng566634ff2024-06-29 14:56:532088 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2089 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062090
Daniel Cheng566634ff2024-06-29 14:56:532091 def testCcIncludeNonBlinkProducesError(self):
2092 mock_input_api = MockInputApi()
2093 mock_input_api.files = [
2094 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2095 ]
Daniel Bratell65b033262019-04-23 08:17:062096
Daniel Cheng566634ff2024-06-29 14:56:532097 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062098
Daniel Cheng566634ff2024-06-29 14:56:532099 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2100 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062101
Daniel Cheng566634ff2024-06-29 14:56:532102 def testCppIncludeBlinkProducesError(self):
2103 mock_input_api = MockInputApi()
2104 mock_input_api.files = [
2105 MockAffectedFile('third_party/blink/test.cpp',
2106 ['#include "foo/file.cpp"']),
2107 ]
Daniel Bratell65b033262019-04-23 08:17:062108
Daniel Cheng566634ff2024-06-29 14:56:532109 mock_output_api = MockOutputApi()
2110
2111 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2112 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062113
2114
Andrew Grieve1b290e4a22020-11-24 20:07:012115class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012116
Daniel Cheng566634ff2024-06-29 14:56:532117 def testAddBareGlobs(self):
2118 mock_input_api = MockInputApi()
2119 mock_input_api.files = [
2120 MockAffectedFile('base/stuff.gni',
2121 ['forward_variables_from(invoker, "*")']),
2122 MockAffectedFile('base/BUILD.gn',
2123 ['forward_variables_from(invoker, "*")']),
2124 ]
2125 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2126 MockOutputApi())
2127 self.assertEqual(1, len(warnings))
2128 msg = '\n'.join(warnings[0].items)
2129 self.assertIn('base/stuff.gni', msg)
2130 # Should not check .gn files. Local templates don't need to care about
2131 # visibility / testonly.
2132 self.assertNotIn('base/BUILD.gn', msg)
2133
2134 def testValidUses(self):
2135 mock_input_api = MockInputApi()
2136 mock_input_api.files = [
2137 MockAffectedFile('base/stuff.gni',
2138 ['forward_variables_from(invoker, "*", [])']),
2139 MockAffectedFile('base/stuff2.gni', [
2140 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2141 ]),
2142 MockAffectedFile(
2143 'base/stuff3.gni',
2144 ['forward_variables_from(invoker, [ "testonly" ])']),
2145 ]
2146 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2147 MockOutputApi())
2148 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012149
2150
Sean Kaucb7c9b32022-10-25 21:25:522151class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522152
Daniel Cheng566634ff2024-06-29 14:56:532153 def testAddAbsolutePath(self):
2154 mock_input_api = MockInputApi()
2155 mock_input_api.files = [
2156 MockAffectedFile('base/BUILD.gn',
2157 ['rebase_path("$target_gen_dir", "//")']),
2158 MockAffectedFile('base/root/BUILD.gn',
2159 ['rebase_path("$target_gen_dir", "/")']),
2160 MockAffectedFile('base/variable/BUILD.gn',
2161 ['rebase_path(target_gen_dir, "/")']),
2162 ]
2163 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2164 self.assertEqual(1, len(warnings))
2165 msg = '\n'.join(warnings[0].items)
2166 self.assertIn('base/BUILD.gn', msg)
2167 self.assertIn('base/root/BUILD.gn', msg)
2168 self.assertIn('base/variable/BUILD.gn', msg)
2169 self.assertEqual(3, len(warnings[0].items))
2170
2171 def testValidUses(self):
2172 mock_input_api = MockInputApi()
2173 mock_input_api.files = [
2174 MockAffectedFile(
2175 'base/foo/BUILD.gn',
2176 ['rebase_path("$target_gen_dir", root_build_dir)']),
2177 MockAffectedFile(
2178 'base/bar/BUILD.gn',
2179 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2180 MockAffectedFile('base/baz/BUILD.gn',
2181 ['rebase_path(target_gen_dir, root_build_dir)']),
2182 MockAffectedFile(
2183 'base/baz/BUILD.gn',
2184 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2185 MockAffectedFile('base/okay_slash/BUILD.gn',
2186 ['rebase_path(".", "//")']),
2187 ]
2188 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2189 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522190
2191
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192192class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192193
Daniel Cheng566634ff2024-06-29 14:56:532194 def testAddHeaderWithoutGn(self):
2195 mock_input_api = MockInputApi()
2196 mock_input_api.files = [
2197 MockAffectedFile('base/stuff.h', ''),
2198 ]
2199 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2200 mock_input_api, MockOutputApi())
2201 self.assertEqual(1, len(warnings))
2202 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192203
Daniel Cheng566634ff2024-06-29 14:56:532204 def testModifyHeader(self):
2205 mock_input_api = MockInputApi()
2206 mock_input_api.files = [
2207 MockAffectedFile('base/stuff.h', '', action='M'),
2208 ]
2209 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2210 mock_input_api, MockOutputApi())
2211 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192212
Daniel Cheng566634ff2024-06-29 14:56:532213 def testDeleteHeader(self):
2214 mock_input_api = MockInputApi()
2215 mock_input_api.files = [
2216 MockAffectedFile('base/stuff.h', '', action='D'),
2217 ]
2218 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2219 mock_input_api, MockOutputApi())
2220 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192221
Daniel Cheng566634ff2024-06-29 14:56:532222 def testAddHeaderWithGn(self):
2223 mock_input_api = MockInputApi()
2224 mock_input_api.files = [
2225 MockAffectedFile('base/stuff.h', ''),
2226 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2227 ]
2228 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2229 mock_input_api, MockOutputApi())
2230 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192231
Daniel Cheng566634ff2024-06-29 14:56:532232 def testAddHeaderWithGni(self):
2233 mock_input_api = MockInputApi()
2234 mock_input_api.files = [
2235 MockAffectedFile('base/stuff.h', ''),
2236 MockAffectedFile('base/files.gni', 'stuff.h'),
2237 ]
2238 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2239 mock_input_api, MockOutputApi())
2240 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192241
Daniel Cheng566634ff2024-06-29 14:56:532242 def testAddHeaderWithOther(self):
2243 mock_input_api = MockInputApi()
2244 mock_input_api.files = [
2245 MockAffectedFile('base/stuff.h', ''),
2246 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2247 ]
2248 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2249 mock_input_api, MockOutputApi())
2250 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192251
Daniel Cheng566634ff2024-06-29 14:56:532252 def testAddHeaderWithWrongGn(self):
2253 mock_input_api = MockInputApi()
2254 mock_input_api.files = [
2255 MockAffectedFile('base/stuff.h', ''),
2256 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2257 ]
2258 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2259 mock_input_api, MockOutputApi())
2260 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192261
Daniel Cheng566634ff2024-06-29 14:56:532262 def testAddHeadersWithGn(self):
2263 mock_input_api = MockInputApi()
2264 mock_input_api.files = [
2265 MockAffectedFile('base/stuff.h', ''),
2266 MockAffectedFile('base/another.h', ''),
2267 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2268 ]
2269 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2270 mock_input_api, MockOutputApi())
2271 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192272
Daniel Cheng566634ff2024-06-29 14:56:532273 def testAddHeadersWithWrongGn(self):
2274 mock_input_api = MockInputApi()
2275 mock_input_api.files = [
2276 MockAffectedFile('base/stuff.h', ''),
2277 MockAffectedFile('base/another.h', ''),
2278 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2279 ]
2280 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2281 mock_input_api, MockOutputApi())
2282 self.assertEqual(1, len(warnings))
2283 self.assertFalse('base/stuff.h' in warnings[0].items)
2284 self.assertTrue('base/another.h' in warnings[0].items)
2285
2286 def testAddHeadersWithWrongGn2(self):
2287 mock_input_api = MockInputApi()
2288 mock_input_api.files = [
2289 MockAffectedFile('base/stuff.h', ''),
2290 MockAffectedFile('base/another.h', ''),
2291 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2292 ]
2293 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2294 mock_input_api, MockOutputApi())
2295 self.assertEqual(1, len(warnings))
2296 self.assertTrue('base/stuff.h' in warnings[0].items)
2297 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192298
2299
Michael Giuffridad3bc8672018-10-25 22:48:022300class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022301
Daniel Cheng566634ff2024-06-29 14:56:532302 def testProductNameInDesc(self):
2303 mock_input_api = MockInputApi()
2304 mock_input_api.files = [
2305 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2306 '<message name="Foo" desc="Welcome to Chrome">',
2307 ' Welcome to Chrome!',
2308 '</message>',
2309 ]),
2310 MockAffectedFile('chrome/app/chromium_strings.grd', [
2311 '<message name="Bar" desc="Welcome to Chrome">',
2312 ' Welcome to Chromium!',
2313 '</message>',
2314 ]),
2315 ]
2316 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2317 mock_input_api, MockOutputApi())
2318 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022319
Daniel Cheng566634ff2024-06-29 14:56:532320 def testChromeInChromium(self):
2321 mock_input_api = MockInputApi()
2322 mock_input_api.files = [
2323 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2324 '<message name="Foo" desc="Welcome to Chrome">',
2325 ' Welcome to Chrome!',
2326 '</message>',
2327 ]),
2328 MockAffectedFile('chrome/app/chromium_strings.grd', [
2329 '<message name="Bar" desc="Welcome to Chrome">',
2330 ' Welcome to Chrome!',
2331 '</message>',
2332 ]),
2333 ]
2334 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2335 mock_input_api, MockOutputApi())
2336 self.assertEqual(1, len(warnings))
2337 self.assertTrue(
2338 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022339
Daniel Cheng566634ff2024-06-29 14:56:532340 def testChromiumInChrome(self):
2341 mock_input_api = MockInputApi()
2342 mock_input_api.files = [
2343 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2344 '<message name="Foo" desc="Welcome to Chrome">',
2345 ' Welcome to Chromium!',
2346 '</message>',
2347 ]),
2348 MockAffectedFile('chrome/app/chromium_strings.grd', [
2349 '<message name="Bar" desc="Welcome to Chrome">',
2350 ' Welcome to Chromium!',
2351 '</message>',
2352 ]),
2353 ]
2354 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2355 mock_input_api, MockOutputApi())
2356 self.assertEqual(1, len(warnings))
2357 self.assertTrue(
2358 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202359
Daniel Cheng566634ff2024-06-29 14:56:532360 def testChromeForTestingInChromium(self):
2361 mock_input_api = MockInputApi()
2362 mock_input_api.files = [
2363 MockAffectedFile('chrome/app/chromium_strings.grd', [
2364 '<message name="Bar" desc="Welcome to Chrome">',
2365 ' Welcome to Chrome for Testing!',
2366 '</message>',
2367 ]),
2368 ]
2369 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2370 mock_input_api, MockOutputApi())
2371 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202372
Daniel Cheng566634ff2024-06-29 14:56:532373 def testChromeForTestingInChrome(self):
2374 mock_input_api = MockInputApi()
2375 mock_input_api.files = [
2376 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2377 '<message name="Bar" desc="Welcome to Chrome">',
2378 ' Welcome to Chrome for Testing!',
2379 '</message>',
2380 ]),
2381 ]
2382 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2383 mock_input_api, MockOutputApi())
2384 self.assertEqual(1, len(warnings))
2385 self.assertTrue(
2386 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022387
Daniel Cheng566634ff2024-06-29 14:56:532388 def testMultipleInstances(self):
2389 mock_input_api = MockInputApi()
2390 mock_input_api.files = [
2391 MockAffectedFile('chrome/app/chromium_strings.grd', [
2392 '<message name="Bar" desc="Welcome to Chrome">',
2393 ' Welcome to Chrome!',
2394 '</message>',
2395 '<message name="Baz" desc="A correct message">',
2396 ' Chromium is the software you are using.',
2397 '</message>',
2398 '<message name="Bat" desc="An incorrect message">',
2399 ' Google Chrome is the software you are using.',
2400 '</message>',
2401 ]),
2402 ]
2403 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2404 mock_input_api, MockOutputApi())
2405 self.assertEqual(1, len(warnings))
2406 self.assertTrue(
2407 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2408 self.assertTrue(
2409 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2410
2411 def testMultipleWarnings(self):
2412 mock_input_api = MockInputApi()
2413 mock_input_api.files = [
2414 MockAffectedFile('chrome/app/chromium_strings.grd', [
2415 '<message name="Bar" desc="Welcome to Chrome">',
2416 ' Welcome to Chrome!',
2417 '</message>',
2418 '<message name="Baz" desc="A correct message">',
2419 ' Chromium is the software you are using.',
2420 '</message>',
2421 '<message name="Bat" desc="An incorrect message">',
2422 ' Google Chrome is the software you are using.',
2423 '</message>',
2424 ]),
2425 MockAffectedFile(
2426 'components/components_google_chrome_strings.grd', [
2427 '<message name="Bar" desc="Welcome to Chrome">',
2428 ' Welcome to Chrome!',
2429 '</message>',
2430 '<message name="Baz" desc="A correct message">',
2431 ' Chromium is the software you are using.',
2432 '</message>',
2433 '<message name="Bat" desc="An incorrect message">',
2434 ' Google Chrome is the software you are using.',
2435 '</message>',
2436 ]),
2437 ]
2438 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2439 mock_input_api, MockOutputApi())
2440 self.assertEqual(2, len(warnings))
2441 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2442 warnings[0].items[0])
2443 self.assertTrue(
2444 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2445 self.assertTrue(
2446 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022447
2448
Daniel Chenga37c03db2022-05-12 17:20:342449class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252450
Daniel Cheng566634ff2024-06-29 14:56:532451 def _createMockInputApi(self):
2452 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472453
Daniel Cheng566634ff2024-06-29 14:56:532454 def FakeRepositoryRoot():
2455 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472456
Daniel Cheng566634ff2024-06-29 14:56:532457 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2458 self._injectFakeOwnersClient(
2459 mock_input_api, ['[email protected]', '[email protected]'])
2460 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342461
Daniel Cheng566634ff2024-06-29 14:56:532462 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342463
Daniel Cheng566634ff2024-06-29 14:56:532464 class FakeGerrit(object):
2465
2466 def IsOwnersOverrideApproved(self, issue):
2467 return False
2468
2469 input_api.change.issue = 123
2470 input_api.gerrit = FakeGerrit()
2471
2472 def _injectFakeOwnersClient(self, input_api, owners):
2473
2474 class FakeOwnersClient(object):
2475
2476 def ListOwners(self, f):
2477 return owners
2478
2479 input_api.owners_client = FakeOwnersClient()
2480
2481 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2482
2483 def MockOwnerAndReviewers(input_api,
2484 email_regexp,
2485 approval_needed=False):
2486 return [owner, reviewers]
2487
2488 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2489 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342490
2491
2492class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532493 _test_cases = [
2494 ('*_messages.cc', 'scary_messages.cc'),
2495 ('*_messages*.h', 'scary_messages.h'),
2496 ('*_messages*.h', 'scary_messages_android.h'),
2497 ('*_param_traits*.*', 'scary_param_traits.h'),
2498 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2499 ('*.mojom', 'scary.mojom'),
2500 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2501 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2502 ('*_type_converter*.*', 'scary_type_converter.h'),
2503 ('*_type_converter*.*', 'scary_type_converter_nacl.h'),
2504 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252505 ]
Daniel Cheng171dad8d2022-05-21 00:40:252506
Daniel Cheng566634ff2024-06-29 14:56:532507 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2508 mock_input_api = self._createMockInputApi()
2509 new_owners_file_path = mock_input_api.os_path.join(
2510 'services', 'goat', 'public', 'OWNERS')
2511 new_owners_file = [
2512 'per-file *.mojom=set noparent',
2513 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2514 ]
Daniel Cheng3008dc12022-05-13 04:02:112515
Daniel Cheng566634ff2024-06-29 14:56:532516 def FakeReadFile(filename):
2517 self.assertEqual(
2518 mock_input_api.os_path.join('chromium', 'src',
2519 new_owners_file_path), filename)
2520 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112521
Daniel Cheng566634ff2024-06-29 14:56:532522 mock_input_api.ReadFile = FakeReadFile
2523 mock_input_api.files = [
2524 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252525 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532526 mock_input_api.os_path.join('services', 'goat', 'public',
2527 'goat.mojom'),
2528 ['// Scary contents.'])
2529 ]
2530 self._setupFakeChange(mock_input_api)
2531 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2532 '[email protected]',
2533 ['[email protected]'])
2534 mock_input_api.is_committing = True
2535 mock_input_api.dry_run = False
2536 mock_output_api = MockOutputApi()
2537 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2538 mock_output_api)
2539 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342540
Daniel Cheng566634ff2024-06-29 14:56:532541 def testMissingSecurityReviewerAtUpload(self):
2542 mock_input_api = self._createMockInputApi()
2543 new_owners_file_path = mock_input_api.os_path.join(
2544 'services', 'goat', 'public', 'OWNERS')
2545 new_owners_file = [
2546 'per-file *.mojom=set noparent',
2547 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2548 ]
Daniel Chenga37c03db2022-05-12 17:20:342549
Daniel Cheng566634ff2024-06-29 14:56:532550 def FakeReadFile(filename):
2551 self.assertEqual(
2552 mock_input_api.os_path.join('chromium', 'src',
2553 new_owners_file_path), filename)
2554 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362555
Daniel Cheng566634ff2024-06-29 14:56:532556 mock_input_api.ReadFile = FakeReadFile
2557 mock_input_api.files = [
2558 MockAffectedFile(new_owners_file_path, new_owners_file),
2559 MockAffectedFile(
2560 mock_input_api.os_path.join('services', 'goat', 'public',
2561 'goat.mojom'),
2562 ['// Scary contents.'])
2563 ]
2564 self._setupFakeChange(mock_input_api)
2565 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2566 '[email protected]',
2567 ['[email protected]'])
2568 mock_input_api.is_committing = False
2569 mock_input_api.dry_run = False
2570 mock_output_api = MockOutputApi()
2571 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2572 mock_output_api)
2573 self.assertEqual(1, len(results))
2574 self.assertEqual('notify', results[0].type)
2575 self.assertEqual(
2576 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2577 'following newly-added files:', results[0].message)
2578
2579 def testMissingSecurityReviewerAtDryRunCommit(self):
2580 mock_input_api = self._createMockInputApi()
2581 new_owners_file_path = mock_input_api.os_path.join(
2582 'services', 'goat', 'public', 'OWNERS')
2583 new_owners_file = [
2584 'per-file *.mojom=set noparent',
2585 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2586 ]
2587
2588 def FakeReadFile(filename):
2589 self.assertEqual(
2590 mock_input_api.os_path.join('chromium', 'src',
2591 new_owners_file_path), filename)
2592 return '\n'.join(new_owners_file)
2593
2594 mock_input_api.ReadFile = FakeReadFile
2595 mock_input_api.files = [
2596 MockAffectedFile(new_owners_file_path, new_owners_file),
2597 MockAffectedFile(
2598 mock_input_api.os_path.join('services', 'goat', 'public',
2599 'goat.mojom'),
2600 ['// Scary contents.'])
2601 ]
2602 self._setupFakeChange(mock_input_api)
2603 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2604 '[email protected]',
2605 ['[email protected]'])
2606 mock_input_api.is_committing = True
2607 mock_input_api.dry_run = True
2608 mock_output_api = MockOutputApi()
2609 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2610 mock_output_api)
2611 self.assertEqual(1, len(results))
2612 self.assertEqual('error', results[0].type)
2613 self.assertEqual(
2614 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2615 'following newly-added files:', results[0].message)
2616
2617 def testMissingSecurityApprovalAtRealCommit(self):
2618 mock_input_api = self._createMockInputApi()
2619 new_owners_file_path = mock_input_api.os_path.join(
2620 'services', 'goat', 'public', 'OWNERS')
2621 new_owners_file = [
2622 'per-file *.mojom=set noparent',
2623 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2624 ]
2625
2626 def FakeReadFile(filename):
2627 self.assertEqual(
2628 mock_input_api.os_path.join('chromium', 'src',
2629 new_owners_file_path), filename)
2630 return '\n'.join(new_owners_file)
2631
2632 mock_input_api.ReadFile = FakeReadFile
2633 mock_input_api.files = [
2634 MockAffectedFile(new_owners_file_path, new_owners_file),
2635 MockAffectedFile(
2636 mock_input_api.os_path.join('services', 'goat', 'public',
2637 'goat.mojom'),
2638 ['// Scary contents.'])
2639 ]
2640 self._setupFakeChange(mock_input_api)
2641 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2642 '[email protected]',
2643 ['[email protected]'])
2644 mock_input_api.is_committing = True
2645 mock_input_api.dry_run = False
2646 mock_output_api = MockOutputApi()
2647 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2648 mock_output_api)
2649 self.assertEqual('error', results[0].type)
2650 self.assertEqual(
2651 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2652 'following newly-added files:', results[0].message)
2653
2654 def testIpcChangeNeedsSecurityOwner(self):
2655 for is_committing in [True, False]:
2656 for pattern, filename in self._test_cases:
2657 with self.subTest(
2658 line=
2659 f'is_committing={is_committing}, filename={filename}'):
2660 mock_input_api = self._createMockInputApi()
2661 mock_input_api.files = [
2662 MockAffectedFile(
2663 mock_input_api.os_path.join(
2664 'services', 'goat', 'public', filename),
2665 ['// Scary contents.'])
2666 ]
2667 self._setupFakeChange(mock_input_api)
2668 self._injectFakeChangeOwnerAndReviewers(
2669 mock_input_api, '[email protected]',
2670 ['[email protected]'])
2671 mock_input_api.is_committing = is_committing
2672 mock_input_api.dry_run = False
2673 mock_output_api = MockOutputApi()
2674 results = PRESUBMIT.CheckSecurityOwners(
2675 mock_input_api, mock_output_api)
2676 self.assertEqual(1, len(results))
2677 self.assertEqual('error', results[0].type)
2678 self.assertTrue(results[0].message.replace(
2679 '\\', '/'
2680 ).startswith(
2681 'Found missing OWNERS lines for security-sensitive files. '
2682 'Please add the following lines to services/goat/public/OWNERS:'
2683 ))
2684 self.assertEqual(['[email protected]'],
2685 mock_output_api.more_cc)
2686
2687 def testServiceManifestChangeNeedsSecurityOwner(self):
2688 mock_input_api = self._createMockInputApi()
2689 mock_input_api.files = [
2690 MockAffectedFile(
2691 mock_input_api.os_path.join('services', 'goat', 'public',
2692 'cpp', 'manifest.cc'),
2693 [
2694 '#include "services/goat/public/cpp/manifest.h"',
2695 'const service_manager::Manifest& GetManifest() {}',
2696 ])
2697 ]
2698 self._setupFakeChange(mock_input_api)
2699 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2700 '[email protected]',
2701 ['[email protected]'])
2702 mock_output_api = MockOutputApi()
2703 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2704 self.assertEqual(1, len(errors))
2705 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2706 'Found missing OWNERS lines for security-sensitive files. '
2707 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2708 ))
2709 self.assertEqual(['[email protected]'],
2710 mock_output_api.more_cc)
2711
2712 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2713 mock_input_api = self._createMockInputApi()
2714 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2715 '[email protected]',
2716 ['[email protected]'])
2717 mock_input_api.files = [
2718 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2719 'const char kNoEnforcement[] = "not a manifest!";',
2720 ])
2721 ]
2722 mock_output_api = MockOutputApi()
2723 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2724 self.assertEqual([], errors)
2725 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032726
2727
Daniel Chenga37c03db2022-05-12 17:20:342728class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032729
Daniel Cheng566634ff2024-06-29 14:56:532730 def testFidlChangeNeedsSecurityOwner(self):
2731 mock_input_api = self._createMockInputApi()
2732 mock_input_api.files = [
2733 MockAffectedFile('potentially/scary/ipc.fidl',
2734 ['library test.fidl'])
2735 ]
2736 self._setupFakeChange(mock_input_api)
2737 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2738 '[email protected]',
2739 ['[email protected]'])
2740 mock_output_api = MockOutputApi()
2741 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2742 self.assertEqual(1, len(errors))
2743 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2744 'Found missing OWNERS lines for security-sensitive files. '
2745 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032746
Daniel Cheng566634ff2024-06-29 14:56:532747 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2748 mock_input_api = self._createMockInputApi()
2749 mock_input_api.files = [
2750 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2751 ['{ "that is no": "manifest!" }'])
2752 ]
2753 self._setupFakeChange(mock_input_api)
2754 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2755 '[email protected]',
2756 ['[email protected]'])
2757 mock_output_api = MockOutputApi()
2758 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2759 self.assertEqual(1, len(errors))
2760 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2761 'Found missing OWNERS lines for security-sensitive files. '
2762 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032763
Daniel Cheng566634ff2024-06-29 14:56:532764 def testComponentManifestV2NeedsSecurityOwner(self):
2765 mock_input_api = self._createMockInputApi()
2766 mock_input_api.files = [
2767 MockAffectedFile('potentially/scary/v2_manifest.cml',
2768 ['{ "that is no": "manifest!" }'])
2769 ]
2770 self._setupFakeChange(mock_input_api)
2771 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2772 '[email protected]',
2773 ['[email protected]'])
2774 mock_output_api = MockOutputApi()
2775 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2776 self.assertEqual(1, len(errors))
2777 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2778 'Found missing OWNERS lines for security-sensitive files. '
2779 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092780
Daniel Cheng566634ff2024-06-29 14:56:532781 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2782 mock_input_api = MockInputApi()
2783 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2784 '[email protected]',
2785 ['[email protected]'])
2786 mock_input_api.files = [
2787 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2788 'const char kNoEnforcement[] = "Security?!? Pah!";',
2789 ])
2790 ]
2791 mock_output_api = MockOutputApi()
2792 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2793 self.assertEqual([], errors)
2794
2795 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2796 mock_input_api = MockInputApi()
2797 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2798 '[email protected]',
2799 ['[email protected]'])
2800 mock_input_api.files = [
2801 MockAffectedFile(
2802 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2803 'const char kNoEnforcement[] = "Security?!? Pah!";',
2804 ])
2805 ]
2806 mock_output_api = MockOutputApi()
2807 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2808 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362809
Daniel Cheng13ca61a882017-08-25 15:11:252810
Daniel Chenga37c03db2022-05-12 17:20:342811class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132812
Daniel Cheng566634ff2024-06-29 14:56:532813 def testDiffGetServiceSandboxType(self):
2814 mock_input_api = MockInputApi()
2815 mock_input_api.files = [
2816 MockAffectedFile('services/goat/teleporter_host.cc', [
2817 'template <>', 'inline content::SandboxType',
2818 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2819 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2820 '#else', ' return SandboxType::kNoSandbox;',
2821 '#endif // !defined(OS_WIN)', '}'
2822 ]),
2823 ]
2824 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2825 mock_input_api)
2826 self.assertEqual(
2827 {
2828 'services/goat/teleporter_host.cc':
2829 set(['content::GetServiceSandboxType<>()'])
2830 }, files_to_functions)
2831
2832 def testDiffRemovingLine(self):
2833 mock_input_api = MockInputApi()
2834 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2835 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132836+++ new 2020-05-04 14:08:32.000000000 -0400
2837@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372838 template <>
2839 inline content::SandboxType
2840-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2841 #if defined(OS_WIN)
2842 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132843"""
Daniel Cheng566634ff2024-06-29 14:56:532844 mock_input_api.files = [mock_file]
2845 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2846 mock_input_api)
2847 self.assertEqual(
2848 {
2849 'services/goat/teleporter_host.cc':
2850 set(['content::GetServiceSandboxType<>()'])
2851 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132852
Daniel Cheng566634ff2024-06-29 14:56:532853 def testChangeOwnersMissing(self):
2854 mock_input_api = self._createMockInputApi()
2855 self._setupFakeChange(mock_input_api)
2856 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2857 '[email protected]',
2858 ['[email protected]'])
2859 mock_input_api.is_committing = False
2860 mock_input_api.files = [
2861 MockAffectedFile('file.cc',
2862 ['GetServiceSandboxType<Goat>(Sandbox)'])
2863 ]
2864 mock_output_api = MockOutputApi()
2865 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2866 mock_output_api)
2867 self.assertEqual(1, len(result))
2868 self.assertEqual(result[0].type, 'notify')
2869 self.assertEqual(result[0].message,
2870 'The following files change calls to security-sensitive functions\n' \
2871 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2872 ' file.cc\n'
2873 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132874
Daniel Cheng566634ff2024-06-29 14:56:532875 def testChangeOwnersMissingAtCommit(self):
2876 mock_input_api = self._createMockInputApi()
2877 self._setupFakeChange(mock_input_api)
2878 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2879 '[email protected]',
2880 ['[email protected]'])
2881 mock_input_api.is_committing = True
2882 mock_input_api.dry_run = False
2883 mock_input_api.files = [
2884 MockAffectedFile('file.cc',
2885 ['GetServiceSandboxType<mojom::Goat>()'])
2886 ]
2887 mock_output_api = MockOutputApi()
2888 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2889 mock_output_api)
2890 self.assertEqual(1, len(result))
2891 self.assertEqual(result[0].type, 'error')
2892 self.assertEqual(result[0].message,
2893 'The following files change calls to security-sensitive functions\n' \
2894 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2895 ' file.cc\n'
2896 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132897
Daniel Cheng566634ff2024-06-29 14:56:532898 def testChangeOwnersPresent(self):
2899 mock_input_api = self._createMockInputApi()
2900 self._injectFakeChangeOwnerAndReviewers(
2901 mock_input_api, '[email protected]',
2902 ['[email protected]', '[email protected]'])
2903 mock_input_api.files = [
2904 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2905 ]
2906 mock_output_api = MockOutputApi()
2907 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2908 mock_output_api)
2909 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132910
Daniel Cheng566634ff2024-06-29 14:56:532911 def testChangeOwnerIsSecurityOwner(self):
2912 mock_input_api = self._createMockInputApi()
2913 self._setupFakeChange(mock_input_api)
2914 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2915 '[email protected]',
2916 ['[email protected]'])
2917 mock_input_api.files = [
2918 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
2919 ]
2920 mock_output_api = MockOutputApi()
2921 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2922 mock_output_api)
2923 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132924
2925
Mario Sanchez Prada2472cab2019-09-18 10:58:312926class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:292927
Daniel Cheng566634ff2024-06-29 14:56:532928 def testBannedJsFunctions(self):
2929 input_api = MockInputApi()
2930 input_api.files = [
2931 MockFile('ash/webui/file.js', ['chrome.send(something);']),
2932 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
2933 ]
Clement Yan9b330cb2022-11-17 05:25:292934
Daniel Cheng566634ff2024-06-29 14:56:532935 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542936
Daniel Cheng566634ff2024-06-29 14:56:532937 self.assertEqual(1, len(results))
2938 self.assertTrue('ash/webui/file.js' in results[0].message)
2939 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:262940
Daniel Cheng566634ff2024-06-29 14:56:532941 def testBannedJavaFunctions(self):
2942 input_api = MockInputApi()
2943 input_api.files = [
2944 MockFile('some/java/problematic/diskread.java',
2945 ['StrictMode.allowThreadDiskReads();']),
2946 MockFile('some/java/problematic/diskwrite.java',
2947 ['StrictMode.allowThreadDiskWrites();']),
2948 MockFile('some/java/ok/diskwrite.java',
2949 ['StrictModeContext.allowDiskWrites();']),
2950 MockFile('some/java/problematic/waitidleforsync.java',
2951 ['instrumentation.waitForIdleSync();']),
2952 MockFile('some/java/problematic/registerreceiver.java',
2953 ['context.registerReceiver();']),
2954 MockFile('some/java/problematic/property.java',
2955 ['new Property<abc, Integer>;']),
2956 MockFile('some/java/problematic/requestlayout.java',
2957 ['requestLayout();']),
2958 MockFile('some/java/problematic/lastprofile.java',
2959 ['ProfileManager.getLastUsedRegularProfile();']),
2960 MockFile('some/java/problematic/getdrawable1.java',
2961 ['ResourcesCompat.getDrawable();']),
2962 MockFile('some/java/problematic/getdrawable2.java',
2963 ['getResources().getDrawable();']),
2964 ]
Min Qinbc44383c2023-02-22 17:25:262965
Daniel Cheng566634ff2024-06-29 14:56:532966 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
2967 self.assertEqual(2, len(errors))
2968 self.assertTrue(
2969 'some/java/problematic/diskread.java' in errors[0].message)
2970 self.assertTrue(
2971 'some/java/problematic/diskwrite.java' in errors[0].message)
2972 self.assertFalse('some/java/ok/diskwrite.java' in errors[0].message)
2973 self.assertFalse('some/java/ok/diskwrite.java' in errors[1].message)
2974 self.assertTrue(
2975 'some/java/problematic/waitidleforsync.java' in errors[0].message)
2976 self.assertTrue(
2977 'some/java/problematic/registerreceiver.java' in errors[1].message)
2978 self.assertTrue(
2979 'some/java/problematic/property.java' in errors[0].message)
2980 self.assertTrue(
2981 'some/java/problematic/requestlayout.java' in errors[0].message)
2982 self.assertTrue(
2983 'some/java/problematic/lastprofile.java' in errors[0].message)
2984 self.assertTrue(
2985 'some/java/problematic/getdrawable1.java' in errors[0].message)
2986 self.assertTrue(
2987 'some/java/problematic/getdrawable2.java' in errors[0].message)
Peter Kasting94a56c42019-10-25 21:54:042988
Daniel Cheng566634ff2024-06-29 14:56:532989 def testBannedCppFunctions(self):
2990 input_api = MockInputApi()
2991 input_api.files = [
2992 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
2993 MockFile('third_party/blink/problematic/file.cc',
2994 ['GetInterfaceProvider()']),
2995 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
2996 MockFile('some/cpp/problematic/file2.cc',
2997 ['set_owned_by_client()']),
2998 MockFile('some/cpp/nocheck/file.cc',
2999 ['using namespace std; // nocheck']),
3000 MockFile('some/cpp/comment/file.cc',
3001 [' // A comment about `using namespace std;`']),
3002 MockFile('some/cpp/problematic/file3.cc', [
3003 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3004 ]),
3005 MockFile('some/cpp/problematic/file4.cc', [
3006 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3007 ]),
3008 MockFile('some/cpp/problematic/file5.cc', [
3009 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3010 ]),
Daniel Cheng89719222024-07-04 04:59:293011 MockFile('allowed_ranges_usage.cc', ['std::ranges::begin(vec)']),
3012 MockFile('banned_ranges_usage.cc',
3013 ['std::ranges::subrange(first, last)']),
3014 MockFile('views_usage.cc', ['std::views::all(vec)']),
Daniel Cheng566634ff2024-06-29 14:56:533015 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163016
Daniel Cheng566634ff2024-06-29 14:56:533017 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043018
Daniel Cheng566634ff2024-06-29 14:56:533019 # warnings are results[0], errors are results[1]
3020 self.assertEqual(2, len(results))
3021 self.assertTrue('some/cpp/problematic/file.cc' in results[1].message)
3022 self.assertTrue(
3023 'third_party/blink/problematic/file.cc' in results[0].message)
3024 self.assertTrue('some/cpp/ok/file.cc' not in results[1].message)
3025 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3026 self.assertTrue('some/cpp/problematic/file3.cc' in results[0].message)
3027 self.assertTrue('some/cpp/problematic/file4.cc' in results[0].message)
3028 self.assertTrue('some/cpp/problematic/file5.cc' in results[0].message)
3029 self.assertFalse('some/cpp/nocheck/file.cc' in results[0].message)
3030 self.assertFalse('some/cpp/nocheck/file.cc' in results[1].message)
3031 self.assertFalse('some/cpp/comment/file.cc' in results[0].message)
3032 self.assertFalse('some/cpp/comment/file.cc' in results[1].message)
Daniel Cheng89719222024-07-04 04:59:293033 self.assertFalse('allowed_ranges_usage.cc' in results[0].message)
3034 self.assertFalse('allowed_ranges_usage.cc' in results[1].message)
3035 self.assertTrue('banned_ranges_usage.cc' in results[1].message)
3036 self.assertTrue('views_usage.cc' in results[1].message)
Daniel Cheng192683f2022-11-01 20:52:443037
Daniel Cheng566634ff2024-06-29 14:56:533038 def testBannedCppRandomFunctions(self):
3039 banned_rngs = [
3040 'absl::BitGen',
3041 'absl::InsecureBitGen',
3042 'std::linear_congruential_engine',
3043 'std::mersenne_twister_engine',
3044 'std::subtract_with_carry_engine',
3045 'std::discard_block_engine',
3046 'std::independent_bits_engine',
3047 'std::shuffle_order_engine',
3048 'std::minstd_rand0',
3049 'std::minstd_rand',
3050 'std::mt19937',
3051 'std::mt19937_64',
3052 'std::ranlux24_base',
3053 'std::ranlux48_base',
3054 'std::ranlux24',
3055 'std::ranlux48',
3056 'std::knuth_b',
3057 'std::default_random_engine',
3058 'std::random_device',
3059 ]
3060 for banned_rng in banned_rngs:
3061 input_api = MockInputApi()
3062 input_api.files = [
3063 MockFile('some/cpp/problematic/file.cc',
3064 [f'{banned_rng} engine;']),
3065 MockFile('third_party/blink/problematic/file.cc',
3066 [f'{banned_rng} engine;']),
3067 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3068 ]
3069 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3070 MockOutputApi())
3071 self.assertEqual(1, len(results), banned_rng)
3072 self.assertTrue(
3073 'some/cpp/problematic/file.cc' in results[0].message,
3074 banned_rng)
3075 self.assertTrue(
3076 'third_party/blink/problematic/file.cc' in results[0].message,
3077 banned_rng)
3078 self.assertFalse('third_party/ok/file.cc' in results[0].message,
3079 banned_rng)
Sylvain Defresnea8b73d252018-02-28 15:45:543080
Daniel Cheng566634ff2024-06-29 14:56:533081 def testBannedIosObjcFunctions(self):
3082 input_api = MockInputApi()
3083 input_api.files = [
3084 MockFile('some/ios/file.mm',
3085 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3086 MockFile('some/mac/file.mm',
3087 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3088 MockFile('another/ios_file.mm',
3089 ['class SomeTest : public testing::Test {};']),
3090 MockFile(
3091 'some/ios/file_egtest.mm',
3092 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3093 MockFile('some/ios/file_unittest.mm', [
3094 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3095 ]),
3096 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543097
Daniel Cheng566634ff2024-06-29 14:56:533098 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3099 self.assertEqual(1, len(errors))
3100 self.assertTrue('some/ios/file.mm' in errors[0].message)
3101 self.assertTrue('another/ios_file.mm' in errors[0].message)
3102 self.assertTrue('some/mac/file.mm' not in errors[0].message)
3103 self.assertTrue('some/ios/file_egtest.mm' in errors[0].message)
3104 self.assertTrue('some/ios/file_unittest.mm' not in errors[0].message)
Carlos Knippschildab192b8c2019-04-08 20:02:383105
Daniel Cheng566634ff2024-06-29 14:56:533106 def testBannedMojoFunctions(self):
3107 input_api = MockInputApi()
3108 input_api.files = [
3109 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3110 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3111 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3112 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223113
Daniel Cheng566634ff2024-06-29 14:56:533114 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383115
Daniel Cheng566634ff2024-06-29 14:56:533116 # warnings are results[0], errors are results[1]
3117 self.assertEqual(1, len(results))
3118 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3119 self.assertTrue(
3120 'third_party/blink/ok/file3.cc' not in results[0].message)
3121 self.assertTrue(
3122 'content/renderer/ok/file3.cc' not in results[0].message)
3123
3124 def testBannedMojomPatterns(self):
3125 input_api = MockInputApi()
3126 input_api.files = [
3127 MockFile(
3128 'bad.mojom',
3129 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3130 MockFile('good.mojom', [
3131 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223132 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3133 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533134 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3135 ]),
3136 ]
Daniel Cheng92c15e32022-03-16 17:48:223137
Daniel Cheng566634ff2024-06-29 14:56:533138 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223139
Daniel Cheng566634ff2024-06-29 14:56:533140 # warnings are results[0], errors are results[1]
3141 self.assertEqual(1, len(results))
3142 self.assertTrue('bad.mojom' in results[0].message)
3143 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223144
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273145class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243146
Daniel Cheng566634ff2024-06-29 14:56:533147 def testTruePositives(self):
3148 mock_input_api = MockInputApi()
3149 mock_input_api.files = [
3150 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3151 MockFile('some/path/foo.mm', ['FooForTesting();']),
3152 MockFile('some/path/foo.cxx', ['FooForTests();']),
3153 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3154 ]
Vaclav Brozekf01ed502018-03-16 19:38:243155
Daniel Cheng566634ff2024-06-29 14:56:533156 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3157 mock_input_api, MockOutputApi())
3158 self.assertEqual(1, len(results))
3159 self.assertEqual(4, len(results[0].items))
3160 self.assertTrue('foo.cc' in results[0].items[0])
3161 self.assertTrue('foo.mm' in results[0].items[1])
3162 self.assertTrue('foo.cxx' in results[0].items[2])
3163 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243164
Daniel Cheng566634ff2024-06-29 14:56:533165 def testFalsePositives(self):
3166 mock_input_api = MockInputApi()
3167 mock_input_api.files = [
3168 MockFile('some/path/foo.h', ['foo_for_testing();']),
3169 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3170 MockFile('some/path/foo.cc', ['::FooForTests();']),
3171 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3172 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3173 ]
Vaclav Brozekf01ed502018-03-16 19:38:243174
Daniel Cheng566634ff2024-06-29 14:56:533175 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3176 mock_input_api, MockOutputApi())
3177 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133178
Daniel Cheng566634ff2024-06-29 14:56:533179 def testAllowedFiles(self):
3180 mock_input_api = MockInputApi()
3181 mock_input_api.files = [
3182 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3183 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3184 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3185 ]
3186
3187 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3188 mock_input_api, MockOutputApi())
3189 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133190
Vaclav Brozekf01ed502018-03-16 19:38:243191
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273192class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233193
Daniel Cheng566634ff2024-06-29 14:56:533194 def testTruePositives(self):
3195 mock_input_api = MockInputApi()
3196 mock_input_api.files = [
3197 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3198 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3199 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3200 MockFile('dir/java/src/mult.java', [
3201 'int x = SomethingLongHere()',
3202 ' * SomethingLongHereForTesting();'
3203 ])
3204 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233205
Daniel Cheng566634ff2024-06-29 14:56:533206 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3207 mock_input_api, MockOutputApi())
3208 self.assertEqual(1, len(results))
3209 self.assertEqual(4, len(results[0].items))
3210 self.assertTrue('foo.java' in results[0].items[0])
3211 self.assertTrue('bar.java' in results[0].items[1])
3212 self.assertTrue('baz.java' in results[0].items[2])
3213 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233214
Daniel Cheng566634ff2024-06-29 14:56:533215 def testFalsePositives(self):
3216 mock_input_api = MockInputApi()
3217 mock_input_api.files = [
3218 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3219 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3220 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3221 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3222 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3223 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3224 MockFile('dir/java/src/bar5.java', [
3225 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3226 ]),
3227 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3228 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3229 MockFile('dir/junit/src/javadoc.java',
3230 ['/** Use FooForTest(); to obtain foo in tests.'
3231 ' */']),
3232 MockFile(
3233 'dir/junit/src/javadoc2.java',
3234 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3235 ' */']),
3236 MockFile('dir/java/src/bar6.java',
3237 ['FooForTesting(); // IN-TEST']),
3238 ]
3239
3240 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3241 mock_input_api, MockOutputApi())
3242 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233243
3244
Mohamed Heikald048240a2019-11-12 16:57:373245class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373246
Daniel Cheng566634ff2024-06-29 14:56:533247 def testTruePositives(self):
3248 mock_input_api = MockInputApi()
3249 mock_input_api.files = [
3250 MockFile('dir/android/res/drawable/foo.png', []),
3251 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3252 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3253 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3254 ]
Mohamed Heikald048240a2019-11-12 16:57:373255
Daniel Cheng566634ff2024-06-29 14:56:533256 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3257 MockOutputApi())
3258 self.assertEqual(1, len(results))
3259 self.assertEqual(4, len(results[0].items))
3260 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3261 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3262 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3263 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373264
Daniel Cheng566634ff2024-06-29 14:56:533265 def testFalsePositives(self):
3266 mock_input_api = MockInputApi()
3267 mock_input_api.files = [
3268 MockFile('dir/pngs/README.md', []),
3269 MockFile('java/test/res/drawable/foo.png', []),
3270 MockFile('third_party/blink/foo.png', []),
3271 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3272 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3273 ]
3274
3275 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3276 MockOutputApi())
3277 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373278
Evan Stade7cd4a2c2022-08-04 23:37:253279class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253280
Daniel Cheng566634ff2024-06-29 14:56:533281 def test(self):
3282 mock_input_api = MockInputApi()
3283 mock_input_api.files = [
3284 MockFile('components/vector_icons/google_jetpack.icon', []),
3285 MockFile('components/vector_icons/generic_jetpack.icon', []),
3286 ]
3287
3288 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3289 mock_input_api, MockOutputApi())
3290 self.assertEqual(1, len(results))
3291 self.assertEqual(1, len(results[0].items))
3292 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373293
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273294class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053295
Daniel Cheng566634ff2024-06-29 14:56:533296 def testTruePositivesNullptr(self):
3297 mock_input_api = MockInputApi()
3298 mock_input_api.files = [
3299 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3300 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3301 ]
Vaclav Brozek851d9602018-04-04 16:13:053302
Daniel Cheng566634ff2024-06-29 14:56:533303 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3304 MockOutputApi())
3305 self.assertEqual(1, len(results))
3306 self.assertTrue('nullptr' in results[0].message)
3307 self.assertEqual(2, len(results[0].items))
3308 self.assertTrue('baz.cc' in results[0].items[0])
3309 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243310
Daniel Cheng566634ff2024-06-29 14:56:533311 def testTruePositivesConstructor(self):
3312 mock_input_api = MockInputApi()
3313 mock_input_api.files = [
3314 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3315 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3316 MockFile('dir/mult.cc', [
3317 'return',
3318 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3319 ]),
3320 MockFile('dir/mult2.cc', [
3321 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3322 ' std::unique_ptr<T>(foo);'
3323 ]),
3324 MockFile('dir/mult3.cc', [
3325 'bar = std::unique_ptr<T>(',
3326 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3327 ]),
3328 MockFile('dir/multi_arg.cc', [
3329 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3330 ]),
3331 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243332
Daniel Cheng566634ff2024-06-29 14:56:533333 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3334 MockOutputApi())
3335 self.assertEqual(1, len(results))
3336 self.assertTrue('std::make_unique' in results[0].message)
3337 self.assertEqual(6, len(results[0].items))
3338 self.assertTrue('foo.cc' in results[0].items[0])
3339 self.assertTrue('bar.mm' in results[0].items[1])
3340 self.assertTrue('mult.cc' in results[0].items[2])
3341 self.assertTrue('mult2.cc' in results[0].items[3])
3342 self.assertTrue('mult3.cc' in results[0].items[4])
3343 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533344
Daniel Cheng566634ff2024-06-29 14:56:533345 def testFalsePositives(self):
3346 mock_input_api = MockInputApi()
3347 mock_input_api.files = [
3348 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3349 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3350 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3351 MockFile('dir/baz.cc',
3352 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3353 MockFile('dir/baz2.cc',
3354 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3355 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3356 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3357 # Changed line is inside a multiline template block.
3358 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3359 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243360
Daniel Cheng566634ff2024-06-29 14:56:533361 # Two-argument invocation of std::unique_ptr is exempt because there is
3362 # no equivalent using std::make_unique.
3363 MockFile('dir/multi_arg.cc',
3364 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3365 ]
3366
3367 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3368 MockOutputApi())
3369 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243370
Danil Chapovalov3518f362018-08-11 16:13:433371class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433372
Daniel Cheng566634ff2024-06-29 14:56:533373 def testBlocksDirectIncludes(self):
3374 mock_input_api = MockInputApi()
3375 mock_input_api.files = [
3376 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3377 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3378 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3379 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3380 ]
3381 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3382 MockOutputApi())
3383 self.assertEqual(1, len(results))
3384 self.assertEqual(4, len(results[0].items))
3385 self.assertTrue('StrCat' in results[0].message)
3386 self.assertTrue('foo_win.cc' in results[0].items[0])
3387 self.assertTrue('bar.h' in results[0].items[1])
3388 self.assertTrue('baz.h' in results[0].items[2])
3389 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433390
Daniel Cheng566634ff2024-06-29 14:56:533391 def testAllowsToIncludeWrapper(self):
3392 mock_input_api = MockInputApi()
3393 mock_input_api.files = [
3394 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3395 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3396 ]
3397 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3398 MockOutputApi())
3399 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323400
Daniel Cheng566634ff2024-06-29 14:56:533401 def testAllowsToCreateWrapper(self):
3402 mock_input_api = MockInputApi()
3403 mock_input_api.files = [
3404 MockFile('base/win/shlwapi.h', [
3405 '#include <shlwapi.h>',
3406 '#include "base/win/windows_defines.inc"'
3407 ]),
3408 ]
3409 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3410 MockOutputApi())
3411 self.assertEqual(0, len(results))
3412
3413 def testIgnoresNonImplAndHeaders(self):
3414 mock_input_api = MockInputApi()
3415 mock_input_api.files = [
3416 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3417 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3418 ]
3419 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3420 MockOutputApi())
3421 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243422
Mustafa Emre Acer51f2f742020-03-09 19:41:123423
Rainhard Findlingfc31844c52020-05-15 09:58:263424class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533425 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263426
Daniel Cheng566634ff2024-06-29 14:56:533427 # An empty grd file.
3428 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143429 <grit latest_public_release="1" current_release="1">
3430 <release seq="1">
3431 <messages></messages>
3432 </release>
3433 </grit>
3434 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533435 # A grd file with a single message.
3436 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143437 <grit latest_public_release="1" current_release="1">
3438 <release seq="1">
3439 <messages>
3440 <message name="IDS_TEST1">
3441 Test string 1
3442 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483443 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3444 translateable="false">
3445 Non translateable message 1, should be ignored
3446 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393447 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343448 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393449 Accessibility label 1, should be ignored
3450 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143451 </messages>
3452 </release>
3453 </grit>
3454 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533455 # A grd file with two messages.
3456 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143457 <grit latest_public_release="1" current_release="1">
3458 <release seq="1">
3459 <messages>
3460 <message name="IDS_TEST1">
3461 Test string 1
3462 </message>
3463 <message name="IDS_TEST2">
3464 Test string 2
3465 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483466 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3467 translateable="false">
3468 Non translateable message 2, should be ignored
3469 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143470 </messages>
3471 </release>
3472 </grit>
3473 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533474 # A grd file with one ICU syntax message without syntax errors.
3475 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263476 <grit latest_public_release="1" current_release="1">
3477 <release seq="1">
3478 <messages>
3479 <message name="IDS_TEST1">
3480 {NUM, plural,
3481 =1 {Test text for numeric one}
3482 other {Test text for plural with {NUM} as number}}
3483 </message>
3484 </messages>
3485 </release>
3486 </grit>
3487 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533488 # A grd file with one ICU syntax message without syntax errors.
3489 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263490 <grit latest_public_release="1" current_release="1">
3491 <release seq="1">
3492 <messages>
3493 <message name="IDS_TEST1">
3494 {NUM, plural,
3495 =1 {Different test text for numeric one}
3496 other {Different test text for plural with {NUM} as number}}
3497 </message>
3498 </messages>
3499 </release>
3500 </grit>
3501 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533502 # A grd file with multiple ICU syntax messages without syntax errors.
3503 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323504 <grit latest_public_release="1" current_release="1">
3505 <release seq="1">
3506 <messages>
3507 <message name="IDS_TEST1">
3508 {NUM, plural,
3509 =0 {New test text for numeric zero}
3510 =1 {Different test text for numeric one}
3511 =2 {New test text for numeric two}
3512 =3 {New test text for numeric three}
3513 other {Different test text for plural with {NUM} as number}}
3514 </message>
3515 </messages>
3516 </release>
3517 </grit>
3518 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533519 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3520 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263521 <grit latest_public_release="1" current_release="1">
3522 <release seq="1">
3523 <messages>
3524 <message name="IDS_TEST1">
3525 {NUM, plural
3526 =1 {Test text for numeric one}
3527 other {Test text for plural with {NUM} as number}}
3528 </message>
3529 </messages>
3530 </release>
3531 </grit>
3532 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143533
Daniel Cheng566634ff2024-06-29 14:56:533534 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3535 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583536
Daniel Cheng566634ff2024-06-29 14:56:533537 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3538 '<grit-part>', '<message name="IDS_PART_TEST1">',
3539 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583540
Daniel Cheng566634ff2024-06-29 14:56:533541 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3542 '<grit-part>', '<message name="IDS_PART_TEST1">',
3543 'Part string 1', '</message>',
3544 '<message name="IDS_PART_TEST2">', 'Part string 2',
3545 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583546
Daniel Cheng566634ff2024-06-29 14:56:533547 NEW_GRDP_CONTENTS3 = (
3548 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093549 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533550 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093551
Daniel Cheng566634ff2024-06-29 14:56:533552 NEW_GRDP_CONTENTS4 = (
3553 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093554 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533555 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093556
Daniel Cheng566634ff2024-06-29 14:56:533557 NEW_GRDP_CONTENTS5 = (
3558 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353559 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533560 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353561
Daniel Cheng566634ff2024-06-29 14:56:533562 NEW_GRDP_CONTENTS6 = (
3563 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353564 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533565 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353566
Daniel Cheng566634ff2024-06-29 14:56:533567 # A grdp file with one ICU syntax message without syntax errors.
3568 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3569 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3570 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3571 '=1 {Test text for numeric one}',
3572 'other {Test text for plural with {NUM} as number}}', '</message>',
3573 '</grit-part>')
3574 # A grdp file with one ICU syntax message without syntax errors.
3575 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3576 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3577 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3578 '=1 {Different test text for numeric one}',
3579 'other {Different test text for plural with {NUM} as number}}',
3580 '</message>', '</grit-part>')
3581 # A grdp file with multiple ICU syntax messages without syntax errors.
3582 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3583 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3584 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3585 '=0 {New test text for numeric zero}',
3586 '=1 {Different test text for numeric one}',
3587 '=2 {New test text for numeric two}',
3588 '=3 {New test text for numeric three}',
3589 'other {Different test text for plural with {NUM} as number}}',
3590 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263591
Daniel Cheng566634ff2024-06-29 14:56:533592 # A grdp file with one ICU syntax message with syntax errors (superfluous
3593 # space).
3594 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3595 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3596 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3597 '= 1 {Test text for numeric one}',
3598 'other {Test text for plural with {NUM} as number}}', '</message>',
3599 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263600
Daniel Cheng566634ff2024-06-29 14:56:533601 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3602 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3603 'changelist. Run '
3604 'tools/translate/upload_screenshots.py to '
3605 'upload them instead:')
3606 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3607 'To ensure the best translations, take '
3608 'screenshots of the relevant UI '
3609 '(https://g.co/chrome/translation) and add '
3610 'these files to your changelist:')
3611 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3612 'files. Remove:')
3613 ICU_SYNTAX_ERROR_MESSAGE = (
3614 'ICU syntax errors were found in the following '
3615 'strings (problems or feedback? Contact '
3616 '[email protected]):')
3617 SHA1_FORMAT_MESSAGE = (
3618 'The following files do not seem to contain valid sha1 '
3619 'hashes. Make sure they contain hashes created by '
3620 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143621
Daniel Cheng566634ff2024-06-29 14:56:533622 def makeInputApi(self, files):
3623 input_api = MockInputApi()
Andrew Grieve713b89b2024-10-15 20:20:083624 input_api.InitFiles(files)
Daniel Cheng566634ff2024-06-29 14:56:533625 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143626
Daniel Cheng566634ff2024-06-29 14:56:533627 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583628
Daniel Cheng566634ff2024-06-29 14:56:533629 def testNoScreenshots(self):
3630 # No new strings (file contents same). Should not warn.
3631 input_api = self.makeInputApi([
3632 MockAffectedFile('test.grd',
3633 self.NEW_GRD_CONTENTS1,
3634 self.NEW_GRD_CONTENTS1,
3635 action='M'),
3636 MockAffectedFile('part.grdp',
3637 self.NEW_GRDP_CONTENTS1,
3638 self.NEW_GRDP_CONTENTS1,
3639 action='M')
3640 ])
3641 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3642 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343643
Daniel Cheng566634ff2024-06-29 14:56:533644 # Add two new strings. Should have two warnings.
3645 input_api = self.makeInputApi([
3646 MockAffectedFile('test.grd',
3647 self.NEW_GRD_CONTENTS2,
3648 self.NEW_GRD_CONTENTS1,
3649 action='M'),
3650 MockAffectedFile('part.grdp',
3651 self.NEW_GRDP_CONTENTS2,
3652 self.NEW_GRDP_CONTENTS1,
3653 action='M')
3654 ])
3655 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3656 self.assertEqual(1, len(warnings))
3657 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3658 self.assertEqual('error', warnings[0].type)
3659 self.assertEqual([
3660 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3661 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3662 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213663
Daniel Cheng566634ff2024-06-29 14:56:533664 # Add four new strings. Should have four warnings.
3665 input_api = self.makeInputApi([
3666 MockAffectedFile('test.grd',
3667 self.NEW_GRD_CONTENTS2,
3668 self.OLD_GRD_CONTENTS,
3669 action='M'),
3670 MockAffectedFile('part.grdp',
3671 self.NEW_GRDP_CONTENTS2,
3672 self.OLD_GRDP_CONTENTS,
3673 action='M')
3674 ])
3675 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3676 self.assertEqual(1, len(warnings))
3677 self.assertEqual('error', warnings[0].type)
3678 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3679 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583680 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583681 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303682 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303683 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533684 ], warnings[0].items)
3685
3686 def testModifiedMessageDescription(self):
3687 # CL modified a message description for a message that does not yet have a
3688 # screenshot. Should not warn.
3689 input_api = self.makeInputApi([
3690 MockAffectedFile('part.grdp',
3691 self.NEW_GRDP_CONTENTS3,
3692 self.NEW_GRDP_CONTENTS4,
3693 action='M')
3694 ])
3695 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3696 self.assertEqual(0, len(warnings))
3697
3698 # CL modified a message description for a message that already has a
3699 # screenshot. Should not warn.
3700 input_api = self.makeInputApi([
3701 MockAffectedFile('part.grdp',
3702 self.NEW_GRDP_CONTENTS3,
3703 self.NEW_GRDP_CONTENTS4,
3704 action='M'),
3705 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3706 self.VALID_SHA1,
3707 action='A')
3708 ])
3709 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3710 self.assertEqual(0, len(warnings))
3711
3712 def testModifiedMessageMeaning(self):
3713 # CL modified a message meaning for a message that does not yet have a
3714 # screenshot. Should warn.
3715 input_api = self.makeInputApi([
3716 MockAffectedFile('part.grdp',
3717 self.NEW_GRDP_CONTENTS5,
3718 self.NEW_GRDP_CONTENTS6,
3719 action='M')
3720 ])
3721 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3722 self.assertEqual(1, len(warnings))
3723
3724 # CL modified a message meaning for a message that already has a
3725 # screenshot. Should not warn.
3726 input_api = self.makeInputApi([
3727 MockAffectedFile('part.grdp',
3728 self.NEW_GRDP_CONTENTS5,
3729 self.NEW_GRDP_CONTENTS6,
3730 action='M'),
3731 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3732 self.VALID_SHA1,
3733 action='A')
3734 ])
3735 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3736 self.assertEqual(0, len(warnings))
3737
3738 def testModifiedIntroducedInvalidSha1(self):
3739 # CL modified a message and the sha1 file changed to invalid
3740 input_api = self.makeInputApi([
3741 MockAffectedFile('part.grdp',
3742 self.NEW_GRDP_CONTENTS5,
3743 self.NEW_GRDP_CONTENTS6,
3744 action='M'),
3745 MockAffectedFile(os.path.join('part_grdp',
3746 'IDS_PART_TEST1.png.sha1'),
3747 ('some invalid sha1', ),
3748 self.VALID_SHA1,
3749 action='M')
3750 ])
3751 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3752 self.assertEqual(1, len(warnings))
3753
3754 def testPngAddedSha1NotAdded(self):
3755 # CL added one new message in a grd file and added the png file associated
3756 # with it, but did not add the corresponding sha1 file. This should warn
3757 # twice:
3758 # - Once for the added png file (because we don't want developers to upload
3759 # actual images)
3760 # - Once for the missing .sha1 file
3761 input_api = self.makeInputApi([
3762 MockAffectedFile('test.grd',
3763 self.NEW_GRD_CONTENTS1,
3764 self.OLD_GRD_CONTENTS,
3765 action='M'),
3766 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3767 'binary',
3768 action='A')
3769 ])
3770 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3771 self.assertEqual(2, len(warnings))
3772 self.assertEqual('error', warnings[0].type)
3773 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3774 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3775 warnings[0].items)
3776 self.assertEqual('error', warnings[1].type)
3777 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3778 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3779 warnings[1].items)
3780
3781 # CL added two messages (one in grd, one in grdp) and added the png files
3782 # associated with the messages, but did not add the corresponding sha1
3783 # files. This should warn twice:
3784 # - Once for the added png files (because we don't want developers to upload
3785 # actual images)
3786 # - Once for the missing .sha1 files
3787 input_api = self.makeInputApi([
3788 # Modified files:
3789 MockAffectedFile('test.grd',
3790 self.NEW_GRD_CONTENTS1,
3791 self.OLD_GRD_CONTENTS,
3792 action='M'),
3793 MockAffectedFile('part.grdp',
3794 self.NEW_GRDP_CONTENTS1,
3795 self.OLD_GRDP_CONTENTS,
3796 action='M'),
3797 # Added files:
3798 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3799 'binary',
3800 action='A'),
3801 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3802 'binary',
3803 action='A')
3804 ])
3805 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3806 self.assertEqual(2, len(warnings))
3807 self.assertEqual('error', warnings[0].type)
3808 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3809 self.assertEqual([
3810 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3811 os.path.join('test_grd', 'IDS_TEST1.png')
3812 ], warnings[0].items)
3813 self.assertEqual('error', warnings[0].type)
3814 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3815 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303816 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533817 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3818 ], warnings[1].items)
3819
3820 def testScreenshotsWithSha1(self):
3821 # CL added four messages (two each in a grd and grdp) and their
3822 # corresponding .sha1 files. No warnings.
3823 input_api = self.makeInputApi([
3824 # Modified files:
3825 MockAffectedFile('test.grd',
3826 self.NEW_GRD_CONTENTS2,
3827 self.OLD_GRD_CONTENTS,
3828 action='M'),
3829 MockAffectedFile('part.grdp',
3830 self.NEW_GRDP_CONTENTS2,
3831 self.OLD_GRDP_CONTENTS,
3832 action='M'),
3833 # Added files:
3834 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3835 self.VALID_SHA1,
3836 action='A'),
3837 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3838 ('0000000000000000000000000000000000000000', ''),
3839 action='A'),
3840 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3841 self.VALID_SHA1,
3842 action='A'),
3843 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3844 self.VALID_SHA1,
3845 action='A'),
3846 ])
3847 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3848 self.assertEqual([], warnings)
3849
3850 def testScreenshotsWithInvalidSha1(self):
3851 input_api = self.makeInputApi([
3852 # Modified files:
3853 MockAffectedFile('test.grd',
3854 self.NEW_GRD_CONTENTS2,
3855 self.OLD_GRD_CONTENTS,
3856 action='M'),
3857 MockAffectedFile('part.grdp',
3858 self.NEW_GRDP_CONTENTS2,
3859 self.OLD_GRDP_CONTENTS,
3860 action='M'),
3861 # Added files:
3862 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3863 self.VALID_SHA1,
3864 action='A'),
3865 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3866 ('‰PNG', 'test'),
3867 action='A'),
3868 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3869 self.VALID_SHA1,
3870 action='A'),
3871 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3872 self.VALID_SHA1,
3873 action='A'),
3874 ])
3875 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3876 self.assertEqual(1, len(warnings))
3877 self.assertEqual('error', warnings[0].type)
3878 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
3879 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3880 warnings[0].items)
3881
3882 def testScreenshotsRemovedWithSha1(self):
3883 # Replace new contents with old contents in grd and grp files, removing
3884 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3885 # Should warn to remove the sha1 files associated with these strings.
3886 input_api = self.makeInputApi([
3887 # Modified files:
3888 MockAffectedFile(
3889 'test.grd',
3890 self.OLD_GRD_CONTENTS, # new_contents
3891 self.NEW_GRD_CONTENTS2, # old_contents
3892 action='M'),
3893 MockAffectedFile(
3894 'part.grdp',
3895 self.OLD_GRDP_CONTENTS, # new_contents
3896 self.NEW_GRDP_CONTENTS2, # old_contents
3897 action='M'),
3898 # Unmodified files:
3899 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3900 self.VALID_SHA1, ''),
3901 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3902 self.VALID_SHA1, ''),
3903 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3904 self.VALID_SHA1, ''),
3905 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3906 self.VALID_SHA1, '')
3907 ])
3908 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3909 self.assertEqual(1, len(warnings))
3910 self.assertEqual('error', warnings[0].type)
3911 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
3912 self.assertEqual([
3913 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303914 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013915 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533916 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3917 ], warnings[0].items)
3918
3919 # Same as above, but this time one of the .sha1 files is also removed.
3920 input_api = self.makeInputApi([
3921 # Modified files:
3922 MockAffectedFile(
3923 'test.grd',
3924 self.OLD_GRD_CONTENTS, # new_contents
3925 self.NEW_GRD_CONTENTS2, # old_contents
3926 action='M'),
3927 MockAffectedFile(
3928 'part.grdp',
3929 self.OLD_GRDP_CONTENTS, # new_contents
3930 self.NEW_GRDP_CONTENTS2, # old_contents
3931 action='M'),
3932 # Unmodified files:
3933 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3934 self.VALID_SHA1, ''),
3935 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3936 self.VALID_SHA1, ''),
3937 # Deleted files:
3938 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3939 '',
3940 'old_contents',
3941 action='D'),
3942 MockAffectedFile(os.path.join('part_grdp',
3943 'IDS_PART_TEST2.png.sha1'),
3944 '',
3945 'old_contents',
3946 action='D')
3947 ])
3948 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3949 self.assertEqual(1, len(warnings))
3950 self.assertEqual('error', warnings[0].type)
3951 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
3952 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583953 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533954 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3955 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143956
Daniel Cheng566634ff2024-06-29 14:56:533957 # Remove all sha1 files. There should be no warnings.
3958 input_api = self.makeInputApi([
3959 # Modified files:
3960 MockAffectedFile('test.grd',
3961 self.OLD_GRD_CONTENTS,
3962 self.NEW_GRD_CONTENTS2,
3963 action='M'),
3964 MockAffectedFile('part.grdp',
3965 self.OLD_GRDP_CONTENTS,
3966 self.NEW_GRDP_CONTENTS2,
3967 action='M'),
3968 # Deleted files:
3969 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3970 self.VALID_SHA1,
3971 action='D'),
3972 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3973 self.VALID_SHA1,
3974 action='D'),
3975 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3976 self.VALID_SHA1,
3977 action='D'),
3978 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3979 self.VALID_SHA1,
3980 action='D')
3981 ])
3982 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3983 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:263984
Daniel Cheng566634ff2024-06-29 14:56:533985 def testIcuSyntax(self):
3986 # Add valid ICU syntax string. Should not raise an error.
3987 input_api = self.makeInputApi([
3988 MockAffectedFile('test.grd',
3989 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
3990 self.NEW_GRD_CONTENTS1,
3991 action='M'),
3992 MockAffectedFile('part.grdp',
3993 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
3994 self.NEW_GRDP_CONTENTS1,
3995 action='M')
3996 ])
3997 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3998 # We expect no ICU syntax errors.
3999 icu_errors = [
4000 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4001 ]
4002 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264003
Daniel Cheng566634ff2024-06-29 14:56:534004 # Valid changes in ICU syntax. Should not raise an error.
4005 input_api = self.makeInputApi([
4006 MockAffectedFile('test.grd',
4007 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4008 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4009 action='M'),
4010 MockAffectedFile('part.grdp',
4011 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4012 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4013 action='M')
4014 ])
4015 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4016 # We expect no ICU syntax errors.
4017 icu_errors = [
4018 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4019 ]
4020 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324021
Daniel Cheng566634ff2024-06-29 14:56:534022 # Valid changes in ICU syntax. Should not raise an error.
4023 input_api = self.makeInputApi([
4024 MockAffectedFile('test.grd',
4025 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4026 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4027 action='M'),
4028 MockAffectedFile('part.grdp',
4029 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4030 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4031 action='M')
4032 ])
4033 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4034 # We expect no ICU syntax errors.
4035 icu_errors = [
4036 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4037 ]
4038 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264039
Daniel Cheng566634ff2024-06-29 14:56:534040 # Add invalid ICU syntax strings. Should raise two errors.
4041 input_api = self.makeInputApi([
4042 MockAffectedFile('test.grd',
4043 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4044 self.NEW_GRD_CONTENTS1,
4045 action='M'),
4046 MockAffectedFile('part.grdp',
4047 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4048 self.NEW_GRD_CONTENTS1,
4049 action='M')
4050 ])
4051 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4052 # We expect 2 ICU syntax errors.
4053 icu_errors = [
4054 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4055 ]
4056 self.assertEqual(1, len(icu_errors))
4057 self.assertEqual([
4058 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4059 'ICU syntax.',
4060 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4061 ], icu_errors[0].items)
4062
4063 # Change two strings to have ICU syntax errors. Should raise two errors.
4064 input_api = self.makeInputApi([
4065 MockAffectedFile('test.grd',
4066 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4067 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4068 action='M'),
4069 MockAffectedFile('part.grdp',
4070 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4071 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4072 action='M')
4073 ])
4074 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4075 # We expect 2 ICU syntax errors.
4076 icu_errors = [
4077 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4078 ]
4079 self.assertEqual(1, len(icu_errors))
4080 self.assertEqual([
4081 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4082 'ICU syntax.',
4083 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4084 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264085
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144086
Mustafa Emre Acer51f2f742020-03-09 19:41:124087class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534088 ERROR_MESSAGE_FORMAT = (
4089 "Failed to get a list of translatable grd files. "
4090 "This happens when:\n"
4091 " - One of the modified grd or grdp files cannot be parsed or\n"
4092 " - %s is not updated.\n"
4093 "Stack:\n")
4094 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4095 # This lists all .grd files under REPO_ROOT.
4096 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4097 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4098 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4099 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124100
Daniel Cheng566634ff2024-06-29 14:56:534101 # Tests that the presubmit doesn't return when no grd or grdp files are
4102 # modified.
4103 def testExpectationsNoModifiedGrd(self):
4104 input_api = MockInputApi()
4105 input_api.files = [
4106 MockAffectedFile('not_used.txt',
4107 'not used',
4108 'not used',
4109 action='M')
4110 ]
4111 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4112 # under tools/translation/testdata. This is OK because the presubmit won't
4113 # run in the first place since there are no modified grd/grps in input_api.
4114 grd_files = ['doesnt_exist_doesnt_matter.grd']
4115 warnings = PRESUBMIT.CheckTranslationExpectations(
4116 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4117 grd_files)
4118 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124119
Daniel Cheng566634ff2024-06-29 14:56:534120 # Tests that the list of files passed to the presubmit matches the list of
4121 # files in the expectations.
4122 def testExpectationsSuccess(self):
4123 # Mock input file list needs a grd or grdp file in order to run the
4124 # presubmit. The file itself doesn't matter.
4125 input_api = MockInputApi()
4126 input_api.files = [
4127 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4128 ]
4129 # List of all grd files in the repo.
4130 grd_files = [
4131 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4132 ]
4133 warnings = PRESUBMIT.CheckTranslationExpectations(
4134 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4135 grd_files)
4136 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124137
Daniel Cheng566634ff2024-06-29 14:56:534138 # Tests that the presubmit warns when a file is listed in expectations, but
4139 # does not actually exist.
4140 def testExpectationsMissingFile(self):
4141 # Mock input file list needs a grd or grdp file in order to run the
4142 # presubmit.
4143 input_api = MockInputApi()
4144 input_api.files = [
4145 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4146 ]
4147 # unlisted.grd is listed under tools/translation/testdata but is not
4148 # included in translation expectations.
4149 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4150 warnings = PRESUBMIT.CheckTranslationExpectations(
4151 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4152 grd_files)
4153 self.assertEqual(1, len(warnings))
4154 self.assertTrue(warnings[0].message.startswith(
4155 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4156 self.assertTrue(
4157 ("test.grd is listed in the translation expectations, "
4158 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124159
Daniel Cheng566634ff2024-06-29 14:56:534160 # Tests that the presubmit warns when a file is not listed in expectations but
4161 # does actually exist.
4162 def testExpectationsUnlistedFile(self):
4163 # Mock input file list needs a grd or grdp file in order to run the
4164 # presubmit.
4165 input_api = MockInputApi()
4166 input_api.files = [
4167 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4168 ]
4169 # unlisted.grd is listed under tools/translation/testdata but is not
4170 # included in translation expectations.
4171 grd_files = [
4172 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4173 ]
4174 warnings = PRESUBMIT.CheckTranslationExpectations(
4175 input_api, MockOutputApi(), self.REPO_ROOT,
4176 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4177 self.assertEqual(1, len(warnings))
4178 self.assertTrue(warnings[0].message.startswith(
4179 self.ERROR_MESSAGE_FORMAT %
4180 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4181 self.assertTrue(("unlisted.grd appears to be translatable "
4182 "(because it contains <file> or <message> elements), "
4183 "but is not listed in the translation expectations."
4184 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124185
Daniel Cheng566634ff2024-06-29 14:56:534186 # Tests that the presubmit warns twice:
4187 # - for a non-existing file listed in expectations
4188 # - for an existing file not listed in expectations
4189 def testMultipleWarnings(self):
4190 # Mock input file list needs a grd or grdp file in order to run the
4191 # presubmit.
4192 input_api = MockInputApi()
4193 input_api.files = [
4194 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4195 ]
4196 # unlisted.grd is listed under tools/translation/testdata but is not
4197 # included in translation expectations.
4198 # test.grd is not listed under tools/translation/testdata but is included
4199 # in translation expectations.
4200 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4201 warnings = PRESUBMIT.CheckTranslationExpectations(
4202 input_api, MockOutputApi(), self.REPO_ROOT,
4203 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4204 self.assertEqual(1, len(warnings))
4205 self.assertTrue(warnings[0].message.startswith(
4206 self.ERROR_MESSAGE_FORMAT %
4207 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4208 self.assertTrue(("unlisted.grd appears to be translatable "
4209 "(because it contains <file> or <message> elements), "
4210 "but is not listed in the translation expectations."
4211 ) in warnings[0].message)
4212 self.assertTrue(
4213 ("test.grd is listed in the translation expectations, "
4214 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124215
4216
Dominic Battre033531052018-09-24 15:45:344217class DISABLETypoInTest(unittest.TestCase):
4218
Daniel Cheng566634ff2024-06-29 14:56:534219 def testPositive(self):
4220 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4221 # where the desire is to disable a test.
4222 tests = [
4223 # Disabled on one platform:
4224 '#if defined(OS_WIN)\n'
4225 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4226 '#else\n'
4227 '#define MAYBE_FoobarTest FoobarTest\n'
4228 '#endif\n',
4229 # Disabled on one platform spread cross lines:
4230 '#if defined(OS_WIN)\n'
4231 '#define MAYBE_FoobarTest \\\n'
4232 ' DISABLE_FoobarTest\n'
4233 '#else\n'
4234 '#define MAYBE_FoobarTest FoobarTest\n'
4235 '#endif\n',
4236 # Disabled on all platforms:
4237 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4238 # Disabled on all platforms but multiple lines
4239 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4240 ]
Dominic Battre033531052018-09-24 15:45:344241
Daniel Cheng566634ff2024-06-29 14:56:534242 for test in tests:
4243 mock_input_api = MockInputApi()
4244 mock_input_api.files = [
4245 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4246 ]
Dominic Battre033531052018-09-24 15:45:344247
Daniel Cheng566634ff2024-06-29 14:56:534248 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4249 mock_input_api, MockOutputApi())
4250 self.assertEqual(
4251 1,
4252 len(results),
4253 msg=('expected len(results) == 1 but got %d in test: %s' %
4254 (len(results), test)))
4255 self.assertTrue(
4256 'foo_unittest.cc' in results[0].message,
4257 msg=(
4258 'expected foo_unittest.cc in message but got %s in test %s'
4259 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344260
Daniel Cheng566634ff2024-06-29 14:56:534261 def testIgnoreNotTestFiles(self):
4262 mock_input_api = MockInputApi()
4263 mock_input_api.files = [
4264 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4265 ]
Dominic Battre033531052018-09-24 15:45:344266
Daniel Cheng566634ff2024-06-29 14:56:534267 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4268 MockOutputApi())
4269 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344270
Daniel Cheng566634ff2024-06-29 14:56:534271 def testIgnoreDeletedFiles(self):
4272 mock_input_api = MockInputApi()
4273 mock_input_api.files = [
4274 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4275 action='D'),
4276 ]
Katie Df13948e2018-09-25 07:33:444277
Daniel Cheng566634ff2024-06-29 14:56:534278 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4279 MockOutputApi())
4280 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344281
Nina Satragnof7660532021-09-20 18:03:354282class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354283
Daniel Cheng566634ff2024-06-29 14:56:534284 def testPositive(self):
4285 test = ('#if defined(HAS_ENERGY)\n'
4286 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4287 '#else\n'
4288 '#define MAYBE_CastExplosion CastExplosion\n'
4289 '#endif\n'
4290 'TEST_F(ArchWizard, CastExplosion) {\n'
4291 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4292 '#define MAYBE_ArchPriest ArchPriest\n'
4293 '#else\n'
4294 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4295 '#endif\n'
4296 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4297 '#if !defined(CRUSADER_IN_PARTY)\n'
4298 '#define MAYBE_Crusader \\\n'
4299 ' DISABLED_Crusader \n'
4300 '#else\n'
4301 '#define MAYBE_Crusader \\\n'
4302 ' Crusader\n'
4303 '#endif\n'
4304 ' TEST_F(\n'
4305 ' Crusader,\n'
4306 ' CastTaunt) { }\n'
4307 '#if defined(LEARNED_BASIC_SKILLS)\n'
4308 '#define MAYBE_CastSteal \\\n'
4309 ' DISABLED_CastSteal \n'
4310 '#else\n'
4311 '#define MAYBE_CastSteal \\\n'
4312 ' CastSteal\n'
4313 '#endif\n'
4314 ' TEST_F(\n'
4315 ' ThiefClass,\n'
4316 ' CastSteal) { }\n')
4317 mock_input_api = MockInputApi()
4318 mock_input_api.files = [
4319 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4320 ]
4321 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4322 mock_input_api, MockOutputApi())
4323 self.assertEqual(4, len(results))
4324 self.assertTrue('CastExplosion' in results[0].message)
4325 self.assertTrue(
4326 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4327 self.assertTrue('ArchPriest' in results[1].message)
4328 self.assertTrue(
4329 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4330 self.assertTrue('Crusader' in results[2].message)
4331 self.assertTrue(
4332 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4333 self.assertTrue('CastSteal' in results[3].message)
4334 self.assertTrue(
4335 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354336
Daniel Cheng566634ff2024-06-29 14:56:534337 def testNegative(self):
4338 test = ('#if defined(HAS_ENERGY)\n'
4339 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4340 '#else\n'
4341 '#define MAYBE_CastExplosion CastExplosion\n'
4342 '#endif\n'
4343 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4344 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4345 '#define MAYBE_ArchPriest ArchPriest\n'
4346 '#else\n'
4347 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4348 '#endif\n'
4349 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4350 '#if !defined(CRUSADER_IN_PARTY)\n'
4351 '#define MAYBE_Crusader \\\n'
4352 ' DISABLED_Crusader \n'
4353 '#else\n'
4354 '#define MAYBE_Crusader \\\n'
4355 ' Crusader\n'
4356 '#endif\n'
4357 ' TEST_F(\n'
4358 ' MAYBE_Crusader,\n'
4359 ' CastTaunt) { }\n'
4360 '#if defined(LEARNED_BASIC_SKILLS)\n'
4361 '#define MAYBE_CastSteal \\\n'
4362 ' DISABLED_CastSteal \n'
4363 '#else\n'
4364 '#define MAYBE_CastSteal \\\n'
4365 ' CastSteal\n'
4366 '#endif\n'
4367 ' TEST_F(\n'
4368 ' ThiefClass,\n'
4369 ' MAYBE_CastSteal) { }\n')
4370
4371 mock_input_api = MockInputApi()
4372 mock_input_api.files = [
4373 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4374 ]
4375 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4376 mock_input_api, MockOutputApi())
4377 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514378
Max Morozb47503b2019-08-08 21:03:274379class CheckFuzzTargetsTest(unittest.TestCase):
4380
Daniel Cheng566634ff2024-06-29 14:56:534381 def _check(self, files):
4382 mock_input_api = MockInputApi()
4383 mock_input_api.files = []
4384 for fname, contents in files.items():
4385 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4386 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4387 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274388
Daniel Cheng566634ff2024-06-29 14:56:534389 def testLibFuzzerSourcesIgnored(self):
4390 results = self._check({
4391 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4392 "LLVMFuzzerInitialize",
4393 })
4394 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274395
Daniel Cheng566634ff2024-06-29 14:56:534396 def testNonCodeFilesIgnored(self):
4397 results = self._check({
4398 "README.md": "LLVMFuzzerInitialize",
4399 })
4400 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274401
Daniel Cheng566634ff2024-06-29 14:56:534402 def testNoErrorHeaderPresent(self):
4403 results = self._check({
4404 "fuzzer.cc":
4405 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4406 "LLVMFuzzerInitialize")
4407 })
4408 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274409
Daniel Cheng566634ff2024-06-29 14:56:534410 def testErrorMissingHeader(self):
4411 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4412 self.assertEqual(len(results), 1)
4413 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274414
4415
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264416class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404417
Daniel Cheng566634ff2024-06-29 14:56:534418 def testSetNoParentTopLevelAllowed(self):
4419 mock_input_api = MockInputApi()
4420 mock_input_api.files = [
4421 MockAffectedFile('goat/OWNERS', [
4422 'set noparent',
4423 '[email protected]',
4424 ])
4425 ]
4426 mock_output_api = MockOutputApi()
4427 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4428 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264429
Daniel Cheng566634ff2024-06-29 14:56:534430 def testSetNoParentMissing(self):
4431 mock_input_api = MockInputApi()
4432 mock_input_api.files = [
4433 MockAffectedFile('services/goat/OWNERS', [
4434 'set noparent',
4435 '[email protected]',
4436 'per-file *.json=set noparent',
4437 'per-file *[email protected]',
4438 ])
4439 ]
4440 mock_output_api = MockOutputApi()
4441 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4442 self.assertEqual(1, len(errors))
4443 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4444 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4445
4446 def testSetNoParentWithCorrectRule(self):
4447 mock_input_api = MockInputApi()
4448 mock_input_api.files = [
4449 MockAffectedFile('services/goat/OWNERS', [
4450 'set noparent',
4451 'file://ipc/SECURITY_OWNERS',
4452 'per-file *.json=set noparent',
4453 'per-file *.json=file://ipc/SECURITY_OWNERS',
4454 ])
4455 ]
4456 mock_output_api = MockOutputApi()
4457 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4458 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264459
4460
Ken Rockotc31f4832020-05-29 18:58:514461class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514462
Daniel Cheng566634ff2024-06-29 14:56:534463 def runTestWithAffectedFiles(self, affected_files):
4464 mock_input_api = MockInputApi()
4465 mock_input_api.files = affected_files
4466 mock_output_api = MockOutputApi()
4467 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4468 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514469
Daniel Cheng566634ff2024-06-29 14:56:534470 def testSafeChangePasses(self):
4471 errors = self.runTestWithAffectedFiles([
4472 MockAffectedFile(
4473 'foo/foo.mojom',
4474 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4475 old_contents=['[Stable] struct S {};'])
4476 ])
4477 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514478
Daniel Cheng566634ff2024-06-29 14:56:534479 def testBadChangeFails(self):
4480 errors = self.runTestWithAffectedFiles([
4481 MockAffectedFile('foo/foo.mojom',
4482 ['[Stable] struct S { int32 x; };'],
4483 old_contents=['[Stable] struct S {};'])
4484 ])
4485 self.assertEqual(1, len(errors))
4486 self.assertTrue('not backward-compatible' in errors[0].message)
4487
4488 def testDeletedFile(self):
4489 """Regression test for https://crbug.com/1091407."""
4490 errors = self.runTestWithAffectedFiles([
4491 MockAffectedFile('a.mojom', [],
4492 old_contents=['struct S {};'],
4493 action='D'),
4494 MockAffectedFile(
4495 'b.mojom', ['struct S {}; struct T { S s; };'],
4496 old_contents=['import "a.mojom"; struct T { S s; };'])
4497 ])
4498 self.assertEqual([], errors)
4499
Ken Rockotad7901f942020-06-04 20:17:094500
Jose Magana2b456f22021-03-09 23:26:404501class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4502
Daniel Cheng566634ff2024-06-29 14:56:534503 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404504
Daniel Cheng566634ff2024-06-29 14:56:534505 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404506
Daniel Cheng566634ff2024-06-29 14:56:534507 def testWarningNMF(self):
4508 mock_input_api = MockInputApi()
4509 mock_input_api.files = [
4510 MockAffectedFile(
4511 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4512 ['"program"', 'B'],
4513 scm_diff='\n'.join([
4514 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4515 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4516 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4517 ]),
4518 action='M')
4519 ]
4520 mock_output_api = MockOutputApi()
4521 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4522 mock_input_api, mock_output_api)
4523 self.assertEqual(1, len(errors))
4524 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4525 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404526
Daniel Cheng566634ff2024-06-29 14:56:534527 def testWarningManifest(self):
4528 mock_input_api = MockInputApi()
4529 mock_input_api.files = [
4530 MockAffectedFile(
4531 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4532 ['"app":"', 'B'],
4533 scm_diff='\n'.join([
4534 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4535 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4536 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4537 ]),
4538 action='M')
4539 ]
4540 mock_output_api = MockOutputApi()
4541 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4542 mock_input_api, mock_output_api)
4543 self.assertEqual(1, len(errors))
4544 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4545 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404546
Daniel Cheng566634ff2024-06-29 14:56:534547 def testOKWarningManifestWithoutApp(self):
4548 mock_input_api = MockInputApi()
4549 mock_input_api.files = [
4550 MockAffectedFile(
4551 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4552 ['"name":"', 'B'],
4553 scm_diff='\n'.join([
4554 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4555 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4556 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4557 ]),
4558 action='M')
4559 ]
4560 mock_output_api = MockOutputApi()
4561 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4562 mock_input_api, mock_output_api)
4563 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404564
Daniel Cheng566634ff2024-06-29 14:56:534565 def testWarningPPAPI(self):
4566 mock_input_api = MockInputApi()
4567 mock_input_api.files = [
4568 MockAffectedFile(
4569 'foo.hpp', ['A', '#include <ppapi.h>', 'B'], ['A', 'B'],
4570 scm_diff='\n'.join([
4571 '--- foo.hpp.old 2020-12-02 20:40:54.430676385 +0100',
4572 '+++ foo.hpp.new 2020-12-02 20:41:02.086700197 +0100',
4573 '@@ -1,2 +1,3 @@', ' A', '+#include <ppapi.h>', ' B'
4574 ]),
4575 action='M')
4576 ]
4577 mock_output_api = MockOutputApi()
4578 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4579 mock_input_api, mock_output_api)
4580 self.assertEqual(1, len(errors))
4581 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4582 self.assertTrue('foo.hpp' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404583
Daniel Cheng566634ff2024-06-29 14:56:534584 def testNoWarningPPAPI(self):
4585 mock_input_api = MockInputApi()
4586 mock_input_api.files = [
4587 MockAffectedFile(
4588 'foo.txt', ['A', 'Peppapig', 'B'], ['A', 'B'],
4589 scm_diff='\n'.join([
4590 '--- foo.txt.old 2020-12-02 20:40:54.430676385 +0100',
4591 '+++ foo.txt.new 2020-12-02 20:41:02.086700197 +0100',
4592 '@@ -1,2 +1,3 @@', ' A', '+Peppapig', ' B'
4593 ]),
4594 action='M')
4595 ]
4596 mock_output_api = MockOutputApi()
4597 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4598 mock_input_api, mock_output_api)
4599 self.assertEqual(0, len(errors))
4600
Jose Magana2b456f22021-03-09 23:26:404601
Dominic Battre645d42342020-12-04 16:14:104602class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534603 # Test that a warning is generated if a preference registration is removed
4604 # from a random file.
4605 def testWarning(self):
4606 mock_input_api = MockInputApi()
4607 mock_input_api.files = [
4608 MockAffectedFile(
4609 'foo.cc', ['A', 'B'],
4610 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4611 scm_diff='\n'.join([
4612 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4613 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4614 '@@ -1,3 +1,2 @@', ' A',
4615 '-prefs->RegisterStringPref("foo", "default");', ' B'
4616 ]),
4617 action='M')
4618 ]
4619 mock_output_api = MockOutputApi()
4620 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4621 mock_input_api, mock_output_api)
4622 self.assertEqual(1, len(errors))
4623 self.assertTrue(
4624 'Discovered possible removal of preference registrations' in
4625 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104626
Daniel Cheng566634ff2024-06-29 14:56:534627 # Test that a warning is inhibited if the preference registration was moved
4628 # to the deprecation functions in browser prefs.
4629 def testNoWarningForMigration(self):
4630 mock_input_api = MockInputApi()
4631 mock_input_api.files = [
4632 # RegisterStringPref was removed from foo.cc.
4633 MockAffectedFile(
4634 'foo.cc', ['A', 'B'],
4635 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4636 scm_diff='\n'.join([
4637 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4638 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4639 '@@ -1,3 +1,2 @@', ' A',
4640 '-prefs->RegisterStringPref("foo", "default");', ' B'
4641 ]),
4642 action='M'),
4643 # But the preference was properly migrated.
4644 MockAffectedFile(
4645 'chrome/browser/prefs/browser_prefs.cc', [
4646 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4647 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4648 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4649 'prefs->RegisterStringPref("foo", "default");',
4650 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4651 ], [
4652 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4653 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4654 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4655 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4656 ],
4657 scm_diff='\n'.join([
4658 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4659 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4660 '@@ -2,3 +2,4 @@',
4661 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4662 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4663 '+prefs->RegisterStringPref("foo", "default");',
4664 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4665 ]),
4666 action='M'),
4667 ]
4668 mock_output_api = MockOutputApi()
4669 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4670 mock_input_api, mock_output_api)
4671 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104672
Daniel Cheng566634ff2024-06-29 14:56:534673 # Test that a warning is NOT inhibited if the preference registration was
4674 # moved to a place outside of the migration functions in browser_prefs.cc
4675 def testWarningForImproperMigration(self):
4676 mock_input_api = MockInputApi()
4677 mock_input_api.files = [
4678 # RegisterStringPref was removed from foo.cc.
4679 MockAffectedFile(
4680 'foo.cc', ['A', 'B'],
4681 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4682 scm_diff='\n'.join([
4683 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4684 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4685 '@@ -1,3 +1,2 @@', ' A',
4686 '-prefs->RegisterStringPref("foo", "default");', ' B'
4687 ]),
4688 action='M'),
4689 # The registration call was moved to a place in browser_prefs.cc that
4690 # is outside the migration functions.
4691 MockAffectedFile(
4692 'chrome/browser/prefs/browser_prefs.cc', [
4693 'prefs->RegisterStringPref("foo", "default");',
4694 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4695 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4696 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4697 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4698 ], [
4699 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4700 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4701 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4702 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4703 ],
4704 scm_diff='\n'.join([
4705 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4706 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4707 '@@ -1,2 +1,3 @@',
4708 '+prefs->RegisterStringPref("foo", "default");',
4709 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4710 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4711 ]),
4712 action='M'),
4713 ]
4714 mock_output_api = MockOutputApi()
4715 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4716 mock_input_api, mock_output_api)
4717 self.assertEqual(1, len(errors))
4718 self.assertTrue(
4719 'Discovered possible removal of preference registrations' in
4720 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104721
Daniel Cheng566634ff2024-06-29 14:56:534722 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4723 # deleted.
4724 def testDeletedMarkerRaisesError(self):
4725 mock_input_api = MockInputApi()
4726 mock_input_api.files = [
4727 MockAffectedFile(
4728 'chrome/browser/prefs/browser_prefs.cc',
4729 [
4730 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4731 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4732 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4733 # The following line is deleted for this test
4734 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4735 ])
4736 ]
4737 mock_output_api = MockOutputApi()
4738 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4739 mock_input_api, mock_output_api)
4740 self.assertEqual(1, len(errors))
4741 self.assertEqual(
4742 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4743 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104744
Sven Zheng76a79ea2022-12-21 21:25:244745class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4746 def testWarning(self):
4747 mock_input_api = MockInputApi()
4748 mock_output_api = MockOutputApi()
4749 mock_input_api.files = [
4750 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4751 ]
4752 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4753 self.assertEqual(1, len(result))
4754 self.assertEqual(result[0].type, 'warning')
4755
4756 def testNoWarningWithBrowserTest(self):
4757 mock_input_api = MockInputApi()
4758 mock_output_api = MockOutputApi()
4759 mock_input_api.files = [
4760 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4761 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4762 ]
4763 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4764 self.assertEqual(0, len(result))
4765
4766 def testNoWarningModifyCrosapi(self):
4767 mock_input_api = MockInputApi()
4768 mock_output_api = MockOutputApi()
4769 mock_input_api.files = [
4770 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4771 ]
4772 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4773 self.assertEqual(0, len(result))
4774
4775 def testNoWarningAddNonMojomFile(self):
4776 mock_input_api = MockInputApi()
4777 mock_output_api = MockOutputApi()
4778 mock_input_api.files = [
4779 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4780 ]
4781 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4782 self.assertEqual(0, len(result))
4783
4784 def testNoWarningNoneRelatedMojom(self):
4785 mock_input_api = MockInputApi()
4786 mock_output_api = MockOutputApi()
4787 mock_input_api.files = [
4788 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4789 ]
4790 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4791 self.assertEqual(0, len(result))
4792
4793
Henrique Ferreiro2a4b55942021-11-29 23:45:364794class AssertAshOnlyCodeTest(unittest.TestCase):
4795 def testErrorsOnlyOnAshDirectories(self):
4796 files_in_ash = [
4797 MockFile('ash/BUILD.gn', []),
4798 MockFile('chrome/browser/ash/BUILD.gn', []),
4799 ]
4800 other_files = [
4801 MockFile('chrome/browser/BUILD.gn', []),
Georg Neis94f87f02024-10-22 08:20:134802 MockFile('chrome/browser/foo/BUILD.gn', ['assert(is_chromeos_ash)']),
Henrique Ferreiro2a4b55942021-11-29 23:45:364803 ]
4804 input_api = MockInputApi()
4805 input_api.files = files_in_ash
4806 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4807 self.assertEqual(2, len(errors))
4808
4809 input_api.files = other_files
4810 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4811 self.assertEqual(0, len(errors))
4812
4813 def testDoesNotErrorOnNonGNFiles(self):
4814 input_api = MockInputApi()
4815 input_api.files = [
4816 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4817 MockFile('chrome/browser/ash/test.cc',
4818 ['assert(is_chromeos_ash)']),
4819 ]
4820 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4821 self.assertEqual(0, len(errors))
4822
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214823 def testDeletedFile(self):
4824 input_api = MockInputApi()
4825 input_api.files = [
4826 MockFile('ash/BUILD.gn', []),
4827 MockFile('ash/foo/BUILD.gn', [], action='D'),
4828 ]
4829 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4830 self.assertEqual(1, len(errors))
4831
Henrique Ferreiro2a4b55942021-11-29 23:45:364832 def testDoesNotErrorWithAssertion(self):
4833 input_api = MockInputApi()
4834 input_api.files = [
4835 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4836 MockFile('chrome/browser/ash/BUILD.gn',
4837 ['assert(is_chromeos_ash)']),
Georg Neis94f87f02024-10-22 08:20:134838 MockFile('chrome/browser/ash/1/BUILD.gn',
4839 ['assert(is_chromeos)']),
4840 MockFile('chrome/browser/ash/2/BUILD.gn',
4841 ['assert(is_chromeos_ash)']),
4842 MockFile('chrome/browser/ash/3/BUILD.gn',
4843 ['assert(is_chromeos, "test")']),
4844 MockFile('chrome/browser/ash/4/BUILD.gn',
Henrique Ferreiro2a4b55942021-11-29 23:45:364845 ['assert(is_chromeos_ash, "test")']),
4846 ]
4847 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4848 self.assertEqual(0, len(errors))
4849
4850
Lukasz Anforowicz7016d05e2021-11-30 03:56:274851class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274852
Daniel Cheng566634ff2024-06-29 14:56:534853 def testAllowedCases(self):
4854 mock_input_api = MockInputApi()
4855 mock_input_api.files = [
4856 # Browser-side files are allowed.
4857 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4858 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4859 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4860 MockAffectedFile('test13/blink/public/common/foo.cc',
4861 ['raw_ptr<int>']),
4862 MockAffectedFile('test14/blink/public/platform/foo.cc',
4863 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274864
Daniel Cheng566634ff2024-06-29 14:56:534865 # Non-C++ files are allowed.
4866 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274867
Daniel Cheng566634ff2024-06-29 14:56:534868 # Renderer code is generally allowed (except specifically
4869 # disallowed directories).
4870 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
4871 ]
4872 mock_output_api = MockOutputApi()
4873 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4874 self.assertFalse(errors)
4875
4876 def testDisallowedCases(self):
4877 mock_input_api = MockInputApi()
4878 mock_input_api.files = [
4879 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
4880 ['raw_ptr<int>']),
4881 MockAffectedFile(
4882 'test2/third_party/blink/renderer/platform/heap/foo.cc',
4883 ['raw_ptr<int>']),
4884 MockAffectedFile(
4885 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
4886 ['raw_ptr<int>']),
4887 MockAffectedFile(
4888 'test4/third_party/blink/renderer/platform/fonts/foo.h',
4889 ['raw_ptr<int>']),
4890 MockAffectedFile(
4891 'test5/third_party/blink/renderer/core/paint/foo.cc',
4892 ['raw_ptr<int>']),
4893 MockAffectedFile(
4894 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
4895 ['raw_ptr<int>']),
4896 MockAffectedFile(
4897 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
4898 ['raw_ptr<int>']),
4899 ]
4900 mock_output_api = MockOutputApi()
4901 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4902 self.assertEqual(len(mock_input_api.files), len(errors))
4903 for error in errors:
4904 self.assertTrue(
4905 'raw_ptr<T> should not be used in this renderer code' in
4906 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:274907
mikt9337567c2023-09-08 18:38:174908class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:174909
Daniel Cheng566634ff2024-06-29 14:56:534910 def testAllowedCases(self):
4911 mock_input_api = MockInputApi()
4912 mock_input_api.files = [
4913 # Non-C++ files are allowed.
4914 MockAffectedFile('test20/renderer/foo.md',
4915 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:174916
Daniel Cheng566634ff2024-06-29 14:56:534917 # Mentions in a comment are allowed.
4918 MockAffectedFile('test30/renderer/foo.cc',
4919 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
4920 ]
4921 mock_output_api = MockOutputApi()
4922 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
4923 mock_input_api, mock_output_api)
4924 self.assertFalse(errors)
4925
4926 def testDisallowedCases(self):
4927 mock_input_api = MockInputApi()
4928 mock_input_api.files = [
4929 MockAffectedFile('test1/foo.h',
4930 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
4931 MockAffectedFile('test2/foo.cc',
4932 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
4933 ]
4934 mock_output_api = MockOutputApi()
4935 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
4936 mock_input_api, mock_output_api)
4937 self.assertEqual(1, len(errors))
4938 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
4939 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:274940
Henrique Ferreirof9819f2e32021-11-30 13:31:564941class AssertPythonShebangTest(unittest.TestCase):
4942 def testError(self):
4943 input_api = MockInputApi()
4944 input_api.files = [
4945 MockFile('ash/test.py', ['#!/usr/bin/python']),
4946 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
4947 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:274948 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:564949 ]
4950 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
4951 self.assertEqual(3, len(errors))
4952
4953 def testNonError(self):
4954 input_api = MockInputApi()
4955 input_api.files = [
4956 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
4957 MockFile('third_party/blink/web_tests/external/test.py',
4958 ['#!/usr/bin/python2']),
4959 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
4960 ]
4961 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
4962 self.assertEqual(0, len(errors))
4963
Kalvin Lee4a3b79de2022-05-26 16:00:164964class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:164965
Daniel Cheng566634ff2024-06-29 14:56:534966 def testPermissibleUsage(self):
4967 input_api = MockInputApi()
4968 input_api.files = [
4969 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
4970 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:164971
Daniel Cheng566634ff2024-06-29 14:56:534972 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
4973 # own thing at their own risk.
4974 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
4975 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
4976 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
4977 ]
4978 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
4979 MockOutputApi())
4980 self.assertEqual(0, len(errors))
4981
4982 def testMissingParentheses(self):
4983 input_api = MockInputApi()
4984 input_api.files = [
4985 MockFile('bad1.cc', ['DCHECK_IS_ON']),
4986 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
4987 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
4988 ]
4989 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
4990 MockOutputApi())
4991 self.assertEqual(3, len(errors))
4992 for error in errors:
4993 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:564994
Sam Maier4cef9242022-10-03 14:21:244995
James Shen81cc0e22022-06-15 21:10:454996class CheckBatchAnnotation(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534997 """Test the CheckBatchAnnotation presubmit check."""
James Shen81cc0e22022-06-15 21:10:454998
Daniel Cheng566634ff2024-06-29 14:56:534999 def testTruePositives(self):
5000 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455001"""
Daniel Cheng566634ff2024-06-29 14:56:535002 mock_input = MockInputApi()
5003 mock_input.files = [
5004 MockFile('path/OneTest.java', ['public class OneTest']),
5005 MockFile('path/TwoTest.java', ['public class TwoTest']),
5006 MockFile('path/ThreeTest.java', [
5007 '@Batch(Batch.PER_CLASS)',
5008 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5009 'public class Three {'
5010 ]),
5011 MockFile('path/FourTest.java', [
5012 '@DoNotBatch(reason = "placeholder reason 1")',
5013 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5014 'public class Four {'
5015 ]),
5016 ]
5017 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
5018 self.assertEqual(2, len(errors))
5019 self.assertEqual(2, len(errors[0].items))
5020 self.assertIn('OneTest.java', errors[0].items[0])
5021 self.assertIn('TwoTest.java', errors[0].items[1])
5022 self.assertEqual(2, len(errors[1].items))
5023 self.assertIn('ThreeTest.java', errors[1].items[0])
5024 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385025
Daniel Cheng566634ff2024-06-29 14:56:535026 def testAnnotationsPresent(self):
5027 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5028 mock_input = MockInputApi()
5029 mock_input.files = [
5030 MockFile('path/OneTest.java',
5031 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5032 MockFile('path/TwoTest.java', [
5033 '@DoNotBatch(reason = "placeholder reasons.")',
5034 'public class Two {'
5035 ]),
5036 MockFile('path/ThreeTest.java', [
5037 '@Batch(Batch.PER_CLASS)',
5038 'public class Three extends BaseTestA {'
5039 ], [
5040 '@Batch(Batch.PER_CLASS)',
5041 'public class Three extends BaseTestB {'
5042 ]),
5043 MockFile('path/FourTest.java', [
5044 '@DoNotBatch(reason = "placeholder reason 1")',
5045 'public class Four extends BaseTestA {'
5046 ], [
5047 '@DoNotBatch(reason = "placeholder reason 2")',
5048 'public class Four extends BaseTestB {'
5049 ]),
5050 MockFile('path/FiveTest.java', [
5051 'import androidx.test.uiautomator.UiDevice;',
5052 'public class Five extends BaseTestA {'
5053 ], [
5054 'import androidx.test.uiautomator.UiDevice;',
5055 'public class Five extends BaseTestB {'
5056 ]),
5057 MockFile('path/SixTest.java', [
5058 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5059 'public class Six extends BaseTestA {'
5060 ], [
5061 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5062 'public class Six extends BaseTestB {'
5063 ]),
5064 MockFile('path/SevenTest.java', [
5065 'import org.robolectric.annotation.Config;',
5066 'public class Seven extends BaseTestA {'
5067 ], [
5068 'import org.robolectric.annotation.Config;',
5069 'public class Seven extends BaseTestB {'
5070 ]),
5071 MockFile(
5072 'path/OtherClass.java',
5073 ['public class OtherClass {'],
5074 ),
5075 MockFile('path/PRESUBMIT.py', [
5076 '@Batch(Batch.PER_CLASS)',
5077 '@DoNotBatch(reason = "placeholder reason)'
5078 ]),
5079 MockFile(
5080 'path/AnnotationTest.java',
5081 ['public @interface SomeAnnotation {'],
5082 ),
5083 ]
5084 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
5085 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455086
Sam Maier4cef9242022-10-03 14:21:245087
5088class CheckMockAnnotation(unittest.TestCase):
5089 """Test the CheckMockAnnotation presubmit check."""
5090
5091 def testTruePositives(self):
5092 """Examples of @Mock or @Spy being used and nothing should be flagged."""
5093 mock_input = MockInputApi()
5094 mock_input.files = [
5095 MockFile('path/OneTest.java', [
5096 'import a.b.c.Bar;',
5097 'import a.b.c.Foo;',
Sam Maierb8a66a02023-10-10 13:50:555098 '@Mock public static Foo f = new Foo();',
Sam Maier4cef9242022-10-03 14:21:245099 'Mockito.mock(new Bar(a, b, c))'
5100 ]),
5101 MockFile('path/TwoTest.java', [
5102 'package x.y.z;',
5103 'import static org.mockito.Mockito.spy;',
5104 '@Spy',
5105 'public static FooBar<Baz> f;',
5106 'a = spy(Baz.class)'
5107 ]),
5108 ]
5109 errors = PRESUBMIT.CheckMockAnnotation(mock_input, MockOutputApi())
5110 self.assertEqual(1, len(errors))
5111 self.assertEqual(2, len(errors[0].items))
5112 self.assertIn('a.b.c.Bar in path/OneTest.java', errors[0].items)
5113 self.assertIn('x.y.z.Baz in path/TwoTest.java', errors[0].items)
5114
5115 def testTrueNegatives(self):
5116 """Examples of when we should not be flagging mock() or spy() calls."""
5117 mock_input = MockInputApi()
5118 mock_input.files = [
5119 MockFile('path/OneTest.java', [
5120 'package a.b.c;',
5121 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5122 'Mockito.mock(Abc.class)'
5123 ]),
5124 MockFile('path/TwoTest.java', [
5125 'package a.b.c;',
5126 'import androidx.test.uiautomator.UiDevice;',
5127 'Mockito.spy(new Def())'
5128 ]),
5129 MockFile('path/ThreeTest.java', [
5130 'package a.b.c;',
5131 'import static org.mockito.Mockito.spy;',
5132 '@Spy',
5133 'public static Foo f = new Abc();',
5134 'a = spy(Foo.class)'
5135 ]),
5136 MockFile('path/FourTest.java', [
5137 'package a.b.c;',
5138 'import static org.mockito.Mockito.mock;',
5139 '@Spy',
5140 'public static Bar b = new Abc(a, b, c, d);',
5141 ' mock(new Bar(a,b,c))'
5142 ]),
5143 MockFile('path/FiveTest.java', [
5144 'package a.b.c;',
5145 '@Mock',
5146 'public static Baz<abc> b;',
Sam Maierb8a66a02023-10-10 13:50:555147 'Mockito.mock(Baz.class)'
5148 ]),
Sam Maier4cef9242022-10-03 14:21:245149 MockFile('path/SixTest.java', [
5150 'package a.b.c;',
5151 'import android.view.View;',
5152 'import java.ArrayList;',
5153 'Mockito.spy(new View())',
5154 'Mockito.mock(ArrayList.class)'
5155 ]),
Sam Maierb8a66a02023-10-10 13:50:555156 MockFile('path/SevenTest.java', [
5157 'package a.b.c;',
5158 '@Mock private static Seven s;',
5159 'Mockito.mock(Seven.class)'
5160 ]),
5161 MockFile('path/EightTest.java', [
5162 'package a.b.c;',
5163 '@Spy Eight e = new Eight2();',
5164 'Mockito.py(new Eight())'
5165 ]),
Sam Maier4cef9242022-10-03 14:21:245166 ]
5167 errors = PRESUBMIT.CheckMockAnnotation(mock_input, MockOutputApi())
5168 self.assertEqual(0, len(errors))
5169
5170
Mike Dougherty1b8be712022-10-20 00:15:135171class AssertNoJsInIosTest(unittest.TestCase):
5172 def testErrorJs(self):
5173 input_api = MockInputApi()
5174 input_api.files = [
5175 MockFile('components/feature/ios/resources/script.js', []),
5176 MockFile('ios/chrome/feature/resources/script.js', []),
5177 ]
5178 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5179 self.assertEqual(1, len(results))
5180 self.assertEqual('error', results[0].type)
5181 self.assertEqual(2, len(results[0].items))
5182
5183 def testNonError(self):
5184 input_api = MockInputApi()
5185 input_api.files = [
5186 MockFile('chrome/resources/script.js', []),
5187 MockFile('components/feature/ios/resources/script.ts', []),
5188 MockFile('ios/chrome/feature/resources/script.ts', []),
5189 MockFile('ios/web/feature/resources/script.ts', []),
5190 MockFile('ios/third_party/script.js', []),
5191 MockFile('third_party/ios/script.js', []),
5192 ]
5193 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5194 self.assertEqual(0, len(results))
5195
5196 def testExistingFilesWarningOnly(self):
5197 input_api = MockInputApi()
5198 input_api.files = [
5199 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5200 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5201 ]
5202 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5203 self.assertEqual(1, len(results))
5204 self.assertEqual('warning', results[0].type)
5205 self.assertEqual(1, len(results[0].items))
5206
Mike Dougherty4d1050b2023-03-14 15:59:535207 def testMovedScriptWarningOnly(self):
5208 input_api = MockInputApi()
5209 input_api.files = [
5210 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5211 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5212 ]
5213 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5214 self.assertEqual(1, len(results))
5215 self.assertEqual('warning', results[0].type)
5216 self.assertEqual(1, len(results[0].items))
5217
Yuanqing Zhu9eef02832022-12-04 14:42:175218class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175219
Daniel Cheng566634ff2024-06-29 14:56:535220 def testHasAbbreviation(self):
5221 """test png file names with abbreviation that fails the check"""
5222 input_api = MockInputApi()
5223 input_api.files = [
5224 MockFile('image_a.png', [], action='A'),
5225 MockFile('image_a_.png', [], action='A'),
5226 MockFile('image_a_name.png', [], action='A'),
5227 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5228 action='A'),
5229 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5230 action='A'),
5231 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5232 action='A'),
5233 ]
5234 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5235 input_api, MockOutputApi())
5236 self.assertEqual(1, len(results))
5237 self.assertEqual('error', results[0].type)
5238 self.assertEqual(len(input_api.files), len(results[0].items))
5239
5240 def testNoAbbreviation(self):
5241 """test png file names without abbreviation that passes the check"""
5242 input_api = MockInputApi()
5243 input_api.files = [
5244 MockFile('a.png', [], action='A'),
5245 MockFile('_a.png', [], action='A'),
5246 MockFile('image.png', [], action='A'),
5247 MockFile('image_ab_.png', [], action='A'),
5248 MockFile('image_ab_name.png', [], action='A'),
5249 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5250 # They should pass now because the path components ahead of the file name are ignored in the check.
5251 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5252 action='A'),
5253 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5254 action='A'),
5255 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5256 action='A'),
5257 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5258 action='A'),
5259 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5260 [],
5261 action='A'),
5262 ]
5263 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5264 input_api, MockOutputApi())
5265 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175266
Arthur Sonzogni7109bd32023-10-03 10:34:425267class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425268
Daniel Cheng566634ff2024-06-29 14:56:535269 def testError(self):
5270 """Test patch adding dangling pointers are reported"""
5271 mock_input_api = MockInputApi()
5272 mock_output_api = MockOutputApi()
5273
5274 mock_input_api.change.DescriptionText = lambda: "description"
5275 mock_input_api.files = [
5276 MockAffectedFile(
5277 local_path="foo/foo.cc",
5278 old_contents=["raw_ptr<T>"],
5279 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5280 )
5281 ]
5282 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5283 mock_output_api)
5284 self.assertEqual(len(msgs), 1)
5285 self.assertEqual(len(msgs[0].message), 10)
5286 self.assertEqual(
5287 msgs[0].message[0],
5288 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5289 )
Arthur Sonzogni7109bd32023-10-03 10:34:425290
5291class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425292
Daniel Cheng566634ff2024-06-29 14:56:535293 def testError(self):
5294 """Test patch adding dangling pointers are reported"""
5295 mock_input_api = MockInputApi()
5296 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425297
Daniel Cheng566634ff2024-06-29 14:56:535298 mock_input_api.change.DescriptionText = lambda: "description"
5299 mock_input_api.files = [
5300 MockAffectedFile(
5301 local_path="foo/foo.cc",
5302 old_contents=["raw_ptr<T>"],
5303 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5304 )
5305 ]
5306 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5307 mock_output_api)
5308 self.assertEqual(len(msgs), 1)
5309 self.assertTrue(
5310 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5311 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425312
Daniel Cheng566634ff2024-06-29 14:56:535313 def testNonCppFile(self):
5314 """Test patch adding dangling pointers are not reported in non C++ files"""
5315 mock_input_api = MockInputApi()
5316 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425317
Daniel Cheng566634ff2024-06-29 14:56:535318 mock_input_api.change.DescriptionText = lambda: "description"
5319 mock_input_api.files = [
5320 MockAffectedFile(
5321 local_path="foo/README.md",
5322 old_contents=[""],
5323 new_contents=["The DanglingUntriaged annotation means"],
5324 )
5325 ]
5326 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5327 mock_output_api)
5328 self.assertEqual(len(msgs), 0)
5329
5330 def testDeveloperAcknowledgeInCommitDescription(self):
5331 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425332 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535333 mock_input_api = MockInputApi()
5334 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425335
Daniel Cheng566634ff2024-06-29 14:56:535336 mock_input_api.files = [
5337 MockAffectedFile(
5338 local_path="foo/foo.cc",
5339 old_contents=["raw_ptr<T>"],
5340 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5341 )
5342 ]
5343 mock_input_api.change.DescriptionText = lambda: (
5344 "DanglingUntriaged-notes: Sorry about this!")
5345 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5346 mock_output_api)
5347 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425348
Daniel Cheng566634ff2024-06-29 14:56:535349 def testDeveloperAcknowledgeInCommitFooter(self):
5350 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425351 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535352 mock_input_api = MockInputApi()
5353 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425354
Daniel Cheng566634ff2024-06-29 14:56:535355 mock_input_api.files = [
5356 MockAffectedFile(
5357 local_path="foo/foo.cc",
5358 old_contents=["raw_ptr<T>"],
5359 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5360 )
5361 ]
5362 mock_input_api.change.DescriptionText = lambda: "description"
5363 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5364 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5365 mock_output_api)
5366 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425367
Daniel Cheng566634ff2024-06-29 14:56:535368 def testCongrats(self):
5369 """Test the presubmit congrats users removing dangling pointers"""
5370 mock_input_api = MockInputApi()
5371 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425372
Daniel Cheng566634ff2024-06-29 14:56:535373 mock_input_api.files = [
5374 MockAffectedFile(
5375 local_path="foo/foo.cc",
5376 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5377 new_contents=["raw_ptr<T>"],
5378 )
5379 ]
5380 mock_input_api.change.DescriptionText = lambda: (
5381 "This patch fixes some DanglingUntriaged pointers!")
5382 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5383 mock_output_api)
5384 self.assertEqual(len(msgs), 1)
5385 self.assertTrue(
5386 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5387 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425388
Daniel Cheng566634ff2024-06-29 14:56:535389 def testRenameFile(self):
5390 """Patch that we do not warn about DanglingUntriaged when moving files"""
5391 mock_input_api = MockInputApi()
5392 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425393
Daniel Cheng566634ff2024-06-29 14:56:535394 mock_input_api.files = [
5395 MockAffectedFile(
5396 local_path="foo/foo.cc",
5397 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5398 new_contents=[""],
5399 action="D",
5400 ),
5401 MockAffectedFile(
5402 local_path="foo/foo.cc",
5403 old_contents=[""],
5404 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5405 action="A",
5406 ),
5407 ]
5408 mock_input_api.change.DescriptionText = lambda: (
5409 "This patch moves files")
5410 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5411 mock_output_api)
5412 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425413
Jan Keitel77be7522023-10-12 20:40:495414class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495415
Daniel Cheng566634ff2024-06-29 14:56:535416 def testNoInlineConstexprInHeaderFile(self):
5417 """Tests that non-inlined constexpr variables in headers fail the test."""
5418 input_api = MockInputApi()
5419 input_api.files = [
5420 MockAffectedFile('src/constants.h',
5421 ['constexpr int kVersion = 5;'])
5422 ]
5423 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5424 input_api, MockOutputApi())
5425 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495426
Daniel Cheng566634ff2024-06-29 14:56:535427 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5428 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5429 input_api = MockInputApi()
5430 input_api.files = [
5431 MockAffectedFile('src/constants.h',
5432 ['constexpr int kVersion = GetVersion();'])
5433 ]
5434 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5435 input_api, MockOutputApi())
5436 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495437
Daniel Cheng566634ff2024-06-29 14:56:535438 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5439 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5440 input_api = MockInputApi()
5441 input_api.files = [
5442 MockAffectedFile('src/constants.h',
5443 ['constexpr int kVersion = (4 + 5)*3;'])
5444 ]
5445 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5446 input_api, MockOutputApi())
5447 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495448
Daniel Cheng566634ff2024-06-29 14:56:535449 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5450 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5451 input_api = MockInputApi()
5452 input_api.files = [
5453 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5454 ]
5455 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5456 input_api, MockOutputApi())
5457 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495458
Daniel Cheng566634ff2024-06-29 14:56:535459 def testNoInlineConstexprInHeaderWithAttribute(self):
5460 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5461 input_api = MockInputApi()
5462 input_api.files = [
5463 MockAffectedFile('src/constants.h',
5464 ['constexpr [[maybe_unused]] int kVersion{5};'])
5465 ]
5466 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5467 input_api, MockOutputApi())
5468 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495469
Daniel Cheng566634ff2024-06-29 14:56:535470 def testInlineConstexprInHeaderWithAttribute(self):
5471 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5472 input_api = MockInputApi()
5473 input_api.files = [
5474 MockAffectedFile(
5475 'src/constants.h',
5476 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5477 MockAffectedFile(
5478 'src/constants.h',
5479 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5480 MockAffectedFile(
5481 'src/constants.h',
5482 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5483 ]
5484 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5485 input_api, MockOutputApi())
5486 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495487
Daniel Cheng566634ff2024-06-29 14:56:535488 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5489 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5490 input_api = MockInputApi()
5491 lines = [
5492 'constexpr char kLongName =',
5493 ' "This is a very long name of something.";'
5494 ]
5495 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5496 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5497 input_api, MockOutputApi())
5498 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495499
Daniel Cheng566634ff2024-06-29 14:56:535500 def testNoInlineConstexprInCCFile(self):
5501 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5502 input_api = MockInputApi()
5503 input_api.files = [
5504 MockAffectedFile('src/implementation.cc',
5505 ['constexpr int kVersion = 5;'])
5506 ]
5507 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5508 input_api, MockOutputApi())
5509 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495510
Daniel Cheng566634ff2024-06-29 14:56:535511 def testInlineConstexprInHeaderFile(self):
5512 """Tests that inlined constexpr variables in header files pass the test."""
5513 input_api = MockInputApi()
5514 input_api.files = [
5515 MockAffectedFile('src/constants.h',
5516 ['constexpr inline int kX = 5;']),
5517 MockAffectedFile('src/version.h',
5518 ['inline constexpr float kY = 5.0f;'])
5519 ]
5520 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5521 input_api, MockOutputApi())
5522 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495523
Daniel Cheng566634ff2024-06-29 14:56:535524 def testConstexprStandaloneFunctionInHeaderFile(self):
5525 """Tests that non-inlined constexpr functions in headers pass the test."""
5526 input_api = MockInputApi()
5527 input_api.files = [
5528 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5529 ]
5530 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5531 input_api, MockOutputApi())
5532 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495533
Daniel Cheng566634ff2024-06-29 14:56:535534 def testConstexprWithAbseilAttributeInHeader(self):
5535 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5536 input_api = MockInputApi()
5537 input_api.files = [
5538 MockAffectedFile('src/helpers.h',
5539 ['ABSL_FOOFOO constexpr int i = 5;'])
5540 ]
5541 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5542 input_api, MockOutputApi())
5543 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495544
Daniel Cheng566634ff2024-06-29 14:56:535545 def testInlineConstexprWithAbseilAttributeInHeader(self):
5546 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5547 input_api = MockInputApi()
5548 input_api.files = [
5549 MockAffectedFile('src/helpers.h',
5550 ['constexpr ABSL_FOO inline int i = 5;'])
5551 ]
5552 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5553 input_api, MockOutputApi())
5554 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495555
Daniel Cheng566634ff2024-06-29 14:56:535556 def testConstexprWithClangAttributeInHeader(self):
5557 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5558 input_api = MockInputApi()
5559 input_api.files = [
5560 MockAffectedFile('src/helpers.h',
5561 ['[[clang::someattribute]] constexpr int i = 5;'])
5562 ]
5563 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5564 input_api, MockOutputApi())
5565 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495566
Daniel Cheng566634ff2024-06-29 14:56:535567 def testInlineConstexprWithClangAttributeInHeader(self):
5568 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5569 input_api = MockInputApi()
5570 input_api.files = [
5571 MockAffectedFile(
5572 'src/helpers.h',
5573 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5574 ]
5575 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5576 input_api, MockOutputApi())
5577 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425578
Daniel Cheng566634ff2024-06-29 14:56:535579 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5580 """Tests that non-inlined constexpr class members pass the test."""
5581 input_api = MockInputApi()
5582 lines = [
5583 'class SomeClass {', ' public:',
5584 ' static constexpr kVersion = 5;', '};'
5585 ]
5586 input_api.files = [MockAffectedFile('src/class.h', lines)]
5587 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5588 input_api, MockOutputApi())
5589 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045590
Daniel Cheng566634ff2024-06-29 14:56:535591 def testTodoBugReferencesWithOldBugId(self):
5592 """Tests that an old monorail bug ID in a TODO fails."""
5593 input_api = MockInputApi()
5594 input_api.files = [
5595 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5596 ]
5597 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5598 self.assertEqual(1, len(warnings))
5599
5600 def testTodoBugReferencesWithUpdatedBugId(self):
5601 """Tests that a new issue tracker bug ID in a TODO passes."""
5602 input_api = MockInputApi()
5603 input_api.files = [
5604 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5605 ]
5606 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5607 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045608
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155609class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535610 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155611
Daniel Cheng566634ff2024-06-29 14:56:535612 def testCppMobilePlatformPath(self):
5613 input_api = MockInputApi()
5614 input_api.files = [
5615 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5616 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5617 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5618 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5619 MockFile('components/foo/delegate_android.cc',
5620 ['IsSyncFeatureActive']),
5621 MockFile('components/foo/delegate_ios.cc',
5622 ['IsSyncFeatureActive']),
5623 MockFile('components/foo/android_delegate.cc',
5624 ['IsSyncFeatureActive']),
5625 MockFile('components/foo/ios_delegate.cc',
5626 ['IsSyncFeatureActive']),
5627 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155628
Daniel Cheng566634ff2024-06-29 14:56:535629 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155630
Daniel Cheng566634ff2024-06-29 14:56:535631 self.assertEqual(1, len(results))
5632 self.assertFalse(
5633 'chrome/browser/android/file.cc' in results[0].message),
5634 self.assertTrue('chrome/android/file.cc' in results[0].message),
5635 self.assertTrue('ios/file.mm' in results[0].message),
5636 self.assertTrue('components/foo/ios/file.cc' in results[0].message),
5637 self.assertTrue(
5638 'components/foo/delegate_android.cc' in results[0].message),
5639 self.assertTrue(
5640 'components/foo/delegate_ios.cc' in results[0].message),
5641 self.assertTrue(
5642 'components/foo/android_delegate.cc' in results[0].message),
5643 self.assertTrue(
5644 'components/foo/ios_delegate.cc' in results[0].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155645
Daniel Cheng566634ff2024-06-29 14:56:535646 def testCppNonMobilePlatformPath(self):
5647 input_api = MockInputApi()
5648 input_api.files = [
5649 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5650 MockFile('bios/file.cc', ['HasSyncConsent']),
5651 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5652 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155653
Daniel Cheng566634ff2024-06-29 14:56:535654 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155655
Daniel Cheng566634ff2024-06-29 14:56:535656 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155657
Daniel Cheng566634ff2024-06-29 14:56:535658 def testJavaPath(self):
5659 input_api = MockInputApi()
5660 input_api.files = [
5661 MockFile('components/foo/file1.java', ['otherFunction']),
5662 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5663 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5664 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5665 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5666 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155667
Daniel Cheng566634ff2024-06-29 14:56:535668 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155669
Daniel Cheng566634ff2024-06-29 14:56:535670 self.assertEqual(1, len(results))
5671 self.assertFalse('components/foo/file1.java' in results[0].message),
5672 self.assertTrue('components/foo/file2.java' in results[0].message),
5673 self.assertTrue('chrome/foo/file3.java' in results[0].message),
5674 self.assertTrue('chrome/foo/file4.java' in results[0].message),
5675 self.assertTrue('chrome/foo/file5.java' in results[0].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155676
5677
[email protected]2299dcf2012-11-15 19:56:245678if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535679 unittest.main()