Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: d193f2080f254a74d8537194dbf4c482eb798141 [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 = {
Justin Lulejiana2fc7882025-04-01 18:34:47396 r'compositor\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53397 '+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 = {
Justin Lulejiana2fc7882025-04-01 18:34:47415 r'compositor\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53416 '+cc',
417 },
Justin Lulejiana2fc7882025-04-01 18:34:47418 r'widget\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53419 '+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 Grieveb77ac76d2024-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([
Joanna Wang130e7bdd2024-12-10 17:39:03512 MockAffectedFile('pdf/DEPS',
513 ['include_rules=["+v8/123", "+foo/bar"]']),
Andrew Grieveb77ac76d2024-11-29 15:01:48514 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Joanna Wang130e7bdd2024-12-10 17:39:03515 # Check that we ignore "DEPS" directories. Note there are real cases
516 # of directories named "deps/" and, especially for case-insensitive file
517 # systems we should prevent these from being considered.
518 MockAffectedFile('foo/bar/DEPS/boofar', ['boofar file contents']),
Andrew Grieve713b89b2024-10-15 20:20:08519 ])
Daniel Cheng566634ff2024-06-29 14:56:53520
521 # mark the additional dep as approved.
522 os_path = self.input_api.os_path
523 self.input_api.owners_client.mockGetFilesApprovalStatus(
524 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.APPROVED})
525 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
526 self.input_api, MockOutputApi())
527 # Then, the check should pass.
528 self.assertEqual([], results)
529
530 def testUnapprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08531 self.input_api.InitFiles([
532 MockAffectedFile('pdf/DEPS', ['include_rules=["+v8/123"]']),
Andrew Grieveb77ac76d2024-11-29 15:01:48533 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Andrew Grieve713b89b2024-10-15 20:20:08534 ])
Daniel Cheng566634ff2024-06-29 14:56:53535
536 # pending.
537 os_path = self.input_api.os_path
538 self.input_api.owners_client.mockGetFilesApprovalStatus(
539 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.PENDING})
540 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
541 self.input_api, MockOutputApi())
542 # the check should fail
543 self.assertIn('You need LGTM', results[0].message)
544 self.assertIn('+v8/123', results[0].message)
545
546 # unless the added dep is from a submodule.
547 self.mockListSubmodules(['v8'])
548 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
549 self.input_api, MockOutputApi())
550 self.assertEqual([], results)
Scott Leebf6a0942024-06-26 22:59:39551
[email protected]f32e2d1e2013-07-26 21:39:08552
[email protected]99171a92014-06-03 08:44:47553class JSONParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47554
Daniel Cheng566634ff2024-06-29 14:56:53555 def testSuccess(self):
556 input_api = MockInputApi()
557 filename = 'valid_json.json'
558 contents = [
559 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
560 ' "key2": 3 // This is an inline comment.', '}'
561 ]
562 input_api.files = [MockFile(filename, contents)]
563 self.assertEqual(None,
564 PRESUBMIT._GetJSONParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47565
Daniel Cheng566634ff2024-06-29 14:56:53566 def testFailure(self):
567 input_api = MockInputApi()
568 test_data = [
569 ('invalid_json_1.json', ['{ x }'], 'Expecting property name'),
570 ('invalid_json_2.json', ['// Hello world!', '{ "hello": "world }'],
571 'Unterminated string starting at:'),
572 ('invalid_json_3.json', ['{ "a": "b", "c": "d", }'],
573 'Expecting property name'),
574 ('invalid_json_4.json', ['{ "a": "b" "c": "d" }'],
575 "Expecting ',' delimiter:"),
576 ]
[email protected]99171a92014-06-03 08:44:47577
Daniel Cheng566634ff2024-06-29 14:56:53578 input_api.files = [
579 MockFile(filename, contents)
580 for (filename, contents, _) in test_data
581 ]
[email protected]99171a92014-06-03 08:44:47582
Daniel Cheng566634ff2024-06-29 14:56:53583 for (filename, _, expected_error) in test_data:
584 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
585 self.assertTrue(
586 expected_error in str(actual_error),
587 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47588
Daniel Cheng566634ff2024-06-29 14:56:53589 def testNoEatComments(self):
590 input_api = MockInputApi()
591 file_with_comments = 'file_with_comments.json'
592 contents_with_comments = [
593 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
594 ' "key2": 3 // This is an inline comment.', '}'
595 ]
596 file_without_comments = 'file_without_comments.json'
597 contents_without_comments = [
598 '{', ' "key1": ["value1", "value2"],', ' "key2": 3', '}'
599 ]
600 input_api.files = [
601 MockFile(file_with_comments, contents_with_comments),
602 MockFile(file_without_comments, contents_without_comments)
603 ]
604
605 self.assertNotEqual(
606 None,
607 str(
608 PRESUBMIT._GetJSONParseError(input_api,
609 file_with_comments,
610 eat_comments=False)))
611 self.assertEqual(
612 None,
613 PRESUBMIT._GetJSONParseError(input_api,
614 file_without_comments,
615 eat_comments=False))
[email protected]99171a92014-06-03 08:44:47616
617
618class IDLParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47619
Daniel Cheng566634ff2024-06-29 14:56:53620 def testSuccess(self):
621 input_api = MockInputApi()
622 filename = 'valid_idl_basics.idl'
623 contents = [
624 '// Tests a valid IDL file.', 'namespace idl_basics {',
625 ' enum EnumType {', ' name1,', ' name2', ' };', '',
626 ' dictionary MyType1 {', ' DOMString a;', ' };', '',
627 ' callback Callback1 = void();',
628 ' callback Callback2 = void(long x);',
629 ' callback Callback3 = void(MyType1 arg);',
630 ' callback Callback4 = void(EnumType type);', '',
631 ' interface Functions {', ' static void function1();',
632 ' static void function2(long x);',
633 ' static void function3(MyType1 arg);',
634 ' static void function4(Callback1 cb);',
635 ' static void function5(Callback2 cb);',
636 ' static void function6(Callback3 cb);',
637 ' static void function7(Callback4 cb);', ' };', '',
638 ' interface Events {', ' static void onFoo1();',
639 ' static void onFoo2(long x);',
640 ' static void onFoo2(MyType1 arg);',
641 ' static void onFoo3(EnumType type);', ' };', '};'
642 ]
643 input_api.files = [MockFile(filename, contents)]
644 self.assertEqual(None,
645 PRESUBMIT._GetIDLParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47646
Daniel Cheng566634ff2024-06-29 14:56:53647 def testFailure(self):
648 input_api = MockInputApi()
649 test_data = [
650 ('invalid_idl_1.idl', [
651 '//', 'namespace test {', ' dictionary {', ' DOMString s;',
652 ' };', '};'
653 ], 'Unexpected "{" after keyword "dictionary".\n'),
654 # TODO(yoz): Disabled because it causes the IDL parser to hang.
655 # See crbug.com/363830.
656 # ('invalid_idl_2.idl',
657 # (['namespace test {',
658 # ' dictionary MissingSemicolon {',
659 # ' DOMString a',
660 # ' DOMString b;',
661 # ' };',
662 # '};'],
663 # 'Unexpected symbol DOMString after symbol a.'),
664 ('invalid_idl_3.idl', [
665 '//', 'namespace test {', ' enum MissingComma {', ' name1',
666 ' name2', ' };', '};'
667 ], 'Unexpected symbol name2 after symbol name1.'),
668 ('invalid_idl_4.idl', [
669 '//', 'namespace test {', ' enum TrailingComma {',
670 ' name1,', ' name2,', ' };', '};'
671 ], 'Trailing comma in block.'),
672 ('invalid_idl_5.idl',
673 ['//', 'namespace test {', ' callback Callback1 = void(;',
674 '};'], 'Unexpected ";" after "(".'),
675 ('invalid_idl_6.idl', [
676 '//', 'namespace test {',
677 ' callback Callback1 = void(long );', '};'
678 ], 'Unexpected ")" after symbol long.'),
679 ('invalid_idl_7.idl', [
680 '//', 'namespace test {', ' interace Events {',
681 ' static void onFoo1();', ' };', '};'
682 ], 'Unexpected symbol Events after symbol interace.'),
683 ('invalid_idl_8.idl', [
684 '//', 'namespace test {', ' interface NotEvent {',
685 ' static void onFoo1();', ' };', '};'
686 ], 'Did not process Interface Interface(NotEvent)'),
687 ('invalid_idl_9.idl', [
688 '//', 'namespace test {', ' interface {',
689 ' static void function1();', ' };', '};'
690 ], 'Interface missing name.'),
691 ]
[email protected]99171a92014-06-03 08:44:47692
Daniel Cheng566634ff2024-06-29 14:56:53693 input_api.files = [
694 MockFile(filename, contents)
695 for (filename, contents, _) in test_data
696 ]
697
698 for (filename, _, expected_error) in test_data:
699 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
700 self.assertTrue(
701 expected_error in str(actual_error),
702 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47703
704
davileene0426252015-03-02 21:10:41705class UserMetricsActionTest(unittest.TestCase):
davileene0426252015-03-02 21:10:41706
Daniel Cheng566634ff2024-06-29 14:56:53707 def testUserMetricsActionInActions(self):
708 input_api = MockInputApi()
709 file_with_user_action = 'file_with_user_action.cc'
710 contents_with_user_action = ['base::UserMetricsAction("AboutChrome")']
davileene0426252015-03-02 21:10:41711
Daniel Cheng566634ff2024-06-29 14:56:53712 input_api.files = [
713 MockFile(file_with_user_action, contents_with_user_action)
714 ]
davileene0426252015-03-02 21:10:41715
Daniel Cheng566634ff2024-06-29 14:56:53716 self.assertEqual([],
717 PRESUBMIT.CheckUserActionUpdate(
718 input_api, MockOutputApi()))
davileene0426252015-03-02 21:10:41719
Daniel Cheng566634ff2024-06-29 14:56:53720 def testUserMetricsActionNotAddedToActions(self):
721 input_api = MockInputApi()
722 file_with_user_action = 'file_with_user_action.cc'
723 contents_with_user_action = [
724 'base::UserMetricsAction("NotInActionsXml")'
725 ]
davileene0426252015-03-02 21:10:41726
Daniel Cheng566634ff2024-06-29 14:56:53727 input_api.files = [
728 MockFile(file_with_user_action, contents_with_user_action)
729 ]
davileene0426252015-03-02 21:10:41730
Daniel Cheng566634ff2024-06-29 14:56:53731 output = PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi())
732 self.assertEqual(
733 ('File %s line %d: %s is missing in '
734 'tools/metrics/actions/actions.xml. Please run '
735 'tools/metrics/actions/extract_actions.py to update.' %
736 (file_with_user_action, 1, 'NotInActionsXml')), output[0].message)
Alexei Svitkine64505a92021-03-11 22:00:54737
Daniel Cheng566634ff2024-06-29 14:56:53738 def testUserMetricsActionInTestFile(self):
739 input_api = MockInputApi()
740 file_with_user_action = 'file_with_user_action_unittest.cc'
741 contents_with_user_action = [
742 'base::UserMetricsAction("NotInActionsXml")'
743 ]
Alexei Svitkine64505a92021-03-11 22:00:54744
Daniel Cheng566634ff2024-06-29 14:56:53745 input_api.files = [
746 MockFile(file_with_user_action, contents_with_user_action)
747 ]
748
749 self.assertEqual([],
750 PRESUBMIT.CheckUserActionUpdate(
751 input_api, MockOutputApi()))
Alexei Svitkine64505a92021-03-11 22:00:54752
davileene0426252015-03-02 21:10:41753
agrievef32bcc72016-04-04 14:57:40754class PydepsNeedsUpdatingTest(unittest.TestCase):
755
Daniel Cheng566634ff2024-06-29 14:56:53756 class MockPopen:
Andrew Grieve4deedb12022-02-03 21:34:50757
Daniel Cheng566634ff2024-06-29 14:56:53758 def __init__(self, stdout):
759 self.stdout = io.StringIO(stdout)
Andrew Grieve4deedb12022-02-03 21:34:50760
Daniel Cheng566634ff2024-06-29 14:56:53761 def wait(self):
762 return 0
Andrew Grieve4deedb12022-02-03 21:34:50763
Daniel Cheng566634ff2024-06-29 14:56:53764 class MockSubprocess:
765 CalledProcessError = subprocess.CalledProcessError
766 PIPE = 0
Andrew Grieve4deedb12022-02-03 21:34:50767
Daniel Cheng566634ff2024-06-29 14:56:53768 def __init__(self):
769 self._popen_func = None
agrievef32bcc72016-04-04 14:57:40770
Daniel Cheng566634ff2024-06-29 14:56:53771 def SetPopenCallback(self, func):
772 self._popen_func = func
Mohamed Heikal7cd4d8312020-06-16 16:49:40773
Daniel Cheng566634ff2024-06-29 14:56:53774 def Popen(self, cmd, *args, **kwargs):
775 return PydepsNeedsUpdatingTest.MockPopen(self._popen_func(cmd))
agrievef32bcc72016-04-04 14:57:40776
Daniel Cheng566634ff2024-06-29 14:56:53777 def _MockParseGclientArgs(self, is_android=True):
778 return lambda: {'checkout_android': 'true' if is_android else 'false'}
agrievef32bcc72016-04-04 14:57:40779
Daniel Cheng566634ff2024-06-29 14:56:53780 def setUp(self):
781 mock_all_pydeps = ['A.pydeps', 'B.pydeps', 'D.pydeps']
782 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
783 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
784 mock_android_pydeps = ['D.pydeps']
785 self.old_ANDROID_SPECIFIC_PYDEPS_FILES = (
786 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES)
787 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = mock_android_pydeps
788 self.old_ParseGclientArgs = PRESUBMIT._ParseGclientArgs
789 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs()
790 self.mock_input_api = MockInputApi()
791 self.mock_output_api = MockOutputApi()
792 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess(
793 )
794 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api,
795 mock_all_pydeps)
796 self.checker._file_cache = {
797 'A.pydeps':
798 '# Generated by:\n# CMD --output A.pydeps A\nA.py\nC.py\n',
799 'B.pydeps':
800 '# Generated by:\n# CMD --output B.pydeps B\nB.py\nC.py\n',
801 'D.pydeps': '# Generated by:\n# CMD --output D.pydeps D\nD.py\n',
802 }
agrievef32bcc72016-04-04 14:57:40803
Daniel Cheng566634ff2024-06-29 14:56:53804 def tearDown(self):
805 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
806 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = (
807 self.old_ANDROID_SPECIFIC_PYDEPS_FILES)
808 PRESUBMIT._ParseGclientArgs = self.old_ParseGclientArgs
pastarmovj89f7ee12016-09-20 14:58:13809
Daniel Cheng566634ff2024-06-29 14:56:53810 def _RunCheck(self):
811 return PRESUBMIT.CheckPydepsNeedsUpdating(
812 self.mock_input_api,
813 self.mock_output_api,
814 checker_for_tests=self.checker)
agrievef32bcc72016-04-04 14:57:40815
Daniel Cheng566634ff2024-06-29 14:56:53816 def testAddedPydep(self):
817 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
818 if not self.mock_input_api.platform.startswith('linux'):
819 return []
agrievef32bcc72016-04-04 14:57:40820
Andrew Grieve713b89b2024-10-15 20:20:08821 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53822 MockAffectedFile('new.pydeps', [], action='A'),
Sophey Dong58cf9bbd2024-10-09 00:08:10823 ])
Andrew Grieve713b89b2024-10-15 20:20:08824
Daniel Cheng566634ff2024-06-29 14:56:53825 results = self._RunCheck()
826 self.assertEqual(1, len(results))
827 self.assertIn('PYDEPS_FILES', str(results[0]))
pastarmovj89f7ee12016-09-20 14:58:13828
Daniel Cheng566634ff2024-06-29 14:56:53829 def testPydepNotInSrc(self):
Andrew Grieve713b89b2024-10-15 20:20:08830 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53831 MockAffectedFile('new.pydeps', [], action='A'),
Andrew Grieve713b89b2024-10-15 20:20:08832 ])
833 self.mock_input_api.os_path.exists = lambda x: False
Daniel Cheng566634ff2024-06-29 14:56:53834 results = self._RunCheck()
835 self.assertEqual(0, len(results))
agrievef32bcc72016-04-04 14:57:40836
Daniel Cheng566634ff2024-06-29 14:56:53837 def testRemovedPydep(self):
838 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
839 if not self.mock_input_api.platform.startswith('linux'):
840 return []
pastarmovj89f7ee12016-09-20 14:58:13841
Andrew Grieve713b89b2024-10-15 20:20:08842 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53843 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
Daniel Cheng566634ff2024-06-29 14:56:53844 ])
845 results = self._RunCheck()
846 self.assertEqual(1, len(results))
847 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40848
Daniel Cheng566634ff2024-06-29 14:56:53849 def testRandomPyIgnored(self):
850 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
851 if not self.mock_input_api.platform.startswith('linux'):
852 return []
agrievef32bcc72016-04-04 14:57:40853
Daniel Cheng566634ff2024-06-29 14:56:53854 self.mock_input_api.files = [
855 MockAffectedFile('random.py', []),
856 ]
pastarmovj89f7ee12016-09-20 14:58:13857
Daniel Cheng566634ff2024-06-29 14:56:53858 results = self._RunCheck()
859 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40860
Daniel Cheng566634ff2024-06-29 14:56:53861 def testRelevantPyNoChange(self):
862 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
863 if not self.mock_input_api.platform.startswith('linux'):
864 return []
agrievef32bcc72016-04-04 14:57:40865
Daniel Cheng566634ff2024-06-29 14:56:53866 self.mock_input_api.files = [
867 MockAffectedFile('A.py', []),
868 ]
agrievef32bcc72016-04-04 14:57:40869
Daniel Cheng566634ff2024-06-29 14:56:53870 def popen_callback(cmd):
871 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
872 return self.checker._file_cache['A.pydeps']
agrievef32bcc72016-04-04 14:57:40873
Daniel Cheng566634ff2024-06-29 14:56:53874 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13875
Daniel Cheng566634ff2024-06-29 14:56:53876 results = self._RunCheck()
877 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40878
Daniel Cheng566634ff2024-06-29 14:56:53879 def testRelevantPyOneChange(self):
880 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
881 if not self.mock_input_api.platform.startswith('linux'):
882 return []
agrievef32bcc72016-04-04 14:57:40883
Daniel Cheng566634ff2024-06-29 14:56:53884 self.mock_input_api.files = [
885 MockAffectedFile('A.py', []),
886 ]
agrievef32bcc72016-04-04 14:57:40887
Daniel Cheng566634ff2024-06-29 14:56:53888 def popen_callback(cmd):
889 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
890 return 'changed data'
agrievef32bcc72016-04-04 14:57:40891
Daniel Cheng566634ff2024-06-29 14:56:53892 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13893
Daniel Cheng566634ff2024-06-29 14:56:53894 results = self._RunCheck()
895 self.assertEqual(1, len(results))
896 # Check that --output "" is not included.
897 self.assertNotIn('""', str(results[0]))
898 self.assertIn('File is stale', str(results[0]))
agrievef32bcc72016-04-04 14:57:40899
Daniel Cheng566634ff2024-06-29 14:56:53900 def testRelevantPyTwoChanges(self):
901 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
902 if not self.mock_input_api.platform.startswith('linux'):
903 return []
agrievef32bcc72016-04-04 14:57:40904
Daniel Cheng566634ff2024-06-29 14:56:53905 self.mock_input_api.files = [
906 MockAffectedFile('C.py', []),
907 ]
agrievef32bcc72016-04-04 14:57:40908
Daniel Cheng566634ff2024-06-29 14:56:53909 def popen_callback(cmd):
910 return 'changed data'
agrievef32bcc72016-04-04 14:57:40911
Daniel Cheng566634ff2024-06-29 14:56:53912 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Mohamed Heikal7cd4d8312020-06-16 16:49:40913
Daniel Cheng566634ff2024-06-29 14:56:53914 results = self._RunCheck()
915 self.assertEqual(2, len(results))
916 self.assertIn('File is stale', str(results[0]))
917 self.assertIn('File is stale', str(results[1]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40918
Daniel Cheng566634ff2024-06-29 14:56:53919 def testRelevantAndroidPyInNonAndroidCheckout(self):
920 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
921 if not self.mock_input_api.platform.startswith('linux'):
922 return []
Mohamed Heikal7cd4d8312020-06-16 16:49:40923
Daniel Cheng566634ff2024-06-29 14:56:53924 self.mock_input_api.files = [
925 MockAffectedFile('D.py', []),
926 ]
Mohamed Heikal7cd4d8312020-06-16 16:49:40927
Daniel Cheng566634ff2024-06-29 14:56:53928 def popen_callback(cmd):
929 self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
930 return 'changed data'
Andrew Grieve5bb4cf702020-10-22 20:21:39931
Daniel Cheng566634ff2024-06-29 14:56:53932 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
933 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(
934 is_android=False)
Andrew Grieve5bb4cf702020-10-22 20:21:39935
Daniel Cheng566634ff2024-06-29 14:56:53936 results = self._RunCheck()
937 self.assertEqual(1, len(results))
938 self.assertIn('Android', str(results[0]))
939 self.assertIn('D.pydeps', str(results[0]))
Andrew Grieve5bb4cf702020-10-22 20:21:39940
Daniel Cheng566634ff2024-06-29 14:56:53941 def testGnPathsAndMissingOutputFlag(self):
942 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
943 if not self.mock_input_api.platform.startswith('linux'):
944 return []
Andrew Grieve5bb4cf702020-10-22 20:21:39945
Daniel Cheng566634ff2024-06-29 14:56:53946 self.checker._file_cache = {
947 'A.pydeps':
948 '# Generated by:\n# CMD --gn-paths A\n//A.py\n//C.py\n',
949 'B.pydeps':
950 '# Generated by:\n# CMD --gn-paths B\n//B.py\n//C.py\n',
951 'D.pydeps': '# Generated by:\n# CMD --gn-paths D\n//D.py\n',
952 }
Andrew Grieve5bb4cf702020-10-22 20:21:39953
Daniel Cheng566634ff2024-06-29 14:56:53954 self.mock_input_api.files = [
955 MockAffectedFile('A.py', []),
956 ]
Andrew Grieve5bb4cf702020-10-22 20:21:39957
Daniel Cheng566634ff2024-06-29 14:56:53958 def popen_callback(cmd):
959 self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""',
960 cmd)
961 return 'changed data'
962
963 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
964
965 results = self._RunCheck()
966 self.assertEqual(1, len(results))
967 self.assertIn('File is stale', str(results[0]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40968
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39969
Daniel Bratell8ba52722018-03-02 16:06:14970class IncludeGuardTest(unittest.TestCase):
Daniel Bratell8ba52722018-03-02 16:06:14971
Daniel Cheng566634ff2024-06-29 14:56:53972 def testIncludeGuardChecks(self):
973 mock_input_api = MockInputApi()
974 mock_output_api = MockOutputApi()
975 mock_input_api.files = [
976 MockAffectedFile('content/browser/thing/foo.h', [
977 '// Comment',
978 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
979 '#define CONTENT_BROWSER_THING_FOO_H_',
980 'struct McBoatFace;',
981 '#endif // CONTENT_BROWSER_THING_FOO_H_',
982 ]),
983 MockAffectedFile('content/browser/thing/bar.h', [
984 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
985 '#define CONTENT_BROWSER_THING_BAR_H_',
986 'namespace content {',
987 '#endif // CONTENT_BROWSER_THING_BAR_H_',
988 '} // namespace content',
989 ]),
990 MockAffectedFile('content/browser/test1.h', [
991 'namespace content {',
992 '} // namespace content',
993 ]),
994 MockAffectedFile('content\\browser\\win.h', [
995 '#ifndef CONTENT_BROWSER_WIN_H_',
996 '#define CONTENT_BROWSER_WIN_H_',
997 'struct McBoatFace;',
998 '#endif // CONTENT_BROWSER_WIN_H_',
999 ]),
1000 MockAffectedFile('content/browser/test2.h', [
1001 '// Comment',
1002 '#ifndef CONTENT_BROWSER_TEST2_H_',
1003 'struct McBoatFace;',
1004 '#endif // CONTENT_BROWSER_TEST2_H_',
1005 ]),
1006 MockAffectedFile('content/browser/internal.h', [
1007 '// Comment',
1008 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
1009 '#define CONTENT_BROWSER_INTERNAL_H_',
1010 '// Comment',
1011 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1012 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1013 'namespace internal {',
1014 '} // namespace internal',
1015 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
1016 'namespace content {',
1017 '} // namespace content',
1018 '#endif // CONTENT_BROWSER_THING_BAR_H_',
1019 ]),
1020 MockAffectedFile('content/browser/thing/foo.cc', [
1021 '// This is a non-header.',
1022 ]),
1023 MockAffectedFile('content/browser/disabled.h', [
1024 '// no-include-guard-because-multiply-included',
1025 'struct McBoatFace;',
1026 ]),
1027 # New files don't allow misspelled include guards.
1028 MockAffectedFile('content/browser/spleling.h', [
1029 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
1030 '#define CONTENT_BROWSER_SPLLEING_H_',
1031 'struct McBoatFace;',
1032 '#endif // CONTENT_BROWSER_SPLLEING_H_',
1033 ]),
1034 # New files don't allow + in include guards.
1035 MockAffectedFile('content/browser/foo+bar.h', [
1036 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
1037 '#define CONTENT_BROWSER_FOO+BAR_H_',
1038 'struct McBoatFace;',
1039 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
1040 ]),
1041 # Old files allow misspelled include guards (for now).
1042 MockAffectedFile('chrome/old.h', [
1043 '// New contents',
1044 '#ifndef CHROME_ODL_H_',
1045 '#define CHROME_ODL_H_',
1046 '#endif // CHROME_ODL_H_',
1047 ], [
1048 '// Old contents',
1049 '#ifndef CHROME_ODL_H_',
1050 '#define CHROME_ODL_H_',
1051 '#endif // CHROME_ODL_H_',
1052 ],
1053 action='M'),
1054 # Using a Blink style include guard outside Blink is wrong.
1055 MockAffectedFile('content/NotInBlink.h', [
1056 '#ifndef NotInBlink_h',
1057 '#define NotInBlink_h',
1058 'struct McBoatFace;',
1059 '#endif // NotInBlink_h',
1060 ]),
1061 # Using a Blink style include guard in Blink is no longer ok.
1062 MockAffectedFile('third_party/blink/InBlink.h', [
1063 '#ifndef InBlink_h',
1064 '#define InBlink_h',
1065 'struct McBoatFace;',
1066 '#endif // InBlink_h',
1067 ]),
1068 # Using a bad include guard in Blink is not ok.
1069 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
1070 '#ifndef WrongInBlink_h',
1071 '#define WrongInBlink_h',
1072 'struct McBoatFace;',
1073 '#endif // WrongInBlink_h',
1074 ]),
1075 # Using a bad include guard in Blink is not supposed to be accepted even
1076 # if it's an old file. However the current presubmit has accepted this
1077 # for a while.
1078 MockAffectedFile('third_party/blink/StillInBlink.h', [
1079 '// New contents',
1080 '#ifndef AcceptedInBlink_h',
1081 '#define AcceptedInBlink_h',
1082 'struct McBoatFace;',
1083 '#endif // AcceptedInBlink_h',
1084 ], [
1085 '// Old contents',
1086 '#ifndef AcceptedInBlink_h',
1087 '#define AcceptedInBlink_h',
1088 'struct McBoatFace;',
1089 '#endif // AcceptedInBlink_h',
1090 ],
1091 action='M'),
1092 # Using a non-Chromium include guard in third_party
1093 # (outside blink) is accepted.
1094 MockAffectedFile('third_party/foo/some_file.h', [
1095 '#ifndef REQUIRED_RPCNDR_H_',
1096 '#define REQUIRED_RPCNDR_H_',
1097 'struct SomeFileFoo;',
1098 '#endif // REQUIRED_RPCNDR_H_',
1099 ]),
1100 # Not having proper include guard in *_message_generator.h
1101 # for old IPC messages is allowed.
1102 MockAffectedFile('content/common/content_message_generator.h', [
1103 '#undef CONTENT_COMMON_FOO_MESSAGES_H_',
1104 '#include "content/common/foo_messages.h"',
1105 '#ifndef CONTENT_COMMON_FOO_MESSAGES_H_',
1106 '#error "Failed to include content/common/foo_messages.h"',
1107 '#endif',
1108 ]),
1109 MockAffectedFile('chrome/renderer/thing/qux.h', [
1110 '// Comment',
1111 '#ifndef CHROME_RENDERER_THING_QUX_H_',
1112 '#define CHROME_RENDERER_THING_QUX_H_',
1113 'struct Boaty;',
1114 '#endif',
1115 ]),
1116 ]
1117 msgs = PRESUBMIT.CheckForIncludeGuards(mock_input_api, mock_output_api)
1118 expected_fail_count = 10
1119 self.assertEqual(
1120 expected_fail_count, len(msgs), 'Expected %d items, found %d: %s' %
1121 (expected_fail_count, len(msgs), msgs))
1122 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
1123 self.assertEqual(
1124 msgs[0].message, 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
1125 'not covering the whole file')
Daniel Bratell8ba52722018-03-02 16:06:141126
Daniel Cheng566634ff2024-06-29 14:56:531127 self.assertIn('content/browser/test1.h', msgs[1].message)
1128 self.assertIn('Recommended name: CONTENT_BROWSER_TEST1_H_',
1129 msgs[1].message)
Daniel Bratell8ba52722018-03-02 16:06:141130
Daniel Cheng566634ff2024-06-29 14:56:531131 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
1132 self.assertEqual(
1133 msgs[2].message, 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
1134 'include guard')
Lei Zhangd84f9512024-05-28 19:43:301135
Daniel Cheng566634ff2024-06-29 14:56:531136 self.assertIn('content/browser/internal.h', msgs[3].message)
1137 self.assertIn(
1138 'Recommended #endif comment: // CONTENT_BROWSER_INTERNAL_H_',
1139 msgs[3].message)
Daniel Bratell8ba52722018-03-02 16:06:141140
Daniel Cheng566634ff2024-06-29 14:56:531141 self.assertEqual(msgs[4].items, ['content/browser/spleling.h:1'])
1142 self.assertEqual(
1143 msgs[4].message, 'Header using the wrong include guard name '
1144 'CONTENT_BROWSER_SPLLEING_H_')
Olivier Robinbba137492018-07-30 11:31:341145
Daniel Cheng566634ff2024-06-29 14:56:531146 self.assertIn('content/browser/foo+bar.h', msgs[5].message)
1147 self.assertIn('Recommended name: CONTENT_BROWSER_FOO_BAR_H_',
1148 msgs[5].message)
Daniel Bratell8ba52722018-03-02 16:06:141149
Daniel Cheng566634ff2024-06-29 14:56:531150 self.assertEqual(msgs[6].items, ['content/NotInBlink.h:1'])
1151 self.assertEqual(
1152 msgs[6].message, 'Header using the wrong include guard name '
1153 'NotInBlink_h')
Daniel Bratell39b5b062018-05-16 18:09:571154
Daniel Cheng566634ff2024-06-29 14:56:531155 self.assertEqual(msgs[7].items, ['third_party/blink/InBlink.h:1'])
1156 self.assertEqual(
1157 msgs[7].message, 'Header using the wrong include guard name '
1158 'InBlink_h')
Daniel Bratell8ba52722018-03-02 16:06:141159
Daniel Cheng566634ff2024-06-29 14:56:531160 self.assertEqual(msgs[8].items, ['third_party/blink/AlsoInBlink.h:1'])
1161 self.assertEqual(
1162 msgs[8].message, 'Header using the wrong include guard name '
1163 'WrongInBlink_h')
1164
1165 self.assertIn('chrome/renderer/thing/qux.h', msgs[9].message)
1166 self.assertIn(
1167 'Recommended #endif comment: // CHROME_RENDERER_THING_QUX_H_',
1168 msgs[9].message)
Lei Zhangd84f9512024-05-28 19:43:301169
1170
Chris Hall59f8d0c72020-05-01 07:31:191171class AccessibilityRelnotesFieldTest(unittest.TestCase):
Chris Hall59f8d0c72020-05-01 07:31:191172
Daniel Cheng566634ff2024-06-29 14:56:531173 def testRelnotesPresent(self):
1174 mock_input_api = MockInputApi()
1175 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191176
Daniel Cheng566634ff2024-06-29 14:56:531177 mock_input_api.files = [
1178 MockAffectedFile('ui/accessibility/foo.bar', [''])
1179 ]
1180 mock_input_api.change.DescriptionText = lambda: 'Commit description'
1181 mock_input_api.change.footers['AX-Relnotes'] = [
1182 'Important user facing change'
1183 ]
Chris Hall59f8d0c72020-05-01 07:31:191184
Daniel Cheng566634ff2024-06-29 14:56:531185 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1186 mock_input_api, mock_output_api)
1187 self.assertEqual(
1188 0, len(msgs),
1189 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191190
Daniel Cheng566634ff2024-06-29 14:56:531191 def testRelnotesMissingFromAccessibilityChange(self):
1192 mock_input_api = MockInputApi()
1193 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191194
Daniel Cheng566634ff2024-06-29 14:56:531195 mock_input_api.files = [
1196 MockAffectedFile('some/file', ['']),
1197 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1198 MockAffectedFile('some/other/file', [''])
1199 ]
1200 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191201
Daniel Cheng566634ff2024-06-29 14:56:531202 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1203 mock_input_api, mock_output_api)
1204 self.assertEqual(
1205 1, len(msgs),
1206 'Expected %d messages, found %d: %s' % (1, len(msgs), msgs))
1207 self.assertTrue(
1208 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1209 'Missing AX-Relnotes field message not found in errors')
Chris Hall59f8d0c72020-05-01 07:31:191210
Daniel Cheng566634ff2024-06-29 14:56:531211 # The relnotes footer is not required for changes which do not touch any
1212 # accessibility directories.
1213 def testIgnoresNonAccessibilityCode(self):
1214 mock_input_api = MockInputApi()
1215 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191216
Daniel Cheng566634ff2024-06-29 14:56:531217 mock_input_api.files = [
1218 MockAffectedFile('some/file', ['']),
1219 MockAffectedFile('some/other/file', [''])
1220 ]
1221 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191222
Daniel Cheng566634ff2024-06-29 14:56:531223 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1224 mock_input_api, mock_output_api)
1225 self.assertEqual(
1226 0, len(msgs),
1227 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191228
Daniel Cheng566634ff2024-06-29 14:56:531229 # Test that our presubmit correctly raises an error for a set of known paths.
1230 def testExpectedPaths(self):
1231 filesToTest = [
1232 "chrome/browser/accessibility/foo.py",
1233 "chrome/browser/ash/arc/accessibility/foo.cc",
1234 "chrome/browser/ui/views/accessibility/foo.h",
1235 "chrome/browser/extensions/api/automation/foo.h",
1236 "chrome/browser/extensions/api/automation_internal/foo.cc",
1237 "chrome/renderer/extensions/accessibility_foo.h",
1238 "chrome/tests/data/accessibility/foo.html",
1239 "content/browser/accessibility/foo.cc",
1240 "content/renderer/accessibility/foo.h",
1241 "content/tests/data/accessibility/foo.cc",
1242 "extensions/renderer/api/automation/foo.h",
1243 "ui/accessibility/foo/bar/baz.cc",
1244 "ui/views/accessibility/foo/bar/baz.h",
1245 ]
Chris Hall59f8d0c72020-05-01 07:31:191246
Daniel Cheng566634ff2024-06-29 14:56:531247 for testFile in filesToTest:
1248 mock_input_api = MockInputApi()
1249 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191250
Daniel Cheng566634ff2024-06-29 14:56:531251 mock_input_api.files = [MockAffectedFile(testFile, [''])]
1252 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391253
Daniel Cheng566634ff2024-06-29 14:56:531254 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1255 mock_input_api, mock_output_api)
1256 self.assertEqual(
1257 1, len(msgs),
1258 'Expected %d messages, found %d: %s, for file %s' %
1259 (1, len(msgs), msgs, testFile))
1260 self.assertTrue(
1261 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1262 ('Missing AX-Relnotes field message not found in errors '
1263 ' for file %s' % (testFile)))
Akihiro Ota08108e542020-05-20 15:30:531264
Daniel Cheng566634ff2024-06-29 14:56:531265 # Test that AX-Relnotes field can appear in the commit description (as long
1266 # as it appears at the beginning of a line).
1267 def testRelnotesInCommitDescription(self):
1268 mock_input_api = MockInputApi()
1269 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531270
Daniel Cheng566634ff2024-06-29 14:56:531271 mock_input_api.files = [
1272 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1273 ]
1274 mock_input_api.change.DescriptionText = lambda: (
1275 'Description:\n' +
1276 'AX-Relnotes: solves all accessibility issues forever')
Akihiro Ota08108e542020-05-20 15:30:531277
Daniel Cheng566634ff2024-06-29 14:56:531278 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1279 mock_input_api, mock_output_api)
1280 self.assertEqual(
1281 0, len(msgs),
1282 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Akihiro Ota08108e542020-05-20 15:30:531283
Daniel Cheng566634ff2024-06-29 14:56:531284 # Test that we don't match AX-Relnotes if it appears in the middle of a line.
1285 def testRelnotesMustAppearAtBeginningOfLine(self):
1286 mock_input_api = MockInputApi()
1287 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531288
Daniel Cheng566634ff2024-06-29 14:56:531289 mock_input_api.files = [
1290 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1291 ]
1292 mock_input_api.change.DescriptionText = lambda: (
1293 'Description:\n' +
1294 'This change has no AX-Relnotes: we should print a warning')
Akihiro Ota08108e542020-05-20 15:30:531295
Daniel Cheng566634ff2024-06-29 14:56:531296 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1297 mock_input_api, mock_output_api)
1298 self.assertTrue(
1299 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1300 'Missing AX-Relnotes field message not found in errors')
Akihiro Ota08108e542020-05-20 15:30:531301
Daniel Cheng566634ff2024-06-29 14:56:531302 # Tests that the AX-Relnotes field can be lowercase and use a '=' in place
1303 # of a ':'.
1304 def testRelnotesLowercaseWithEqualSign(self):
1305 mock_input_api = MockInputApi()
1306 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531307
Daniel Cheng566634ff2024-06-29 14:56:531308 mock_input_api.files = [
1309 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1310 ]
1311 mock_input_api.change.DescriptionText = lambda: (
1312 'Description:\n' +
1313 'ax-relnotes= this is a valid format for accessibility relnotes')
1314
1315 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1316 mock_input_api, mock_output_api)
1317 self.assertEqual(
1318 0, len(msgs),
1319 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1320
Akihiro Ota08108e542020-05-20 15:30:531321
Mark Schillaci44c90b42024-11-22 20:44:381322class AccessibilityAriaElementAttributeGettersTest(unittest.TestCase):
1323
1324 # Test warning is surfaced for various possible uses of bad methods.
1325 def testMatchingLines(self):
1326 mock_input_api = MockInputApi()
1327 mock_input_api.files = [
1328 MockFile(
1329 "third_party/blink/renderer/core/accessibility/ax_object.h",
1330 [
1331 "->getAttribute(html_names::kAriaCheckedAttr)",
1332 "node->hasAttribute(html_names::kRoleAttr)",
1333 "->FastHasAttribute(html_names::kAriaLabelAttr)",
1334 " .FastGetAttribute(html_names::kAriaCurrentAttr);",
1335
1336 ],
1337 action='M'
1338 ),
1339 MockFile(
1340 "third_party/blink/renderer/core/accessibility/ax_table.cc",
1341 [
1342 "bool result = node->hasAttribute(html_names::kFooAttr);",
1343 "foo->getAttribute(html_names::kAriaInvalidValueAttr)",
1344 "foo->GetAriaCurrentState(html_names::kAriaCurrentStateAttr)",
1345 ],
1346 action='M'
1347 ),
1348 ]
1349
1350 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1351 self.assertEqual(1, len(results))
1352 self.assertEqual(5, len(results[0].items))
1353 self.assertIn("ax_object.h:1", results[0].items[0])
1354 self.assertIn("ax_object.h:2", results[0].items[1])
1355 self.assertIn("ax_object.h:3", results[0].items[2])
1356 self.assertIn("ax_object.h:4", results[0].items[3])
1357 self.assertIn("ax_table.cc:2", results[0].items[4])
1358 self.assertIn("Please use ARIA-specific attribute access", results[0].message)
1359
1360 # Test no warnings for files that are not accessibility related.
1361 def testNonMatchingFiles(self):
1362 mock_input_api = MockInputApi()
1363 mock_input_api.files = [
1364 MockFile(
1365 "content/browser/foobar/foo.cc",
1366 ["->getAttribute(html_names::kAriaCheckedAttr)"],
1367 action='M'),
1368 MockFile(
1369 "third_party/blink/renderer/core/foo.cc",
1370 ["node->hasAttribute(html_names::kRoleAttr)"],
1371 action='M'),
1372 ]
1373 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1374 self.assertEqual(0, len(results))
1375
1376 # Test no warning when methods are used with different attribute params.
1377 def testNoBadParam(self):
1378 mock_input_api = MockInputApi()
1379 mock_input_api.files = [
1380 MockFile(
1381 "third_party/blink/renderer/core/accessibility/ax_object.h",
1382 [
1383 "->getAttribute(html_names::kCheckedAttr)",
1384 "->hasAttribute(html_names::kIdAttr)",
1385 ],
1386 action='M'
1387 )
1388 ]
1389
1390 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1391 self.assertEqual(0, len(results))
1392
1393 # Test no warning when attribute params are used for different methods.
1394 def testNoMethod(self):
1395 mock_input_api = MockInputApi()
1396 mock_input_api.files = [
1397 MockFile(
1398 "third_party/blink/renderer/core/accessibility/ax_object.cc",
1399 [
1400 "foo(html_names::kAriaCheckedAttr)",
1401 "bar(html_names::kRoleAttr)"
1402 ],
1403 action='M'
1404 )
1405 ]
1406
1407 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1408 self.assertEqual(0, len(results))
1409
1410
yolandyan45001472016-12-21 21:12:421411class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
yolandyan45001472016-12-21 21:12:421412
Daniel Cheng566634ff2024-06-29 14:56:531413 def testCheckAndroidTestAnnotationUsage(self):
1414 mock_input_api = MockInputApi()
1415 mock_output_api = MockOutputApi()
1416
1417 mock_input_api.files = [
1418 MockAffectedFile('LalaLand.java', ['random stuff']),
1419 MockAffectedFile('CorrectUsage.java', [
1420 'import androidx.test.filters.LargeTest;',
1421 'import androidx.test.filters.MediumTest;',
1422 'import androidx.test.filters.SmallTest;',
1423 ]),
1424 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1425 'import android.test.suitebuilder.annotation.LargeTest;',
1426 ]),
1427 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1428 'import android.test.suitebuilder.annotation.MediumTest;',
1429 ]),
1430 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1431 'import android.test.suitebuilder.annotation.SmallTest;',
1432 ]),
1433 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1434 'import android.test.suitebuilder.annotation.Smoke;',
1435 ])
1436 ]
1437 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1438 mock_input_api, mock_output_api)
1439 self.assertEqual(
1440 1, len(msgs),
1441 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1442 self.assertEqual(
1443 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1444 (4, len(msgs[0].items), msgs[0].items))
1445 self.assertTrue(
1446 'UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1447 'UsedDeprecatedLargeTestAnnotation not found in errors')
1448 self.assertTrue(
1449 'UsedDeprecatedMediumTestAnnotation.java:1' in msgs[0].items,
1450 'UsedDeprecatedMediumTestAnnotation not found in errors')
1451 self.assertTrue(
1452 'UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1453 'UsedDeprecatedSmallTestAnnotation not found in errors')
1454 self.assertTrue(
1455 'UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1456 'UsedDeprecatedSmokeAnnotation not found in errors')
1457
yolandyan45001472016-12-21 21:12:421458
Min Qinbc44383c2023-02-22 17:25:261459class AndroidBannedImportTest(unittest.TestCase):
Min Qinbc44383c2023-02-22 17:25:261460
Daniel Cheng566634ff2024-06-29 14:56:531461 def testCheckAndroidNoBannedImports(self):
1462 mock_input_api = MockInputApi()
1463 mock_output_api = MockOutputApi()
1464
1465 test_files = [
1466 MockAffectedFile('RandomStufff.java', ['random stuff']),
1467 MockAffectedFile('NoBannedImports.java', [
1468 'import androidx.test.filters.LargeTest;',
1469 'import androidx.test.filters.MediumTest;',
1470 'import androidx.test.filters.SmallTest;',
1471 ]),
1472 MockAffectedFile('BannedUri.java', [
1473 'import java.net.URI;',
1474 ]),
1475 MockAffectedFile('BannedTargetApi.java', [
1476 'import android.annotation.TargetApi;',
1477 ]),
Daniel Cheng566634ff2024-06-29 14:56:531478 MockAffectedFile('BannedActivityTestRule.java', [
1479 'import androidx.test.rule.ActivityTestRule;',
1480 ]),
1481 MockAffectedFile('BannedVectorDrawableCompat.java', [
1482 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
1483 ])
1484 ]
1485 msgs = []
1486 for file in test_files:
1487 mock_input_api.files = [file]
1488 msgs.append(
1489 PRESUBMIT._CheckAndroidNoBannedImports(mock_input_api,
1490 mock_output_api))
1491 self.assertEqual(0, len(msgs[0]))
1492 self.assertEqual(0, len(msgs[1]))
1493 self.assertTrue(msgs[2][0].message.startswith(
1494 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261495 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531496 BannedUri.java:1:""")))
1497 self.assertTrue(msgs[3][0].message.startswith(
1498 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261499 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531500 BannedTargetApi.java:1:""")))
1501 self.assertTrue(msgs[4][0].message.startswith(
1502 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261503 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531504 BannedActivityTestRule.java:1:""")))
Theo Cristea1d9a90a2024-11-14 13:31:301505 self.assertTrue(msgs[5][0].message.startswith(
Daniel Cheng566634ff2024-06-29 14:56:531506 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261507 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531508 BannedVectorDrawableCompat.java:1:""")))
1509
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391510
Mohamed Heikal5e5b7922020-10-29 18:57:591511class CheckNoDownstreamDepsTest(unittest.TestCase):
Mohamed Heikal5e5b7922020-10-29 18:57:591512
Daniel Cheng566634ff2024-06-29 14:56:531513 def testInvalidDepFromUpstream(self):
1514 mock_input_api = MockInputApi()
1515 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591516
Daniel Cheng566634ff2024-06-29 14:56:531517 mock_input_api.files = [
1518 MockAffectedFile('BUILD.gn',
1519 ['deps = [', ' "//clank/target:test",', ']']),
1520 MockAffectedFile('chrome/android/BUILD.gn',
1521 ['deps = [ "//clank/target:test" ]']),
1522 MockAffectedFile(
1523 'chrome/chrome_java_deps.gni',
1524 ['java_deps = [', ' "//clank/target:test",', ']']),
1525 ]
1526 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1527 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1528 mock_output_api)
1529 self.assertEqual(
1530 1, len(msgs),
1531 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1532 self.assertEqual(
1533 3, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1534 (3, len(msgs[0].items), msgs[0].items))
1535 self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
1536 'BUILD.gn not found in errors')
1537 self.assertTrue(
1538 any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
1539 'chrome/android/BUILD.gn:1 not found in errors')
1540 self.assertTrue(
1541 any('chrome/chrome_java_deps.gni:2' in item
1542 for item in msgs[0].items),
1543 'chrome/chrome_java_deps.gni:2 not found in errors')
Mohamed Heikal5e5b7922020-10-29 18:57:591544
Daniel Cheng566634ff2024-06-29 14:56:531545 def testAllowsComments(self):
1546 mock_input_api = MockInputApi()
1547 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591548
Daniel Cheng566634ff2024-06-29 14:56:531549 mock_input_api.files = [
1550 MockAffectedFile('BUILD.gn', [
1551 '# real implementation in //clank/target:test',
1552 ]),
1553 ]
1554 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1555 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1556 mock_output_api)
1557 self.assertEqual(
1558 0, len(msgs),
1559 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591560
Daniel Cheng566634ff2024-06-29 14:56:531561 def testOnlyChecksBuildFiles(self):
1562 mock_input_api = MockInputApi()
1563 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591564
Daniel Cheng566634ff2024-06-29 14:56:531565 mock_input_api.files = [
1566 MockAffectedFile('README.md',
1567 ['DEPS = [ "//clank/target:test" ]']),
1568 MockAffectedFile('chrome/android/java/file.java',
1569 ['//clank/ only function']),
1570 ]
1571 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1572 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1573 mock_output_api)
1574 self.assertEqual(
1575 0, len(msgs),
1576 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591577
Daniel Cheng566634ff2024-06-29 14:56:531578 def testValidDepFromDownstream(self):
1579 mock_input_api = MockInputApi()
1580 mock_output_api = MockOutputApi()
1581
1582 mock_input_api.files = [
1583 MockAffectedFile('BUILD.gn',
1584 ['DEPS = [', ' "//clank/target:test",', ']']),
1585 MockAffectedFile('java/BUILD.gn',
1586 ['DEPS = [ "//clank/target:test" ]']),
1587 ]
1588 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
1589 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1590 mock_output_api)
1591 self.assertEqual(
1592 0, len(msgs),
1593 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591594
yolandyan45001472016-12-21 21:12:421595
Jinsong Fan91ebbbd2019-04-16 14:57:171596class AndroidDebuggableBuildTest(unittest.TestCase):
1597
Daniel Cheng566634ff2024-06-29 14:56:531598 def testCheckAndroidDebuggableBuild(self):
1599 mock_input_api = MockInputApi()
1600 mock_output_api = MockOutputApi()
Jinsong Fan91ebbbd2019-04-16 14:57:171601
Daniel Cheng566634ff2024-06-29 14:56:531602 mock_input_api.files = [
1603 MockAffectedFile('RandomStuff.java', ['random stuff']),
1604 MockAffectedFile('CorrectUsage.java', [
1605 'import org.chromium.base.BuildInfo;',
1606 'some random stuff',
1607 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1608 ]),
1609 MockAffectedFile('JustCheckUserdebugBuild.java', [
1610 'import android.os.Build;',
1611 'some random stuff',
1612 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1613 ]),
1614 MockAffectedFile('JustCheckEngineeringBuild.java', [
1615 'import android.os.Build;',
1616 'some random stuff',
1617 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1618 ]),
1619 MockAffectedFile('UsedBuildType.java', [
1620 'import android.os.Build;',
1621 'some random stuff',
1622 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1623 '|| "eng".equals(Build.TYPE)',
1624 ]),
1625 MockAffectedFile('UsedExplicitBuildType.java', [
1626 'some random stuff',
1627 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1628 '|| "eng".equals(android.os.Build.TYPE)',
1629 ]),
1630 ]
Jinsong Fan91ebbbd2019-04-16 14:57:171631
Daniel Cheng566634ff2024-06-29 14:56:531632 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(mock_input_api,
1633 mock_output_api)
1634 self.assertEqual(
1635 1, len(msgs),
1636 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1637 self.assertEqual(
1638 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1639 (4, len(msgs[0].items), msgs[0].items))
1640 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1641 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1642 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1643 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
Jinsong Fan91ebbbd2019-04-16 14:57:171644
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391645
dgn4401aa52015-04-29 16:26:171646class LogUsageTest(unittest.TestCase):
1647
Daniel Cheng566634ff2024-06-29 14:56:531648 def testCheckAndroidCrLogUsage(self):
1649 mock_input_api = MockInputApi()
1650 mock_output_api = MockOutputApi()
dgnaa68d5e2015-06-10 10:08:221651
Daniel Cheng566634ff2024-06-29 14:56:531652 mock_input_api.files = [
1653 MockAffectedFile('RandomStuff.java', ['random stuff']),
1654 MockAffectedFile('HasAndroidLog.java', [
1655 'import android.util.Log;',
1656 'some random stuff',
1657 'Log.d("TAG", "foo");',
1658 ]),
1659 MockAffectedFile('HasExplicitUtilLog.java', [
1660 'some random stuff',
1661 'android.util.Log.d("TAG", "foo");',
1662 ]),
1663 MockAffectedFile('IsInBasePackage.java', [
1664 'package org.chromium.base;',
1665 'private static final String TAG = "cr_Foo";',
1666 'Log.d(TAG, "foo");',
1667 ]),
1668 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1669 'package org.chromium.base;',
1670 'import android.util.Log;',
1671 'private static final String TAG = "cr_Foo";',
1672 'Log.d(TAG, "foo");',
1673 ]),
1674 MockAffectedFile('HasBothLog.java', [
1675 'import org.chromium.base.Log;',
1676 'some random stuff',
1677 'private static final String TAG = "cr_Foo";',
1678 'Log.d(TAG, "foo");',
1679 'android.util.Log.d("TAG", "foo");',
1680 ]),
1681 MockAffectedFile('HasCorrectTag.java', [
1682 'import org.chromium.base.Log;',
1683 'some random stuff',
1684 'private static final String TAG = "cr_Foo";',
1685 'Log.d(TAG, "foo");',
1686 ]),
1687 MockAffectedFile('HasOldTag.java', [
1688 'import org.chromium.base.Log;',
1689 'some random stuff',
1690 'private static final String TAG = "cr.Foo";',
1691 'Log.d(TAG, "foo");',
1692 ]),
1693 MockAffectedFile('HasDottedTag.java', [
1694 'import org.chromium.base.Log;',
1695 'some random stuff',
1696 'private static final String TAG = "cr_foo.bar";',
1697 'Log.d(TAG, "foo");',
1698 ]),
1699 MockAffectedFile('HasDottedTagPublic.java', [
1700 'import org.chromium.base.Log;',
1701 'some random stuff',
1702 'public static final String TAG = "cr_foo.bar";',
1703 'Log.d(TAG, "foo");',
1704 ]),
1705 MockAffectedFile('HasNoTagDecl.java', [
1706 'import org.chromium.base.Log;',
1707 'some random stuff',
1708 'Log.d(TAG, "foo");',
1709 ]),
1710 MockAffectedFile('HasIncorrectTagDecl.java', [
1711 'import org.chromium.base.Log;',
1712 'private static final String TAHG = "cr_Foo";',
1713 'some random stuff',
1714 'Log.d(TAG, "foo");',
1715 ]),
1716 MockAffectedFile('HasInlineTag.java', [
1717 'import org.chromium.base.Log;',
1718 'some random stuff',
1719 'private static final String TAG = "cr_Foo";',
1720 'Log.d("TAG", "foo");',
1721 ]),
1722 MockAffectedFile('HasInlineTagWithSpace.java', [
1723 'import org.chromium.base.Log;',
1724 'some random stuff',
1725 'private static final String TAG = "cr_Foo";',
1726 'Log.d("log message", "foo");',
1727 ]),
1728 MockAffectedFile('HasUnprefixedTag.java', [
1729 'import org.chromium.base.Log;',
1730 'some random stuff',
1731 'private static final String TAG = "rubbish";',
1732 'Log.d(TAG, "foo");',
1733 ]),
1734 MockAffectedFile('HasTooLongTag.java', [
1735 'import org.chromium.base.Log;',
1736 'some random stuff',
1737 'private static final String TAG = "21_characters_long___";',
1738 'Log.d(TAG, "foo");',
1739 ]),
1740 MockAffectedFile('HasTooLongTagWithNoLogCallsInDiff.java', [
1741 'import org.chromium.base.Log;',
1742 'some random stuff',
1743 'private static final String TAG = "21_characters_long___";',
1744 ]),
1745 ]
dgnaa68d5e2015-06-10 10:08:221746
Daniel Cheng566634ff2024-06-29 14:56:531747 msgs = PRESUBMIT._CheckAndroidCrLogUsage(mock_input_api,
1748 mock_output_api)
dgnaa68d5e2015-06-10 10:08:221749
Daniel Cheng566634ff2024-06-29 14:56:531750 self.assertEqual(
1751 5, len(msgs),
1752 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
dgnaa68d5e2015-06-10 10:08:221753
Daniel Cheng566634ff2024-06-29 14:56:531754 # Declaration format
1755 nb = len(msgs[0].items)
1756 self.assertEqual(
1757 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
1758 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1759 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
dgnaa68d5e2015-06-10 10:08:221760
Daniel Cheng566634ff2024-06-29 14:56:531761 # Tag length
1762 nb = len(msgs[1].items)
1763 self.assertEqual(
1764 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[1].items))
1765 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
1766 self.assertTrue(
1767 'HasTooLongTagWithNoLogCallsInDiff.java' in msgs[1].items)
Geoff Huang77e3d6f2023-12-25 06:27:381768
Daniel Cheng566634ff2024-06-29 14:56:531769 # Tag must be a variable named TAG
1770 nb = len(msgs[2].items)
1771 self.assertEqual(
1772 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[2].items))
1773 self.assertTrue('HasBothLog.java:5' in msgs[2].items)
1774 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
1775 self.assertTrue('HasInlineTagWithSpace.java:4' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221776
Daniel Cheng566634ff2024-06-29 14:56:531777 # Util Log usage
1778 nb = len(msgs[3].items)
1779 self.assertEqual(
Sky Malice5766d282025-07-25 20:41:421780 5, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1781 self.assertTrue('HasAndroidLog.java:1' in msgs[3].items)
Daniel Cheng566634ff2024-06-29 14:56:531782 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1783 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
Sky Malice5766d282025-07-25 20:41:421784 self.assertTrue('IsInBasePackageButImportsLog.java:2' in msgs[3].items)
Daniel Cheng566634ff2024-06-29 14:56:531785 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381786
Daniel Cheng566634ff2024-06-29 14:56:531787 # Tag must not contain
1788 nb = len(msgs[4].items)
1789 self.assertEqual(
1790 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1791 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1792 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1793 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511794
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391795
estadee17314a02017-01-12 16:22:161796class GoogleAnswerUrlFormatTest(unittest.TestCase):
1797
Daniel Cheng566634ff2024-06-29 14:56:531798 def testCatchAnswerUrlId(self):
1799 input_api = MockInputApi()
1800 input_api.files = [
1801 MockFile('somewhere/file.cc', [
1802 'char* host = '
1803 ' "https://support.google.com/chrome/answer/123456";'
1804 ]),
1805 MockFile('somewhere_else/file.cc', [
1806 'char* host = '
1807 ' "https://support.google.com/chrome/a/answer/123456";'
1808 ]),
1809 ]
estadee17314a02017-01-12 16:22:161810
Daniel Cheng566634ff2024-06-29 14:56:531811 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1812 input_api, MockOutputApi())
1813 self.assertEqual(1, len(warnings))
1814 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161815
Daniel Cheng566634ff2024-06-29 14:56:531816 def testAllowAnswerUrlParam(self):
1817 input_api = MockInputApi()
1818 input_api.files = [
1819 MockFile('somewhere/file.cc', [
1820 'char* host = '
1821 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1822 ]),
1823 ]
estadee17314a02017-01-12 16:22:161824
Daniel Cheng566634ff2024-06-29 14:56:531825 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1826 input_api, MockOutputApi())
1827 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161828
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391829
reillyi38965732015-11-16 18:27:331830class HardcodedGoogleHostsTest(unittest.TestCase):
1831
Daniel Cheng566634ff2024-06-29 14:56:531832 def testWarnOnAssignedLiterals(self):
1833 input_api = MockInputApi()
1834 input_api.files = [
1835 MockFile('content/file.cc',
1836 ['char* host = "https://www.google.com";']),
1837 MockFile('content/file.cc',
1838 ['char* host = "https://www.googleapis.com";']),
1839 MockFile('content/file.cc',
1840 ['char* host = "https://clients1.google.com";']),
1841 ]
reillyi38965732015-11-16 18:27:331842
Daniel Cheng566634ff2024-06-29 14:56:531843 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1844 input_api, MockOutputApi())
1845 self.assertEqual(1, len(warnings))
1846 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331847
Daniel Cheng566634ff2024-06-29 14:56:531848 def testAllowInComment(self):
1849 input_api = MockInputApi()
1850 input_api.files = [
1851 MockFile('content/file.cc',
1852 ['char* host = "https://www.aol.com"; // google.com'])
1853 ]
reillyi38965732015-11-16 18:27:331854
Daniel Cheng566634ff2024-06-29 14:56:531855 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1856 input_api, MockOutputApi())
1857 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331858
dgn4401aa52015-04-29 16:26:171859
James Cook6b6597c2019-11-06 22:05:291860class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1861
Daniel Cheng566634ff2024-06-29 14:56:531862 def testWarnsOnChromeOsDirectories(self):
1863 files = [
1864 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1865 MockFile('chrome/browser/chromeos/file.cc',
1866 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1867 MockFile('chromeos/file.cc',
1868 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1869 MockFile('components/arc/file.cc',
1870 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1871 MockFile('components/exo/file.cc',
1872 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1873 ]
1874 input_api = MockInputApi()
1875 for file in files:
1876 input_api.files = [file]
1877 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1878 input_api, MockOutputApi())
1879 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291880
Daniel Cheng566634ff2024-06-29 14:56:531881 def testDoesNotWarnOnSyncOsPref(self):
1882 input_api = MockInputApi()
1883 input_api.files = [
1884 MockFile('chromeos/file.cc',
1885 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1886 ]
1887 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1888 input_api, MockOutputApi())
1889 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291890
Daniel Cheng566634ff2024-06-29 14:56:531891 def testDoesNotWarnOnOtherDirectories(self):
1892 input_api = MockInputApi()
1893 input_api.files = [
1894 MockFile('chrome/browser/ui/file.cc',
1895 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1896 MockFile('components/sync/file.cc',
1897 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1898 MockFile('content/browser/file.cc',
1899 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1900 MockFile('a/notchromeos/file.cc',
1901 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1902 ]
1903 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1904 input_api, MockOutputApi())
1905 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291906
Daniel Cheng566634ff2024-06-29 14:56:531907 def testSeparateWarningForPriorityPrefs(self):
1908 input_api = MockInputApi()
1909 input_api.files = [
1910 MockFile('chromeos/file.cc', [
1911 'PrefRegistrySyncable::SYNCABLE_PREF',
1912 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
1913 ]),
1914 ]
1915 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1916 input_api, MockOutputApi())
1917 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:291918
1919
jbriance9e12f162016-11-25 07:57:501920class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:501921
Daniel Cheng566634ff2024-06-29 14:56:531922 def testCheckHeadersOnlyOutsideThirdParty(self):
1923 mock_input_api = MockInputApi()
1924 mock_input_api.files = [
1925 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
1926 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
1927 ]
1928 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1929 mock_input_api, MockOutputApi())
1930 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501931
Daniel Cheng566634ff2024-06-29 14:56:531932 def testNoNestedDeclaration(self):
1933 mock_input_api = MockInputApi()
1934 mock_input_api.files = [
1935 MockAffectedFile('somewhere/header.h', [
1936 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
1937 ])
1938 ]
1939 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1940 mock_input_api, MockOutputApi())
1941 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501942
Daniel Cheng566634ff2024-06-29 14:56:531943 def testSubStrings(self):
1944 mock_input_api = MockInputApi()
1945 mock_input_api.files = [
1946 MockAffectedFile('somewhere/header.h', [
1947 'class NotUsefulClass;', 'struct SomeStruct;',
1948 'UsefulClass *p1;', 'SomeStructPtr *p2;'
1949 ])
1950 ]
1951 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1952 mock_input_api, MockOutputApi())
1953 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:501954
Daniel Cheng566634ff2024-06-29 14:56:531955 def testUselessForwardDeclaration(self):
1956 mock_input_api = MockInputApi()
1957 mock_input_api.files = [
1958 MockAffectedFile('somewhere/header.h', [
1959 'class DummyClass;', 'struct DummyStruct;',
1960 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
1961 ])
1962 ]
1963 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1964 mock_input_api, MockOutputApi())
1965 self.assertEqual(2, len(warnings))
1966
1967 def testBlinkHeaders(self):
1968 mock_input_api = MockInputApi()
1969 mock_input_api.files = [
1970 MockAffectedFile('third_party/blink/header.h', [
1971 'class DummyClass;',
1972 'struct DummyStruct;',
1973 ]),
1974 MockAffectedFile('third_party\\blink\\header.h', [
1975 'class DummyClass;',
1976 'struct DummyStruct;',
1977 ])
1978 ]
1979 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1980 mock_input_api, MockOutputApi())
1981 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:311982
jbriance9e12f162016-11-25 07:57:501983
rlanday6802cf632017-05-30 17:48:361984class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:361985
Daniel Cheng566634ff2024-06-29 14:56:531986 def testThirdPartyNotWebKitIgnored(self):
1987 mock_input_api = MockInputApi()
1988 mock_input_api.files = [
1989 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1990 MockAffectedFile('third_party/test/test.cpp',
1991 '#include "../header.h"'),
1992 ]
rlanday6802cf632017-05-30 17:48:361993
Daniel Cheng566634ff2024-06-29 14:56:531994 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:361995
Daniel Cheng566634ff2024-06-29 14:56:531996 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
1997 mock_output_api)
1998 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:361999
Daniel Cheng566634ff2024-06-29 14:56:532000 def testNonCppFileIgnored(self):
2001 mock_input_api = MockInputApi()
2002 mock_input_api.files = [
2003 MockAffectedFile('test.py', '#include "../header.h"'),
2004 ]
rlanday6802cf632017-05-30 17:48:362005
Daniel Cheng566634ff2024-06-29 14:56:532006 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362007
Daniel Cheng566634ff2024-06-29 14:56:532008 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2009 mock_output_api)
2010 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362011
Daniel Cheng566634ff2024-06-29 14:56:532012 def testInnocuousChangesAllowed(self):
2013 mock_input_api = MockInputApi()
2014 mock_input_api.files = [
2015 MockAffectedFile('test.cpp', '#include "header.h"'),
2016 MockAffectedFile('test2.cpp', '../'),
2017 ]
rlanday6802cf632017-05-30 17:48:362018
Daniel Cheng566634ff2024-06-29 14:56:532019 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362020
Daniel Cheng566634ff2024-06-29 14:56:532021 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2022 mock_output_api)
2023 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362024
Daniel Cheng566634ff2024-06-29 14:56:532025 def testRelativeIncludeNonWebKitProducesError(self):
2026 mock_input_api = MockInputApi()
2027 mock_input_api.files = [
2028 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2029 ]
rlanday6802cf632017-05-30 17:48:362030
Daniel Cheng566634ff2024-06-29 14:56:532031 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362032
Daniel Cheng566634ff2024-06-29 14:56:532033 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2034 mock_output_api)
2035 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362036
Daniel Cheng566634ff2024-06-29 14:56:532037 def testRelativeIncludeWebKitProducesError(self):
2038 mock_input_api = MockInputApi()
2039 mock_input_api.files = [
2040 MockAffectedFile('third_party/blink/test.cpp',
2041 ['#include "../header.h']),
2042 ]
rlanday6802cf632017-05-30 17:48:362043
Daniel Cheng566634ff2024-06-29 14:56:532044 mock_output_api = MockOutputApi()
2045
2046 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2047 mock_output_api)
2048 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242049
Daniel Cheng13ca61a882017-08-25 15:11:252050
Daniel Bratell65b033262019-04-23 08:17:062051class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062052
Daniel Cheng566634ff2024-06-29 14:56:532053 def testThirdPartyNotBlinkIgnored(self):
2054 mock_input_api = MockInputApi()
2055 mock_input_api.files = [
2056 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2057 ]
Daniel Bratell65b033262019-04-23 08:17:062058
Daniel Cheng566634ff2024-06-29 14:56:532059 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062060
Daniel Cheng566634ff2024-06-29 14:56:532061 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2062 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062063
Daniel Cheng566634ff2024-06-29 14:56:532064 def testPythonFileIgnored(self):
2065 mock_input_api = MockInputApi()
2066 mock_input_api.files = [
2067 MockAffectedFile('test.py', '#include "file.cc"'),
2068 ]
Daniel Bratell65b033262019-04-23 08:17:062069
Daniel Cheng566634ff2024-06-29 14:56:532070 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062071
Daniel Cheng566634ff2024-06-29 14:56:532072 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2073 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062074
Daniel Cheng566634ff2024-06-29 14:56:532075 def testIncFilesAccepted(self):
2076 mock_input_api = MockInputApi()
2077 mock_input_api.files = [
2078 MockAffectedFile('test.py', '#include "file.inc"'),
2079 ]
Daniel Bratell65b033262019-04-23 08:17:062080
Daniel Cheng566634ff2024-06-29 14:56:532081 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062082
Daniel Cheng566634ff2024-06-29 14:56:532083 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2084 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062085
Daniel Cheng566634ff2024-06-29 14:56:532086 def testInnocuousChangesAllowed(self):
2087 mock_input_api = MockInputApi()
2088 mock_input_api.files = [
2089 MockAffectedFile('test.cpp', '#include "header.h"'),
2090 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2091 ]
Daniel Bratell65b033262019-04-23 08:17:062092
Daniel Cheng566634ff2024-06-29 14:56:532093 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062094
Daniel Cheng566634ff2024-06-29 14:56:532095 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2096 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062097
Daniel Cheng566634ff2024-06-29 14:56:532098 def testCcIncludeNonBlinkProducesError(self):
2099 mock_input_api = MockInputApi()
2100 mock_input_api.files = [
2101 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2102 ]
Daniel Bratell65b033262019-04-23 08:17:062103
Daniel Cheng566634ff2024-06-29 14:56:532104 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062105
Daniel Cheng566634ff2024-06-29 14:56:532106 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2107 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062108
Daniel Cheng566634ff2024-06-29 14:56:532109 def testCppIncludeBlinkProducesError(self):
2110 mock_input_api = MockInputApi()
2111 mock_input_api.files = [
2112 MockAffectedFile('third_party/blink/test.cpp',
2113 ['#include "foo/file.cpp"']),
2114 ]
Daniel Bratell65b033262019-04-23 08:17:062115
Daniel Cheng566634ff2024-06-29 14:56:532116 mock_output_api = MockOutputApi()
2117
2118 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2119 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062120
2121
Andrew Grieve1b290e4a22020-11-24 20:07:012122class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012123
Daniel Cheng566634ff2024-06-29 14:56:532124 def testAddBareGlobs(self):
2125 mock_input_api = MockInputApi()
2126 mock_input_api.files = [
2127 MockAffectedFile('base/stuff.gni',
2128 ['forward_variables_from(invoker, "*")']),
2129 MockAffectedFile('base/BUILD.gn',
2130 ['forward_variables_from(invoker, "*")']),
2131 ]
2132 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2133 MockOutputApi())
2134 self.assertEqual(1, len(warnings))
2135 msg = '\n'.join(warnings[0].items)
2136 self.assertIn('base/stuff.gni', msg)
2137 # Should not check .gn files. Local templates don't need to care about
2138 # visibility / testonly.
2139 self.assertNotIn('base/BUILD.gn', msg)
2140
2141 def testValidUses(self):
2142 mock_input_api = MockInputApi()
2143 mock_input_api.files = [
2144 MockAffectedFile('base/stuff.gni',
2145 ['forward_variables_from(invoker, "*", [])']),
2146 MockAffectedFile('base/stuff2.gni', [
2147 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2148 ]),
2149 MockAffectedFile(
2150 'base/stuff3.gni',
2151 ['forward_variables_from(invoker, [ "testonly" ])']),
2152 ]
2153 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2154 MockOutputApi())
2155 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012156
2157
Sean Kaucb7c9b32022-10-25 21:25:522158class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522159
Daniel Cheng566634ff2024-06-29 14:56:532160 def testAddAbsolutePath(self):
2161 mock_input_api = MockInputApi()
2162 mock_input_api.files = [
2163 MockAffectedFile('base/BUILD.gn',
2164 ['rebase_path("$target_gen_dir", "//")']),
2165 MockAffectedFile('base/root/BUILD.gn',
2166 ['rebase_path("$target_gen_dir", "/")']),
2167 MockAffectedFile('base/variable/BUILD.gn',
2168 ['rebase_path(target_gen_dir, "/")']),
2169 ]
2170 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2171 self.assertEqual(1, len(warnings))
2172 msg = '\n'.join(warnings[0].items)
2173 self.assertIn('base/BUILD.gn', msg)
2174 self.assertIn('base/root/BUILD.gn', msg)
2175 self.assertIn('base/variable/BUILD.gn', msg)
2176 self.assertEqual(3, len(warnings[0].items))
2177
2178 def testValidUses(self):
2179 mock_input_api = MockInputApi()
2180 mock_input_api.files = [
2181 MockAffectedFile(
2182 'base/foo/BUILD.gn',
2183 ['rebase_path("$target_gen_dir", root_build_dir)']),
2184 MockAffectedFile(
2185 'base/bar/BUILD.gn',
2186 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2187 MockAffectedFile('base/baz/BUILD.gn',
2188 ['rebase_path(target_gen_dir, root_build_dir)']),
2189 MockAffectedFile(
2190 'base/baz/BUILD.gn',
2191 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2192 MockAffectedFile('base/okay_slash/BUILD.gn',
2193 ['rebase_path(".", "//")']),
2194 ]
2195 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2196 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522197
2198
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192199class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192200
Daniel Cheng566634ff2024-06-29 14:56:532201 def testAddHeaderWithoutGn(self):
2202 mock_input_api = MockInputApi()
2203 mock_input_api.files = [
2204 MockAffectedFile('base/stuff.h', ''),
2205 ]
2206 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2207 mock_input_api, MockOutputApi())
2208 self.assertEqual(1, len(warnings))
2209 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192210
Daniel Cheng566634ff2024-06-29 14:56:532211 def testModifyHeader(self):
2212 mock_input_api = MockInputApi()
2213 mock_input_api.files = [
2214 MockAffectedFile('base/stuff.h', '', action='M'),
2215 ]
2216 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2217 mock_input_api, MockOutputApi())
2218 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192219
Daniel Cheng566634ff2024-06-29 14:56:532220 def testDeleteHeader(self):
2221 mock_input_api = MockInputApi()
2222 mock_input_api.files = [
2223 MockAffectedFile('base/stuff.h', '', action='D'),
2224 ]
2225 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2226 mock_input_api, MockOutputApi())
2227 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192228
Daniel Cheng566634ff2024-06-29 14:56:532229 def testAddHeaderWithGn(self):
2230 mock_input_api = MockInputApi()
2231 mock_input_api.files = [
2232 MockAffectedFile('base/stuff.h', ''),
2233 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2234 ]
2235 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2236 mock_input_api, MockOutputApi())
2237 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192238
Daniel Cheng566634ff2024-06-29 14:56:532239 def testAddHeaderWithGni(self):
2240 mock_input_api = MockInputApi()
2241 mock_input_api.files = [
2242 MockAffectedFile('base/stuff.h', ''),
2243 MockAffectedFile('base/files.gni', 'stuff.h'),
2244 ]
2245 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2246 mock_input_api, MockOutputApi())
2247 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192248
Daniel Cheng566634ff2024-06-29 14:56:532249 def testAddHeaderWithOther(self):
2250 mock_input_api = MockInputApi()
2251 mock_input_api.files = [
2252 MockAffectedFile('base/stuff.h', ''),
2253 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2254 ]
2255 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2256 mock_input_api, MockOutputApi())
2257 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192258
Daniel Cheng566634ff2024-06-29 14:56:532259 def testAddHeaderWithWrongGn(self):
2260 mock_input_api = MockInputApi()
2261 mock_input_api.files = [
2262 MockAffectedFile('base/stuff.h', ''),
2263 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2264 ]
2265 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2266 mock_input_api, MockOutputApi())
2267 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192268
Daniel Cheng566634ff2024-06-29 14:56:532269 def testAddHeadersWithGn(self):
2270 mock_input_api = MockInputApi()
2271 mock_input_api.files = [
2272 MockAffectedFile('base/stuff.h', ''),
2273 MockAffectedFile('base/another.h', ''),
2274 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2275 ]
2276 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2277 mock_input_api, MockOutputApi())
2278 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192279
Daniel Cheng566634ff2024-06-29 14:56:532280 def testAddHeadersWithWrongGn(self):
2281 mock_input_api = MockInputApi()
2282 mock_input_api.files = [
2283 MockAffectedFile('base/stuff.h', ''),
2284 MockAffectedFile('base/another.h', ''),
2285 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2286 ]
2287 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2288 mock_input_api, MockOutputApi())
2289 self.assertEqual(1, len(warnings))
2290 self.assertFalse('base/stuff.h' in warnings[0].items)
2291 self.assertTrue('base/another.h' in warnings[0].items)
2292
2293 def testAddHeadersWithWrongGn2(self):
2294 mock_input_api = MockInputApi()
2295 mock_input_api.files = [
2296 MockAffectedFile('base/stuff.h', ''),
2297 MockAffectedFile('base/another.h', ''),
2298 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2299 ]
2300 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2301 mock_input_api, MockOutputApi())
2302 self.assertEqual(1, len(warnings))
2303 self.assertTrue('base/stuff.h' in warnings[0].items)
2304 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192305
2306
Michael Giuffridad3bc8672018-10-25 22:48:022307class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022308
Daniel Cheng566634ff2024-06-29 14:56:532309 def testProductNameInDesc(self):
2310 mock_input_api = MockInputApi()
2311 mock_input_api.files = [
2312 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2313 '<message name="Foo" desc="Welcome to Chrome">',
2314 ' Welcome to Chrome!',
2315 '</message>',
2316 ]),
2317 MockAffectedFile('chrome/app/chromium_strings.grd', [
2318 '<message name="Bar" desc="Welcome to Chrome">',
2319 ' Welcome to Chromium!',
2320 '</message>',
2321 ]),
2322 ]
2323 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2324 mock_input_api, MockOutputApi())
2325 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022326
Daniel Cheng566634ff2024-06-29 14:56:532327 def testChromeInChromium(self):
2328 mock_input_api = MockInputApi()
2329 mock_input_api.files = [
2330 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2331 '<message name="Foo" desc="Welcome to Chrome">',
2332 ' Welcome to Chrome!',
2333 '</message>',
2334 ]),
2335 MockAffectedFile('chrome/app/chromium_strings.grd', [
2336 '<message name="Bar" desc="Welcome to Chrome">',
2337 ' Welcome to Chrome!',
2338 '</message>',
2339 ]),
2340 ]
2341 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2342 mock_input_api, MockOutputApi())
2343 self.assertEqual(1, len(warnings))
2344 self.assertTrue(
2345 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022346
Daniel Cheng566634ff2024-06-29 14:56:532347 def testChromiumInChrome(self):
2348 mock_input_api = MockInputApi()
2349 mock_input_api.files = [
2350 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2351 '<message name="Foo" desc="Welcome to Chrome">',
2352 ' Welcome to Chromium!',
2353 '</message>',
2354 ]),
2355 MockAffectedFile('chrome/app/chromium_strings.grd', [
2356 '<message name="Bar" desc="Welcome to Chrome">',
2357 ' Welcome to Chromium!',
2358 '</message>',
2359 ]),
2360 ]
2361 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2362 mock_input_api, MockOutputApi())
2363 self.assertEqual(1, len(warnings))
2364 self.assertTrue(
2365 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202366
Daniel Cheng566634ff2024-06-29 14:56:532367 def testChromeForTestingInChromium(self):
2368 mock_input_api = MockInputApi()
2369 mock_input_api.files = [
2370 MockAffectedFile('chrome/app/chromium_strings.grd', [
2371 '<message name="Bar" desc="Welcome to Chrome">',
2372 ' Welcome to Chrome for Testing!',
2373 '</message>',
2374 ]),
2375 ]
2376 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2377 mock_input_api, MockOutputApi())
2378 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202379
Daniel Cheng566634ff2024-06-29 14:56:532380 def testChromeForTestingInChrome(self):
2381 mock_input_api = MockInputApi()
2382 mock_input_api.files = [
2383 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2384 '<message name="Bar" desc="Welcome to Chrome">',
2385 ' Welcome to Chrome for Testing!',
2386 '</message>',
2387 ]),
2388 ]
2389 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2390 mock_input_api, MockOutputApi())
2391 self.assertEqual(1, len(warnings))
2392 self.assertTrue(
2393 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022394
Daniel Cheng566634ff2024-06-29 14:56:532395 def testMultipleInstances(self):
2396 mock_input_api = MockInputApi()
2397 mock_input_api.files = [
2398 MockAffectedFile('chrome/app/chromium_strings.grd', [
2399 '<message name="Bar" desc="Welcome to Chrome">',
2400 ' Welcome to Chrome!',
2401 '</message>',
2402 '<message name="Baz" desc="A correct message">',
2403 ' Chromium is the software you are using.',
2404 '</message>',
2405 '<message name="Bat" desc="An incorrect message">',
2406 ' Google Chrome is the software you are using.',
2407 '</message>',
2408 ]),
2409 ]
2410 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2411 mock_input_api, MockOutputApi())
2412 self.assertEqual(1, len(warnings))
2413 self.assertTrue(
2414 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2415 self.assertTrue(
2416 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2417
2418 def testMultipleWarnings(self):
2419 mock_input_api = MockInputApi()
2420 mock_input_api.files = [
2421 MockAffectedFile('chrome/app/chromium_strings.grd', [
2422 '<message name="Bar" desc="Welcome to Chrome">',
2423 ' Welcome to Chrome!',
2424 '</message>',
2425 '<message name="Baz" desc="A correct message">',
2426 ' Chromium is the software you are using.',
2427 '</message>',
2428 '<message name="Bat" desc="An incorrect message">',
2429 ' Google Chrome is the software you are using.',
2430 '</message>',
2431 ]),
2432 MockAffectedFile(
2433 'components/components_google_chrome_strings.grd', [
2434 '<message name="Bar" desc="Welcome to Chrome">',
2435 ' Welcome to Chrome!',
2436 '</message>',
2437 '<message name="Baz" desc="A correct message">',
2438 ' Chromium is the software you are using.',
2439 '</message>',
2440 '<message name="Bat" desc="An incorrect message">',
2441 ' Google Chrome is the software you are using.',
2442 '</message>',
2443 ]),
2444 ]
2445 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2446 mock_input_api, MockOutputApi())
2447 self.assertEqual(2, len(warnings))
2448 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2449 warnings[0].items[0])
2450 self.assertTrue(
2451 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2452 self.assertTrue(
2453 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022454
2455
Daniel Chenga37c03db2022-05-12 17:20:342456class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252457
Daniel Cheng566634ff2024-06-29 14:56:532458 def _createMockInputApi(self):
2459 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472460
Daniel Cheng566634ff2024-06-29 14:56:532461 def FakeRepositoryRoot():
2462 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472463
Daniel Cheng566634ff2024-06-29 14:56:532464 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2465 self._injectFakeOwnersClient(
2466 mock_input_api, ['[email protected]', '[email protected]'])
2467 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342468
Daniel Cheng566634ff2024-06-29 14:56:532469 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342470
Daniel Cheng566634ff2024-06-29 14:56:532471 class FakeGerrit(object):
2472
2473 def IsOwnersOverrideApproved(self, issue):
2474 return False
2475
2476 input_api.change.issue = 123
2477 input_api.gerrit = FakeGerrit()
2478
2479 def _injectFakeOwnersClient(self, input_api, owners):
2480
2481 class FakeOwnersClient(object):
2482
2483 def ListOwners(self, f):
2484 return owners
2485
2486 input_api.owners_client = FakeOwnersClient()
2487
2488 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2489
2490 def MockOwnerAndReviewers(input_api,
2491 email_regexp,
2492 approval_needed=False):
2493 return [owner, reviewers]
2494
2495 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2496 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342497
2498
2499class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532500 _test_cases = [
2501 ('*_messages.cc', 'scary_messages.cc'),
2502 ('*_messages*.h', 'scary_messages.h'),
2503 ('*_messages*.h', 'scary_messages_android.h'),
2504 ('*_param_traits*.*', 'scary_param_traits.h'),
2505 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2506 ('*.mojom', 'scary.mojom'),
2507 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2508 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2509 ('*_type_converter*.*', 'scary_type_converter.h'),
Daniel Cheng566634ff2024-06-29 14:56:532510 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252511 ]
Daniel Cheng171dad8d2022-05-21 00:40:252512
Daniel Cheng566634ff2024-06-29 14:56:532513 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2514 mock_input_api = self._createMockInputApi()
2515 new_owners_file_path = mock_input_api.os_path.join(
2516 'services', 'goat', 'public', 'OWNERS')
2517 new_owners_file = [
2518 'per-file *.mojom=set noparent',
2519 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2520 ]
Daniel Cheng3008dc12022-05-13 04:02:112521
Daniel Cheng566634ff2024-06-29 14:56:532522 def FakeReadFile(filename):
2523 self.assertEqual(
2524 mock_input_api.os_path.join('chromium', 'src',
2525 new_owners_file_path), filename)
2526 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112527
Daniel Cheng566634ff2024-06-29 14:56:532528 mock_input_api.ReadFile = FakeReadFile
2529 mock_input_api.files = [
2530 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252531 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532532 mock_input_api.os_path.join('services', 'goat', 'public',
2533 'goat.mojom'),
2534 ['// Scary contents.'])
2535 ]
2536 self._setupFakeChange(mock_input_api)
2537 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2538 '[email protected]',
2539 ['[email protected]'])
2540 mock_input_api.is_committing = True
2541 mock_input_api.dry_run = False
2542 mock_output_api = MockOutputApi()
2543 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2544 mock_output_api)
2545 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342546
Daniel Cheng566634ff2024-06-29 14:56:532547 def testMissingSecurityReviewerAtUpload(self):
2548 mock_input_api = self._createMockInputApi()
2549 new_owners_file_path = mock_input_api.os_path.join(
2550 'services', 'goat', 'public', 'OWNERS')
2551 new_owners_file = [
2552 'per-file *.mojom=set noparent',
2553 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2554 ]
Daniel Chenga37c03db2022-05-12 17:20:342555
Daniel Cheng566634ff2024-06-29 14:56:532556 def FakeReadFile(filename):
2557 self.assertEqual(
2558 mock_input_api.os_path.join('chromium', 'src',
2559 new_owners_file_path), filename)
2560 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362561
Daniel Cheng566634ff2024-06-29 14:56:532562 mock_input_api.ReadFile = FakeReadFile
2563 mock_input_api.files = [
2564 MockAffectedFile(new_owners_file_path, new_owners_file),
2565 MockAffectedFile(
2566 mock_input_api.os_path.join('services', 'goat', 'public',
2567 'goat.mojom'),
2568 ['// Scary contents.'])
2569 ]
2570 self._setupFakeChange(mock_input_api)
2571 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2572 '[email protected]',
2573 ['[email protected]'])
2574 mock_input_api.is_committing = False
2575 mock_input_api.dry_run = False
2576 mock_output_api = MockOutputApi()
2577 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2578 mock_output_api)
2579 self.assertEqual(1, len(results))
2580 self.assertEqual('notify', results[0].type)
2581 self.assertEqual(
2582 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2583 'following newly-added files:', results[0].message)
2584
2585 def testMissingSecurityReviewerAtDryRunCommit(self):
2586 mock_input_api = self._createMockInputApi()
2587 new_owners_file_path = mock_input_api.os_path.join(
2588 'services', 'goat', 'public', 'OWNERS')
2589 new_owners_file = [
2590 'per-file *.mojom=set noparent',
2591 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2592 ]
2593
2594 def FakeReadFile(filename):
2595 self.assertEqual(
2596 mock_input_api.os_path.join('chromium', 'src',
2597 new_owners_file_path), filename)
2598 return '\n'.join(new_owners_file)
2599
2600 mock_input_api.ReadFile = FakeReadFile
2601 mock_input_api.files = [
2602 MockAffectedFile(new_owners_file_path, new_owners_file),
2603 MockAffectedFile(
2604 mock_input_api.os_path.join('services', 'goat', 'public',
2605 'goat.mojom'),
2606 ['// Scary contents.'])
2607 ]
2608 self._setupFakeChange(mock_input_api)
2609 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2610 '[email protected]',
2611 ['[email protected]'])
2612 mock_input_api.is_committing = True
2613 mock_input_api.dry_run = True
2614 mock_output_api = MockOutputApi()
2615 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2616 mock_output_api)
2617 self.assertEqual(1, len(results))
2618 self.assertEqual('error', results[0].type)
2619 self.assertEqual(
2620 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2621 'following newly-added files:', results[0].message)
2622
2623 def testMissingSecurityApprovalAtRealCommit(self):
2624 mock_input_api = self._createMockInputApi()
2625 new_owners_file_path = mock_input_api.os_path.join(
2626 'services', 'goat', 'public', 'OWNERS')
2627 new_owners_file = [
2628 'per-file *.mojom=set noparent',
2629 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2630 ]
2631
2632 def FakeReadFile(filename):
2633 self.assertEqual(
2634 mock_input_api.os_path.join('chromium', 'src',
2635 new_owners_file_path), filename)
2636 return '\n'.join(new_owners_file)
2637
2638 mock_input_api.ReadFile = FakeReadFile
2639 mock_input_api.files = [
2640 MockAffectedFile(new_owners_file_path, new_owners_file),
2641 MockAffectedFile(
2642 mock_input_api.os_path.join('services', 'goat', 'public',
2643 'goat.mojom'),
2644 ['// Scary contents.'])
2645 ]
2646 self._setupFakeChange(mock_input_api)
2647 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2648 '[email protected]',
2649 ['[email protected]'])
2650 mock_input_api.is_committing = True
2651 mock_input_api.dry_run = False
2652 mock_output_api = MockOutputApi()
2653 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2654 mock_output_api)
2655 self.assertEqual('error', results[0].type)
2656 self.assertEqual(
2657 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2658 'following newly-added files:', results[0].message)
2659
2660 def testIpcChangeNeedsSecurityOwner(self):
2661 for is_committing in [True, False]:
2662 for pattern, filename in self._test_cases:
2663 with self.subTest(
2664 line=
2665 f'is_committing={is_committing}, filename={filename}'):
2666 mock_input_api = self._createMockInputApi()
2667 mock_input_api.files = [
2668 MockAffectedFile(
2669 mock_input_api.os_path.join(
2670 'services', 'goat', 'public', filename),
2671 ['// Scary contents.'])
2672 ]
2673 self._setupFakeChange(mock_input_api)
2674 self._injectFakeChangeOwnerAndReviewers(
2675 mock_input_api, '[email protected]',
2676 ['[email protected]'])
2677 mock_input_api.is_committing = is_committing
2678 mock_input_api.dry_run = False
2679 mock_output_api = MockOutputApi()
2680 results = PRESUBMIT.CheckSecurityOwners(
2681 mock_input_api, mock_output_api)
2682 self.assertEqual(1, len(results))
2683 self.assertEqual('error', results[0].type)
2684 self.assertTrue(results[0].message.replace(
2685 '\\', '/'
2686 ).startswith(
2687 'Found missing OWNERS lines for security-sensitive files. '
2688 'Please add the following lines to services/goat/public/OWNERS:'
2689 ))
2690 self.assertEqual(['[email protected]'],
2691 mock_output_api.more_cc)
2692
2693 def testServiceManifestChangeNeedsSecurityOwner(self):
2694 mock_input_api = self._createMockInputApi()
2695 mock_input_api.files = [
2696 MockAffectedFile(
2697 mock_input_api.os_path.join('services', 'goat', 'public',
2698 'cpp', 'manifest.cc'),
2699 [
2700 '#include "services/goat/public/cpp/manifest.h"',
2701 'const service_manager::Manifest& GetManifest() {}',
2702 ])
2703 ]
2704 self._setupFakeChange(mock_input_api)
2705 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2706 '[email protected]',
2707 ['[email protected]'])
2708 mock_output_api = MockOutputApi()
2709 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2710 self.assertEqual(1, len(errors))
2711 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2712 'Found missing OWNERS lines for security-sensitive files. '
2713 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2714 ))
2715 self.assertEqual(['[email protected]'],
2716 mock_output_api.more_cc)
2717
2718 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2719 mock_input_api = self._createMockInputApi()
2720 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2721 '[email protected]',
2722 ['[email protected]'])
2723 mock_input_api.files = [
2724 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2725 'const char kNoEnforcement[] = "not a manifest!";',
2726 ])
2727 ]
2728 mock_output_api = MockOutputApi()
2729 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2730 self.assertEqual([], errors)
2731 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032732
2733
Daniel Chenga37c03db2022-05-12 17:20:342734class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032735
Daniel Cheng566634ff2024-06-29 14:56:532736 def testFidlChangeNeedsSecurityOwner(self):
2737 mock_input_api = self._createMockInputApi()
2738 mock_input_api.files = [
2739 MockAffectedFile('potentially/scary/ipc.fidl',
2740 ['library test.fidl'])
2741 ]
2742 self._setupFakeChange(mock_input_api)
2743 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2744 '[email protected]',
2745 ['[email protected]'])
2746 mock_output_api = MockOutputApi()
2747 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2748 self.assertEqual(1, len(errors))
2749 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2750 'Found missing OWNERS lines for security-sensitive files. '
2751 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032752
Daniel Cheng566634ff2024-06-29 14:56:532753 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2754 mock_input_api = self._createMockInputApi()
2755 mock_input_api.files = [
2756 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2757 ['{ "that is no": "manifest!" }'])
2758 ]
2759 self._setupFakeChange(mock_input_api)
2760 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2761 '[email protected]',
2762 ['[email protected]'])
2763 mock_output_api = MockOutputApi()
2764 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2765 self.assertEqual(1, len(errors))
2766 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2767 'Found missing OWNERS lines for security-sensitive files. '
2768 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032769
Daniel Cheng566634ff2024-06-29 14:56:532770 def testComponentManifestV2NeedsSecurityOwner(self):
2771 mock_input_api = self._createMockInputApi()
2772 mock_input_api.files = [
2773 MockAffectedFile('potentially/scary/v2_manifest.cml',
2774 ['{ "that is no": "manifest!" }'])
2775 ]
2776 self._setupFakeChange(mock_input_api)
2777 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2778 '[email protected]',
2779 ['[email protected]'])
2780 mock_output_api = MockOutputApi()
2781 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2782 self.assertEqual(1, len(errors))
2783 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2784 'Found missing OWNERS lines for security-sensitive files. '
2785 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092786
Daniel Cheng566634ff2024-06-29 14:56:532787 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2788 mock_input_api = MockInputApi()
2789 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2790 '[email protected]',
2791 ['[email protected]'])
2792 mock_input_api.files = [
2793 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2794 'const char kNoEnforcement[] = "Security?!? Pah!";',
2795 ])
2796 ]
2797 mock_output_api = MockOutputApi()
2798 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2799 self.assertEqual([], errors)
2800
2801 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2802 mock_input_api = MockInputApi()
2803 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2804 '[email protected]',
2805 ['[email protected]'])
2806 mock_input_api.files = [
2807 MockAffectedFile(
2808 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2809 'const char kNoEnforcement[] = "Security?!? Pah!";',
2810 ])
2811 ]
2812 mock_output_api = MockOutputApi()
2813 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2814 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362815
Daniel Cheng13ca61a882017-08-25 15:11:252816
Daniel Chenga37c03db2022-05-12 17:20:342817class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132818
Daniel Cheng566634ff2024-06-29 14:56:532819 def testDiffGetServiceSandboxType(self):
2820 mock_input_api = MockInputApi()
2821 mock_input_api.files = [
2822 MockAffectedFile('services/goat/teleporter_host.cc', [
2823 'template <>', 'inline content::SandboxType',
2824 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2825 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2826 '#else', ' return SandboxType::kNoSandbox;',
2827 '#endif // !defined(OS_WIN)', '}'
2828 ]),
2829 ]
2830 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2831 mock_input_api)
2832 self.assertEqual(
2833 {
2834 'services/goat/teleporter_host.cc':
2835 set(['content::GetServiceSandboxType<>()'])
2836 }, files_to_functions)
2837
2838 def testDiffRemovingLine(self):
2839 mock_input_api = MockInputApi()
2840 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2841 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132842+++ new 2020-05-04 14:08:32.000000000 -0400
2843@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372844 template <>
2845 inline content::SandboxType
2846-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2847 #if defined(OS_WIN)
2848 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132849"""
Daniel Cheng566634ff2024-06-29 14:56:532850 mock_input_api.files = [mock_file]
2851 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2852 mock_input_api)
2853 self.assertEqual(
2854 {
2855 'services/goat/teleporter_host.cc':
2856 set(['content::GetServiceSandboxType<>()'])
2857 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132858
Daniel Cheng566634ff2024-06-29 14:56:532859 def testChangeOwnersMissing(self):
2860 mock_input_api = self._createMockInputApi()
2861 self._setupFakeChange(mock_input_api)
2862 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2863 '[email protected]',
2864 ['[email protected]'])
2865 mock_input_api.is_committing = False
2866 mock_input_api.files = [
2867 MockAffectedFile('file.cc',
2868 ['GetServiceSandboxType<Goat>(Sandbox)'])
2869 ]
2870 mock_output_api = MockOutputApi()
2871 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2872 mock_output_api)
2873 self.assertEqual(1, len(result))
2874 self.assertEqual(result[0].type, 'notify')
2875 self.assertEqual(result[0].message,
2876 'The following files change calls to security-sensitive functions\n' \
2877 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2878 ' file.cc\n'
2879 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132880
Daniel Cheng566634ff2024-06-29 14:56:532881 def testChangeOwnersMissingAtCommit(self):
2882 mock_input_api = self._createMockInputApi()
2883 self._setupFakeChange(mock_input_api)
2884 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2885 '[email protected]',
2886 ['[email protected]'])
2887 mock_input_api.is_committing = True
2888 mock_input_api.dry_run = False
2889 mock_input_api.files = [
2890 MockAffectedFile('file.cc',
2891 ['GetServiceSandboxType<mojom::Goat>()'])
2892 ]
2893 mock_output_api = MockOutputApi()
2894 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2895 mock_output_api)
2896 self.assertEqual(1, len(result))
2897 self.assertEqual(result[0].type, 'error')
2898 self.assertEqual(result[0].message,
2899 'The following files change calls to security-sensitive functions\n' \
2900 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2901 ' file.cc\n'
2902 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132903
Daniel Cheng566634ff2024-06-29 14:56:532904 def testChangeOwnersPresent(self):
2905 mock_input_api = self._createMockInputApi()
2906 self._injectFakeChangeOwnerAndReviewers(
2907 mock_input_api, '[email protected]',
2908 ['[email protected]', '[email protected]'])
2909 mock_input_api.files = [
2910 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2911 ]
2912 mock_output_api = MockOutputApi()
2913 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2914 mock_output_api)
2915 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132916
Daniel Cheng566634ff2024-06-29 14:56:532917 def testChangeOwnerIsSecurityOwner(self):
2918 mock_input_api = self._createMockInputApi()
2919 self._setupFakeChange(mock_input_api)
2920 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2921 '[email protected]',
2922 ['[email protected]'])
2923 mock_input_api.files = [
2924 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
2925 ]
2926 mock_output_api = MockOutputApi()
2927 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2928 mock_output_api)
2929 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132930
2931
Mario Sanchez Prada2472cab2019-09-18 10:58:312932class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:292933
Daniel Cheng566634ff2024-06-29 14:56:532934 def testBannedJsFunctions(self):
2935 input_api = MockInputApi()
2936 input_api.files = [
2937 MockFile('ash/webui/file.js', ['chrome.send(something);']),
2938 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
2939 ]
Clement Yan9b330cb2022-11-17 05:25:292940
Daniel Cheng566634ff2024-06-29 14:56:532941 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542942
Daniel Cheng566634ff2024-06-29 14:56:532943 self.assertEqual(1, len(results))
2944 self.assertTrue('ash/webui/file.js' in results[0].message)
2945 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:262946
Daniel Cheng566634ff2024-06-29 14:56:532947 def testBannedJavaFunctions(self):
2948 input_api = MockInputApi()
2949 input_api.files = [
2950 MockFile('some/java/problematic/diskread.java',
2951 ['StrictMode.allowThreadDiskReads();']),
2952 MockFile('some/java/problematic/diskwrite.java',
2953 ['StrictMode.allowThreadDiskWrites();']),
2954 MockFile('some/java/ok/diskwrite.java',
2955 ['StrictModeContext.allowDiskWrites();']),
2956 MockFile('some/java/problematic/waitidleforsync.java',
2957 ['instrumentation.waitForIdleSync();']),
2958 MockFile('some/java/problematic/registerreceiver.java',
2959 ['context.registerReceiver();']),
2960 MockFile('some/java/problematic/property.java',
2961 ['new Property<abc, Integer>;']),
2962 MockFile('some/java/problematic/requestlayout.java',
2963 ['requestLayout();']),
2964 MockFile('some/java/problematic/lastprofile.java',
2965 ['ProfileManager.getLastUsedRegularProfile();']),
2966 MockFile('some/java/problematic/getdrawable1.java',
2967 ['ResourcesCompat.getDrawable();']),
2968 MockFile('some/java/problematic/getdrawable2.java',
2969 ['getResources().getDrawable();']),
Jenna Himawan859865d2025-02-25 22:22:312970 MockFile('some/java/problematic/announceForAccessibility.java',
2971 ['view.announceForAccessibility(accessibilityText);']),
2972 MockFile(
2973 'some/java/problematic/accessibilityTypeAnnouncement.java', [
2974 'accessibilityEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);'
2975 ]),
Sirisha Kavuluru042e4772025-07-03 02:41:092976 MockFile(
Nate Fischerd541ff82025-03-11 21:34:192977 'content/java/problematic/desktopandroid.java', [
Sirisha Kavuluru042e4772025-07-03 02:41:092978 'if (DeviceInfo.isDesktop()) {}'
Nate Fischerd541ff82025-03-11 21:34:192979 ]),
Daniel Cheng566634ff2024-06-29 14:56:532980 ]
Min Qinbc44383c2023-02-22 17:25:262981
Daniel Cheng566634ff2024-06-29 14:56:532982 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:152983 self.assertEqual(12, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:532984 self.assertTrue(
2985 'some/java/problematic/diskread.java' in errors[0].message)
2986 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152987 'some/java/problematic/diskwrite.java' in errors[1].message)
2988 self.assertTrue(all('some/java/ok/diskwrite.java' not in e.message for e in errors))
Daniel Cheng566634ff2024-06-29 14:56:532989 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152990 'some/java/problematic/waitidleforsync.java' in errors[2].message)
Daniel Cheng566634ff2024-06-29 14:56:532991 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152992 'some/java/problematic/registerreceiver.java' in errors[3].message)
Daniel Cheng566634ff2024-06-29 14:56:532993 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152994 'some/java/problematic/property.java' in errors[4].message)
Daniel Cheng566634ff2024-06-29 14:56:532995 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152996 'some/java/problematic/requestlayout.java' in errors[5].message)
Daniel Cheng566634ff2024-06-29 14:56:532997 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152998 'some/java/problematic/lastprofile.java' in errors[6].message)
Daniel Cheng566634ff2024-06-29 14:56:532999 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153000 'some/java/problematic/getdrawable1.java' in errors[7].message)
Daniel Cheng566634ff2024-06-29 14:56:533001 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153002 'some/java/problematic/getdrawable2.java' in errors[8].message)
Jenna Himawan859865d2025-02-25 22:22:313003 self.assertTrue('some/java/problematic/announceForAccessibility.java'
Ben Pastenee79d66112025-04-23 19:46:153004 in errors[9].message)
Jenna Himawan859865d2025-02-25 22:22:313005 self.assertTrue(
3006 'some/java/problematic/accessibilityTypeAnnouncement.java' in
Ben Pastenee79d66112025-04-23 19:46:153007 errors[10].message)
Nate Fischerd541ff82025-03-11 21:34:193008 self.assertTrue(
3009 'content/java/problematic/desktopandroid.java' in
Ben Pastenee79d66112025-04-23 19:46:153010 errors[11].message)
Jenna Himawan859865d2025-02-25 22:22:313011
Peter Kasting94a56c42019-10-25 21:54:043012
Daniel Cheng566634ff2024-06-29 14:56:533013 def testBannedCppFunctions(self):
3014 input_api = MockInputApi()
3015 input_api.files = [
3016 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
3017 MockFile('third_party/blink/problematic/file.cc',
3018 ['GetInterfaceProvider()']),
3019 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
Daniel Cheng566634ff2024-06-29 14:56:533020 MockFile('some/cpp/nocheck/file.cc',
3021 ['using namespace std; // nocheck']),
3022 MockFile('some/cpp/comment/file.cc',
3023 [' // A comment about `using namespace std;`']),
Peter Kasting13607932025-04-10 22:52:383024 MockFile('some/cpp/problematic/file2.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533025 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3026 ]),
Peter Kasting13607932025-04-10 22:52:383027 MockFile('some/cpp/problematic/file3.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533028 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3029 ]),
Peter Kasting13607932025-04-10 22:52:383030 MockFile('some/cpp/problematic/file4.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533031 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3032 ]),
Daniel Cheng70a35272025-05-06 16:41:343033 MockFile(
3034 'allowed_ranges_usage.cc',
3035 [
3036 'std::ranges::begin(vec);',
Michael Tang626d8982025-05-08 23:24:293037 'std::ranges::subrange(first, last);',
Daniel Cheng70a35272025-05-06 16:41:343038 # std::ranges::view is a concept and allowed, but the views
3039 # library itself is not (see below)
3040 'static_assert(std::ranges::view<SomeType>);'
3041 ]),
3042 MockFile(
3043 'banned_ranges_usage.cc',
3044 [
Michael Tang626d8982025-05-08 23:24:293045 'std::ranges::borrowed_subrange_t(subrange);',
Daniel Cheng70a35272025-05-06 16:41:343046 # Edge case: make sure std::ranges::views is disallowed,
3047 # even though std::ranges::view is allowed.
3048 'std::ranges::views::take(first, count);'
3049 ]),
Daniel Cheng89719222024-07-04 04:59:293050 MockFile('views_usage.cc', ['std::views::all(vec)']),
Daniel Cheng70a35272025-05-06 16:41:343051 MockFile('content/desktop_android.cc', [
3052 '// some first line',
3053 '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
3054 '// some third line',
3055 ]),
Daniel Cheng566634ff2024-06-29 14:56:533056 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163057
Daniel Cheng566634ff2024-06-29 14:56:533058 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043059
Ben Pastenee79d66112025-04-23 19:46:153060 # Each entry in results corresponds to a BanRule with a violation, in
3061 # the order they were encountered.
Daniel Cheng70a35272025-05-06 16:41:343062 self.assertEqual(9, len(results))
Ben Pastenee79d66112025-04-23 19:46:153063 self.assertTrue('some/cpp/problematic/file.cc' in results[0].message)
Daniel Cheng566634ff2024-06-29 14:56:533064 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153065 'third_party/blink/problematic/file.cc' in results[1].message)
3066 self.assertTrue(all('some/cpp/ok/file.cc' not in r.message for r in results))
3067 self.assertTrue('some/cpp/problematic/file2.cc' in results[2].message)
3068 self.assertTrue('some/cpp/problematic/file3.cc' in results[3].message)
3069 self.assertTrue('some/cpp/problematic/file4.cc' in results[4].message)
3070 self.assertTrue(all('some/cpp/nocheck/file.cc' not in r.message for r in results))
3071 self.assertTrue(all('some/cpp/comment/file.cc' not in r.message for r in results))
3072 self.assertTrue(all('allowed_ranges_usage.cc' not in r.message for r in results))
3073 self.assertTrue('banned_ranges_usage.cc' in results[5].message)
Daniel Cheng70a35272025-05-06 16:41:343074 self.assertTrue('banned_ranges_usage.cc' in results[6].message)
3075 self.assertTrue('views_usage.cc' in results[7].message)
3076 self.assertTrue('content/desktop_android.cc' in results[8].message)
Ben Pastenee79d66112025-04-23 19:46:153077
3078 # Check ResultLocation data. Line nums start at 1.
Daniel Cheng70a35272025-05-06 16:41:343079 self.assertEqual(results[8].locations[0].file_path,
3080 'content/desktop_android.cc')
3081 self.assertEqual(results[8].locations[0].start_line, 2)
3082 self.assertEqual(results[8].locations[0].end_line, 2)
Daniel Cheng192683f2022-11-01 20:52:443083
Daniel Cheng566634ff2024-06-29 14:56:533084 def testBannedCppRandomFunctions(self):
3085 banned_rngs = [
3086 'absl::BitGen',
3087 'absl::InsecureBitGen',
3088 'std::linear_congruential_engine',
3089 'std::mersenne_twister_engine',
3090 'std::subtract_with_carry_engine',
3091 'std::discard_block_engine',
3092 'std::independent_bits_engine',
3093 'std::shuffle_order_engine',
3094 'std::minstd_rand0',
3095 'std::minstd_rand',
3096 'std::mt19937',
3097 'std::mt19937_64',
3098 'std::ranlux24_base',
3099 'std::ranlux48_base',
3100 'std::ranlux24',
3101 'std::ranlux48',
3102 'std::knuth_b',
3103 'std::default_random_engine',
3104 'std::random_device',
3105 ]
3106 for banned_rng in banned_rngs:
3107 input_api = MockInputApi()
3108 input_api.files = [
3109 MockFile('some/cpp/problematic/file.cc',
3110 [f'{banned_rng} engine;']),
3111 MockFile('third_party/blink/problematic/file.cc',
3112 [f'{banned_rng} engine;']),
3113 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3114 ]
3115 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3116 MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153117 self.assertEqual(2, len(results), banned_rng)
Daniel Cheng566634ff2024-06-29 14:56:533118 self.assertTrue(
3119 'some/cpp/problematic/file.cc' in results[0].message,
3120 banned_rng)
3121 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153122 'third_party/blink/problematic/file.cc' in results[1].message,
Daniel Cheng566634ff2024-06-29 14:56:533123 banned_rng)
Ben Pastenee79d66112025-04-23 19:46:153124 self.assertTrue(all('third_party/ok/file.cc' not in r.message for r in results))
Sylvain Defresnea8b73d252018-02-28 15:45:543125
Daniel Cheng566634ff2024-06-29 14:56:533126 def testBannedIosObjcFunctions(self):
3127 input_api = MockInputApi()
3128 input_api.files = [
3129 MockFile('some/ios/file.mm',
3130 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3131 MockFile('some/mac/file.mm',
3132 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3133 MockFile('another/ios_file.mm',
3134 ['class SomeTest : public testing::Test {};']),
3135 MockFile(
3136 'some/ios/file_egtest.mm',
3137 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3138 MockFile('some/ios/file_unittest.mm', [
3139 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3140 ]),
3141 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543142
Daniel Cheng566634ff2024-06-29 14:56:533143 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153144 self.assertEqual(3, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:533145 self.assertTrue('some/ios/file.mm' in errors[0].message)
Ben Pastenee79d66112025-04-23 19:46:153146 self.assertTrue('another/ios_file.mm' in errors[1].message)
3147 self.assertTrue(all('some/mac/file.mm' not in e.message for e in errors))
3148 self.assertTrue('some/ios/file_egtest.mm' in errors[2].message)
3149 self.assertTrue(all('some/ios/file_unittest.mm' not in e.message for e in errors))
Carlos Knippschildab192b8c2019-04-08 20:02:383150
Daniel Cheng566634ff2024-06-29 14:56:533151 def testBannedMojoFunctions(self):
3152 input_api = MockInputApi()
3153 input_api.files = [
3154 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3155 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3156 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3157 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223158
Daniel Cheng566634ff2024-06-29 14:56:533159 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383160
Ben Pastenee79d66112025-04-23 19:46:153161 # Each entry in results corresponds to a BanRule with a violation, in
3162 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533163 self.assertEqual(1, len(results))
3164 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3165 self.assertTrue(
3166 'third_party/blink/ok/file3.cc' not in results[0].message)
3167 self.assertTrue(
3168 'content/renderer/ok/file3.cc' not in results[0].message)
3169
Justin Lulejian09fd06872025-04-01 22:03:283170 def testBannedMojomPatterns_SharedBuffer(self):
Daniel Cheng566634ff2024-06-29 14:56:533171 input_api = MockInputApi()
3172 input_api.files = [
3173 MockFile(
3174 'bad.mojom',
3175 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3176 MockFile('good.mojom', [
3177 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223178 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3179 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533180 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3181 ]),
3182 ]
Daniel Cheng92c15e32022-03-16 17:48:223183
Daniel Cheng566634ff2024-06-29 14:56:533184 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223185
Ben Pastenee79d66112025-04-23 19:46:153186 # Each entry in results corresponds to a BanRule with a violation, in
3187 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533188 self.assertEqual(1, len(results))
3189 self.assertTrue('bad.mojom' in results[0].message)
3190 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223191
Justin Lulejian09fd06872025-04-01 22:03:283192 def testBannedMojomPatterns_ExtensionId(self):
3193 input_api = MockInputApi()
3194 input_api.files = [
3195 # Pattern tests.
3196 MockFile('extensions/bad.mojom', ['string extension_id']),
3197 MockFile('extensions/bad_struct.mojom',
3198 ['struct Bad {', ' string extension_id;', '};']),
3199 MockFile('extensions/good.mojom', ['ExtensionId extension_id']),
3200 MockFile('extensions/good_struct.mojom',
3201 ['struct Bad {', ' ExtensionId extension_id;', '};']),
3202
3203 # Path exclusion tests.
3204 MockFile('some/included/extensions/path/bad_extension_id.mojom',
3205 ['string extension_id']),
3206 MockFile('some/excluded/path/bad_extension_id.mojom',
3207 ['string extension_id']),
3208 ]
3209
Ben Pastenee79d66112025-04-23 19:46:153210 # Each entry in results corresponds to a BanRule with a violation, in
3211 # the order they were encountered.
Justin Lulejian09fd06872025-04-01 22:03:283212 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3213
Ben Pastenee79d66112025-04-23 19:46:153214 self.assertEqual(3, len(results))
Justin Lulejian09fd06872025-04-01 22:03:283215
3216 # Pattern test assertions.
3217 self.assertTrue('bad.mojom' in results[0].message)
Ben Pastenee79d66112025-04-23 19:46:153218 self.assertTrue('bad_struct.mojom' in results[1].message)
3219 self.assertTrue(all('good.mojom' not in r.message for r in results))
3220 self.assertTrue(all('good_struct.mojom' not in r.message for r in results))
Justin Lulejian09fd06872025-04-01 22:03:283221
3222 # Path exclusion assertions.
3223 self.assertTrue('some/included/extensions/path/bad_extension_id.mojom'
Ben Pastenee79d66112025-04-23 19:46:153224 in results[2].message)
3225 self.assertTrue(all('some/excluded/path/bad_extension_id.mojom' not in r.message for r in results))
3226
Justin Lulejian09fd06872025-04-01 22:03:283227
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273228class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243229
Daniel Cheng566634ff2024-06-29 14:56:533230 def testTruePositives(self):
3231 mock_input_api = MockInputApi()
3232 mock_input_api.files = [
3233 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3234 MockFile('some/path/foo.mm', ['FooForTesting();']),
3235 MockFile('some/path/foo.cxx', ['FooForTests();']),
3236 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3237 ]
Vaclav Brozekf01ed502018-03-16 19:38:243238
Daniel Cheng566634ff2024-06-29 14:56:533239 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3240 mock_input_api, MockOutputApi())
3241 self.assertEqual(1, len(results))
3242 self.assertEqual(4, len(results[0].items))
3243 self.assertTrue('foo.cc' in results[0].items[0])
3244 self.assertTrue('foo.mm' in results[0].items[1])
3245 self.assertTrue('foo.cxx' in results[0].items[2])
3246 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243247
Daniel Cheng566634ff2024-06-29 14:56:533248 def testFalsePositives(self):
3249 mock_input_api = MockInputApi()
3250 mock_input_api.files = [
3251 MockFile('some/path/foo.h', ['foo_for_testing();']),
3252 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3253 MockFile('some/path/foo.cc', ['::FooForTests();']),
3254 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3255 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3256 ]
Vaclav Brozekf01ed502018-03-16 19:38:243257
Daniel Cheng566634ff2024-06-29 14:56:533258 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3259 mock_input_api, MockOutputApi())
3260 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133261
Daniel Cheng566634ff2024-06-29 14:56:533262 def testAllowedFiles(self):
3263 mock_input_api = MockInputApi()
3264 mock_input_api.files = [
3265 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3266 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3267 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3268 ]
3269
3270 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3271 mock_input_api, MockOutputApi())
3272 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133273
Vaclav Brozekf01ed502018-03-16 19:38:243274
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273275class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233276
Daniel Cheng566634ff2024-06-29 14:56:533277 def testTruePositives(self):
3278 mock_input_api = MockInputApi()
3279 mock_input_api.files = [
3280 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3281 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3282 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3283 MockFile('dir/java/src/mult.java', [
3284 'int x = SomethingLongHere()',
3285 ' * SomethingLongHereForTesting();'
3286 ])
3287 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233288
Daniel Cheng566634ff2024-06-29 14:56:533289 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3290 mock_input_api, MockOutputApi())
3291 self.assertEqual(1, len(results))
3292 self.assertEqual(4, len(results[0].items))
3293 self.assertTrue('foo.java' in results[0].items[0])
3294 self.assertTrue('bar.java' in results[0].items[1])
3295 self.assertTrue('baz.java' in results[0].items[2])
3296 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233297
Daniel Cheng566634ff2024-06-29 14:56:533298 def testFalsePositives(self):
3299 mock_input_api = MockInputApi()
3300 mock_input_api.files = [
3301 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3302 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3303 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3304 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3305 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3306 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3307 MockFile('dir/java/src/bar5.java', [
3308 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3309 ]),
3310 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3311 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3312 MockFile('dir/junit/src/javadoc.java',
3313 ['/** Use FooForTest(); to obtain foo in tests.'
3314 ' */']),
3315 MockFile(
3316 'dir/junit/src/javadoc2.java',
3317 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3318 ' */']),
3319 MockFile('dir/java/src/bar6.java',
3320 ['FooForTesting(); // IN-TEST']),
3321 ]
3322
3323 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3324 mock_input_api, MockOutputApi())
3325 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233326
3327
Mohamed Heikald048240a2019-11-12 16:57:373328class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373329
Daniel Cheng566634ff2024-06-29 14:56:533330 def testTruePositives(self):
3331 mock_input_api = MockInputApi()
3332 mock_input_api.files = [
3333 MockFile('dir/android/res/drawable/foo.png', []),
3334 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3335 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3336 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3337 ]
Mohamed Heikald048240a2019-11-12 16:57:373338
Daniel Cheng566634ff2024-06-29 14:56:533339 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3340 MockOutputApi())
3341 self.assertEqual(1, len(results))
3342 self.assertEqual(4, len(results[0].items))
3343 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3344 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3345 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3346 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373347
Daniel Cheng566634ff2024-06-29 14:56:533348 def testFalsePositives(self):
3349 mock_input_api = MockInputApi()
3350 mock_input_api.files = [
3351 MockFile('dir/pngs/README.md', []),
3352 MockFile('java/test/res/drawable/foo.png', []),
3353 MockFile('third_party/blink/foo.png', []),
3354 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3355 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3356 ]
3357
3358 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3359 MockOutputApi())
3360 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373361
Evan Stade7cd4a2c2022-08-04 23:37:253362class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253363
Daniel Cheng566634ff2024-06-29 14:56:533364 def test(self):
3365 mock_input_api = MockInputApi()
3366 mock_input_api.files = [
3367 MockFile('components/vector_icons/google_jetpack.icon', []),
3368 MockFile('components/vector_icons/generic_jetpack.icon', []),
3369 ]
3370
3371 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3372 mock_input_api, MockOutputApi())
3373 self.assertEqual(1, len(results))
3374 self.assertEqual(1, len(results[0].items))
3375 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373376
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273377class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053378
Daniel Cheng566634ff2024-06-29 14:56:533379 def testTruePositivesNullptr(self):
3380 mock_input_api = MockInputApi()
3381 mock_input_api.files = [
3382 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3383 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3384 ]
Vaclav Brozek851d9602018-04-04 16:13:053385
Daniel Cheng566634ff2024-06-29 14:56:533386 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3387 MockOutputApi())
3388 self.assertEqual(1, len(results))
3389 self.assertTrue('nullptr' in results[0].message)
3390 self.assertEqual(2, len(results[0].items))
3391 self.assertTrue('baz.cc' in results[0].items[0])
3392 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243393
Daniel Cheng566634ff2024-06-29 14:56:533394 def testTruePositivesConstructor(self):
3395 mock_input_api = MockInputApi()
3396 mock_input_api.files = [
3397 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3398 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3399 MockFile('dir/mult.cc', [
3400 'return',
3401 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3402 ]),
3403 MockFile('dir/mult2.cc', [
3404 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3405 ' std::unique_ptr<T>(foo);'
3406 ]),
3407 MockFile('dir/mult3.cc', [
3408 'bar = std::unique_ptr<T>(',
3409 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3410 ]),
3411 MockFile('dir/multi_arg.cc', [
3412 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3413 ]),
3414 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243415
Daniel Cheng566634ff2024-06-29 14:56:533416 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3417 MockOutputApi())
3418 self.assertEqual(1, len(results))
3419 self.assertTrue('std::make_unique' in results[0].message)
3420 self.assertEqual(6, len(results[0].items))
3421 self.assertTrue('foo.cc' in results[0].items[0])
3422 self.assertTrue('bar.mm' in results[0].items[1])
3423 self.assertTrue('mult.cc' in results[0].items[2])
3424 self.assertTrue('mult2.cc' in results[0].items[3])
3425 self.assertTrue('mult3.cc' in results[0].items[4])
3426 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533427
Daniel Cheng566634ff2024-06-29 14:56:533428 def testFalsePositives(self):
3429 mock_input_api = MockInputApi()
3430 mock_input_api.files = [
3431 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3432 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3433 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3434 MockFile('dir/baz.cc',
3435 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3436 MockFile('dir/baz2.cc',
3437 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3438 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3439 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3440 # Changed line is inside a multiline template block.
3441 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3442 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243443
Daniel Cheng566634ff2024-06-29 14:56:533444 # Two-argument invocation of std::unique_ptr is exempt because there is
3445 # no equivalent using std::make_unique.
3446 MockFile('dir/multi_arg.cc',
3447 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3448 ]
3449
3450 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3451 MockOutputApi())
3452 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243453
Danil Chapovalov3518f362018-08-11 16:13:433454class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433455
Daniel Cheng566634ff2024-06-29 14:56:533456 def testBlocksDirectIncludes(self):
3457 mock_input_api = MockInputApi()
3458 mock_input_api.files = [
3459 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3460 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3461 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3462 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3463 ]
3464 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3465 MockOutputApi())
3466 self.assertEqual(1, len(results))
3467 self.assertEqual(4, len(results[0].items))
3468 self.assertTrue('StrCat' in results[0].message)
3469 self.assertTrue('foo_win.cc' in results[0].items[0])
3470 self.assertTrue('bar.h' in results[0].items[1])
3471 self.assertTrue('baz.h' in results[0].items[2])
3472 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433473
Daniel Cheng566634ff2024-06-29 14:56:533474 def testAllowsToIncludeWrapper(self):
3475 mock_input_api = MockInputApi()
3476 mock_input_api.files = [
3477 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3478 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3479 ]
3480 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3481 MockOutputApi())
3482 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323483
Daniel Cheng566634ff2024-06-29 14:56:533484 def testAllowsToCreateWrapper(self):
3485 mock_input_api = MockInputApi()
3486 mock_input_api.files = [
3487 MockFile('base/win/shlwapi.h', [
3488 '#include <shlwapi.h>',
3489 '#include "base/win/windows_defines.inc"'
3490 ]),
3491 ]
3492 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3493 MockOutputApi())
3494 self.assertEqual(0, len(results))
3495
3496 def testIgnoresNonImplAndHeaders(self):
3497 mock_input_api = MockInputApi()
3498 mock_input_api.files = [
3499 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3500 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3501 ]
3502 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3503 MockOutputApi())
3504 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243505
Mustafa Emre Acer51f2f742020-03-09 19:41:123506
Rainhard Findlingfc31844c52020-05-15 09:58:263507class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533508 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263509
Daniel Cheng566634ff2024-06-29 14:56:533510 # An empty grd file.
3511 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143512 <grit latest_public_release="1" current_release="1">
3513 <release seq="1">
3514 <messages></messages>
3515 </release>
3516 </grit>
3517 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533518 # A grd file with a single message.
3519 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143520 <grit latest_public_release="1" current_release="1">
3521 <release seq="1">
3522 <messages>
3523 <message name="IDS_TEST1">
3524 Test string 1
3525 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483526 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3527 translateable="false">
3528 Non translateable message 1, should be ignored
3529 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393530 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343531 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393532 Accessibility label 1, should be ignored
3533 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143534 </messages>
3535 </release>
3536 </grit>
3537 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533538 # A grd file with two messages.
3539 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143540 <grit latest_public_release="1" current_release="1">
3541 <release seq="1">
3542 <messages>
3543 <message name="IDS_TEST1">
3544 Test string 1
3545 </message>
3546 <message name="IDS_TEST2">
3547 Test string 2
3548 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483549 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3550 translateable="false">
3551 Non translateable message 2, should be ignored
3552 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143553 </messages>
3554 </release>
3555 </grit>
3556 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533557 # A grd file with one ICU syntax message without syntax errors.
3558 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263559 <grit latest_public_release="1" current_release="1">
3560 <release seq="1">
3561 <messages>
3562 <message name="IDS_TEST1">
3563 {NUM, plural,
3564 =1 {Test text for numeric one}
3565 other {Test text for plural with {NUM} as number}}
3566 </message>
3567 </messages>
3568 </release>
3569 </grit>
3570 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533571 # A grd file with one ICU syntax message without syntax errors.
3572 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263573 <grit latest_public_release="1" current_release="1">
3574 <release seq="1">
3575 <messages>
3576 <message name="IDS_TEST1">
3577 {NUM, plural,
3578 =1 {Different test text for numeric one}
3579 other {Different test text for plural with {NUM} as number}}
3580 </message>
3581 </messages>
3582 </release>
3583 </grit>
3584 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533585 # A grd file with multiple ICU syntax messages without syntax errors.
3586 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323587 <grit latest_public_release="1" current_release="1">
3588 <release seq="1">
3589 <messages>
3590 <message name="IDS_TEST1">
3591 {NUM, plural,
3592 =0 {New test text for numeric zero}
3593 =1 {Different test text for numeric one}
3594 =2 {New test text for numeric two}
3595 =3 {New test text for numeric three}
3596 other {Different test text for plural with {NUM} as number}}
3597 </message>
3598 </messages>
3599 </release>
3600 </grit>
3601 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533602 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3603 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263604 <grit latest_public_release="1" current_release="1">
3605 <release seq="1">
3606 <messages>
3607 <message name="IDS_TEST1">
3608 {NUM, plural
3609 =1 {Test text for numeric one}
3610 other {Test text for plural with {NUM} as number}}
3611 </message>
3612 </messages>
3613 </release>
3614 </grit>
3615 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143616
Daniel Cheng566634ff2024-06-29 14:56:533617 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3618 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583619
Daniel Cheng566634ff2024-06-29 14:56:533620 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3621 '<grit-part>', '<message name="IDS_PART_TEST1">',
3622 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583623
Daniel Cheng566634ff2024-06-29 14:56:533624 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3625 '<grit-part>', '<message name="IDS_PART_TEST1">',
3626 'Part string 1', '</message>',
3627 '<message name="IDS_PART_TEST2">', 'Part string 2',
3628 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583629
Daniel Cheng566634ff2024-06-29 14:56:533630 NEW_GRDP_CONTENTS3 = (
3631 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093632 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533633 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093634
Daniel Cheng566634ff2024-06-29 14:56:533635 NEW_GRDP_CONTENTS4 = (
3636 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093637 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533638 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093639
Daniel Cheng566634ff2024-06-29 14:56:533640 NEW_GRDP_CONTENTS5 = (
3641 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353642 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533643 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353644
Daniel Cheng566634ff2024-06-29 14:56:533645 NEW_GRDP_CONTENTS6 = (
3646 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353647 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533648 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353649
Daniel Cheng566634ff2024-06-29 14:56:533650 # A grdp file with one ICU syntax message without syntax errors.
3651 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3652 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3653 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3654 '=1 {Test text for numeric one}',
3655 'other {Test text for plural with {NUM} as number}}', '</message>',
3656 '</grit-part>')
3657 # A grdp file with one ICU syntax message without syntax errors.
3658 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3659 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3660 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3661 '=1 {Different test text for numeric one}',
3662 'other {Different test text for plural with {NUM} as number}}',
3663 '</message>', '</grit-part>')
3664 # A grdp file with multiple ICU syntax messages without syntax errors.
3665 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3666 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3667 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3668 '=0 {New test text for numeric zero}',
3669 '=1 {Different test text for numeric one}',
3670 '=2 {New test text for numeric two}',
3671 '=3 {New test text for numeric three}',
3672 'other {Different test text for plural with {NUM} as number}}',
3673 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263674
Daniel Cheng566634ff2024-06-29 14:56:533675 # A grdp file with one ICU syntax message with syntax errors (superfluous
3676 # space).
3677 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3678 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3679 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3680 '= 1 {Test text for numeric one}',
3681 'other {Test text for plural with {NUM} as number}}', '</message>',
3682 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263683
Daniel Cheng566634ff2024-06-29 14:56:533684 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3685 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3686 'changelist. Run '
3687 'tools/translate/upload_screenshots.py to '
3688 'upload them instead:')
3689 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3690 'To ensure the best translations, take '
3691 'screenshots of the relevant UI '
3692 '(https://g.co/chrome/translation) and add '
3693 'these files to your changelist:')
3694 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3695 'files. Remove:')
3696 ICU_SYNTAX_ERROR_MESSAGE = (
3697 'ICU syntax errors were found in the following '
3698 'strings (problems or feedback? Contact '
3699 '[email protected]):')
3700 SHA1_FORMAT_MESSAGE = (
3701 'The following files do not seem to contain valid sha1 '
3702 'hashes. Make sure they contain hashes created by '
3703 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143704
Daniel Cheng566634ff2024-06-29 14:56:533705 def makeInputApi(self, files):
3706 input_api = MockInputApi()
Andrew Grieve713b89b2024-10-15 20:20:083707 input_api.InitFiles(files)
Daniel Cheng566634ff2024-06-29 14:56:533708 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143709
Daniel Cheng566634ff2024-06-29 14:56:533710 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583711
Daniel Cheng566634ff2024-06-29 14:56:533712 def testNoScreenshots(self):
3713 # No new strings (file contents same). Should not warn.
3714 input_api = self.makeInputApi([
3715 MockAffectedFile('test.grd',
3716 self.NEW_GRD_CONTENTS1,
3717 self.NEW_GRD_CONTENTS1,
3718 action='M'),
3719 MockAffectedFile('part.grdp',
3720 self.NEW_GRDP_CONTENTS1,
3721 self.NEW_GRDP_CONTENTS1,
3722 action='M')
3723 ])
3724 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3725 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343726
Daniel Cheng566634ff2024-06-29 14:56:533727 # Add two new strings. Should have two warnings.
3728 input_api = self.makeInputApi([
3729 MockAffectedFile('test.grd',
3730 self.NEW_GRD_CONTENTS2,
3731 self.NEW_GRD_CONTENTS1,
3732 action='M'),
3733 MockAffectedFile('part.grdp',
3734 self.NEW_GRDP_CONTENTS2,
3735 self.NEW_GRDP_CONTENTS1,
3736 action='M')
3737 ])
3738 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3739 self.assertEqual(1, len(warnings))
3740 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3741 self.assertEqual('error', warnings[0].type)
3742 self.assertEqual([
3743 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3744 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3745 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213746
Daniel Cheng566634ff2024-06-29 14:56:533747 # Add four new strings. Should have four warnings.
3748 input_api = self.makeInputApi([
3749 MockAffectedFile('test.grd',
3750 self.NEW_GRD_CONTENTS2,
3751 self.OLD_GRD_CONTENTS,
3752 action='M'),
3753 MockAffectedFile('part.grdp',
3754 self.NEW_GRDP_CONTENTS2,
3755 self.OLD_GRDP_CONTENTS,
3756 action='M')
3757 ])
3758 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3759 self.assertEqual(1, len(warnings))
3760 self.assertEqual('error', warnings[0].type)
3761 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3762 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583763 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583764 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303765 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303766 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533767 ], warnings[0].items)
3768
3769 def testModifiedMessageDescription(self):
3770 # CL modified a message description for a message that does not yet have a
3771 # screenshot. Should not warn.
3772 input_api = self.makeInputApi([
3773 MockAffectedFile('part.grdp',
3774 self.NEW_GRDP_CONTENTS3,
3775 self.NEW_GRDP_CONTENTS4,
3776 action='M')
3777 ])
3778 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3779 self.assertEqual(0, len(warnings))
3780
3781 # CL modified a message description for a message that already has a
3782 # screenshot. Should not warn.
3783 input_api = self.makeInputApi([
3784 MockAffectedFile('part.grdp',
3785 self.NEW_GRDP_CONTENTS3,
3786 self.NEW_GRDP_CONTENTS4,
3787 action='M'),
3788 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3789 self.VALID_SHA1,
3790 action='A')
3791 ])
3792 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3793 self.assertEqual(0, len(warnings))
3794
3795 def testModifiedMessageMeaning(self):
3796 # CL modified a message meaning for a message that does not yet have a
3797 # screenshot. Should warn.
3798 input_api = self.makeInputApi([
3799 MockAffectedFile('part.grdp',
3800 self.NEW_GRDP_CONTENTS5,
3801 self.NEW_GRDP_CONTENTS6,
3802 action='M')
3803 ])
3804 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3805 self.assertEqual(1, len(warnings))
3806
3807 # CL modified a message meaning for a message that already has a
3808 # screenshot. Should not warn.
3809 input_api = self.makeInputApi([
3810 MockAffectedFile('part.grdp',
3811 self.NEW_GRDP_CONTENTS5,
3812 self.NEW_GRDP_CONTENTS6,
3813 action='M'),
3814 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3815 self.VALID_SHA1,
3816 action='A')
3817 ])
3818 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3819 self.assertEqual(0, len(warnings))
3820
3821 def testModifiedIntroducedInvalidSha1(self):
3822 # CL modified a message and the sha1 file changed to invalid
3823 input_api = self.makeInputApi([
3824 MockAffectedFile('part.grdp',
3825 self.NEW_GRDP_CONTENTS5,
3826 self.NEW_GRDP_CONTENTS6,
3827 action='M'),
3828 MockAffectedFile(os.path.join('part_grdp',
3829 'IDS_PART_TEST1.png.sha1'),
3830 ('some invalid sha1', ),
3831 self.VALID_SHA1,
3832 action='M')
3833 ])
3834 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3835 self.assertEqual(1, len(warnings))
3836
3837 def testPngAddedSha1NotAdded(self):
3838 # CL added one new message in a grd file and added the png file associated
3839 # with it, but did not add the corresponding sha1 file. This should warn
3840 # twice:
3841 # - Once for the added png file (because we don't want developers to upload
3842 # actual images)
3843 # - Once for the missing .sha1 file
3844 input_api = self.makeInputApi([
3845 MockAffectedFile('test.grd',
3846 self.NEW_GRD_CONTENTS1,
3847 self.OLD_GRD_CONTENTS,
3848 action='M'),
3849 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3850 'binary',
3851 action='A')
3852 ])
3853 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3854 self.assertEqual(2, len(warnings))
3855 self.assertEqual('error', warnings[0].type)
3856 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3857 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3858 warnings[0].items)
3859 self.assertEqual('error', warnings[1].type)
3860 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3861 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3862 warnings[1].items)
3863
3864 # CL added two messages (one in grd, one in grdp) and added the png files
3865 # associated with the messages, but did not add the corresponding sha1
3866 # files. This should warn twice:
3867 # - Once for the added png files (because we don't want developers to upload
3868 # actual images)
3869 # - Once for the missing .sha1 files
3870 input_api = self.makeInputApi([
3871 # Modified files:
3872 MockAffectedFile('test.grd',
3873 self.NEW_GRD_CONTENTS1,
3874 self.OLD_GRD_CONTENTS,
3875 action='M'),
3876 MockAffectedFile('part.grdp',
3877 self.NEW_GRDP_CONTENTS1,
3878 self.OLD_GRDP_CONTENTS,
3879 action='M'),
3880 # Added files:
3881 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3882 'binary',
3883 action='A'),
3884 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3885 'binary',
3886 action='A')
3887 ])
3888 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3889 self.assertEqual(2, len(warnings))
3890 self.assertEqual('error', warnings[0].type)
3891 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3892 self.assertEqual([
3893 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3894 os.path.join('test_grd', 'IDS_TEST1.png')
3895 ], warnings[0].items)
3896 self.assertEqual('error', warnings[0].type)
3897 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3898 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303899 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533900 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3901 ], warnings[1].items)
3902
3903 def testScreenshotsWithSha1(self):
3904 # CL added four messages (two each in a grd and grdp) and their
3905 # corresponding .sha1 files. No warnings.
3906 input_api = self.makeInputApi([
3907 # Modified files:
3908 MockAffectedFile('test.grd',
3909 self.NEW_GRD_CONTENTS2,
3910 self.OLD_GRD_CONTENTS,
3911 action='M'),
3912 MockAffectedFile('part.grdp',
3913 self.NEW_GRDP_CONTENTS2,
3914 self.OLD_GRDP_CONTENTS,
3915 action='M'),
3916 # Added files:
3917 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3918 self.VALID_SHA1,
3919 action='A'),
3920 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3921 ('0000000000000000000000000000000000000000', ''),
3922 action='A'),
3923 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3924 self.VALID_SHA1,
3925 action='A'),
3926 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3927 self.VALID_SHA1,
3928 action='A'),
3929 ])
3930 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3931 self.assertEqual([], warnings)
3932
3933 def testScreenshotsWithInvalidSha1(self):
3934 input_api = self.makeInputApi([
3935 # Modified files:
3936 MockAffectedFile('test.grd',
3937 self.NEW_GRD_CONTENTS2,
3938 self.OLD_GRD_CONTENTS,
3939 action='M'),
3940 MockAffectedFile('part.grdp',
3941 self.NEW_GRDP_CONTENTS2,
3942 self.OLD_GRDP_CONTENTS,
3943 action='M'),
3944 # Added files:
3945 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3946 self.VALID_SHA1,
3947 action='A'),
3948 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3949 ('‰PNG', 'test'),
3950 action='A'),
3951 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3952 self.VALID_SHA1,
3953 action='A'),
3954 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3955 self.VALID_SHA1,
3956 action='A'),
3957 ])
3958 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3959 self.assertEqual(1, len(warnings))
3960 self.assertEqual('error', warnings[0].type)
3961 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
3962 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3963 warnings[0].items)
3964
3965 def testScreenshotsRemovedWithSha1(self):
3966 # Replace new contents with old contents in grd and grp files, removing
3967 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3968 # Should warn to remove the sha1 files associated with these strings.
3969 input_api = self.makeInputApi([
3970 # Modified files:
3971 MockAffectedFile(
3972 'test.grd',
3973 self.OLD_GRD_CONTENTS, # new_contents
3974 self.NEW_GRD_CONTENTS2, # old_contents
3975 action='M'),
3976 MockAffectedFile(
3977 'part.grdp',
3978 self.OLD_GRDP_CONTENTS, # new_contents
3979 self.NEW_GRDP_CONTENTS2, # old_contents
3980 action='M'),
3981 # Unmodified files:
3982 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3983 self.VALID_SHA1, ''),
3984 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3985 self.VALID_SHA1, ''),
3986 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3987 self.VALID_SHA1, ''),
3988 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3989 self.VALID_SHA1, '')
3990 ])
3991 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3992 self.assertEqual(1, len(warnings))
3993 self.assertEqual('error', warnings[0].type)
3994 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
3995 self.assertEqual([
3996 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303997 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013998 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533999 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
4000 ], warnings[0].items)
4001
4002 # Same as above, but this time one of the .sha1 files is also removed.
4003 input_api = self.makeInputApi([
4004 # Modified files:
4005 MockAffectedFile(
4006 'test.grd',
4007 self.OLD_GRD_CONTENTS, # new_contents
4008 self.NEW_GRD_CONTENTS2, # old_contents
4009 action='M'),
4010 MockAffectedFile(
4011 'part.grdp',
4012 self.OLD_GRDP_CONTENTS, # new_contents
4013 self.NEW_GRDP_CONTENTS2, # old_contents
4014 action='M'),
4015 # Unmodified files:
4016 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4017 self.VALID_SHA1, ''),
4018 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4019 self.VALID_SHA1, ''),
4020 # Deleted files:
4021 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4022 '',
4023 'old_contents',
4024 action='D'),
4025 MockAffectedFile(os.path.join('part_grdp',
4026 'IDS_PART_TEST2.png.sha1'),
4027 '',
4028 'old_contents',
4029 action='D')
4030 ])
4031 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4032 self.assertEqual(1, len(warnings))
4033 self.assertEqual('error', warnings[0].type)
4034 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4035 self.assertEqual([
meacerff8a9b62019-12-10 19:43:584036 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534037 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
4038 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144039
Daniel Cheng566634ff2024-06-29 14:56:534040 # Remove all sha1 files. There should be no warnings.
4041 input_api = self.makeInputApi([
4042 # Modified files:
4043 MockAffectedFile('test.grd',
4044 self.OLD_GRD_CONTENTS,
4045 self.NEW_GRD_CONTENTS2,
4046 action='M'),
4047 MockAffectedFile('part.grdp',
4048 self.OLD_GRDP_CONTENTS,
4049 self.NEW_GRDP_CONTENTS2,
4050 action='M'),
4051 # Deleted files:
4052 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4053 self.VALID_SHA1,
4054 action='D'),
4055 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4056 self.VALID_SHA1,
4057 action='D'),
4058 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4059 self.VALID_SHA1,
4060 action='D'),
4061 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4062 self.VALID_SHA1,
4063 action='D')
4064 ])
4065 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4066 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:264067
Daniel Cheng566634ff2024-06-29 14:56:534068 def testIcuSyntax(self):
4069 # Add valid ICU syntax string. Should not raise an error.
4070 input_api = self.makeInputApi([
4071 MockAffectedFile('test.grd',
4072 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4073 self.NEW_GRD_CONTENTS1,
4074 action='M'),
4075 MockAffectedFile('part.grdp',
4076 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4077 self.NEW_GRDP_CONTENTS1,
4078 action='M')
4079 ])
4080 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4081 # We expect no ICU syntax errors.
4082 icu_errors = [
4083 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4084 ]
4085 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264086
Daniel Cheng566634ff2024-06-29 14:56:534087 # Valid changes in ICU syntax. Should not raise an error.
4088 input_api = self.makeInputApi([
4089 MockAffectedFile('test.grd',
4090 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4091 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4092 action='M'),
4093 MockAffectedFile('part.grdp',
4094 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4095 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4096 action='M')
4097 ])
4098 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4099 # We expect no ICU syntax errors.
4100 icu_errors = [
4101 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4102 ]
4103 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324104
Daniel Cheng566634ff2024-06-29 14:56:534105 # Valid changes in ICU syntax. Should not raise an error.
4106 input_api = self.makeInputApi([
4107 MockAffectedFile('test.grd',
4108 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4109 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4110 action='M'),
4111 MockAffectedFile('part.grdp',
4112 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4113 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4114 action='M')
4115 ])
4116 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4117 # We expect no ICU syntax errors.
4118 icu_errors = [
4119 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4120 ]
4121 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264122
Daniel Cheng566634ff2024-06-29 14:56:534123 # Add invalid ICU syntax strings. Should raise two errors.
4124 input_api = self.makeInputApi([
4125 MockAffectedFile('test.grd',
4126 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4127 self.NEW_GRD_CONTENTS1,
4128 action='M'),
4129 MockAffectedFile('part.grdp',
4130 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4131 self.NEW_GRD_CONTENTS1,
4132 action='M')
4133 ])
4134 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4135 # We expect 2 ICU syntax errors.
4136 icu_errors = [
4137 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4138 ]
4139 self.assertEqual(1, len(icu_errors))
4140 self.assertEqual([
4141 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4142 'ICU syntax.',
4143 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4144 ], icu_errors[0].items)
4145
4146 # Change two strings to have ICU syntax errors. Should raise two errors.
4147 input_api = self.makeInputApi([
4148 MockAffectedFile('test.grd',
4149 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4150 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4151 action='M'),
4152 MockAffectedFile('part.grdp',
4153 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4154 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4155 action='M')
4156 ])
4157 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4158 # We expect 2 ICU syntax errors.
4159 icu_errors = [
4160 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4161 ]
4162 self.assertEqual(1, len(icu_errors))
4163 self.assertEqual([
4164 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4165 'ICU syntax.',
4166 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4167 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264168
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144169
Mustafa Emre Acer51f2f742020-03-09 19:41:124170class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534171 ERROR_MESSAGE_FORMAT = (
4172 "Failed to get a list of translatable grd files. "
4173 "This happens when:\n"
4174 " - One of the modified grd or grdp files cannot be parsed or\n"
4175 " - %s is not updated.\n"
4176 "Stack:\n")
4177 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4178 # This lists all .grd files under REPO_ROOT.
4179 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4180 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4181 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4182 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124183
Daniel Cheng566634ff2024-06-29 14:56:534184 # Tests that the presubmit doesn't return when no grd or grdp files are
4185 # modified.
4186 def testExpectationsNoModifiedGrd(self):
4187 input_api = MockInputApi()
4188 input_api.files = [
4189 MockAffectedFile('not_used.txt',
4190 'not used',
4191 'not used',
4192 action='M')
4193 ]
4194 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4195 # under tools/translation/testdata. This is OK because the presubmit won't
4196 # run in the first place since there are no modified grd/grps in input_api.
4197 grd_files = ['doesnt_exist_doesnt_matter.grd']
4198 warnings = PRESUBMIT.CheckTranslationExpectations(
4199 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4200 grd_files)
4201 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124202
Daniel Cheng566634ff2024-06-29 14:56:534203 # Tests that the list of files passed to the presubmit matches the list of
4204 # files in the expectations.
4205 def testExpectationsSuccess(self):
4206 # Mock input file list needs a grd or grdp file in order to run the
4207 # presubmit. The file itself doesn't matter.
4208 input_api = MockInputApi()
4209 input_api.files = [
4210 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4211 ]
4212 # List of all grd files in the repo.
4213 grd_files = [
4214 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4215 ]
4216 warnings = PRESUBMIT.CheckTranslationExpectations(
4217 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4218 grd_files)
4219 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124220
Ben Mason5d4c3242025-04-15 20:28:374221 # Tests that the list of files passed to the presubmit does not
4222 # contain duplicate basenames.
4223 def testExpectationsSuccess(self):
4224 # Mock input file list needs a grd or grdp file in order to run the
4225 # presubmit. The file itself doesn't matter.
4226 input_api = MockInputApi()
4227 input_api.files = [
4228 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4229 ]
4230 # List of all grd files in the repo.
4231 grd_files = [
4232 'dir1/test.grd', 'unlisted.grd', 'not_translated.grd',
4233 'internal.grd', 'dir2/test.grd'
4234 ]
4235 warnings = PRESUBMIT.CheckTranslationExpectations(
4236 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4237 grd_files)
4238 self.assertEqual(1, len(warnings))
4239 self.assertTrue(
4240 ("Multiple string files have the same basename. "
4241 "This will result in missing translations. "
4242 "Files: dir1/test.grd, dir2/test.grd") in warnings[0].message)
4243
Daniel Cheng566634ff2024-06-29 14:56:534244 # Tests that the presubmit warns when a file is listed in expectations, but
4245 # does not actually exist.
4246 def testExpectationsMissingFile(self):
4247 # Mock input file list needs a grd or grdp file in order to run the
4248 # presubmit.
4249 input_api = MockInputApi()
4250 input_api.files = [
4251 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4252 ]
4253 # unlisted.grd is listed under tools/translation/testdata but is not
4254 # included in translation expectations.
4255 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4256 warnings = PRESUBMIT.CheckTranslationExpectations(
4257 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4258 grd_files)
4259 self.assertEqual(1, len(warnings))
4260 self.assertTrue(warnings[0].message.startswith(
4261 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4262 self.assertTrue(
4263 ("test.grd is listed in the translation expectations, "
4264 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124265
Daniel Cheng566634ff2024-06-29 14:56:534266 # Tests that the presubmit warns when a file is not listed in expectations but
4267 # does actually exist.
4268 def testExpectationsUnlistedFile(self):
4269 # Mock input file list needs a grd or grdp file in order to run the
4270 # presubmit.
4271 input_api = MockInputApi()
4272 input_api.files = [
4273 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4274 ]
4275 # unlisted.grd is listed under tools/translation/testdata but is not
4276 # included in translation expectations.
4277 grd_files = [
4278 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4279 ]
4280 warnings = PRESUBMIT.CheckTranslationExpectations(
4281 input_api, MockOutputApi(), self.REPO_ROOT,
4282 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4283 self.assertEqual(1, len(warnings))
4284 self.assertTrue(warnings[0].message.startswith(
4285 self.ERROR_MESSAGE_FORMAT %
4286 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4287 self.assertTrue(("unlisted.grd appears to be translatable "
4288 "(because it contains <file> or <message> elements), "
4289 "but is not listed in the translation expectations."
4290 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124291
Daniel Cheng566634ff2024-06-29 14:56:534292 # Tests that the presubmit warns twice:
4293 # - for a non-existing file listed in expectations
4294 # - for an existing file not listed in expectations
4295 def testMultipleWarnings(self):
4296 # Mock input file list needs a grd or grdp file in order to run the
4297 # presubmit.
4298 input_api = MockInputApi()
4299 input_api.files = [
4300 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4301 ]
4302 # unlisted.grd is listed under tools/translation/testdata but is not
4303 # included in translation expectations.
4304 # test.grd is not listed under tools/translation/testdata but is included
4305 # in translation expectations.
4306 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4307 warnings = PRESUBMIT.CheckTranslationExpectations(
4308 input_api, MockOutputApi(), self.REPO_ROOT,
4309 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4310 self.assertEqual(1, len(warnings))
4311 self.assertTrue(warnings[0].message.startswith(
4312 self.ERROR_MESSAGE_FORMAT %
4313 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4314 self.assertTrue(("unlisted.grd appears to be translatable "
4315 "(because it contains <file> or <message> elements), "
4316 "but is not listed in the translation expectations."
4317 ) in warnings[0].message)
4318 self.assertTrue(
4319 ("test.grd is listed in the translation expectations, "
4320 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124321
4322
Dominic Battre033531052018-09-24 15:45:344323class DISABLETypoInTest(unittest.TestCase):
4324
Daniel Cheng566634ff2024-06-29 14:56:534325 def testPositive(self):
4326 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4327 # where the desire is to disable a test.
4328 tests = [
4329 # Disabled on one platform:
4330 '#if defined(OS_WIN)\n'
4331 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4332 '#else\n'
4333 '#define MAYBE_FoobarTest FoobarTest\n'
4334 '#endif\n',
4335 # Disabled on one platform spread cross lines:
4336 '#if defined(OS_WIN)\n'
4337 '#define MAYBE_FoobarTest \\\n'
4338 ' DISABLE_FoobarTest\n'
4339 '#else\n'
4340 '#define MAYBE_FoobarTest FoobarTest\n'
4341 '#endif\n',
4342 # Disabled on all platforms:
4343 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4344 # Disabled on all platforms but multiple lines
4345 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4346 ]
Dominic Battre033531052018-09-24 15:45:344347
Daniel Cheng566634ff2024-06-29 14:56:534348 for test in tests:
4349 mock_input_api = MockInputApi()
4350 mock_input_api.files = [
4351 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4352 ]
Dominic Battre033531052018-09-24 15:45:344353
Daniel Cheng566634ff2024-06-29 14:56:534354 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4355 mock_input_api, MockOutputApi())
4356 self.assertEqual(
4357 1,
4358 len(results),
4359 msg=('expected len(results) == 1 but got %d in test: %s' %
4360 (len(results), test)))
4361 self.assertTrue(
4362 'foo_unittest.cc' in results[0].message,
4363 msg=(
4364 'expected foo_unittest.cc in message but got %s in test %s'
4365 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344366
Daniel Cheng566634ff2024-06-29 14:56:534367 def testIgnoreNotTestFiles(self):
4368 mock_input_api = MockInputApi()
4369 mock_input_api.files = [
4370 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4371 ]
Dominic Battre033531052018-09-24 15:45:344372
Daniel Cheng566634ff2024-06-29 14:56:534373 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4374 MockOutputApi())
4375 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344376
Daniel Cheng566634ff2024-06-29 14:56:534377 def testIgnoreDeletedFiles(self):
4378 mock_input_api = MockInputApi()
4379 mock_input_api.files = [
4380 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4381 action='D'),
4382 ]
Katie Df13948e2018-09-25 07:33:444383
Daniel Cheng566634ff2024-06-29 14:56:534384 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4385 MockOutputApi())
4386 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344387
Nina Satragnof7660532021-09-20 18:03:354388class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354389
Daniel Cheng566634ff2024-06-29 14:56:534390 def testPositive(self):
4391 test = ('#if defined(HAS_ENERGY)\n'
4392 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4393 '#else\n'
4394 '#define MAYBE_CastExplosion CastExplosion\n'
4395 '#endif\n'
4396 'TEST_F(ArchWizard, CastExplosion) {\n'
4397 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4398 '#define MAYBE_ArchPriest ArchPriest\n'
4399 '#else\n'
4400 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4401 '#endif\n'
4402 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4403 '#if !defined(CRUSADER_IN_PARTY)\n'
4404 '#define MAYBE_Crusader \\\n'
4405 ' DISABLED_Crusader \n'
4406 '#else\n'
4407 '#define MAYBE_Crusader \\\n'
4408 ' Crusader\n'
4409 '#endif\n'
4410 ' TEST_F(\n'
4411 ' Crusader,\n'
4412 ' CastTaunt) { }\n'
4413 '#if defined(LEARNED_BASIC_SKILLS)\n'
4414 '#define MAYBE_CastSteal \\\n'
4415 ' DISABLED_CastSteal \n'
4416 '#else\n'
4417 '#define MAYBE_CastSteal \\\n'
4418 ' CastSteal\n'
4419 '#endif\n'
4420 ' TEST_F(\n'
4421 ' ThiefClass,\n'
4422 ' CastSteal) { }\n')
4423 mock_input_api = MockInputApi()
4424 mock_input_api.files = [
4425 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4426 ]
4427 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4428 mock_input_api, MockOutputApi())
4429 self.assertEqual(4, len(results))
4430 self.assertTrue('CastExplosion' in results[0].message)
4431 self.assertTrue(
4432 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4433 self.assertTrue('ArchPriest' in results[1].message)
4434 self.assertTrue(
4435 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4436 self.assertTrue('Crusader' in results[2].message)
4437 self.assertTrue(
4438 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4439 self.assertTrue('CastSteal' in results[3].message)
4440 self.assertTrue(
4441 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354442
Daniel Cheng566634ff2024-06-29 14:56:534443 def testNegative(self):
4444 test = ('#if defined(HAS_ENERGY)\n'
4445 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4446 '#else\n'
4447 '#define MAYBE_CastExplosion CastExplosion\n'
4448 '#endif\n'
4449 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4450 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4451 '#define MAYBE_ArchPriest ArchPriest\n'
4452 '#else\n'
4453 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4454 '#endif\n'
4455 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4456 '#if !defined(CRUSADER_IN_PARTY)\n'
4457 '#define MAYBE_Crusader \\\n'
4458 ' DISABLED_Crusader \n'
4459 '#else\n'
4460 '#define MAYBE_Crusader \\\n'
4461 ' Crusader\n'
4462 '#endif\n'
4463 ' TEST_F(\n'
4464 ' MAYBE_Crusader,\n'
4465 ' CastTaunt) { }\n'
4466 '#if defined(LEARNED_BASIC_SKILLS)\n'
4467 '#define MAYBE_CastSteal \\\n'
4468 ' DISABLED_CastSteal \n'
4469 '#else\n'
4470 '#define MAYBE_CastSteal \\\n'
4471 ' CastSteal\n'
4472 '#endif\n'
4473 ' TEST_F(\n'
4474 ' ThiefClass,\n'
4475 ' MAYBE_CastSteal) { }\n')
4476
4477 mock_input_api = MockInputApi()
4478 mock_input_api.files = [
4479 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4480 ]
4481 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4482 mock_input_api, MockOutputApi())
4483 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514484
Max Morozb47503b2019-08-08 21:03:274485class CheckFuzzTargetsTest(unittest.TestCase):
4486
Daniel Cheng566634ff2024-06-29 14:56:534487 def _check(self, files):
4488 mock_input_api = MockInputApi()
4489 mock_input_api.files = []
4490 for fname, contents in files.items():
4491 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4492 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4493 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274494
Daniel Cheng566634ff2024-06-29 14:56:534495 def testLibFuzzerSourcesIgnored(self):
4496 results = self._check({
4497 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4498 "LLVMFuzzerInitialize",
4499 })
4500 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274501
Daniel Cheng566634ff2024-06-29 14:56:534502 def testNonCodeFilesIgnored(self):
4503 results = self._check({
4504 "README.md": "LLVMFuzzerInitialize",
4505 })
4506 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274507
Daniel Cheng566634ff2024-06-29 14:56:534508 def testNoErrorHeaderPresent(self):
4509 results = self._check({
4510 "fuzzer.cc":
4511 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4512 "LLVMFuzzerInitialize")
4513 })
4514 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274515
Daniel Cheng566634ff2024-06-29 14:56:534516 def testErrorMissingHeader(self):
4517 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4518 self.assertEqual(len(results), 1)
4519 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274520
4521
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264522class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404523
Daniel Cheng566634ff2024-06-29 14:56:534524 def testSetNoParentTopLevelAllowed(self):
4525 mock_input_api = MockInputApi()
4526 mock_input_api.files = [
4527 MockAffectedFile('goat/OWNERS', [
4528 'set noparent',
4529 '[email protected]',
4530 ])
4531 ]
4532 mock_output_api = MockOutputApi()
4533 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4534 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264535
Daniel Cheng566634ff2024-06-29 14:56:534536 def testSetNoParentMissing(self):
4537 mock_input_api = MockInputApi()
4538 mock_input_api.files = [
4539 MockAffectedFile('services/goat/OWNERS', [
4540 'set noparent',
4541 '[email protected]',
4542 'per-file *.json=set noparent',
4543 'per-file *[email protected]',
4544 ])
4545 ]
4546 mock_output_api = MockOutputApi()
4547 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4548 self.assertEqual(1, len(errors))
4549 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4550 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4551
4552 def testSetNoParentWithCorrectRule(self):
4553 mock_input_api = MockInputApi()
4554 mock_input_api.files = [
4555 MockAffectedFile('services/goat/OWNERS', [
4556 'set noparent',
4557 'file://ipc/SECURITY_OWNERS',
4558 'per-file *.json=set noparent',
4559 'per-file *.json=file://ipc/SECURITY_OWNERS',
4560 ])
4561 ]
4562 mock_output_api = MockOutputApi()
4563 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4564 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264565
4566
Ken Rockotc31f4832020-05-29 18:58:514567class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514568
Daniel Cheng566634ff2024-06-29 14:56:534569 def runTestWithAffectedFiles(self, affected_files):
4570 mock_input_api = MockInputApi()
4571 mock_input_api.files = affected_files
4572 mock_output_api = MockOutputApi()
4573 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4574 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514575
Daniel Cheng566634ff2024-06-29 14:56:534576 def testSafeChangePasses(self):
4577 errors = self.runTestWithAffectedFiles([
4578 MockAffectedFile(
4579 'foo/foo.mojom',
4580 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4581 old_contents=['[Stable] struct S {};'])
4582 ])
4583 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514584
Daniel Cheng566634ff2024-06-29 14:56:534585 def testBadChangeFails(self):
4586 errors = self.runTestWithAffectedFiles([
4587 MockAffectedFile('foo/foo.mojom',
4588 ['[Stable] struct S { int32 x; };'],
4589 old_contents=['[Stable] struct S {};'])
4590 ])
4591 self.assertEqual(1, len(errors))
4592 self.assertTrue('not backward-compatible' in errors[0].message)
4593
4594 def testDeletedFile(self):
4595 """Regression test for https://crbug.com/1091407."""
4596 errors = self.runTestWithAffectedFiles([
4597 MockAffectedFile('a.mojom', [],
4598 old_contents=['struct S {};'],
4599 action='D'),
4600 MockAffectedFile(
4601 'b.mojom', ['struct S {}; struct T { S s; };'],
4602 old_contents=['import "a.mojom"; struct T { S s; };'])
4603 ])
4604 self.assertEqual([], errors)
4605
Ken Rockotad7901f942020-06-04 20:17:094606
Jose Magana2b456f22021-03-09 23:26:404607class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4608
Daniel Cheng566634ff2024-06-29 14:56:534609 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404610
Daniel Cheng566634ff2024-06-29 14:56:534611 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404612
Daniel Cheng566634ff2024-06-29 14:56:534613 def testWarningNMF(self):
4614 mock_input_api = MockInputApi()
4615 mock_input_api.files = [
4616 MockAffectedFile(
4617 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4618 ['"program"', 'B'],
4619 scm_diff='\n'.join([
4620 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4621 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4622 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4623 ]),
4624 action='M')
4625 ]
4626 mock_output_api = MockOutputApi()
4627 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4628 mock_input_api, mock_output_api)
4629 self.assertEqual(1, len(errors))
4630 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4631 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404632
Daniel Cheng566634ff2024-06-29 14:56:534633 def testWarningManifest(self):
4634 mock_input_api = MockInputApi()
4635 mock_input_api.files = [
4636 MockAffectedFile(
4637 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4638 ['"app":"', 'B'],
4639 scm_diff='\n'.join([
4640 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4641 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4642 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4643 ]),
4644 action='M')
4645 ]
4646 mock_output_api = MockOutputApi()
4647 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4648 mock_input_api, mock_output_api)
4649 self.assertEqual(1, len(errors))
4650 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4651 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404652
Daniel Cheng566634ff2024-06-29 14:56:534653 def testOKWarningManifestWithoutApp(self):
4654 mock_input_api = MockInputApi()
4655 mock_input_api.files = [
4656 MockAffectedFile(
4657 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4658 ['"name":"', 'B'],
4659 scm_diff='\n'.join([
4660 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4661 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4662 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4663 ]),
4664 action='M')
4665 ]
4666 mock_output_api = MockOutputApi()
4667 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4668 mock_input_api, mock_output_api)
4669 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404670
Jose Magana2b456f22021-03-09 23:26:404671
Dominic Battre645d42342020-12-04 16:14:104672class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534673 # Test that a warning is generated if a preference registration is removed
4674 # from a random file.
4675 def testWarning(self):
4676 mock_input_api = MockInputApi()
4677 mock_input_api.files = [
4678 MockAffectedFile(
4679 'foo.cc', ['A', 'B'],
4680 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4681 scm_diff='\n'.join([
4682 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4683 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4684 '@@ -1,3 +1,2 @@', ' A',
4685 '-prefs->RegisterStringPref("foo", "default");', ' B'
4686 ]),
4687 action='M')
4688 ]
4689 mock_output_api = MockOutputApi()
4690 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4691 mock_input_api, mock_output_api)
4692 self.assertEqual(1, len(errors))
4693 self.assertTrue(
4694 'Discovered possible removal of preference registrations' in
4695 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104696
Daniel Cheng566634ff2024-06-29 14:56:534697 # Test that a warning is inhibited if the preference registration was moved
4698 # to the deprecation functions in browser prefs.
4699 def testNoWarningForMigration(self):
4700 mock_input_api = MockInputApi()
4701 mock_input_api.files = [
4702 # RegisterStringPref was removed from foo.cc.
4703 MockAffectedFile(
4704 'foo.cc', ['A', 'B'],
4705 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4706 scm_diff='\n'.join([
4707 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4708 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4709 '@@ -1,3 +1,2 @@', ' A',
4710 '-prefs->RegisterStringPref("foo", "default");', ' B'
4711 ]),
4712 action='M'),
4713 # But the preference was properly migrated.
4714 MockAffectedFile(
4715 'chrome/browser/prefs/browser_prefs.cc', [
4716 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4717 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4718 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4719 'prefs->RegisterStringPref("foo", "default");',
4720 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4721 ], [
4722 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4723 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4724 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4725 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4726 ],
4727 scm_diff='\n'.join([
4728 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4729 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4730 '@@ -2,3 +2,4 @@',
4731 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4732 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4733 '+prefs->RegisterStringPref("foo", "default");',
4734 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4735 ]),
4736 action='M'),
4737 ]
4738 mock_output_api = MockOutputApi()
4739 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4740 mock_input_api, mock_output_api)
4741 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104742
Daniel Cheng566634ff2024-06-29 14:56:534743 # Test that a warning is NOT inhibited if the preference registration was
4744 # moved to a place outside of the migration functions in browser_prefs.cc
4745 def testWarningForImproperMigration(self):
4746 mock_input_api = MockInputApi()
4747 mock_input_api.files = [
4748 # RegisterStringPref was removed from foo.cc.
4749 MockAffectedFile(
4750 'foo.cc', ['A', 'B'],
4751 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4752 scm_diff='\n'.join([
4753 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4754 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4755 '@@ -1,3 +1,2 @@', ' A',
4756 '-prefs->RegisterStringPref("foo", "default");', ' B'
4757 ]),
4758 action='M'),
4759 # The registration call was moved to a place in browser_prefs.cc that
4760 # is outside the migration functions.
4761 MockAffectedFile(
4762 'chrome/browser/prefs/browser_prefs.cc', [
4763 'prefs->RegisterStringPref("foo", "default");',
4764 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4765 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4766 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4767 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4768 ], [
4769 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4770 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4771 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4772 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4773 ],
4774 scm_diff='\n'.join([
4775 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4776 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4777 '@@ -1,2 +1,3 @@',
4778 '+prefs->RegisterStringPref("foo", "default");',
4779 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4780 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4781 ]),
4782 action='M'),
4783 ]
4784 mock_output_api = MockOutputApi()
4785 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4786 mock_input_api, mock_output_api)
4787 self.assertEqual(1, len(errors))
4788 self.assertTrue(
4789 'Discovered possible removal of preference registrations' in
4790 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104791
Daniel Cheng566634ff2024-06-29 14:56:534792 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4793 # deleted.
4794 def testDeletedMarkerRaisesError(self):
4795 mock_input_api = MockInputApi()
4796 mock_input_api.files = [
4797 MockAffectedFile(
4798 'chrome/browser/prefs/browser_prefs.cc',
4799 [
4800 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4801 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4802 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4803 # The following line is deleted for this test
4804 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4805 ])
4806 ]
4807 mock_output_api = MockOutputApi()
4808 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4809 mock_input_api, mock_output_api)
4810 self.assertEqual(1, len(errors))
4811 self.assertEqual(
4812 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4813 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104814
Sven Zheng76a79ea2022-12-21 21:25:244815class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4816 def testWarning(self):
4817 mock_input_api = MockInputApi()
4818 mock_output_api = MockOutputApi()
4819 mock_input_api.files = [
4820 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4821 ]
4822 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4823 self.assertEqual(1, len(result))
4824 self.assertEqual(result[0].type, 'warning')
4825
4826 def testNoWarningWithBrowserTest(self):
4827 mock_input_api = MockInputApi()
4828 mock_output_api = MockOutputApi()
4829 mock_input_api.files = [
4830 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4831 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4832 ]
4833 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4834 self.assertEqual(0, len(result))
4835
4836 def testNoWarningModifyCrosapi(self):
4837 mock_input_api = MockInputApi()
4838 mock_output_api = MockOutputApi()
4839 mock_input_api.files = [
4840 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4841 ]
4842 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4843 self.assertEqual(0, len(result))
4844
4845 def testNoWarningAddNonMojomFile(self):
4846 mock_input_api = MockInputApi()
4847 mock_output_api = MockOutputApi()
4848 mock_input_api.files = [
4849 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4850 ]
4851 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4852 self.assertEqual(0, len(result))
4853
4854 def testNoWarningNoneRelatedMojom(self):
4855 mock_input_api = MockInputApi()
4856 mock_output_api = MockOutputApi()
4857 mock_input_api.files = [
4858 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4859 ]
4860 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4861 self.assertEqual(0, len(result))
4862
4863
Henrique Ferreiro2a4b55942021-11-29 23:45:364864class AssertAshOnlyCodeTest(unittest.TestCase):
4865 def testErrorsOnlyOnAshDirectories(self):
4866 files_in_ash = [
4867 MockFile('ash/BUILD.gn', []),
4868 MockFile('chrome/browser/ash/BUILD.gn', []),
4869 ]
4870 other_files = [
4871 MockFile('chrome/browser/BUILD.gn', []),
Georg Neis94f87f02024-10-22 08:20:134872 MockFile('chrome/browser/foo/BUILD.gn', ['assert(is_chromeos_ash)']),
Henrique Ferreiro2a4b55942021-11-29 23:45:364873 ]
4874 input_api = MockInputApi()
4875 input_api.files = files_in_ash
4876 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4877 self.assertEqual(2, len(errors))
4878
4879 input_api.files = other_files
4880 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4881 self.assertEqual(0, len(errors))
4882
4883 def testDoesNotErrorOnNonGNFiles(self):
4884 input_api = MockInputApi()
4885 input_api.files = [
4886 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4887 MockFile('chrome/browser/ash/test.cc',
4888 ['assert(is_chromeos_ash)']),
4889 ]
4890 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4891 self.assertEqual(0, len(errors))
4892
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214893 def testDeletedFile(self):
4894 input_api = MockInputApi()
4895 input_api.files = [
4896 MockFile('ash/BUILD.gn', []),
4897 MockFile('ash/foo/BUILD.gn', [], action='D'),
4898 ]
4899 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4900 self.assertEqual(1, len(errors))
4901
Henrique Ferreiro2a4b55942021-11-29 23:45:364902 def testDoesNotErrorWithAssertion(self):
4903 input_api = MockInputApi()
4904 input_api.files = [
4905 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4906 MockFile('chrome/browser/ash/BUILD.gn',
4907 ['assert(is_chromeos_ash)']),
Georg Neis94f87f02024-10-22 08:20:134908 MockFile('chrome/browser/ash/1/BUILD.gn',
4909 ['assert(is_chromeos)']),
4910 MockFile('chrome/browser/ash/2/BUILD.gn',
4911 ['assert(is_chromeos_ash)']),
4912 MockFile('chrome/browser/ash/3/BUILD.gn',
4913 ['assert(is_chromeos, "test")']),
4914 MockFile('chrome/browser/ash/4/BUILD.gn',
Henrique Ferreiro2a4b55942021-11-29 23:45:364915 ['assert(is_chromeos_ash, "test")']),
4916 ]
4917 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4918 self.assertEqual(0, len(errors))
4919
4920
Lukasz Anforowicz7016d05e2021-11-30 03:56:274921class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274922
Daniel Cheng566634ff2024-06-29 14:56:534923 def testAllowedCases(self):
4924 mock_input_api = MockInputApi()
4925 mock_input_api.files = [
4926 # Browser-side files are allowed.
4927 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4928 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4929 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4930 MockAffectedFile('test13/blink/public/common/foo.cc',
4931 ['raw_ptr<int>']),
4932 MockAffectedFile('test14/blink/public/platform/foo.cc',
4933 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274934
Daniel Cheng566634ff2024-06-29 14:56:534935 # Non-C++ files are allowed.
4936 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274937
Daniel Cheng566634ff2024-06-29 14:56:534938 # Renderer code is generally allowed (except specifically
4939 # disallowed directories).
4940 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
4941 ]
4942 mock_output_api = MockOutputApi()
4943 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4944 self.assertFalse(errors)
4945
4946 def testDisallowedCases(self):
4947 mock_input_api = MockInputApi()
4948 mock_input_api.files = [
4949 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
4950 ['raw_ptr<int>']),
4951 MockAffectedFile(
4952 'test2/third_party/blink/renderer/platform/heap/foo.cc',
4953 ['raw_ptr<int>']),
4954 MockAffectedFile(
4955 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
4956 ['raw_ptr<int>']),
4957 MockAffectedFile(
4958 'test4/third_party/blink/renderer/platform/fonts/foo.h',
4959 ['raw_ptr<int>']),
4960 MockAffectedFile(
4961 'test5/third_party/blink/renderer/core/paint/foo.cc',
4962 ['raw_ptr<int>']),
4963 MockAffectedFile(
4964 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
4965 ['raw_ptr<int>']),
4966 MockAffectedFile(
4967 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
4968 ['raw_ptr<int>']),
4969 ]
4970 mock_output_api = MockOutputApi()
4971 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4972 self.assertEqual(len(mock_input_api.files), len(errors))
4973 for error in errors:
4974 self.assertTrue(
4975 'raw_ptr<T> should not be used in this renderer code' in
4976 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:274977
mikt9337567c2023-09-08 18:38:174978class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:174979
Daniel Cheng566634ff2024-06-29 14:56:534980 def testAllowedCases(self):
4981 mock_input_api = MockInputApi()
4982 mock_input_api.files = [
4983 # Non-C++ files are allowed.
4984 MockAffectedFile('test20/renderer/foo.md',
4985 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:174986
Daniel Cheng566634ff2024-06-29 14:56:534987 # Mentions in a comment are allowed.
4988 MockAffectedFile('test30/renderer/foo.cc',
4989 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
4990 ]
4991 mock_output_api = MockOutputApi()
4992 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
4993 mock_input_api, mock_output_api)
4994 self.assertFalse(errors)
4995
4996 def testDisallowedCases(self):
4997 mock_input_api = MockInputApi()
4998 mock_input_api.files = [
4999 MockAffectedFile('test1/foo.h',
5000 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5001 MockAffectedFile('test2/foo.cc',
5002 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5003 ]
5004 mock_output_api = MockOutputApi()
5005 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5006 mock_input_api, mock_output_api)
5007 self.assertEqual(1, len(errors))
5008 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
5009 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275010
Henrique Ferreirof9819f2e32021-11-30 13:31:565011class AssertPythonShebangTest(unittest.TestCase):
5012 def testError(self):
5013 input_api = MockInputApi()
5014 input_api.files = [
5015 MockFile('ash/test.py', ['#!/usr/bin/python']),
5016 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
5017 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:275018 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:565019 ]
5020 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5021 self.assertEqual(3, len(errors))
5022
5023 def testNonError(self):
5024 input_api = MockInputApi()
5025 input_api.files = [
5026 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
5027 MockFile('third_party/blink/web_tests/external/test.py',
5028 ['#!/usr/bin/python2']),
5029 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
5030 ]
5031 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5032 self.assertEqual(0, len(errors))
5033
Kalvin Lee4a3b79de2022-05-26 16:00:165034class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:165035
Daniel Cheng566634ff2024-06-29 14:56:535036 def testPermissibleUsage(self):
5037 input_api = MockInputApi()
5038 input_api.files = [
5039 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
5040 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:165041
Daniel Cheng566634ff2024-06-29 14:56:535042 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
5043 # own thing at their own risk.
5044 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
5045 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
5046 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
5047 ]
5048 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5049 MockOutputApi())
5050 self.assertEqual(0, len(errors))
5051
5052 def testMissingParentheses(self):
5053 input_api = MockInputApi()
5054 input_api.files = [
5055 MockFile('bad1.cc', ['DCHECK_IS_ON']),
5056 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
5057 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
5058 ]
5059 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5060 MockOutputApi())
5061 self.assertEqual(3, len(errors))
5062 for error in errors:
5063 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:565064
Sam Maier4cef9242022-10-03 14:21:245065
Andrew Grieve5a66ae72024-12-13 15:21:535066class CheckAndroidTestAnnotations(unittest.TestCase):
5067 """Test the CheckAndroidTestAnnotations presubmit check."""
James Shen81cc0e22022-06-15 21:10:455068
Andrew Grieve5a66ae72024-12-13 15:21:535069 def testBatchTruePositives(self):
Daniel Cheng566634ff2024-06-29 14:56:535070 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455071"""
Daniel Cheng566634ff2024-06-29 14:56:535072 mock_input = MockInputApi()
5073 mock_input.files = [
5074 MockFile('path/OneTest.java', ['public class OneTest']),
5075 MockFile('path/TwoTest.java', ['public class TwoTest']),
5076 MockFile('path/ThreeTest.java', [
5077 '@Batch(Batch.PER_CLASS)',
Andrew Grieve5a66ae72024-12-13 15:21:535078 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535079 'public class Three {'
5080 ]),
5081 MockFile('path/FourTest.java', [
5082 '@DoNotBatch(reason = "placeholder reason 1")',
Andrew Grieve5a66ae72024-12-13 15:21:535083 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535084 'public class Four {'
5085 ]),
5086 ]
Andrew Grieve5a66ae72024-12-13 15:21:535087 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535088 self.assertEqual(2, len(errors))
5089 self.assertEqual(2, len(errors[0].items))
5090 self.assertIn('OneTest.java', errors[0].items[0])
5091 self.assertIn('TwoTest.java', errors[0].items[1])
5092 self.assertEqual(2, len(errors[1].items))
5093 self.assertIn('ThreeTest.java', errors[1].items[0])
5094 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385095
Andrew Grieve5a66ae72024-12-13 15:21:535096 def testBatchAnnotationsPresent(self):
Daniel Cheng566634ff2024-06-29 14:56:535097 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5098 mock_input = MockInputApi()
5099 mock_input.files = [
5100 MockFile('path/OneTest.java',
5101 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5102 MockFile('path/TwoTest.java', [
5103 '@DoNotBatch(reason = "placeholder reasons.")',
5104 'public class Two {'
5105 ]),
5106 MockFile('path/ThreeTest.java', [
5107 '@Batch(Batch.PER_CLASS)',
5108 'public class Three extends BaseTestA {'
5109 ], [
5110 '@Batch(Batch.PER_CLASS)',
5111 'public class Three extends BaseTestB {'
5112 ]),
5113 MockFile('path/FourTest.java', [
5114 '@DoNotBatch(reason = "placeholder reason 1")',
5115 'public class Four extends BaseTestA {'
5116 ], [
5117 '@DoNotBatch(reason = "placeholder reason 2")',
5118 'public class Four extends BaseTestB {'
5119 ]),
5120 MockFile('path/FiveTest.java', [
5121 'import androidx.test.uiautomator.UiDevice;',
5122 'public class Five extends BaseTestA {'
5123 ], [
5124 'import androidx.test.uiautomator.UiDevice;',
5125 'public class Five extends BaseTestB {'
5126 ]),
5127 MockFile('path/SixTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535128 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535129 'public class Six extends BaseTestA {'
5130 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535131 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535132 'public class Six extends BaseTestB {'
5133 ]),
5134 MockFile('path/SevenTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535135 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535136 'public class Seven extends BaseTestA {'
5137 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535138 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535139 'public class Seven extends BaseTestB {'
5140 ]),
5141 MockFile(
5142 'path/OtherClass.java',
5143 ['public class OtherClass {'],
5144 ),
5145 MockFile('path/PRESUBMIT.py', [
5146 '@Batch(Batch.PER_CLASS)',
5147 '@DoNotBatch(reason = "placeholder reason)'
5148 ]),
5149 MockFile(
5150 'path/AnnotationTest.java',
5151 ['public @interface SomeAnnotation {'],
5152 ),
5153 ]
Andrew Grieve5a66ae72024-12-13 15:21:535154 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535155 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455156
Andrew Grieve5a66ae72024-12-13 15:21:535157 def testWrongRobolectricTestRunner(self):
5158 mock_input = MockInputApi()
5159 mock_input.files = [
5160 MockFile('path/OneTest.java', [
5161 '@RunWith(RobolectricTestRunner.class)',
5162 'public class ThreeTest {'
5163 ]),
5164 MockFile('path/TwoTest.java', [
5165 'import org.chromium.base.test.BaseRobolectricTestRule;',
5166 '@RunWith(RobolectricTestRunner.class)',
5167 'public class TwoTest {'
5168 ]),
5169 MockFile('path/ThreeTest.java', [
5170 '@RunWith(FooRobolectricTestRunner.class)',
5171 'public class ThreeTest {'
5172 ]),
5173 MockFile('webapks/FourTest.java', [
5174 '@RunWith(RobolectricTestRunner.class)',
5175 'public class ThreeTest {'
5176 ]),
5177 ]
5178 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
5179 self.assertEqual(1, len(errors))
5180 self.assertEqual(1, len(errors[0].items))
5181 self.assertIn('OneTest.java', errors[0].items[0])
5182
Sam Maier4cef9242022-10-03 14:21:245183
Henrique Nakashima224ee2482025-03-21 18:35:025184class CheckAndroidNullAwayAnnotatedClasses(unittest.TestCase):
5185 """Test the _CheckAndroidNullAwayAnnotatedClasses presubmit check."""
5186
5187 def testDetectsInClasses(self):
5188 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in classes."""
5189 mock_input = MockInputApi()
5190 mock_input.files = [
5191 MockFile('path/OneMissing.java', ['public class OneMissing']),
5192 MockFile('path/TwoMarked.java', [
5193 '@NullMarked',
5194 'public class TwoMarked {',
5195 ]),
5196 MockFile('path/ThreeMarked.java', [
5197 '@NullUnmarked',
5198 'public class ThreeMarked {',
5199 ]),
5200 MockFile('path/FourMissing.java', ['class FourMissing']),
5201 ]
5202 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5203 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425204 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025205 self.assertEqual(2, len(results[0].items))
5206 self.assertIn('OneMissing.java', results[0].items[0])
5207 self.assertIn('FourMissing.java', results[0].items[1])
5208
5209 def testDetectsInAnnotations(self):
5210 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in annotations."""
5211 mock_input = MockInputApi()
5212 mock_input.files = [
5213 MockFile('path/OneMissing.java', ['@interface OneMissing']),
5214 MockFile('path/TwoMarked.java', [
5215 '@NullMarked',
5216 '@interface TwoMarked {',
5217 ]),
5218 ]
5219 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5220 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425221 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025222 self.assertEqual(1, len(results[0].items))
5223 self.assertIn('OneMissing.java', results[0].items[0])
5224
5225 def testDetectsInInterfaces(self):
5226 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in interfaces."""
5227 mock_input = MockInputApi()
5228 mock_input.files = [
5229 MockFile('path/OneMissing.java', ['interface OneMissing']),
5230 MockFile('path/TwoMarked.java', [
5231 '@NullMarked',
5232 'interface TwoMarked {',
5233 ]),
5234 ]
5235 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5236 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425237 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025238 self.assertEqual(1, len(results[0].items))
5239 self.assertIn('OneMissing.java', results[0].items[0])
5240
Henrique Nakashimac6605432025-04-24 18:11:595241 def testOnlyChecksAddedFiles(self):
5242 """Tests that missing @NullMarked or @NullUnmarked is only flagged in newly added files."""
5243 mock_input = MockInputApi()
5244 mock_input.files = [
5245 MockFile('path/OneMissing.java', ['public class OneMissing'], action='M'),
5246 ]
5247 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5248 self.assertEqual(0, len(results))
5249
Henrique Nakashima224ee2482025-03-21 18:35:025250 def testExcludesTests(self):
5251 """Tests that missing @NullMarked or @NullUnmarked are not flagged in tests."""
5252 mock_input = MockInputApi()
5253 mock_input.files = [
5254 MockFile('path/OneTest.java', ['public class OneTest']),
5255 ]
5256 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5257 self.assertEqual(0, len(results))
5258
5259 def testExcludesTestSupport(self):
5260 """Tests that missing @NullMarked or @NullUnmarked are not flagged in test support classes."""
5261 mock_input = MockInputApi()
5262 mock_input.files = [
5263 MockFile('path/test/Two.java', [
5264 'public class Two'
5265 ]),
5266 ]
5267 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5268 self.assertEqual(0, len(results))
5269
5270
Mike Dougherty1b8be712022-10-20 00:15:135271class AssertNoJsInIosTest(unittest.TestCase):
5272 def testErrorJs(self):
5273 input_api = MockInputApi()
5274 input_api.files = [
5275 MockFile('components/feature/ios/resources/script.js', []),
5276 MockFile('ios/chrome/feature/resources/script.js', []),
5277 ]
5278 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5279 self.assertEqual(1, len(results))
5280 self.assertEqual('error', results[0].type)
5281 self.assertEqual(2, len(results[0].items))
5282
5283 def testNonError(self):
5284 input_api = MockInputApi()
5285 input_api.files = [
5286 MockFile('chrome/resources/script.js', []),
5287 MockFile('components/feature/ios/resources/script.ts', []),
5288 MockFile('ios/chrome/feature/resources/script.ts', []),
5289 MockFile('ios/web/feature/resources/script.ts', []),
5290 MockFile('ios/third_party/script.js', []),
5291 MockFile('third_party/ios/script.js', []),
5292 ]
5293 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5294 self.assertEqual(0, len(results))
5295
5296 def testExistingFilesWarningOnly(self):
5297 input_api = MockInputApi()
5298 input_api.files = [
5299 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5300 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5301 ]
5302 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5303 self.assertEqual(1, len(results))
5304 self.assertEqual('warning', results[0].type)
5305 self.assertEqual(1, len(results[0].items))
5306
Mike Dougherty4d1050b2023-03-14 15:59:535307 def testMovedScriptWarningOnly(self):
5308 input_api = MockInputApi()
5309 input_api.files = [
5310 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5311 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5312 ]
5313 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5314 self.assertEqual(1, len(results))
5315 self.assertEqual('warning', results[0].type)
5316 self.assertEqual(1, len(results[0].items))
5317
Yuanqing Zhu9eef02832022-12-04 14:42:175318class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175319
Daniel Cheng566634ff2024-06-29 14:56:535320 def testHasAbbreviation(self):
5321 """test png file names with abbreviation that fails the check"""
5322 input_api = MockInputApi()
5323 input_api.files = [
5324 MockFile('image_a.png', [], action='A'),
5325 MockFile('image_a_.png', [], action='A'),
5326 MockFile('image_a_name.png', [], action='A'),
5327 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5328 action='A'),
5329 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5330 action='A'),
5331 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5332 action='A'),
5333 ]
5334 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5335 input_api, MockOutputApi())
5336 self.assertEqual(1, len(results))
5337 self.assertEqual('error', results[0].type)
5338 self.assertEqual(len(input_api.files), len(results[0].items))
5339
5340 def testNoAbbreviation(self):
5341 """test png file names without abbreviation that passes the check"""
5342 input_api = MockInputApi()
5343 input_api.files = [
5344 MockFile('a.png', [], action='A'),
5345 MockFile('_a.png', [], action='A'),
5346 MockFile('image.png', [], action='A'),
5347 MockFile('image_ab_.png', [], action='A'),
5348 MockFile('image_ab_name.png', [], action='A'),
5349 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5350 # They should pass now because the path components ahead of the file name are ignored in the check.
5351 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5352 action='A'),
5353 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5354 action='A'),
5355 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5356 action='A'),
5357 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5358 action='A'),
5359 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5360 [],
5361 action='A'),
5362 ]
5363 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5364 input_api, MockOutputApi())
5365 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175366
Arthur Sonzogni7109bd32023-10-03 10:34:425367class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425368
Daniel Cheng566634ff2024-06-29 14:56:535369 def testError(self):
5370 """Test patch adding dangling pointers are reported"""
5371 mock_input_api = MockInputApi()
5372 mock_output_api = MockOutputApi()
5373
5374 mock_input_api.change.DescriptionText = lambda: "description"
5375 mock_input_api.files = [
5376 MockAffectedFile(
5377 local_path="foo/foo.cc",
5378 old_contents=["raw_ptr<T>"],
5379 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5380 )
5381 ]
5382 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5383 mock_output_api)
5384 self.assertEqual(len(msgs), 1)
5385 self.assertEqual(len(msgs[0].message), 10)
5386 self.assertEqual(
5387 msgs[0].message[0],
5388 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5389 )
Arthur Sonzogni7109bd32023-10-03 10:34:425390
5391class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425392
Daniel Cheng566634ff2024-06-29 14:56:535393 def testError(self):
5394 """Test patch adding dangling pointers are reported"""
5395 mock_input_api = MockInputApi()
5396 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425397
Daniel Cheng566634ff2024-06-29 14:56:535398 mock_input_api.change.DescriptionText = lambda: "description"
5399 mock_input_api.files = [
5400 MockAffectedFile(
5401 local_path="foo/foo.cc",
5402 old_contents=["raw_ptr<T>"],
5403 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5404 )
5405 ]
5406 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5407 mock_output_api)
5408 self.assertEqual(len(msgs), 1)
5409 self.assertTrue(
5410 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5411 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425412
Daniel Cheng566634ff2024-06-29 14:56:535413 def testNonCppFile(self):
5414 """Test patch adding dangling pointers are not reported in non C++ files"""
5415 mock_input_api = MockInputApi()
5416 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425417
Daniel Cheng566634ff2024-06-29 14:56:535418 mock_input_api.change.DescriptionText = lambda: "description"
5419 mock_input_api.files = [
5420 MockAffectedFile(
5421 local_path="foo/README.md",
5422 old_contents=[""],
5423 new_contents=["The DanglingUntriaged annotation means"],
5424 )
5425 ]
5426 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5427 mock_output_api)
5428 self.assertEqual(len(msgs), 0)
5429
5430 def testDeveloperAcknowledgeInCommitDescription(self):
5431 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425432 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535433 mock_input_api = MockInputApi()
5434 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425435
Daniel Cheng566634ff2024-06-29 14:56:535436 mock_input_api.files = [
5437 MockAffectedFile(
5438 local_path="foo/foo.cc",
5439 old_contents=["raw_ptr<T>"],
5440 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5441 )
5442 ]
5443 mock_input_api.change.DescriptionText = lambda: (
5444 "DanglingUntriaged-notes: Sorry about this!")
5445 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5446 mock_output_api)
5447 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425448
Daniel Cheng566634ff2024-06-29 14:56:535449 def testDeveloperAcknowledgeInCommitFooter(self):
5450 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425451 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535452 mock_input_api = MockInputApi()
5453 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425454
Daniel Cheng566634ff2024-06-29 14:56:535455 mock_input_api.files = [
5456 MockAffectedFile(
5457 local_path="foo/foo.cc",
5458 old_contents=["raw_ptr<T>"],
5459 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5460 )
5461 ]
5462 mock_input_api.change.DescriptionText = lambda: "description"
5463 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5464 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5465 mock_output_api)
5466 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425467
Daniel Cheng566634ff2024-06-29 14:56:535468 def testCongrats(self):
5469 """Test the presubmit congrats users removing dangling pointers"""
5470 mock_input_api = MockInputApi()
5471 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425472
Daniel Cheng566634ff2024-06-29 14:56:535473 mock_input_api.files = [
5474 MockAffectedFile(
5475 local_path="foo/foo.cc",
5476 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5477 new_contents=["raw_ptr<T>"],
5478 )
5479 ]
5480 mock_input_api.change.DescriptionText = lambda: (
5481 "This patch fixes some DanglingUntriaged pointers!")
5482 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5483 mock_output_api)
5484 self.assertEqual(len(msgs), 1)
5485 self.assertTrue(
5486 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5487 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425488
Daniel Cheng566634ff2024-06-29 14:56:535489 def testRenameFile(self):
5490 """Patch that we do not warn about DanglingUntriaged when moving files"""
5491 mock_input_api = MockInputApi()
5492 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425493
Daniel Cheng566634ff2024-06-29 14:56:535494 mock_input_api.files = [
5495 MockAffectedFile(
5496 local_path="foo/foo.cc",
5497 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5498 new_contents=[""],
5499 action="D",
5500 ),
5501 MockAffectedFile(
5502 local_path="foo/foo.cc",
5503 old_contents=[""],
5504 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5505 action="A",
5506 ),
5507 ]
5508 mock_input_api.change.DescriptionText = lambda: (
5509 "This patch moves files")
5510 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5511 mock_output_api)
5512 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425513
Jan Keitel77be7522023-10-12 20:40:495514class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495515
Daniel Cheng566634ff2024-06-29 14:56:535516 def testNoInlineConstexprInHeaderFile(self):
5517 """Tests that non-inlined constexpr variables in headers fail the test."""
5518 input_api = MockInputApi()
5519 input_api.files = [
5520 MockAffectedFile('src/constants.h',
5521 ['constexpr int kVersion = 5;'])
5522 ]
5523 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5524 input_api, MockOutputApi())
5525 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495526
Daniel Cheng566634ff2024-06-29 14:56:535527 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5528 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5529 input_api = MockInputApi()
5530 input_api.files = [
5531 MockAffectedFile('src/constants.h',
5532 ['constexpr int kVersion = GetVersion();'])
5533 ]
5534 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5535 input_api, MockOutputApi())
5536 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495537
Daniel Cheng566634ff2024-06-29 14:56:535538 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5539 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5540 input_api = MockInputApi()
5541 input_api.files = [
5542 MockAffectedFile('src/constants.h',
5543 ['constexpr int kVersion = (4 + 5)*3;'])
5544 ]
5545 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5546 input_api, MockOutputApi())
5547 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495548
Daniel Cheng566634ff2024-06-29 14:56:535549 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5550 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5551 input_api = MockInputApi()
5552 input_api.files = [
5553 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5554 ]
5555 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5556 input_api, MockOutputApi())
5557 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495558
Daniel Cheng566634ff2024-06-29 14:56:535559 def testNoInlineConstexprInHeaderWithAttribute(self):
5560 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5561 input_api = MockInputApi()
5562 input_api.files = [
5563 MockAffectedFile('src/constants.h',
5564 ['constexpr [[maybe_unused]] int kVersion{5};'])
5565 ]
5566 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5567 input_api, MockOutputApi())
5568 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495569
Daniel Cheng566634ff2024-06-29 14:56:535570 def testInlineConstexprInHeaderWithAttribute(self):
5571 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5572 input_api = MockInputApi()
5573 input_api.files = [
5574 MockAffectedFile(
5575 'src/constants.h',
5576 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5577 MockAffectedFile(
5578 'src/constants.h',
5579 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5580 MockAffectedFile(
5581 'src/constants.h',
5582 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5583 ]
5584 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5585 input_api, MockOutputApi())
5586 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495587
Daniel Cheng566634ff2024-06-29 14:56:535588 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5589 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5590 input_api = MockInputApi()
5591 lines = [
5592 'constexpr char kLongName =',
5593 ' "This is a very long name of something.";'
5594 ]
5595 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5596 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5597 input_api, MockOutputApi())
5598 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495599
Daniel Cheng566634ff2024-06-29 14:56:535600 def testNoInlineConstexprInCCFile(self):
5601 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5602 input_api = MockInputApi()
5603 input_api.files = [
5604 MockAffectedFile('src/implementation.cc',
5605 ['constexpr int kVersion = 5;'])
5606 ]
5607 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5608 input_api, MockOutputApi())
5609 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495610
Daniel Cheng566634ff2024-06-29 14:56:535611 def testInlineConstexprInHeaderFile(self):
5612 """Tests that inlined constexpr variables in header files pass the test."""
5613 input_api = MockInputApi()
5614 input_api.files = [
5615 MockAffectedFile('src/constants.h',
5616 ['constexpr inline int kX = 5;']),
5617 MockAffectedFile('src/version.h',
5618 ['inline constexpr float kY = 5.0f;'])
5619 ]
5620 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5621 input_api, MockOutputApi())
5622 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495623
Daniel Cheng566634ff2024-06-29 14:56:535624 def testConstexprStandaloneFunctionInHeaderFile(self):
5625 """Tests that non-inlined constexpr functions in headers pass the test."""
5626 input_api = MockInputApi()
5627 input_api.files = [
5628 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5629 ]
5630 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5631 input_api, MockOutputApi())
5632 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495633
Daniel Cheng566634ff2024-06-29 14:56:535634 def testConstexprWithAbseilAttributeInHeader(self):
5635 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5636 input_api = MockInputApi()
5637 input_api.files = [
5638 MockAffectedFile('src/helpers.h',
5639 ['ABSL_FOOFOO constexpr int i = 5;'])
5640 ]
5641 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5642 input_api, MockOutputApi())
5643 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495644
Daniel Cheng566634ff2024-06-29 14:56:535645 def testInlineConstexprWithAbseilAttributeInHeader(self):
5646 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5647 input_api = MockInputApi()
5648 input_api.files = [
5649 MockAffectedFile('src/helpers.h',
5650 ['constexpr ABSL_FOO inline int i = 5;'])
5651 ]
5652 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5653 input_api, MockOutputApi())
5654 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495655
Daniel Cheng566634ff2024-06-29 14:56:535656 def testConstexprWithClangAttributeInHeader(self):
5657 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5658 input_api = MockInputApi()
5659 input_api.files = [
5660 MockAffectedFile('src/helpers.h',
5661 ['[[clang::someattribute]] constexpr int i = 5;'])
5662 ]
5663 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5664 input_api, MockOutputApi())
5665 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495666
Daniel Cheng566634ff2024-06-29 14:56:535667 def testInlineConstexprWithClangAttributeInHeader(self):
5668 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5669 input_api = MockInputApi()
5670 input_api.files = [
5671 MockAffectedFile(
5672 'src/helpers.h',
5673 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5674 ]
5675 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5676 input_api, MockOutputApi())
5677 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425678
Daniel Cheng566634ff2024-06-29 14:56:535679 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5680 """Tests that non-inlined constexpr class members pass the test."""
5681 input_api = MockInputApi()
5682 lines = [
5683 'class SomeClass {', ' public:',
5684 ' static constexpr kVersion = 5;', '};'
5685 ]
5686 input_api.files = [MockAffectedFile('src/class.h', lines)]
5687 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5688 input_api, MockOutputApi())
5689 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045690
Daniel Cheng566634ff2024-06-29 14:56:535691 def testTodoBugReferencesWithOldBugId(self):
5692 """Tests that an old monorail bug ID in a TODO fails."""
5693 input_api = MockInputApi()
5694 input_api.files = [
5695 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5696 ]
5697 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5698 self.assertEqual(1, len(warnings))
5699
5700 def testTodoBugReferencesWithUpdatedBugId(self):
5701 """Tests that a new issue tracker bug ID in a TODO passes."""
5702 input_api = MockInputApi()
5703 input_api.files = [
5704 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5705 ]
5706 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5707 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045708
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155709class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535710 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155711
Daniel Cheng566634ff2024-06-29 14:56:535712 def testCppMobilePlatformPath(self):
5713 input_api = MockInputApi()
5714 input_api.files = [
5715 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5716 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5717 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5718 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5719 MockFile('components/foo/delegate_android.cc',
5720 ['IsSyncFeatureActive']),
5721 MockFile('components/foo/delegate_ios.cc',
5722 ['IsSyncFeatureActive']),
5723 MockFile('components/foo/android_delegate.cc',
5724 ['IsSyncFeatureActive']),
5725 MockFile('components/foo/ios_delegate.cc',
5726 ['IsSyncFeatureActive']),
5727 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155728
Daniel Cheng566634ff2024-06-29 14:56:535729 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155730
Ben Pastenee79d66112025-04-23 19:46:155731 self.assertEqual(7, len(results))
5732 self.assertTrue(all('chrome/browser/android/file.cc' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535733 self.assertTrue('chrome/android/file.cc' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155734 self.assertTrue('ios/file.mm' in results[1].message),
5735 self.assertTrue('components/foo/ios/file.cc' in results[2].message),
Daniel Cheng566634ff2024-06-29 14:56:535736 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155737 'components/foo/delegate_android.cc' in results[3].message),
Daniel Cheng566634ff2024-06-29 14:56:535738 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155739 'components/foo/delegate_ios.cc' in results[4].message),
Daniel Cheng566634ff2024-06-29 14:56:535740 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155741 'components/foo/android_delegate.cc' in results[5].message),
Daniel Cheng566634ff2024-06-29 14:56:535742 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155743 'components/foo/ios_delegate.cc' in results[6].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155744
Daniel Cheng566634ff2024-06-29 14:56:535745 def testCppNonMobilePlatformPath(self):
5746 input_api = MockInputApi()
5747 input_api.files = [
5748 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5749 MockFile('bios/file.cc', ['HasSyncConsent']),
5750 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5751 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155752
Daniel Cheng566634ff2024-06-29 14:56:535753 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155754
Daniel Cheng566634ff2024-06-29 14:56:535755 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155756
Daniel Cheng566634ff2024-06-29 14:56:535757 def testJavaPath(self):
5758 input_api = MockInputApi()
5759 input_api.files = [
5760 MockFile('components/foo/file1.java', ['otherFunction']),
5761 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5762 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5763 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5764 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5765 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155766
Daniel Cheng566634ff2024-06-29 14:56:535767 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155768
Ben Pastenee79d66112025-04-23 19:46:155769 self.assertEqual(4, len(results))
5770 self.assertTrue(all('components/foo/file1.java' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535771 self.assertTrue('components/foo/file2.java' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155772 self.assertTrue('chrome/foo/file3.java' in results[1].message),
5773 self.assertTrue('chrome/foo/file4.java' in results[2].message),
5774 self.assertTrue('chrome/foo/file5.java' in results[3].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155775
5776
Erik Chen1396bbe2025-01-27 23:39:365777class CheckAnonymousNamespaceTest(unittest.TestCase):
5778 """Test the presubmit for anonymous namespaces."""
5779
5780 def testAnonymousNamespace(self):
5781 input_api = MockInputApi()
5782 input_api.files = [
5783 MockFile('chrome/test.h', ['namespace {']),
5784 MockFile('chrome/test.cc', ['namespace {']),
5785 MockFile('chrome/test.java', ['namespace {']),
5786 MockFile('chrome/test.cpp', ['namespace {']),
5787 MockFile('chrome/test.txt', ['namespace {']),
5788 ]
5789
5790 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
5791
5792 self.assertEqual(1, len(results))
5793 self.assertTrue(
5794 'chrome/test.h' in results[0].message),
5795 self.assertFalse(
5796 'chrome/test.cc' in results[0].message),
5797 self.assertFalse(
5798 'chrome/test.java' in results[0].message),
5799 self.assertFalse(
5800 'chrome/test.cpp' in results[0].message),
5801 self.assertFalse(
5802 'chrome/test.txt' in results[0].message),
5803
5804
[email protected]2299dcf2012-11-15 19:56:245805if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535806 unittest.main()