blob: 65b2b67c101e647cb375e1d365df5e9d290ef18f [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
marja@chromium.org2299dcf2012-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
yoz@chromium.org99171a92014-06-03 08:44:478import subprocess
Min Qinbc44383c2023-02-22 17:25:269import textwrap
marja@chromium.org2299dcf2012-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
marja@chromium.org2299dcf2012-11-15 19:56:2416
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3917
yoz@chromium.org99171a92014-06-03 08:44:4718_TEST_DATA_DIR = 'base/test/data/presubmit'
19
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3920
dbeam@chromium.orgb00342e7f2013-03-26 16:21:5421class VersionControlConflictsTest(unittest.TestCase):
dbeam@chromium.org70ca77752012-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
enne@chromium.orgb8079ae4a2012-12-05 19:56:4945class BadExtensionsTest(unittest.TestCase):
enne@chromium.orgb8079ae4a2012-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 ]
enne@chromium.orgb8079ae4a2012-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])
enne@chromium.orgb8079ae4a2012-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 ]
enne@chromium.orgb8079ae4a2012-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))
enne@chromium.orgb8079ae4a2012-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])
dbeam@chromium.orgb00342e7f2013-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 {}))
tony@chromium.orgf32e2d1e2013-07-26 21:39:08447
Andrew Grieveb77ac762024-11-29 15:01:48448 def testFindAddedDepsThatRequireReview(self):
449 caring = ['new_usages_require_review = True']
450 self.input_api.InitFiles([
451 MockAffectedFile('cares/DEPS', caring),
452 MockAffectedFile('cares/inherits/DEPS', []),
453 MockAffectedFile('willynilly/DEPS', []),
454 MockAffectedFile('willynilly/butactually/DEPS', caring),
455 ])
456
457 expected = {
458 'cares': True,
459 'cares/sub/sub': True,
460 'cares/inherits': True,
461 'cares/inherits/sub': True,
462 'willynilly': False,
463 'willynilly/butactually': True,
464 'willynilly/butactually/sub': True,
465 }
466 results = PRESUBMIT._FindAddedDepsThatRequireReview(
467 self.input_api, set(expected))
468 actual = {k: k in results for k in expected}
469 self.assertEqual(expected, actual)
470
Daniel Cheng566634ff2024-06-29 14:56:53471 class FakeOwnersClient(object):
472 APPROVED = "APPROVED"
473 PENDING = "PENDING"
474 returns = {}
Scott Leebf6a0942024-06-26 22:59:39475
Daniel Cheng566634ff2024-06-29 14:56:53476 def ListOwners(self, *args, **kwargs):
477 return self.returns.get(self.ListOwners.__name__, "")
Scott Leebf6a0942024-06-26 22:59:39478
Daniel Cheng566634ff2024-06-29 14:56:53479 def mockListOwners(self, owners):
480 self.returns[self.ListOwners.__name__] = owners
Scott Leebf6a0942024-06-26 22:59:39481
Daniel Cheng566634ff2024-06-29 14:56:53482 def GetFilesApprovalStatus(self, *args, **kwargs):
483 return self.returns.get(self.GetFilesApprovalStatus.__name__, {})
Scott Leebf6a0942024-06-26 22:59:39484
Daniel Cheng566634ff2024-06-29 14:56:53485 def mockGetFilesApprovalStatus(self, status):
486 self.returns[self.GetFilesApprovalStatus.__name__] = status
Scott Leebf6a0942024-06-26 22:59:39487
Daniel Cheng566634ff2024-06-29 14:56:53488 def SuggestOwners(self, *args, **kwargs):
489 return ["eng1", "eng2", "eng3"]
Scott Leebf6a0942024-06-26 22:59:39490
Daniel Cheng566634ff2024-06-29 14:56:53491 class fakeGerrit(object):
Scott Leebf6a0942024-06-26 22:59:39492
Daniel Cheng566634ff2024-06-29 14:56:53493 def IsOwnersOverrideApproved(self, issue):
494 return False
Scott Leebf6a0942024-06-26 22:59:39495
Daniel Cheng566634ff2024-06-29 14:56:53496 def mockOwnersAndReviewers(self, owner, reviewers):
Scott Leebf6a0942024-06-26 22:59:39497
Daniel Cheng566634ff2024-06-29 14:56:53498 def mock(*args, **kwargs):
499 return [owner, reviewers]
Scott Leebf6a0942024-06-26 22:59:39500
Daniel Cheng566634ff2024-06-29 14:56:53501 self.input_api.canned_checks.GetCodereviewOwnerAndReviewers = mock
Scott Leebf6a0942024-06-26 22:59:39502
Daniel Cheng566634ff2024-06-29 14:56:53503 def mockListSubmodules(self, paths):
Scott Leebf6a0942024-06-26 22:59:39504
Daniel Cheng566634ff2024-06-29 14:56:53505 def mock(*args, **kwargs):
506 return paths
Scott Leebf6a0942024-06-26 22:59:39507
Daniel Cheng566634ff2024-06-29 14:56:53508 self.input_api.ListSubmodules = mock
509
510 def testApprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08511 self.input_api.InitFiles([
Joanna Wang130e7bdd2024-12-10 17:39:03512 MockAffectedFile('pdf/DEPS',
513 ['include_rules=["+v8/123", "+foo/bar"]']),
Andrew Grieveb77ac762024-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 Grieveb77ac762024-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
tony@chromium.orgf32e2d1e2013-07-26 21:39:08552
yoz@chromium.org99171a92014-06-03 08:44:47553class JSONParsingTest(unittest.TestCase):
yoz@chromium.org99171a92014-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))
yoz@chromium.org99171a92014-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 ]
yoz@chromium.org99171a92014-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 ]
yoz@chromium.org99171a92014-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))
yoz@chromium.org99171a92014-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))
yoz@chromium.org99171a92014-06-03 08:44:47616
617
618class IDLParsingTest(unittest.TestCase):
yoz@chromium.org99171a92014-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))
yoz@chromium.org99171a92014-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 ]
yoz@chromium.org99171a92014-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))
yoz@chromium.org99171a92014-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(
1780 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1781 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1782 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
1783 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381784
Daniel Cheng566634ff2024-06-29 14:56:531785 # Tag must not contain
1786 nb = len(msgs[4].items)
1787 self.assertEqual(
1788 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1789 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1790 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1791 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511792
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391793
estadee17314a02017-01-12 16:22:161794class GoogleAnswerUrlFormatTest(unittest.TestCase):
1795
Daniel Cheng566634ff2024-06-29 14:56:531796 def testCatchAnswerUrlId(self):
1797 input_api = MockInputApi()
1798 input_api.files = [
1799 MockFile('somewhere/file.cc', [
1800 'char* host = '
1801 ' "https://support.google.com/chrome/answer/123456";'
1802 ]),
1803 MockFile('somewhere_else/file.cc', [
1804 'char* host = '
1805 ' "https://support.google.com/chrome/a/answer/123456";'
1806 ]),
1807 ]
estadee17314a02017-01-12 16:22:161808
Daniel Cheng566634ff2024-06-29 14:56:531809 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1810 input_api, MockOutputApi())
1811 self.assertEqual(1, len(warnings))
1812 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161813
Daniel Cheng566634ff2024-06-29 14:56:531814 def testAllowAnswerUrlParam(self):
1815 input_api = MockInputApi()
1816 input_api.files = [
1817 MockFile('somewhere/file.cc', [
1818 'char* host = '
1819 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1820 ]),
1821 ]
estadee17314a02017-01-12 16:22:161822
Daniel Cheng566634ff2024-06-29 14:56:531823 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1824 input_api, MockOutputApi())
1825 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161826
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391827
reillyi38965732015-11-16 18:27:331828class HardcodedGoogleHostsTest(unittest.TestCase):
1829
Daniel Cheng566634ff2024-06-29 14:56:531830 def testWarnOnAssignedLiterals(self):
1831 input_api = MockInputApi()
1832 input_api.files = [
1833 MockFile('content/file.cc',
1834 ['char* host = "https://www.google.com";']),
1835 MockFile('content/file.cc',
1836 ['char* host = "https://www.googleapis.com";']),
1837 MockFile('content/file.cc',
1838 ['char* host = "https://clients1.google.com";']),
1839 ]
reillyi38965732015-11-16 18:27:331840
Daniel Cheng566634ff2024-06-29 14:56:531841 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1842 input_api, MockOutputApi())
1843 self.assertEqual(1, len(warnings))
1844 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331845
Daniel Cheng566634ff2024-06-29 14:56:531846 def testAllowInComment(self):
1847 input_api = MockInputApi()
1848 input_api.files = [
1849 MockFile('content/file.cc',
1850 ['char* host = "https://www.aol.com"; // google.com'])
1851 ]
reillyi38965732015-11-16 18:27:331852
Daniel Cheng566634ff2024-06-29 14:56:531853 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1854 input_api, MockOutputApi())
1855 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331856
dgn4401aa52015-04-29 16:26:171857
James Cook6b6597c2019-11-06 22:05:291858class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1859
Daniel Cheng566634ff2024-06-29 14:56:531860 def testWarnsOnChromeOsDirectories(self):
1861 files = [
1862 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1863 MockFile('chrome/browser/chromeos/file.cc',
1864 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1865 MockFile('chromeos/file.cc',
1866 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1867 MockFile('components/arc/file.cc',
1868 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1869 MockFile('components/exo/file.cc',
1870 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1871 ]
1872 input_api = MockInputApi()
1873 for file in files:
1874 input_api.files = [file]
1875 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1876 input_api, MockOutputApi())
1877 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291878
Daniel Cheng566634ff2024-06-29 14:56:531879 def testDoesNotWarnOnSyncOsPref(self):
1880 input_api = MockInputApi()
1881 input_api.files = [
1882 MockFile('chromeos/file.cc',
1883 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1884 ]
1885 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1886 input_api, MockOutputApi())
1887 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291888
Daniel Cheng566634ff2024-06-29 14:56:531889 def testDoesNotWarnOnOtherDirectories(self):
1890 input_api = MockInputApi()
1891 input_api.files = [
1892 MockFile('chrome/browser/ui/file.cc',
1893 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1894 MockFile('components/sync/file.cc',
1895 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1896 MockFile('content/browser/file.cc',
1897 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1898 MockFile('a/notchromeos/file.cc',
1899 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1900 ]
1901 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1902 input_api, MockOutputApi())
1903 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291904
Daniel Cheng566634ff2024-06-29 14:56:531905 def testSeparateWarningForPriorityPrefs(self):
1906 input_api = MockInputApi()
1907 input_api.files = [
1908 MockFile('chromeos/file.cc', [
1909 'PrefRegistrySyncable::SYNCABLE_PREF',
1910 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
1911 ]),
1912 ]
1913 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1914 input_api, MockOutputApi())
1915 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:291916
1917
jbriance9e12f162016-11-25 07:57:501918class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:501919
Daniel Cheng566634ff2024-06-29 14:56:531920 def testCheckHeadersOnlyOutsideThirdParty(self):
1921 mock_input_api = MockInputApi()
1922 mock_input_api.files = [
1923 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
1924 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
1925 ]
1926 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1927 mock_input_api, MockOutputApi())
1928 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501929
Daniel Cheng566634ff2024-06-29 14:56:531930 def testNoNestedDeclaration(self):
1931 mock_input_api = MockInputApi()
1932 mock_input_api.files = [
1933 MockAffectedFile('somewhere/header.h', [
1934 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
1935 ])
1936 ]
1937 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1938 mock_input_api, MockOutputApi())
1939 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501940
Daniel Cheng566634ff2024-06-29 14:56:531941 def testSubStrings(self):
1942 mock_input_api = MockInputApi()
1943 mock_input_api.files = [
1944 MockAffectedFile('somewhere/header.h', [
1945 'class NotUsefulClass;', 'struct SomeStruct;',
1946 'UsefulClass *p1;', 'SomeStructPtr *p2;'
1947 ])
1948 ]
1949 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1950 mock_input_api, MockOutputApi())
1951 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:501952
Daniel Cheng566634ff2024-06-29 14:56:531953 def testUselessForwardDeclaration(self):
1954 mock_input_api = MockInputApi()
1955 mock_input_api.files = [
1956 MockAffectedFile('somewhere/header.h', [
1957 'class DummyClass;', 'struct DummyStruct;',
1958 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
1959 ])
1960 ]
1961 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1962 mock_input_api, MockOutputApi())
1963 self.assertEqual(2, len(warnings))
1964
1965 def testBlinkHeaders(self):
1966 mock_input_api = MockInputApi()
1967 mock_input_api.files = [
1968 MockAffectedFile('third_party/blink/header.h', [
1969 'class DummyClass;',
1970 'struct DummyStruct;',
1971 ]),
1972 MockAffectedFile('third_party\\blink\\header.h', [
1973 'class DummyClass;',
1974 'struct DummyStruct;',
1975 ])
1976 ]
1977 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1978 mock_input_api, MockOutputApi())
1979 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:311980
jbriance9e12f162016-11-25 07:57:501981
rlanday6802cf632017-05-30 17:48:361982class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:361983
Daniel Cheng566634ff2024-06-29 14:56:531984 def testThirdPartyNotWebKitIgnored(self):
1985 mock_input_api = MockInputApi()
1986 mock_input_api.files = [
1987 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1988 MockAffectedFile('third_party/test/test.cpp',
1989 '#include "../header.h"'),
1990 ]
rlanday6802cf632017-05-30 17:48:361991
Daniel Cheng566634ff2024-06-29 14:56:531992 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:361993
Daniel Cheng566634ff2024-06-29 14:56:531994 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
1995 mock_output_api)
1996 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:361997
Daniel Cheng566634ff2024-06-29 14:56:531998 def testNonCppFileIgnored(self):
1999 mock_input_api = MockInputApi()
2000 mock_input_api.files = [
2001 MockAffectedFile('test.py', '#include "../header.h"'),
2002 ]
rlanday6802cf632017-05-30 17:48:362003
Daniel Cheng566634ff2024-06-29 14:56:532004 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362005
Daniel Cheng566634ff2024-06-29 14:56:532006 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2007 mock_output_api)
2008 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362009
Daniel Cheng566634ff2024-06-29 14:56:532010 def testInnocuousChangesAllowed(self):
2011 mock_input_api = MockInputApi()
2012 mock_input_api.files = [
2013 MockAffectedFile('test.cpp', '#include "header.h"'),
2014 MockAffectedFile('test2.cpp', '../'),
2015 ]
rlanday6802cf632017-05-30 17:48:362016
Daniel Cheng566634ff2024-06-29 14:56:532017 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362018
Daniel Cheng566634ff2024-06-29 14:56:532019 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2020 mock_output_api)
2021 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362022
Daniel Cheng566634ff2024-06-29 14:56:532023 def testRelativeIncludeNonWebKitProducesError(self):
2024 mock_input_api = MockInputApi()
2025 mock_input_api.files = [
2026 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2027 ]
rlanday6802cf632017-05-30 17:48:362028
Daniel Cheng566634ff2024-06-29 14:56:532029 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362030
Daniel Cheng566634ff2024-06-29 14:56:532031 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2032 mock_output_api)
2033 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362034
Daniel Cheng566634ff2024-06-29 14:56:532035 def testRelativeIncludeWebKitProducesError(self):
2036 mock_input_api = MockInputApi()
2037 mock_input_api.files = [
2038 MockAffectedFile('third_party/blink/test.cpp',
2039 ['#include "../header.h']),
2040 ]
rlanday6802cf632017-05-30 17:48:362041
Daniel Cheng566634ff2024-06-29 14:56:532042 mock_output_api = MockOutputApi()
2043
2044 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2045 mock_output_api)
2046 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242047
Daniel Cheng13ca61a882017-08-25 15:11:252048
Daniel Bratell65b033262019-04-23 08:17:062049class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062050
Daniel Cheng566634ff2024-06-29 14:56:532051 def testThirdPartyNotBlinkIgnored(self):
2052 mock_input_api = MockInputApi()
2053 mock_input_api.files = [
2054 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2055 ]
Daniel Bratell65b033262019-04-23 08:17:062056
Daniel Cheng566634ff2024-06-29 14:56:532057 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062058
Daniel Cheng566634ff2024-06-29 14:56:532059 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2060 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062061
Daniel Cheng566634ff2024-06-29 14:56:532062 def testPythonFileIgnored(self):
2063 mock_input_api = MockInputApi()
2064 mock_input_api.files = [
2065 MockAffectedFile('test.py', '#include "file.cc"'),
2066 ]
Daniel Bratell65b033262019-04-23 08:17:062067
Daniel Cheng566634ff2024-06-29 14:56:532068 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062069
Daniel Cheng566634ff2024-06-29 14:56:532070 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2071 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062072
Daniel Cheng566634ff2024-06-29 14:56:532073 def testIncFilesAccepted(self):
2074 mock_input_api = MockInputApi()
2075 mock_input_api.files = [
2076 MockAffectedFile('test.py', '#include "file.inc"'),
2077 ]
Daniel Bratell65b033262019-04-23 08:17:062078
Daniel Cheng566634ff2024-06-29 14:56:532079 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062080
Daniel Cheng566634ff2024-06-29 14:56:532081 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2082 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062083
Daniel Cheng566634ff2024-06-29 14:56:532084 def testInnocuousChangesAllowed(self):
2085 mock_input_api = MockInputApi()
2086 mock_input_api.files = [
2087 MockAffectedFile('test.cpp', '#include "header.h"'),
2088 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2089 ]
Daniel Bratell65b033262019-04-23 08:17:062090
Daniel Cheng566634ff2024-06-29 14:56:532091 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062092
Daniel Cheng566634ff2024-06-29 14:56:532093 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2094 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062095
Daniel Cheng566634ff2024-06-29 14:56:532096 def testCcIncludeNonBlinkProducesError(self):
2097 mock_input_api = MockInputApi()
2098 mock_input_api.files = [
2099 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2100 ]
Daniel Bratell65b033262019-04-23 08:17:062101
Daniel Cheng566634ff2024-06-29 14:56:532102 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062103
Daniel Cheng566634ff2024-06-29 14:56:532104 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2105 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062106
Daniel Cheng566634ff2024-06-29 14:56:532107 def testCppIncludeBlinkProducesError(self):
2108 mock_input_api = MockInputApi()
2109 mock_input_api.files = [
2110 MockAffectedFile('third_party/blink/test.cpp',
2111 ['#include "foo/file.cpp"']),
2112 ]
Daniel Bratell65b033262019-04-23 08:17:062113
Daniel Cheng566634ff2024-06-29 14:56:532114 mock_output_api = MockOutputApi()
2115
2116 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2117 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062118
2119
Andrew Grieve1b290e4a22020-11-24 20:07:012120class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012121
Daniel Cheng566634ff2024-06-29 14:56:532122 def testAddBareGlobs(self):
2123 mock_input_api = MockInputApi()
2124 mock_input_api.files = [
2125 MockAffectedFile('base/stuff.gni',
2126 ['forward_variables_from(invoker, "*")']),
2127 MockAffectedFile('base/BUILD.gn',
2128 ['forward_variables_from(invoker, "*")']),
2129 ]
2130 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2131 MockOutputApi())
2132 self.assertEqual(1, len(warnings))
2133 msg = '\n'.join(warnings[0].items)
2134 self.assertIn('base/stuff.gni', msg)
2135 # Should not check .gn files. Local templates don't need to care about
2136 # visibility / testonly.
2137 self.assertNotIn('base/BUILD.gn', msg)
2138
2139 def testValidUses(self):
2140 mock_input_api = MockInputApi()
2141 mock_input_api.files = [
2142 MockAffectedFile('base/stuff.gni',
2143 ['forward_variables_from(invoker, "*", [])']),
2144 MockAffectedFile('base/stuff2.gni', [
2145 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2146 ]),
2147 MockAffectedFile(
2148 'base/stuff3.gni',
2149 ['forward_variables_from(invoker, [ "testonly" ])']),
2150 ]
2151 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2152 MockOutputApi())
2153 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012154
2155
Sean Kaucb7c9b32022-10-25 21:25:522156class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522157
Daniel Cheng566634ff2024-06-29 14:56:532158 def testAddAbsolutePath(self):
2159 mock_input_api = MockInputApi()
2160 mock_input_api.files = [
2161 MockAffectedFile('base/BUILD.gn',
2162 ['rebase_path("$target_gen_dir", "//")']),
2163 MockAffectedFile('base/root/BUILD.gn',
2164 ['rebase_path("$target_gen_dir", "/")']),
2165 MockAffectedFile('base/variable/BUILD.gn',
2166 ['rebase_path(target_gen_dir, "/")']),
2167 ]
2168 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2169 self.assertEqual(1, len(warnings))
2170 msg = '\n'.join(warnings[0].items)
2171 self.assertIn('base/BUILD.gn', msg)
2172 self.assertIn('base/root/BUILD.gn', msg)
2173 self.assertIn('base/variable/BUILD.gn', msg)
2174 self.assertEqual(3, len(warnings[0].items))
2175
2176 def testValidUses(self):
2177 mock_input_api = MockInputApi()
2178 mock_input_api.files = [
2179 MockAffectedFile(
2180 'base/foo/BUILD.gn',
2181 ['rebase_path("$target_gen_dir", root_build_dir)']),
2182 MockAffectedFile(
2183 'base/bar/BUILD.gn',
2184 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2185 MockAffectedFile('base/baz/BUILD.gn',
2186 ['rebase_path(target_gen_dir, root_build_dir)']),
2187 MockAffectedFile(
2188 'base/baz/BUILD.gn',
2189 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2190 MockAffectedFile('base/okay_slash/BUILD.gn',
2191 ['rebase_path(".", "//")']),
2192 ]
2193 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2194 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522195
2196
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192197class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192198
Daniel Cheng566634ff2024-06-29 14:56:532199 def testAddHeaderWithoutGn(self):
2200 mock_input_api = MockInputApi()
2201 mock_input_api.files = [
2202 MockAffectedFile('base/stuff.h', ''),
2203 ]
2204 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2205 mock_input_api, MockOutputApi())
2206 self.assertEqual(1, len(warnings))
2207 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192208
Daniel Cheng566634ff2024-06-29 14:56:532209 def testModifyHeader(self):
2210 mock_input_api = MockInputApi()
2211 mock_input_api.files = [
2212 MockAffectedFile('base/stuff.h', '', action='M'),
2213 ]
2214 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2215 mock_input_api, MockOutputApi())
2216 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192217
Daniel Cheng566634ff2024-06-29 14:56:532218 def testDeleteHeader(self):
2219 mock_input_api = MockInputApi()
2220 mock_input_api.files = [
2221 MockAffectedFile('base/stuff.h', '', action='D'),
2222 ]
2223 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2224 mock_input_api, MockOutputApi())
2225 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192226
Daniel Cheng566634ff2024-06-29 14:56:532227 def testAddHeaderWithGn(self):
2228 mock_input_api = MockInputApi()
2229 mock_input_api.files = [
2230 MockAffectedFile('base/stuff.h', ''),
2231 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2232 ]
2233 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2234 mock_input_api, MockOutputApi())
2235 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192236
Daniel Cheng566634ff2024-06-29 14:56:532237 def testAddHeaderWithGni(self):
2238 mock_input_api = MockInputApi()
2239 mock_input_api.files = [
2240 MockAffectedFile('base/stuff.h', ''),
2241 MockAffectedFile('base/files.gni', 'stuff.h'),
2242 ]
2243 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2244 mock_input_api, MockOutputApi())
2245 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192246
Daniel Cheng566634ff2024-06-29 14:56:532247 def testAddHeaderWithOther(self):
2248 mock_input_api = MockInputApi()
2249 mock_input_api.files = [
2250 MockAffectedFile('base/stuff.h', ''),
2251 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2252 ]
2253 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2254 mock_input_api, MockOutputApi())
2255 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192256
Daniel Cheng566634ff2024-06-29 14:56:532257 def testAddHeaderWithWrongGn(self):
2258 mock_input_api = MockInputApi()
2259 mock_input_api.files = [
2260 MockAffectedFile('base/stuff.h', ''),
2261 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2262 ]
2263 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2264 mock_input_api, MockOutputApi())
2265 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192266
Daniel Cheng566634ff2024-06-29 14:56:532267 def testAddHeadersWithGn(self):
2268 mock_input_api = MockInputApi()
2269 mock_input_api.files = [
2270 MockAffectedFile('base/stuff.h', ''),
2271 MockAffectedFile('base/another.h', ''),
2272 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2273 ]
2274 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2275 mock_input_api, MockOutputApi())
2276 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192277
Daniel Cheng566634ff2024-06-29 14:56:532278 def testAddHeadersWithWrongGn(self):
2279 mock_input_api = MockInputApi()
2280 mock_input_api.files = [
2281 MockAffectedFile('base/stuff.h', ''),
2282 MockAffectedFile('base/another.h', ''),
2283 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2284 ]
2285 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2286 mock_input_api, MockOutputApi())
2287 self.assertEqual(1, len(warnings))
2288 self.assertFalse('base/stuff.h' in warnings[0].items)
2289 self.assertTrue('base/another.h' in warnings[0].items)
2290
2291 def testAddHeadersWithWrongGn2(self):
2292 mock_input_api = MockInputApi()
2293 mock_input_api.files = [
2294 MockAffectedFile('base/stuff.h', ''),
2295 MockAffectedFile('base/another.h', ''),
2296 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2297 ]
2298 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2299 mock_input_api, MockOutputApi())
2300 self.assertEqual(1, len(warnings))
2301 self.assertTrue('base/stuff.h' in warnings[0].items)
2302 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192303
2304
Michael Giuffridad3bc8672018-10-25 22:48:022305class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022306
Daniel Cheng566634ff2024-06-29 14:56:532307 def testProductNameInDesc(self):
2308 mock_input_api = MockInputApi()
2309 mock_input_api.files = [
2310 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2311 '<message name="Foo" desc="Welcome to Chrome">',
2312 ' Welcome to Chrome!',
2313 '</message>',
2314 ]),
2315 MockAffectedFile('chrome/app/chromium_strings.grd', [
2316 '<message name="Bar" desc="Welcome to Chrome">',
2317 ' Welcome to Chromium!',
2318 '</message>',
2319 ]),
2320 ]
2321 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2322 mock_input_api, MockOutputApi())
2323 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022324
Daniel Cheng566634ff2024-06-29 14:56:532325 def testChromeInChromium(self):
2326 mock_input_api = MockInputApi()
2327 mock_input_api.files = [
2328 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2329 '<message name="Foo" desc="Welcome to Chrome">',
2330 ' Welcome to Chrome!',
2331 '</message>',
2332 ]),
2333 MockAffectedFile('chrome/app/chromium_strings.grd', [
2334 '<message name="Bar" desc="Welcome to Chrome">',
2335 ' Welcome to Chrome!',
2336 '</message>',
2337 ]),
2338 ]
2339 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2340 mock_input_api, MockOutputApi())
2341 self.assertEqual(1, len(warnings))
2342 self.assertTrue(
2343 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022344
Daniel Cheng566634ff2024-06-29 14:56:532345 def testChromiumInChrome(self):
2346 mock_input_api = MockInputApi()
2347 mock_input_api.files = [
2348 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2349 '<message name="Foo" desc="Welcome to Chrome">',
2350 ' Welcome to Chromium!',
2351 '</message>',
2352 ]),
2353 MockAffectedFile('chrome/app/chromium_strings.grd', [
2354 '<message name="Bar" desc="Welcome to Chrome">',
2355 ' Welcome to Chromium!',
2356 '</message>',
2357 ]),
2358 ]
2359 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2360 mock_input_api, MockOutputApi())
2361 self.assertEqual(1, len(warnings))
2362 self.assertTrue(
2363 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202364
Daniel Cheng566634ff2024-06-29 14:56:532365 def testChromeForTestingInChromium(self):
2366 mock_input_api = MockInputApi()
2367 mock_input_api.files = [
2368 MockAffectedFile('chrome/app/chromium_strings.grd', [
2369 '<message name="Bar" desc="Welcome to Chrome">',
2370 ' Welcome to Chrome for Testing!',
2371 '</message>',
2372 ]),
2373 ]
2374 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2375 mock_input_api, MockOutputApi())
2376 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202377
Daniel Cheng566634ff2024-06-29 14:56:532378 def testChromeForTestingInChrome(self):
2379 mock_input_api = MockInputApi()
2380 mock_input_api.files = [
2381 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2382 '<message name="Bar" desc="Welcome to Chrome">',
2383 ' Welcome to Chrome for Testing!',
2384 '</message>',
2385 ]),
2386 ]
2387 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2388 mock_input_api, MockOutputApi())
2389 self.assertEqual(1, len(warnings))
2390 self.assertTrue(
2391 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022392
Daniel Cheng566634ff2024-06-29 14:56:532393 def testMultipleInstances(self):
2394 mock_input_api = MockInputApi()
2395 mock_input_api.files = [
2396 MockAffectedFile('chrome/app/chromium_strings.grd', [
2397 '<message name="Bar" desc="Welcome to Chrome">',
2398 ' Welcome to Chrome!',
2399 '</message>',
2400 '<message name="Baz" desc="A correct message">',
2401 ' Chromium is the software you are using.',
2402 '</message>',
2403 '<message name="Bat" desc="An incorrect message">',
2404 ' Google Chrome is the software you are using.',
2405 '</message>',
2406 ]),
2407 ]
2408 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2409 mock_input_api, MockOutputApi())
2410 self.assertEqual(1, len(warnings))
2411 self.assertTrue(
2412 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2413 self.assertTrue(
2414 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2415
2416 def testMultipleWarnings(self):
2417 mock_input_api = MockInputApi()
2418 mock_input_api.files = [
2419 MockAffectedFile('chrome/app/chromium_strings.grd', [
2420 '<message name="Bar" desc="Welcome to Chrome">',
2421 ' Welcome to Chrome!',
2422 '</message>',
2423 '<message name="Baz" desc="A correct message">',
2424 ' Chromium is the software you are using.',
2425 '</message>',
2426 '<message name="Bat" desc="An incorrect message">',
2427 ' Google Chrome is the software you are using.',
2428 '</message>',
2429 ]),
2430 MockAffectedFile(
2431 'components/components_google_chrome_strings.grd', [
2432 '<message name="Bar" desc="Welcome to Chrome">',
2433 ' Welcome to Chrome!',
2434 '</message>',
2435 '<message name="Baz" desc="A correct message">',
2436 ' Chromium is the software you are using.',
2437 '</message>',
2438 '<message name="Bat" desc="An incorrect message">',
2439 ' Google Chrome is the software you are using.',
2440 '</message>',
2441 ]),
2442 ]
2443 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2444 mock_input_api, MockOutputApi())
2445 self.assertEqual(2, len(warnings))
2446 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2447 warnings[0].items[0])
2448 self.assertTrue(
2449 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2450 self.assertTrue(
2451 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022452
2453
Daniel Chenga37c03db2022-05-12 17:20:342454class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252455
Daniel Cheng566634ff2024-06-29 14:56:532456 def _createMockInputApi(self):
2457 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472458
Daniel Cheng566634ff2024-06-29 14:56:532459 def FakeRepositoryRoot():
2460 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472461
Daniel Cheng566634ff2024-06-29 14:56:532462 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2463 self._injectFakeOwnersClient(
2464 mock_input_api, ['apple@chromium.org', 'orange@chromium.org'])
2465 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342466
Daniel Cheng566634ff2024-06-29 14:56:532467 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342468
Daniel Cheng566634ff2024-06-29 14:56:532469 class FakeGerrit(object):
2470
2471 def IsOwnersOverrideApproved(self, issue):
2472 return False
2473
2474 input_api.change.issue = 123
2475 input_api.gerrit = FakeGerrit()
2476
2477 def _injectFakeOwnersClient(self, input_api, owners):
2478
2479 class FakeOwnersClient(object):
2480
2481 def ListOwners(self, f):
2482 return owners
2483
2484 input_api.owners_client = FakeOwnersClient()
2485
2486 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2487
2488 def MockOwnerAndReviewers(input_api,
2489 email_regexp,
2490 approval_needed=False):
2491 return [owner, reviewers]
2492
2493 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2494 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342495
2496
2497class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532498 _test_cases = [
2499 ('*_messages.cc', 'scary_messages.cc'),
2500 ('*_messages*.h', 'scary_messages.h'),
2501 ('*_messages*.h', 'scary_messages_android.h'),
2502 ('*_param_traits*.*', 'scary_param_traits.h'),
2503 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2504 ('*.mojom', 'scary.mojom'),
2505 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2506 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2507 ('*_type_converter*.*', 'scary_type_converter.h'),
2508 ('*_type_converter*.*', 'scary_type_converter_nacl.h'),
2509 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252510 ]
Daniel Cheng171dad8d2022-05-21 00:40:252511
Daniel Cheng566634ff2024-06-29 14:56:532512 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2513 mock_input_api = self._createMockInputApi()
2514 new_owners_file_path = mock_input_api.os_path.join(
2515 'services', 'goat', 'public', 'OWNERS')
2516 new_owners_file = [
2517 'per-file *.mojom=set noparent',
2518 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2519 ]
Daniel Cheng3008dc12022-05-13 04:02:112520
Daniel Cheng566634ff2024-06-29 14:56:532521 def FakeReadFile(filename):
2522 self.assertEqual(
2523 mock_input_api.os_path.join('chromium', 'src',
2524 new_owners_file_path), filename)
2525 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112526
Daniel Cheng566634ff2024-06-29 14:56:532527 mock_input_api.ReadFile = FakeReadFile
2528 mock_input_api.files = [
2529 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252530 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532531 mock_input_api.os_path.join('services', 'goat', 'public',
2532 'goat.mojom'),
2533 ['// Scary contents.'])
2534 ]
2535 self._setupFakeChange(mock_input_api)
2536 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2537 'owner@chromium.org',
2538 ['orange@chromium.org'])
2539 mock_input_api.is_committing = True
2540 mock_input_api.dry_run = False
2541 mock_output_api = MockOutputApi()
2542 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2543 mock_output_api)
2544 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342545
Daniel Cheng566634ff2024-06-29 14:56:532546 def testMissingSecurityReviewerAtUpload(self):
2547 mock_input_api = self._createMockInputApi()
2548 new_owners_file_path = mock_input_api.os_path.join(
2549 'services', 'goat', 'public', 'OWNERS')
2550 new_owners_file = [
2551 'per-file *.mojom=set noparent',
2552 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2553 ]
Daniel Chenga37c03db2022-05-12 17:20:342554
Daniel Cheng566634ff2024-06-29 14:56:532555 def FakeReadFile(filename):
2556 self.assertEqual(
2557 mock_input_api.os_path.join('chromium', 'src',
2558 new_owners_file_path), filename)
2559 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362560
Daniel Cheng566634ff2024-06-29 14:56:532561 mock_input_api.ReadFile = FakeReadFile
2562 mock_input_api.files = [
2563 MockAffectedFile(new_owners_file_path, new_owners_file),
2564 MockAffectedFile(
2565 mock_input_api.os_path.join('services', 'goat', 'public',
2566 'goat.mojom'),
2567 ['// Scary contents.'])
2568 ]
2569 self._setupFakeChange(mock_input_api)
2570 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2571 'owner@chromium.org',
2572 ['banana@chromium.org'])
2573 mock_input_api.is_committing = False
2574 mock_input_api.dry_run = False
2575 mock_output_api = MockOutputApi()
2576 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2577 mock_output_api)
2578 self.assertEqual(1, len(results))
2579 self.assertEqual('notify', results[0].type)
2580 self.assertEqual(
2581 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2582 'following newly-added files:', results[0].message)
2583
2584 def testMissingSecurityReviewerAtDryRunCommit(self):
2585 mock_input_api = self._createMockInputApi()
2586 new_owners_file_path = mock_input_api.os_path.join(
2587 'services', 'goat', 'public', 'OWNERS')
2588 new_owners_file = [
2589 'per-file *.mojom=set noparent',
2590 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2591 ]
2592
2593 def FakeReadFile(filename):
2594 self.assertEqual(
2595 mock_input_api.os_path.join('chromium', 'src',
2596 new_owners_file_path), filename)
2597 return '\n'.join(new_owners_file)
2598
2599 mock_input_api.ReadFile = FakeReadFile
2600 mock_input_api.files = [
2601 MockAffectedFile(new_owners_file_path, new_owners_file),
2602 MockAffectedFile(
2603 mock_input_api.os_path.join('services', 'goat', 'public',
2604 'goat.mojom'),
2605 ['// Scary contents.'])
2606 ]
2607 self._setupFakeChange(mock_input_api)
2608 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2609 'owner@chromium.org',
2610 ['banana@chromium.org'])
2611 mock_input_api.is_committing = True
2612 mock_input_api.dry_run = True
2613 mock_output_api = MockOutputApi()
2614 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2615 mock_output_api)
2616 self.assertEqual(1, len(results))
2617 self.assertEqual('error', results[0].type)
2618 self.assertEqual(
2619 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2620 'following newly-added files:', results[0].message)
2621
2622 def testMissingSecurityApprovalAtRealCommit(self):
2623 mock_input_api = self._createMockInputApi()
2624 new_owners_file_path = mock_input_api.os_path.join(
2625 'services', 'goat', 'public', 'OWNERS')
2626 new_owners_file = [
2627 'per-file *.mojom=set noparent',
2628 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2629 ]
2630
2631 def FakeReadFile(filename):
2632 self.assertEqual(
2633 mock_input_api.os_path.join('chromium', 'src',
2634 new_owners_file_path), filename)
2635 return '\n'.join(new_owners_file)
2636
2637 mock_input_api.ReadFile = FakeReadFile
2638 mock_input_api.files = [
2639 MockAffectedFile(new_owners_file_path, new_owners_file),
2640 MockAffectedFile(
2641 mock_input_api.os_path.join('services', 'goat', 'public',
2642 'goat.mojom'),
2643 ['// Scary contents.'])
2644 ]
2645 self._setupFakeChange(mock_input_api)
2646 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2647 'owner@chromium.org',
2648 ['banana@chromium.org'])
2649 mock_input_api.is_committing = True
2650 mock_input_api.dry_run = False
2651 mock_output_api = MockOutputApi()
2652 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2653 mock_output_api)
2654 self.assertEqual('error', results[0].type)
2655 self.assertEqual(
2656 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2657 'following newly-added files:', results[0].message)
2658
2659 def testIpcChangeNeedsSecurityOwner(self):
2660 for is_committing in [True, False]:
2661 for pattern, filename in self._test_cases:
2662 with self.subTest(
2663 line=
2664 f'is_committing={is_committing}, filename={filename}'):
2665 mock_input_api = self._createMockInputApi()
2666 mock_input_api.files = [
2667 MockAffectedFile(
2668 mock_input_api.os_path.join(
2669 'services', 'goat', 'public', filename),
2670 ['// Scary contents.'])
2671 ]
2672 self._setupFakeChange(mock_input_api)
2673 self._injectFakeChangeOwnerAndReviewers(
2674 mock_input_api, 'owner@chromium.org',
2675 ['banana@chromium.org'])
2676 mock_input_api.is_committing = is_committing
2677 mock_input_api.dry_run = False
2678 mock_output_api = MockOutputApi()
2679 results = PRESUBMIT.CheckSecurityOwners(
2680 mock_input_api, mock_output_api)
2681 self.assertEqual(1, len(results))
2682 self.assertEqual('error', results[0].type)
2683 self.assertTrue(results[0].message.replace(
2684 '\\', '/'
2685 ).startswith(
2686 'Found missing OWNERS lines for security-sensitive files. '
2687 'Please add the following lines to services/goat/public/OWNERS:'
2688 ))
2689 self.assertEqual(['ipc-security-reviews@chromium.org'],
2690 mock_output_api.more_cc)
2691
2692 def testServiceManifestChangeNeedsSecurityOwner(self):
2693 mock_input_api = self._createMockInputApi()
2694 mock_input_api.files = [
2695 MockAffectedFile(
2696 mock_input_api.os_path.join('services', 'goat', 'public',
2697 'cpp', 'manifest.cc'),
2698 [
2699 '#include "services/goat/public/cpp/manifest.h"',
2700 'const service_manager::Manifest& GetManifest() {}',
2701 ])
2702 ]
2703 self._setupFakeChange(mock_input_api)
2704 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2705 'owner@chromium.org',
2706 ['banana@chromium.org'])
2707 mock_output_api = MockOutputApi()
2708 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2709 self.assertEqual(1, len(errors))
2710 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2711 'Found missing OWNERS lines for security-sensitive files. '
2712 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2713 ))
2714 self.assertEqual(['ipc-security-reviews@chromium.org'],
2715 mock_output_api.more_cc)
2716
2717 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2718 mock_input_api = self._createMockInputApi()
2719 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2720 'owner@chromium.org',
2721 ['banana@chromium.org'])
2722 mock_input_api.files = [
2723 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2724 'const char kNoEnforcement[] = "not a manifest!";',
2725 ])
2726 ]
2727 mock_output_api = MockOutputApi()
2728 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2729 self.assertEqual([], errors)
2730 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032731
2732
Daniel Chenga37c03db2022-05-12 17:20:342733class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032734
Daniel Cheng566634ff2024-06-29 14:56:532735 def testFidlChangeNeedsSecurityOwner(self):
2736 mock_input_api = self._createMockInputApi()
2737 mock_input_api.files = [
2738 MockAffectedFile('potentially/scary/ipc.fidl',
2739 ['library test.fidl'])
2740 ]
2741 self._setupFakeChange(mock_input_api)
2742 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2743 'owner@chromium.org',
2744 ['banana@chromium.org'])
2745 mock_output_api = MockOutputApi()
2746 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2747 self.assertEqual(1, len(errors))
2748 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2749 'Found missing OWNERS lines for security-sensitive files. '
2750 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032751
Daniel Cheng566634ff2024-06-29 14:56:532752 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2753 mock_input_api = self._createMockInputApi()
2754 mock_input_api.files = [
2755 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2756 ['{ "that is no": "manifest!" }'])
2757 ]
2758 self._setupFakeChange(mock_input_api)
2759 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2760 'owner@chromium.org',
2761 ['banana@chromium.org'])
2762 mock_output_api = MockOutputApi()
2763 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2764 self.assertEqual(1, len(errors))
2765 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2766 'Found missing OWNERS lines for security-sensitive files. '
2767 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032768
Daniel Cheng566634ff2024-06-29 14:56:532769 def testComponentManifestV2NeedsSecurityOwner(self):
2770 mock_input_api = self._createMockInputApi()
2771 mock_input_api.files = [
2772 MockAffectedFile('potentially/scary/v2_manifest.cml',
2773 ['{ "that is no": "manifest!" }'])
2774 ]
2775 self._setupFakeChange(mock_input_api)
2776 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2777 'owner@chromium.org',
2778 ['banana@chromium.org'])
2779 mock_output_api = MockOutputApi()
2780 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2781 self.assertEqual(1, len(errors))
2782 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2783 'Found missing OWNERS lines for security-sensitive files. '
2784 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092785
Daniel Cheng566634ff2024-06-29 14:56:532786 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2787 mock_input_api = MockInputApi()
2788 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2789 'owner@chromium.org',
2790 ['banana@chromium.org'])
2791 mock_input_api.files = [
2792 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2793 'const char kNoEnforcement[] = "Security?!? Pah!";',
2794 ])
2795 ]
2796 mock_output_api = MockOutputApi()
2797 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2798 self.assertEqual([], errors)
2799
2800 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2801 mock_input_api = MockInputApi()
2802 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2803 'owner@chromium.org',
2804 ['banana@chromium.org'])
2805 mock_input_api.files = [
2806 MockAffectedFile(
2807 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2808 'const char kNoEnforcement[] = "Security?!? Pah!";',
2809 ])
2810 ]
2811 mock_output_api = MockOutputApi()
2812 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2813 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362814
Daniel Cheng13ca61a882017-08-25 15:11:252815
Daniel Chenga37c03db2022-05-12 17:20:342816class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132817
Daniel Cheng566634ff2024-06-29 14:56:532818 def testDiffGetServiceSandboxType(self):
2819 mock_input_api = MockInputApi()
2820 mock_input_api.files = [
2821 MockAffectedFile('services/goat/teleporter_host.cc', [
2822 'template <>', 'inline content::SandboxType',
2823 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2824 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2825 '#else', ' return SandboxType::kNoSandbox;',
2826 '#endif // !defined(OS_WIN)', '}'
2827 ]),
2828 ]
2829 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2830 mock_input_api)
2831 self.assertEqual(
2832 {
2833 'services/goat/teleporter_host.cc':
2834 set(['content::GetServiceSandboxType<>()'])
2835 }, files_to_functions)
2836
2837 def testDiffRemovingLine(self):
2838 mock_input_api = MockInputApi()
2839 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2840 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132841+++ new 2020-05-04 14:08:32.000000000 -0400
2842@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372843 template <>
2844 inline content::SandboxType
2845-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2846 #if defined(OS_WIN)
2847 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132848"""
Daniel Cheng566634ff2024-06-29 14:56:532849 mock_input_api.files = [mock_file]
2850 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2851 mock_input_api)
2852 self.assertEqual(
2853 {
2854 'services/goat/teleporter_host.cc':
2855 set(['content::GetServiceSandboxType<>()'])
2856 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132857
Daniel Cheng566634ff2024-06-29 14:56:532858 def testChangeOwnersMissing(self):
2859 mock_input_api = self._createMockInputApi()
2860 self._setupFakeChange(mock_input_api)
2861 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2862 'owner@chromium.org',
2863 ['banana@chromium.org'])
2864 mock_input_api.is_committing = False
2865 mock_input_api.files = [
2866 MockAffectedFile('file.cc',
2867 ['GetServiceSandboxType<Goat>(Sandbox)'])
2868 ]
2869 mock_output_api = MockOutputApi()
2870 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2871 mock_output_api)
2872 self.assertEqual(1, len(result))
2873 self.assertEqual(result[0].type, 'notify')
2874 self.assertEqual(result[0].message,
2875 'The following files change calls to security-sensitive functions\n' \
2876 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2877 ' file.cc\n'
2878 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132879
Daniel Cheng566634ff2024-06-29 14:56:532880 def testChangeOwnersMissingAtCommit(self):
2881 mock_input_api = self._createMockInputApi()
2882 self._setupFakeChange(mock_input_api)
2883 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2884 'owner@chromium.org',
2885 ['banana@chromium.org'])
2886 mock_input_api.is_committing = True
2887 mock_input_api.dry_run = False
2888 mock_input_api.files = [
2889 MockAffectedFile('file.cc',
2890 ['GetServiceSandboxType<mojom::Goat>()'])
2891 ]
2892 mock_output_api = MockOutputApi()
2893 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2894 mock_output_api)
2895 self.assertEqual(1, len(result))
2896 self.assertEqual(result[0].type, 'error')
2897 self.assertEqual(result[0].message,
2898 'The following files change calls to security-sensitive functions\n' \
2899 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2900 ' file.cc\n'
2901 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132902
Daniel Cheng566634ff2024-06-29 14:56:532903 def testChangeOwnersPresent(self):
2904 mock_input_api = self._createMockInputApi()
2905 self._injectFakeChangeOwnerAndReviewers(
2906 mock_input_api, 'owner@chromium.org',
2907 ['apple@chromium.org', 'banana@chromium.org'])
2908 mock_input_api.files = [
2909 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2910 ]
2911 mock_output_api = MockOutputApi()
2912 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2913 mock_output_api)
2914 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132915
Daniel Cheng566634ff2024-06-29 14:56:532916 def testChangeOwnerIsSecurityOwner(self):
2917 mock_input_api = self._createMockInputApi()
2918 self._setupFakeChange(mock_input_api)
2919 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2920 'orange@chromium.org',
2921 ['pear@chromium.org'])
2922 mock_input_api.files = [
2923 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
2924 ]
2925 mock_output_api = MockOutputApi()
2926 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2927 mock_output_api)
2928 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132929
2930
Mario Sanchez Prada2472cab2019-09-18 10:58:312931class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:292932
Daniel Cheng566634ff2024-06-29 14:56:532933 def testBannedJsFunctions(self):
2934 input_api = MockInputApi()
2935 input_api.files = [
2936 MockFile('ash/webui/file.js', ['chrome.send(something);']),
2937 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
2938 ]
Clement Yan9b330cb2022-11-17 05:25:292939
Daniel Cheng566634ff2024-06-29 14:56:532940 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542941
Daniel Cheng566634ff2024-06-29 14:56:532942 self.assertEqual(1, len(results))
2943 self.assertTrue('ash/webui/file.js' in results[0].message)
2944 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:262945
Daniel Cheng566634ff2024-06-29 14:56:532946 def testBannedJavaFunctions(self):
2947 input_api = MockInputApi()
2948 input_api.files = [
2949 MockFile('some/java/problematic/diskread.java',
2950 ['StrictMode.allowThreadDiskReads();']),
2951 MockFile('some/java/problematic/diskwrite.java',
2952 ['StrictMode.allowThreadDiskWrites();']),
2953 MockFile('some/java/ok/diskwrite.java',
2954 ['StrictModeContext.allowDiskWrites();']),
2955 MockFile('some/java/problematic/waitidleforsync.java',
2956 ['instrumentation.waitForIdleSync();']),
2957 MockFile('some/java/problematic/registerreceiver.java',
2958 ['context.registerReceiver();']),
2959 MockFile('some/java/problematic/property.java',
2960 ['new Property<abc, Integer>;']),
2961 MockFile('some/java/problematic/requestlayout.java',
2962 ['requestLayout();']),
2963 MockFile('some/java/problematic/lastprofile.java',
2964 ['ProfileManager.getLastUsedRegularProfile();']),
2965 MockFile('some/java/problematic/getdrawable1.java',
2966 ['ResourcesCompat.getDrawable();']),
2967 MockFile('some/java/problematic/getdrawable2.java',
2968 ['getResources().getDrawable();']),
Jenna Himawan859865d2025-02-25 22:22:312969 MockFile('some/java/problematic/announceForAccessibility.java',
2970 ['view.announceForAccessibility(accessibilityText);']),
2971 MockFile(
2972 'some/java/problematic/accessibilityTypeAnnouncement.java', [
2973 'accessibilityEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);'
2974 ]),
Nate Fischerd541ff82025-03-11 21:34:192975 MockFile(
2976 'content/java/problematic/desktopandroid.java', [
2977 'if (BuildConfig.IS_DESKTOP_ANDROID) {}'
2978 ]),
Daniel Cheng566634ff2024-06-29 14:56:532979 ]
Min Qinbc44383c2023-02-22 17:25:262980
Daniel Cheng566634ff2024-06-29 14:56:532981 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:152982 self.assertEqual(12, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:532983 self.assertTrue(
2984 'some/java/problematic/diskread.java' in errors[0].message)
2985 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152986 'some/java/problematic/diskwrite.java' in errors[1].message)
2987 self.assertTrue(all('some/java/ok/diskwrite.java' not in e.message for e in errors))
Daniel Cheng566634ff2024-06-29 14:56:532988 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152989 'some/java/problematic/waitidleforsync.java' in errors[2].message)
Daniel Cheng566634ff2024-06-29 14:56:532990 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152991 'some/java/problematic/registerreceiver.java' in errors[3].message)
Daniel Cheng566634ff2024-06-29 14:56:532992 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152993 'some/java/problematic/property.java' in errors[4].message)
Daniel Cheng566634ff2024-06-29 14:56:532994 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152995 'some/java/problematic/requestlayout.java' in errors[5].message)
Daniel Cheng566634ff2024-06-29 14:56:532996 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152997 'some/java/problematic/lastprofile.java' in errors[6].message)
Daniel Cheng566634ff2024-06-29 14:56:532998 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152999 'some/java/problematic/getdrawable1.java' in errors[7].message)
Daniel Cheng566634ff2024-06-29 14:56:533000 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153001 'some/java/problematic/getdrawable2.java' in errors[8].message)
Jenna Himawan859865d2025-02-25 22:22:313002 self.assertTrue('some/java/problematic/announceForAccessibility.java'
Ben Pastenee79d66112025-04-23 19:46:153003 in errors[9].message)
Jenna Himawan859865d2025-02-25 22:22:313004 self.assertTrue(
3005 'some/java/problematic/accessibilityTypeAnnouncement.java' in
Ben Pastenee79d66112025-04-23 19:46:153006 errors[10].message)
Nate Fischerd541ff82025-03-11 21:34:193007 self.assertTrue(
3008 'content/java/problematic/desktopandroid.java' in
Ben Pastenee79d66112025-04-23 19:46:153009 errors[11].message)
Jenna Himawan859865d2025-02-25 22:22:313010
Peter Kasting94a56c42019-10-25 21:54:043011
Daniel Cheng566634ff2024-06-29 14:56:533012 def testBannedCppFunctions(self):
3013 input_api = MockInputApi()
3014 input_api.files = [
3015 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
3016 MockFile('third_party/blink/problematic/file.cc',
3017 ['GetInterfaceProvider()']),
3018 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
Daniel Cheng566634ff2024-06-29 14:56:533019 MockFile('some/cpp/nocheck/file.cc',
3020 ['using namespace std; // nocheck']),
3021 MockFile('some/cpp/comment/file.cc',
3022 [' // A comment about `using namespace std;`']),
Peter Kasting13607932025-04-10 22:52:383023 MockFile('some/cpp/problematic/file2.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533024 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3025 ]),
Peter Kasting13607932025-04-10 22:52:383026 MockFile('some/cpp/problematic/file3.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533027 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3028 ]),
Peter Kasting13607932025-04-10 22:52:383029 MockFile('some/cpp/problematic/file4.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533030 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3031 ]),
Daniel Cheng70a35272025-05-06 16:41:343032 MockFile(
3033 'allowed_ranges_usage.cc',
3034 [
3035 'std::ranges::begin(vec);',
Michael Tang626d8982025-05-08 23:24:293036 'std::ranges::subrange(first, last);',
Daniel Cheng70a35272025-05-06 16:41:343037 # std::ranges::view is a concept and allowed, but the views
3038 # library itself is not (see below)
3039 'static_assert(std::ranges::view<SomeType>);'
3040 ]),
3041 MockFile(
3042 'banned_ranges_usage.cc',
3043 [
Michael Tang626d8982025-05-08 23:24:293044 'std::ranges::borrowed_subrange_t(subrange);',
Daniel Cheng70a35272025-05-06 16:41:343045 # Edge case: make sure std::ranges::views is disallowed,
3046 # even though std::ranges::view is allowed.
3047 'std::ranges::views::take(first, count);'
3048 ]),
Daniel Cheng89719222024-07-04 04:59:293049 MockFile('views_usage.cc', ['std::views::all(vec)']),
Daniel Cheng70a35272025-05-06 16:41:343050 MockFile('content/desktop_android.cc', [
3051 '// some first line',
3052 '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
3053 '// some third line',
3054 ]),
Daniel Cheng566634ff2024-06-29 14:56:533055 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163056
Daniel Cheng566634ff2024-06-29 14:56:533057 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043058
Ben Pastenee79d66112025-04-23 19:46:153059 # Each entry in results corresponds to a BanRule with a violation, in
3060 # the order they were encountered.
Daniel Cheng70a35272025-05-06 16:41:343061 self.assertEqual(9, len(results))
Ben Pastenee79d66112025-04-23 19:46:153062 self.assertTrue('some/cpp/problematic/file.cc' in results[0].message)
Daniel Cheng566634ff2024-06-29 14:56:533063 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153064 'third_party/blink/problematic/file.cc' in results[1].message)
3065 self.assertTrue(all('some/cpp/ok/file.cc' not in r.message for r in results))
3066 self.assertTrue('some/cpp/problematic/file2.cc' in results[2].message)
3067 self.assertTrue('some/cpp/problematic/file3.cc' in results[3].message)
3068 self.assertTrue('some/cpp/problematic/file4.cc' in results[4].message)
3069 self.assertTrue(all('some/cpp/nocheck/file.cc' not in r.message for r in results))
3070 self.assertTrue(all('some/cpp/comment/file.cc' not in r.message for r in results))
3071 self.assertTrue(all('allowed_ranges_usage.cc' not in r.message for r in results))
3072 self.assertTrue('banned_ranges_usage.cc' in results[5].message)
Daniel Cheng70a35272025-05-06 16:41:343073 self.assertTrue('banned_ranges_usage.cc' in results[6].message)
3074 self.assertTrue('views_usage.cc' in results[7].message)
3075 self.assertTrue('content/desktop_android.cc' in results[8].message)
Ben Pastenee79d66112025-04-23 19:46:153076
3077 # Check ResultLocation data. Line nums start at 1.
Daniel Cheng70a35272025-05-06 16:41:343078 self.assertEqual(results[8].locations[0].file_path,
3079 'content/desktop_android.cc')
3080 self.assertEqual(results[8].locations[0].start_line, 2)
3081 self.assertEqual(results[8].locations[0].end_line, 2)
Daniel Cheng192683f2022-11-01 20:52:443082
Daniel Cheng566634ff2024-06-29 14:56:533083 def testBannedCppRandomFunctions(self):
3084 banned_rngs = [
3085 'absl::BitGen',
3086 'absl::InsecureBitGen',
3087 'std::linear_congruential_engine',
3088 'std::mersenne_twister_engine',
3089 'std::subtract_with_carry_engine',
3090 'std::discard_block_engine',
3091 'std::independent_bits_engine',
3092 'std::shuffle_order_engine',
3093 'std::minstd_rand0',
3094 'std::minstd_rand',
3095 'std::mt19937',
3096 'std::mt19937_64',
3097 'std::ranlux24_base',
3098 'std::ranlux48_base',
3099 'std::ranlux24',
3100 'std::ranlux48',
3101 'std::knuth_b',
3102 'std::default_random_engine',
3103 'std::random_device',
3104 ]
3105 for banned_rng in banned_rngs:
3106 input_api = MockInputApi()
3107 input_api.files = [
3108 MockFile('some/cpp/problematic/file.cc',
3109 [f'{banned_rng} engine;']),
3110 MockFile('third_party/blink/problematic/file.cc',
3111 [f'{banned_rng} engine;']),
3112 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3113 ]
3114 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3115 MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153116 self.assertEqual(2, len(results), banned_rng)
Daniel Cheng566634ff2024-06-29 14:56:533117 self.assertTrue(
3118 'some/cpp/problematic/file.cc' in results[0].message,
3119 banned_rng)
3120 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153121 'third_party/blink/problematic/file.cc' in results[1].message,
Daniel Cheng566634ff2024-06-29 14:56:533122 banned_rng)
Ben Pastenee79d66112025-04-23 19:46:153123 self.assertTrue(all('third_party/ok/file.cc' not in r.message for r in results))
Sylvain Defresnea8b73d252018-02-28 15:45:543124
Daniel Cheng566634ff2024-06-29 14:56:533125 def testBannedIosObjcFunctions(self):
3126 input_api = MockInputApi()
3127 input_api.files = [
3128 MockFile('some/ios/file.mm',
3129 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3130 MockFile('some/mac/file.mm',
3131 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3132 MockFile('another/ios_file.mm',
3133 ['class SomeTest : public testing::Test {};']),
3134 MockFile(
3135 'some/ios/file_egtest.mm',
3136 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3137 MockFile('some/ios/file_unittest.mm', [
3138 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3139 ]),
3140 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543141
Daniel Cheng566634ff2024-06-29 14:56:533142 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153143 self.assertEqual(3, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:533144 self.assertTrue('some/ios/file.mm' in errors[0].message)
Ben Pastenee79d66112025-04-23 19:46:153145 self.assertTrue('another/ios_file.mm' in errors[1].message)
3146 self.assertTrue(all('some/mac/file.mm' not in e.message for e in errors))
3147 self.assertTrue('some/ios/file_egtest.mm' in errors[2].message)
3148 self.assertTrue(all('some/ios/file_unittest.mm' not in e.message for e in errors))
Carlos Knippschildab192b8c2019-04-08 20:02:383149
Daniel Cheng566634ff2024-06-29 14:56:533150 def testBannedMojoFunctions(self):
3151 input_api = MockInputApi()
3152 input_api.files = [
3153 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3154 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3155 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3156 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223157
Daniel Cheng566634ff2024-06-29 14:56:533158 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383159
Ben Pastenee79d66112025-04-23 19:46:153160 # Each entry in results corresponds to a BanRule with a violation, in
3161 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533162 self.assertEqual(1, len(results))
3163 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3164 self.assertTrue(
3165 'third_party/blink/ok/file3.cc' not in results[0].message)
3166 self.assertTrue(
3167 'content/renderer/ok/file3.cc' not in results[0].message)
3168
Justin Lulejian09fd06872025-04-01 22:03:283169 def testBannedMojomPatterns_SharedBuffer(self):
Daniel Cheng566634ff2024-06-29 14:56:533170 input_api = MockInputApi()
3171 input_api.files = [
3172 MockFile(
3173 'bad.mojom',
3174 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3175 MockFile('good.mojom', [
3176 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223177 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3178 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533179 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3180 ]),
3181 ]
Daniel Cheng92c15e32022-03-16 17:48:223182
Daniel Cheng566634ff2024-06-29 14:56:533183 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223184
Ben Pastenee79d66112025-04-23 19:46:153185 # Each entry in results corresponds to a BanRule with a violation, in
3186 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533187 self.assertEqual(1, len(results))
3188 self.assertTrue('bad.mojom' in results[0].message)
3189 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223190
Justin Lulejian09fd06872025-04-01 22:03:283191 def testBannedMojomPatterns_ExtensionId(self):
3192 input_api = MockInputApi()
3193 input_api.files = [
3194 # Pattern tests.
3195 MockFile('extensions/bad.mojom', ['string extension_id']),
3196 MockFile('extensions/bad_struct.mojom',
3197 ['struct Bad {', ' string extension_id;', '};']),
3198 MockFile('extensions/good.mojom', ['ExtensionId extension_id']),
3199 MockFile('extensions/good_struct.mojom',
3200 ['struct Bad {', ' ExtensionId extension_id;', '};']),
3201
3202 # Path exclusion tests.
3203 MockFile('some/included/extensions/path/bad_extension_id.mojom',
3204 ['string extension_id']),
3205 MockFile('some/excluded/path/bad_extension_id.mojom',
3206 ['string extension_id']),
3207 ]
3208
Ben Pastenee79d66112025-04-23 19:46:153209 # Each entry in results corresponds to a BanRule with a violation, in
3210 # the order they were encountered.
Justin Lulejian09fd06872025-04-01 22:03:283211 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3212
Ben Pastenee79d66112025-04-23 19:46:153213 self.assertEqual(3, len(results))
Justin Lulejian09fd06872025-04-01 22:03:283214
3215 # Pattern test assertions.
3216 self.assertTrue('bad.mojom' in results[0].message)
Ben Pastenee79d66112025-04-23 19:46:153217 self.assertTrue('bad_struct.mojom' in results[1].message)
3218 self.assertTrue(all('good.mojom' not in r.message for r in results))
3219 self.assertTrue(all('good_struct.mojom' not in r.message for r in results))
Justin Lulejian09fd06872025-04-01 22:03:283220
3221 # Path exclusion assertions.
3222 self.assertTrue('some/included/extensions/path/bad_extension_id.mojom'
Ben Pastenee79d66112025-04-23 19:46:153223 in results[2].message)
3224 self.assertTrue(all('some/excluded/path/bad_extension_id.mojom' not in r.message for r in results))
3225
Justin Lulejian09fd06872025-04-01 22:03:283226
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273227class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243228
Daniel Cheng566634ff2024-06-29 14:56:533229 def testTruePositives(self):
3230 mock_input_api = MockInputApi()
3231 mock_input_api.files = [
3232 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3233 MockFile('some/path/foo.mm', ['FooForTesting();']),
3234 MockFile('some/path/foo.cxx', ['FooForTests();']),
3235 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3236 ]
Vaclav Brozekf01ed502018-03-16 19:38:243237
Daniel Cheng566634ff2024-06-29 14:56:533238 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3239 mock_input_api, MockOutputApi())
3240 self.assertEqual(1, len(results))
3241 self.assertEqual(4, len(results[0].items))
3242 self.assertTrue('foo.cc' in results[0].items[0])
3243 self.assertTrue('foo.mm' in results[0].items[1])
3244 self.assertTrue('foo.cxx' in results[0].items[2])
3245 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243246
Daniel Cheng566634ff2024-06-29 14:56:533247 def testFalsePositives(self):
3248 mock_input_api = MockInputApi()
3249 mock_input_api.files = [
3250 MockFile('some/path/foo.h', ['foo_for_testing();']),
3251 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3252 MockFile('some/path/foo.cc', ['::FooForTests();']),
3253 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3254 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3255 ]
Vaclav Brozekf01ed502018-03-16 19:38:243256
Daniel Cheng566634ff2024-06-29 14:56:533257 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3258 mock_input_api, MockOutputApi())
3259 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133260
Daniel Cheng566634ff2024-06-29 14:56:533261 def testAllowedFiles(self):
3262 mock_input_api = MockInputApi()
3263 mock_input_api.files = [
3264 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3265 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3266 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3267 ]
3268
3269 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3270 mock_input_api, MockOutputApi())
3271 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133272
Vaclav Brozekf01ed502018-03-16 19:38:243273
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273274class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233275
Daniel Cheng566634ff2024-06-29 14:56:533276 def testTruePositives(self):
3277 mock_input_api = MockInputApi()
3278 mock_input_api.files = [
3279 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3280 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3281 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3282 MockFile('dir/java/src/mult.java', [
3283 'int x = SomethingLongHere()',
3284 ' * SomethingLongHereForTesting();'
3285 ])
3286 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233287
Daniel Cheng566634ff2024-06-29 14:56:533288 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3289 mock_input_api, MockOutputApi())
3290 self.assertEqual(1, len(results))
3291 self.assertEqual(4, len(results[0].items))
3292 self.assertTrue('foo.java' in results[0].items[0])
3293 self.assertTrue('bar.java' in results[0].items[1])
3294 self.assertTrue('baz.java' in results[0].items[2])
3295 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233296
Daniel Cheng566634ff2024-06-29 14:56:533297 def testFalsePositives(self):
3298 mock_input_api = MockInputApi()
3299 mock_input_api.files = [
3300 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3301 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3302 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3303 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3304 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3305 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3306 MockFile('dir/java/src/bar5.java', [
3307 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3308 ]),
3309 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3310 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3311 MockFile('dir/junit/src/javadoc.java',
3312 ['/** Use FooForTest(); to obtain foo in tests.'
3313 ' */']),
3314 MockFile(
3315 'dir/junit/src/javadoc2.java',
3316 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3317 ' */']),
3318 MockFile('dir/java/src/bar6.java',
3319 ['FooForTesting(); // IN-TEST']),
3320 ]
3321
3322 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3323 mock_input_api, MockOutputApi())
3324 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233325
3326
Mohamed Heikald048240a2019-11-12 16:57:373327class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373328
Daniel Cheng566634ff2024-06-29 14:56:533329 def testTruePositives(self):
3330 mock_input_api = MockInputApi()
3331 mock_input_api.files = [
3332 MockFile('dir/android/res/drawable/foo.png', []),
3333 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3334 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3335 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3336 ]
Mohamed Heikald048240a2019-11-12 16:57:373337
Daniel Cheng566634ff2024-06-29 14:56:533338 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3339 MockOutputApi())
3340 self.assertEqual(1, len(results))
3341 self.assertEqual(4, len(results[0].items))
3342 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3343 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3344 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3345 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373346
Daniel Cheng566634ff2024-06-29 14:56:533347 def testFalsePositives(self):
3348 mock_input_api = MockInputApi()
3349 mock_input_api.files = [
3350 MockFile('dir/pngs/README.md', []),
3351 MockFile('java/test/res/drawable/foo.png', []),
3352 MockFile('third_party/blink/foo.png', []),
3353 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3354 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3355 ]
3356
3357 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3358 MockOutputApi())
3359 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373360
Evan Stade7cd4a2c2022-08-04 23:37:253361class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253362
Daniel Cheng566634ff2024-06-29 14:56:533363 def test(self):
3364 mock_input_api = MockInputApi()
3365 mock_input_api.files = [
3366 MockFile('components/vector_icons/google_jetpack.icon', []),
3367 MockFile('components/vector_icons/generic_jetpack.icon', []),
3368 ]
3369
3370 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3371 mock_input_api, MockOutputApi())
3372 self.assertEqual(1, len(results))
3373 self.assertEqual(1, len(results[0].items))
3374 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373375
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273376class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053377
Daniel Cheng566634ff2024-06-29 14:56:533378 def testTruePositivesNullptr(self):
3379 mock_input_api = MockInputApi()
3380 mock_input_api.files = [
3381 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3382 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3383 ]
Vaclav Brozek851d9602018-04-04 16:13:053384
Daniel Cheng566634ff2024-06-29 14:56:533385 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3386 MockOutputApi())
3387 self.assertEqual(1, len(results))
3388 self.assertTrue('nullptr' in results[0].message)
3389 self.assertEqual(2, len(results[0].items))
3390 self.assertTrue('baz.cc' in results[0].items[0])
3391 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243392
Daniel Cheng566634ff2024-06-29 14:56:533393 def testTruePositivesConstructor(self):
3394 mock_input_api = MockInputApi()
3395 mock_input_api.files = [
3396 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3397 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3398 MockFile('dir/mult.cc', [
3399 'return',
3400 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3401 ]),
3402 MockFile('dir/mult2.cc', [
3403 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3404 ' std::unique_ptr<T>(foo);'
3405 ]),
3406 MockFile('dir/mult3.cc', [
3407 'bar = std::unique_ptr<T>(',
3408 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3409 ]),
3410 MockFile('dir/multi_arg.cc', [
3411 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3412 ]),
3413 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243414
Daniel Cheng566634ff2024-06-29 14:56:533415 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3416 MockOutputApi())
3417 self.assertEqual(1, len(results))
3418 self.assertTrue('std::make_unique' in results[0].message)
3419 self.assertEqual(6, len(results[0].items))
3420 self.assertTrue('foo.cc' in results[0].items[0])
3421 self.assertTrue('bar.mm' in results[0].items[1])
3422 self.assertTrue('mult.cc' in results[0].items[2])
3423 self.assertTrue('mult2.cc' in results[0].items[3])
3424 self.assertTrue('mult3.cc' in results[0].items[4])
3425 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533426
Daniel Cheng566634ff2024-06-29 14:56:533427 def testFalsePositives(self):
3428 mock_input_api = MockInputApi()
3429 mock_input_api.files = [
3430 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3431 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3432 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3433 MockFile('dir/baz.cc',
3434 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3435 MockFile('dir/baz2.cc',
3436 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3437 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3438 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3439 # Changed line is inside a multiline template block.
3440 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3441 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243442
Daniel Cheng566634ff2024-06-29 14:56:533443 # Two-argument invocation of std::unique_ptr is exempt because there is
3444 # no equivalent using std::make_unique.
3445 MockFile('dir/multi_arg.cc',
3446 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3447 ]
3448
3449 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3450 MockOutputApi())
3451 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243452
Danil Chapovalov3518f362018-08-11 16:13:433453class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433454
Daniel Cheng566634ff2024-06-29 14:56:533455 def testBlocksDirectIncludes(self):
3456 mock_input_api = MockInputApi()
3457 mock_input_api.files = [
3458 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3459 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3460 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3461 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3462 ]
3463 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3464 MockOutputApi())
3465 self.assertEqual(1, len(results))
3466 self.assertEqual(4, len(results[0].items))
3467 self.assertTrue('StrCat' in results[0].message)
3468 self.assertTrue('foo_win.cc' in results[0].items[0])
3469 self.assertTrue('bar.h' in results[0].items[1])
3470 self.assertTrue('baz.h' in results[0].items[2])
3471 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433472
Daniel Cheng566634ff2024-06-29 14:56:533473 def testAllowsToIncludeWrapper(self):
3474 mock_input_api = MockInputApi()
3475 mock_input_api.files = [
3476 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3477 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3478 ]
3479 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3480 MockOutputApi())
3481 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323482
Daniel Cheng566634ff2024-06-29 14:56:533483 def testAllowsToCreateWrapper(self):
3484 mock_input_api = MockInputApi()
3485 mock_input_api.files = [
3486 MockFile('base/win/shlwapi.h', [
3487 '#include <shlwapi.h>',
3488 '#include "base/win/windows_defines.inc"'
3489 ]),
3490 ]
3491 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3492 MockOutputApi())
3493 self.assertEqual(0, len(results))
3494
3495 def testIgnoresNonImplAndHeaders(self):
3496 mock_input_api = MockInputApi()
3497 mock_input_api.files = [
3498 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3499 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3500 ]
3501 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3502 MockOutputApi())
3503 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243504
Mustafa Emre Acer51f2f742020-03-09 19:41:123505
Rainhard Findlingfc31844c52020-05-15 09:58:263506class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533507 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263508
Daniel Cheng566634ff2024-06-29 14:56:533509 # An empty grd file.
3510 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143511 <grit latest_public_release="1" current_release="1">
3512 <release seq="1">
3513 <messages></messages>
3514 </release>
3515 </grit>
3516 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533517 # A grd file with a single message.
3518 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143519 <grit latest_public_release="1" current_release="1">
3520 <release seq="1">
3521 <messages>
3522 <message name="IDS_TEST1">
3523 Test string 1
3524 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483525 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3526 translateable="false">
3527 Non translateable message 1, should be ignored
3528 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393529 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343530 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393531 Accessibility label 1, should be ignored
3532 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143533 </messages>
3534 </release>
3535 </grit>
3536 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533537 # A grd file with two messages.
3538 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143539 <grit latest_public_release="1" current_release="1">
3540 <release seq="1">
3541 <messages>
3542 <message name="IDS_TEST1">
3543 Test string 1
3544 </message>
3545 <message name="IDS_TEST2">
3546 Test string 2
3547 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483548 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3549 translateable="false">
3550 Non translateable message 2, should be ignored
3551 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143552 </messages>
3553 </release>
3554 </grit>
3555 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533556 # A grd file with one ICU syntax message without syntax errors.
3557 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263558 <grit latest_public_release="1" current_release="1">
3559 <release seq="1">
3560 <messages>
3561 <message name="IDS_TEST1">
3562 {NUM, plural,
3563 =1 {Test text for numeric one}
3564 other {Test text for plural with {NUM} as number}}
3565 </message>
3566 </messages>
3567 </release>
3568 </grit>
3569 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533570 # A grd file with one ICU syntax message without syntax errors.
3571 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263572 <grit latest_public_release="1" current_release="1">
3573 <release seq="1">
3574 <messages>
3575 <message name="IDS_TEST1">
3576 {NUM, plural,
3577 =1 {Different test text for numeric one}
3578 other {Different test text for plural with {NUM} as number}}
3579 </message>
3580 </messages>
3581 </release>
3582 </grit>
3583 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533584 # A grd file with multiple ICU syntax messages without syntax errors.
3585 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323586 <grit latest_public_release="1" current_release="1">
3587 <release seq="1">
3588 <messages>
3589 <message name="IDS_TEST1">
3590 {NUM, plural,
3591 =0 {New test text for numeric zero}
3592 =1 {Different test text for numeric one}
3593 =2 {New test text for numeric two}
3594 =3 {New test text for numeric three}
3595 other {Different test text for plural with {NUM} as number}}
3596 </message>
3597 </messages>
3598 </release>
3599 </grit>
3600 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533601 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3602 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263603 <grit latest_public_release="1" current_release="1">
3604 <release seq="1">
3605 <messages>
3606 <message name="IDS_TEST1">
3607 {NUM, plural
3608 =1 {Test text for numeric one}
3609 other {Test text for plural with {NUM} as number}}
3610 </message>
3611 </messages>
3612 </release>
3613 </grit>
3614 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143615
Daniel Cheng566634ff2024-06-29 14:56:533616 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3617 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583618
Daniel Cheng566634ff2024-06-29 14:56:533619 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3620 '<grit-part>', '<message name="IDS_PART_TEST1">',
3621 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583622
Daniel Cheng566634ff2024-06-29 14:56:533623 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3624 '<grit-part>', '<message name="IDS_PART_TEST1">',
3625 'Part string 1', '</message>',
3626 '<message name="IDS_PART_TEST2">', 'Part string 2',
3627 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583628
Daniel Cheng566634ff2024-06-29 14:56:533629 NEW_GRDP_CONTENTS3 = (
3630 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093631 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533632 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093633
Daniel Cheng566634ff2024-06-29 14:56:533634 NEW_GRDP_CONTENTS4 = (
3635 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093636 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533637 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093638
Daniel Cheng566634ff2024-06-29 14:56:533639 NEW_GRDP_CONTENTS5 = (
3640 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353641 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533642 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353643
Daniel Cheng566634ff2024-06-29 14:56:533644 NEW_GRDP_CONTENTS6 = (
3645 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353646 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533647 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353648
Daniel Cheng566634ff2024-06-29 14:56:533649 # A grdp file with one ICU syntax message without syntax errors.
3650 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3651 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3652 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3653 '=1 {Test text for numeric one}',
3654 'other {Test text for plural with {NUM} as number}}', '</message>',
3655 '</grit-part>')
3656 # A grdp file with one ICU syntax message without syntax errors.
3657 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3658 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3659 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3660 '=1 {Different test text for numeric one}',
3661 'other {Different test text for plural with {NUM} as number}}',
3662 '</message>', '</grit-part>')
3663 # A grdp file with multiple ICU syntax messages without syntax errors.
3664 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3665 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3666 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3667 '=0 {New test text for numeric zero}',
3668 '=1 {Different test text for numeric one}',
3669 '=2 {New test text for numeric two}',
3670 '=3 {New test text for numeric three}',
3671 'other {Different test text for plural with {NUM} as number}}',
3672 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263673
Daniel Cheng566634ff2024-06-29 14:56:533674 # A grdp file with one ICU syntax message with syntax errors (superfluous
3675 # space).
3676 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3677 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3678 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3679 '= 1 {Test text for numeric one}',
3680 'other {Test text for plural with {NUM} as number}}', '</message>',
3681 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263682
Daniel Cheng566634ff2024-06-29 14:56:533683 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3684 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3685 'changelist. Run '
3686 'tools/translate/upload_screenshots.py to '
3687 'upload them instead:')
3688 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3689 'To ensure the best translations, take '
3690 'screenshots of the relevant UI '
3691 '(https://g.co/chrome/translation) and add '
3692 'these files to your changelist:')
3693 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3694 'files. Remove:')
3695 ICU_SYNTAX_ERROR_MESSAGE = (
3696 'ICU syntax errors were found in the following '
3697 'strings (problems or feedback? Contact '
3698 'rainhard@chromium.org):')
3699 SHA1_FORMAT_MESSAGE = (
3700 'The following files do not seem to contain valid sha1 '
3701 'hashes. Make sure they contain hashes created by '
3702 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143703
Daniel Cheng566634ff2024-06-29 14:56:533704 def makeInputApi(self, files):
3705 input_api = MockInputApi()
Andrew Grieve713b89b2024-10-15 20:20:083706 input_api.InitFiles(files)
Daniel Cheng566634ff2024-06-29 14:56:533707 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143708
Daniel Cheng566634ff2024-06-29 14:56:533709 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583710
Daniel Cheng566634ff2024-06-29 14:56:533711 def testNoScreenshots(self):
3712 # No new strings (file contents same). Should not warn.
3713 input_api = self.makeInputApi([
3714 MockAffectedFile('test.grd',
3715 self.NEW_GRD_CONTENTS1,
3716 self.NEW_GRD_CONTENTS1,
3717 action='M'),
3718 MockAffectedFile('part.grdp',
3719 self.NEW_GRDP_CONTENTS1,
3720 self.NEW_GRDP_CONTENTS1,
3721 action='M')
3722 ])
3723 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3724 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343725
Daniel Cheng566634ff2024-06-29 14:56:533726 # Add two new strings. Should have two warnings.
3727 input_api = self.makeInputApi([
3728 MockAffectedFile('test.grd',
3729 self.NEW_GRD_CONTENTS2,
3730 self.NEW_GRD_CONTENTS1,
3731 action='M'),
3732 MockAffectedFile('part.grdp',
3733 self.NEW_GRDP_CONTENTS2,
3734 self.NEW_GRDP_CONTENTS1,
3735 action='M')
3736 ])
3737 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3738 self.assertEqual(1, len(warnings))
3739 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3740 self.assertEqual('error', warnings[0].type)
3741 self.assertEqual([
3742 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3743 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3744 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213745
Daniel Cheng566634ff2024-06-29 14:56:533746 # Add four new strings. Should have four warnings.
3747 input_api = self.makeInputApi([
3748 MockAffectedFile('test.grd',
3749 self.NEW_GRD_CONTENTS2,
3750 self.OLD_GRD_CONTENTS,
3751 action='M'),
3752 MockAffectedFile('part.grdp',
3753 self.NEW_GRDP_CONTENTS2,
3754 self.OLD_GRDP_CONTENTS,
3755 action='M')
3756 ])
3757 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3758 self.assertEqual(1, len(warnings))
3759 self.assertEqual('error', warnings[0].type)
3760 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3761 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583762 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583763 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303764 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303765 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533766 ], warnings[0].items)
3767
3768 def testModifiedMessageDescription(self):
3769 # CL modified a message description for a message that does not yet have a
3770 # screenshot. Should not warn.
3771 input_api = self.makeInputApi([
3772 MockAffectedFile('part.grdp',
3773 self.NEW_GRDP_CONTENTS3,
3774 self.NEW_GRDP_CONTENTS4,
3775 action='M')
3776 ])
3777 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3778 self.assertEqual(0, len(warnings))
3779
3780 # CL modified a message description for a message that already has a
3781 # screenshot. Should not warn.
3782 input_api = self.makeInputApi([
3783 MockAffectedFile('part.grdp',
3784 self.NEW_GRDP_CONTENTS3,
3785 self.NEW_GRDP_CONTENTS4,
3786 action='M'),
3787 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3788 self.VALID_SHA1,
3789 action='A')
3790 ])
3791 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3792 self.assertEqual(0, len(warnings))
3793
3794 def testModifiedMessageMeaning(self):
3795 # CL modified a message meaning for a message that does not yet have a
3796 # screenshot. Should warn.
3797 input_api = self.makeInputApi([
3798 MockAffectedFile('part.grdp',
3799 self.NEW_GRDP_CONTENTS5,
3800 self.NEW_GRDP_CONTENTS6,
3801 action='M')
3802 ])
3803 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3804 self.assertEqual(1, len(warnings))
3805
3806 # CL modified a message meaning for a message that already has a
3807 # screenshot. Should not warn.
3808 input_api = self.makeInputApi([
3809 MockAffectedFile('part.grdp',
3810 self.NEW_GRDP_CONTENTS5,
3811 self.NEW_GRDP_CONTENTS6,
3812 action='M'),
3813 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3814 self.VALID_SHA1,
3815 action='A')
3816 ])
3817 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3818 self.assertEqual(0, len(warnings))
3819
3820 def testModifiedIntroducedInvalidSha1(self):
3821 # CL modified a message and the sha1 file changed to invalid
3822 input_api = self.makeInputApi([
3823 MockAffectedFile('part.grdp',
3824 self.NEW_GRDP_CONTENTS5,
3825 self.NEW_GRDP_CONTENTS6,
3826 action='M'),
3827 MockAffectedFile(os.path.join('part_grdp',
3828 'IDS_PART_TEST1.png.sha1'),
3829 ('some invalid sha1', ),
3830 self.VALID_SHA1,
3831 action='M')
3832 ])
3833 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3834 self.assertEqual(1, len(warnings))
3835
3836 def testPngAddedSha1NotAdded(self):
3837 # CL added one new message in a grd file and added the png file associated
3838 # with it, but did not add the corresponding sha1 file. This should warn
3839 # twice:
3840 # - Once for the added png file (because we don't want developers to upload
3841 # actual images)
3842 # - Once for the missing .sha1 file
3843 input_api = self.makeInputApi([
3844 MockAffectedFile('test.grd',
3845 self.NEW_GRD_CONTENTS1,
3846 self.OLD_GRD_CONTENTS,
3847 action='M'),
3848 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3849 'binary',
3850 action='A')
3851 ])
3852 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3853 self.assertEqual(2, len(warnings))
3854 self.assertEqual('error', warnings[0].type)
3855 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3856 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3857 warnings[0].items)
3858 self.assertEqual('error', warnings[1].type)
3859 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3860 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3861 warnings[1].items)
3862
3863 # CL added two messages (one in grd, one in grdp) and added the png files
3864 # associated with the messages, but did not add the corresponding sha1
3865 # files. This should warn twice:
3866 # - Once for the added png files (because we don't want developers to upload
3867 # actual images)
3868 # - Once for the missing .sha1 files
3869 input_api = self.makeInputApi([
3870 # Modified files:
3871 MockAffectedFile('test.grd',
3872 self.NEW_GRD_CONTENTS1,
3873 self.OLD_GRD_CONTENTS,
3874 action='M'),
3875 MockAffectedFile('part.grdp',
3876 self.NEW_GRDP_CONTENTS1,
3877 self.OLD_GRDP_CONTENTS,
3878 action='M'),
3879 # Added files:
3880 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3881 'binary',
3882 action='A'),
3883 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3884 'binary',
3885 action='A')
3886 ])
3887 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3888 self.assertEqual(2, len(warnings))
3889 self.assertEqual('error', warnings[0].type)
3890 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3891 self.assertEqual([
3892 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3893 os.path.join('test_grd', 'IDS_TEST1.png')
3894 ], warnings[0].items)
3895 self.assertEqual('error', warnings[0].type)
3896 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3897 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303898 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533899 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3900 ], warnings[1].items)
3901
3902 def testScreenshotsWithSha1(self):
3903 # CL added four messages (two each in a grd and grdp) and their
3904 # corresponding .sha1 files. No warnings.
3905 input_api = self.makeInputApi([
3906 # Modified files:
3907 MockAffectedFile('test.grd',
3908 self.NEW_GRD_CONTENTS2,
3909 self.OLD_GRD_CONTENTS,
3910 action='M'),
3911 MockAffectedFile('part.grdp',
3912 self.NEW_GRDP_CONTENTS2,
3913 self.OLD_GRDP_CONTENTS,
3914 action='M'),
3915 # Added files:
3916 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3917 self.VALID_SHA1,
3918 action='A'),
3919 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3920 ('0000000000000000000000000000000000000000', ''),
3921 action='A'),
3922 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3923 self.VALID_SHA1,
3924 action='A'),
3925 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3926 self.VALID_SHA1,
3927 action='A'),
3928 ])
3929 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3930 self.assertEqual([], warnings)
3931
3932 def testScreenshotsWithInvalidSha1(self):
3933 input_api = self.makeInputApi([
3934 # Modified files:
3935 MockAffectedFile('test.grd',
3936 self.NEW_GRD_CONTENTS2,
3937 self.OLD_GRD_CONTENTS,
3938 action='M'),
3939 MockAffectedFile('part.grdp',
3940 self.NEW_GRDP_CONTENTS2,
3941 self.OLD_GRDP_CONTENTS,
3942 action='M'),
3943 # Added files:
3944 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3945 self.VALID_SHA1,
3946 action='A'),
3947 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3948 ('‰PNG', 'test'),
3949 action='A'),
3950 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3951 self.VALID_SHA1,
3952 action='A'),
3953 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3954 self.VALID_SHA1,
3955 action='A'),
3956 ])
3957 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3958 self.assertEqual(1, len(warnings))
3959 self.assertEqual('error', warnings[0].type)
3960 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
3961 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3962 warnings[0].items)
3963
3964 def testScreenshotsRemovedWithSha1(self):
3965 # Replace new contents with old contents in grd and grp files, removing
3966 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3967 # Should warn to remove the sha1 files associated with these strings.
3968 input_api = self.makeInputApi([
3969 # Modified files:
3970 MockAffectedFile(
3971 'test.grd',
3972 self.OLD_GRD_CONTENTS, # new_contents
3973 self.NEW_GRD_CONTENTS2, # old_contents
3974 action='M'),
3975 MockAffectedFile(
3976 'part.grdp',
3977 self.OLD_GRDP_CONTENTS, # new_contents
3978 self.NEW_GRDP_CONTENTS2, # old_contents
3979 action='M'),
3980 # Unmodified files:
3981 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3982 self.VALID_SHA1, ''),
3983 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3984 self.VALID_SHA1, ''),
3985 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3986 self.VALID_SHA1, ''),
3987 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3988 self.VALID_SHA1, '')
3989 ])
3990 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3991 self.assertEqual(1, len(warnings))
3992 self.assertEqual('error', warnings[0].type)
3993 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
3994 self.assertEqual([
3995 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303996 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013997 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533998 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3999 ], warnings[0].items)
4000
4001 # Same as above, but this time one of the .sha1 files is also removed.
4002 input_api = self.makeInputApi([
4003 # Modified files:
4004 MockAffectedFile(
4005 'test.grd',
4006 self.OLD_GRD_CONTENTS, # new_contents
4007 self.NEW_GRD_CONTENTS2, # old_contents
4008 action='M'),
4009 MockAffectedFile(
4010 'part.grdp',
4011 self.OLD_GRDP_CONTENTS, # new_contents
4012 self.NEW_GRDP_CONTENTS2, # old_contents
4013 action='M'),
4014 # Unmodified files:
4015 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4016 self.VALID_SHA1, ''),
4017 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4018 self.VALID_SHA1, ''),
4019 # Deleted files:
4020 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4021 '',
4022 'old_contents',
4023 action='D'),
4024 MockAffectedFile(os.path.join('part_grdp',
4025 'IDS_PART_TEST2.png.sha1'),
4026 '',
4027 'old_contents',
4028 action='D')
4029 ])
4030 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4031 self.assertEqual(1, len(warnings))
4032 self.assertEqual('error', warnings[0].type)
4033 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4034 self.assertEqual([
meacerff8a9b62019-12-10 19:43:584035 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534036 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
4037 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144038
Daniel Cheng566634ff2024-06-29 14:56:534039 # Remove all sha1 files. There should be no warnings.
4040 input_api = self.makeInputApi([
4041 # Modified files:
4042 MockAffectedFile('test.grd',
4043 self.OLD_GRD_CONTENTS,
4044 self.NEW_GRD_CONTENTS2,
4045 action='M'),
4046 MockAffectedFile('part.grdp',
4047 self.OLD_GRDP_CONTENTS,
4048 self.NEW_GRDP_CONTENTS2,
4049 action='M'),
4050 # Deleted files:
4051 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4052 self.VALID_SHA1,
4053 action='D'),
4054 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4055 self.VALID_SHA1,
4056 action='D'),
4057 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4058 self.VALID_SHA1,
4059 action='D'),
4060 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4061 self.VALID_SHA1,
4062 action='D')
4063 ])
4064 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4065 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:264066
Daniel Cheng566634ff2024-06-29 14:56:534067 def testIcuSyntax(self):
4068 # Add valid ICU syntax string. Should not raise an error.
4069 input_api = self.makeInputApi([
4070 MockAffectedFile('test.grd',
4071 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4072 self.NEW_GRD_CONTENTS1,
4073 action='M'),
4074 MockAffectedFile('part.grdp',
4075 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4076 self.NEW_GRDP_CONTENTS1,
4077 action='M')
4078 ])
4079 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4080 # We expect no ICU syntax errors.
4081 icu_errors = [
4082 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4083 ]
4084 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264085
Daniel Cheng566634ff2024-06-29 14:56:534086 # Valid changes in ICU syntax. Should not raise an error.
4087 input_api = self.makeInputApi([
4088 MockAffectedFile('test.grd',
4089 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4090 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4091 action='M'),
4092 MockAffectedFile('part.grdp',
4093 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4094 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4095 action='M')
4096 ])
4097 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4098 # We expect no ICU syntax errors.
4099 icu_errors = [
4100 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4101 ]
4102 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324103
Daniel Cheng566634ff2024-06-29 14:56:534104 # Valid changes in ICU syntax. Should not raise an error.
4105 input_api = self.makeInputApi([
4106 MockAffectedFile('test.grd',
4107 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4108 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4109 action='M'),
4110 MockAffectedFile('part.grdp',
4111 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4112 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4113 action='M')
4114 ])
4115 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4116 # We expect no ICU syntax errors.
4117 icu_errors = [
4118 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4119 ]
4120 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264121
Daniel Cheng566634ff2024-06-29 14:56:534122 # Add invalid ICU syntax strings. Should raise two errors.
4123 input_api = self.makeInputApi([
4124 MockAffectedFile('test.grd',
4125 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4126 self.NEW_GRD_CONTENTS1,
4127 action='M'),
4128 MockAffectedFile('part.grdp',
4129 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4130 self.NEW_GRD_CONTENTS1,
4131 action='M')
4132 ])
4133 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4134 # We expect 2 ICU syntax errors.
4135 icu_errors = [
4136 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4137 ]
4138 self.assertEqual(1, len(icu_errors))
4139 self.assertEqual([
4140 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4141 'ICU syntax.',
4142 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4143 ], icu_errors[0].items)
4144
4145 # Change two strings to have ICU syntax errors. Should raise two errors.
4146 input_api = self.makeInputApi([
4147 MockAffectedFile('test.grd',
4148 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4149 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4150 action='M'),
4151 MockAffectedFile('part.grdp',
4152 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4153 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4154 action='M')
4155 ])
4156 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4157 # We expect 2 ICU syntax errors.
4158 icu_errors = [
4159 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4160 ]
4161 self.assertEqual(1, len(icu_errors))
4162 self.assertEqual([
4163 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4164 'ICU syntax.',
4165 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4166 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264167
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144168
Mustafa Emre Acer51f2f742020-03-09 19:41:124169class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534170 ERROR_MESSAGE_FORMAT = (
4171 "Failed to get a list of translatable grd files. "
4172 "This happens when:\n"
4173 " - One of the modified grd or grdp files cannot be parsed or\n"
4174 " - %s is not updated.\n"
4175 "Stack:\n")
4176 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4177 # This lists all .grd files under REPO_ROOT.
4178 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4179 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4180 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4181 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124182
Daniel Cheng566634ff2024-06-29 14:56:534183 # Tests that the presubmit doesn't return when no grd or grdp files are
4184 # modified.
4185 def testExpectationsNoModifiedGrd(self):
4186 input_api = MockInputApi()
4187 input_api.files = [
4188 MockAffectedFile('not_used.txt',
4189 'not used',
4190 'not used',
4191 action='M')
4192 ]
4193 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4194 # under tools/translation/testdata. This is OK because the presubmit won't
4195 # run in the first place since there are no modified grd/grps in input_api.
4196 grd_files = ['doesnt_exist_doesnt_matter.grd']
4197 warnings = PRESUBMIT.CheckTranslationExpectations(
4198 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4199 grd_files)
4200 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124201
Daniel Cheng566634ff2024-06-29 14:56:534202 # Tests that the list of files passed to the presubmit matches the list of
4203 # files in the expectations.
4204 def testExpectationsSuccess(self):
4205 # Mock input file list needs a grd or grdp file in order to run the
4206 # presubmit. The file itself doesn't matter.
4207 input_api = MockInputApi()
4208 input_api.files = [
4209 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4210 ]
4211 # List of all grd files in the repo.
4212 grd_files = [
4213 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4214 ]
4215 warnings = PRESUBMIT.CheckTranslationExpectations(
4216 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4217 grd_files)
4218 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124219
Ben Mason5d4c3242025-04-15 20:28:374220 # Tests that the list of files passed to the presubmit does not
4221 # contain duplicate basenames.
4222 def testExpectationsSuccess(self):
4223 # Mock input file list needs a grd or grdp file in order to run the
4224 # presubmit. The file itself doesn't matter.
4225 input_api = MockInputApi()
4226 input_api.files = [
4227 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4228 ]
4229 # List of all grd files in the repo.
4230 grd_files = [
4231 'dir1/test.grd', 'unlisted.grd', 'not_translated.grd',
4232 'internal.grd', 'dir2/test.grd'
4233 ]
4234 warnings = PRESUBMIT.CheckTranslationExpectations(
4235 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4236 grd_files)
4237 self.assertEqual(1, len(warnings))
4238 self.assertTrue(
4239 ("Multiple string files have the same basename. "
4240 "This will result in missing translations. "
4241 "Files: dir1/test.grd, dir2/test.grd") in warnings[0].message)
4242
Daniel Cheng566634ff2024-06-29 14:56:534243 # Tests that the presubmit warns when a file is listed in expectations, but
4244 # does not actually exist.
4245 def testExpectationsMissingFile(self):
4246 # Mock input file list needs a grd or grdp file in order to run the
4247 # presubmit.
4248 input_api = MockInputApi()
4249 input_api.files = [
4250 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4251 ]
4252 # unlisted.grd is listed under tools/translation/testdata but is not
4253 # included in translation expectations.
4254 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4255 warnings = PRESUBMIT.CheckTranslationExpectations(
4256 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4257 grd_files)
4258 self.assertEqual(1, len(warnings))
4259 self.assertTrue(warnings[0].message.startswith(
4260 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4261 self.assertTrue(
4262 ("test.grd is listed in the translation expectations, "
4263 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124264
Daniel Cheng566634ff2024-06-29 14:56:534265 # Tests that the presubmit warns when a file is not listed in expectations but
4266 # does actually exist.
4267 def testExpectationsUnlistedFile(self):
4268 # Mock input file list needs a grd or grdp file in order to run the
4269 # presubmit.
4270 input_api = MockInputApi()
4271 input_api.files = [
4272 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4273 ]
4274 # unlisted.grd is listed under tools/translation/testdata but is not
4275 # included in translation expectations.
4276 grd_files = [
4277 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4278 ]
4279 warnings = PRESUBMIT.CheckTranslationExpectations(
4280 input_api, MockOutputApi(), self.REPO_ROOT,
4281 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4282 self.assertEqual(1, len(warnings))
4283 self.assertTrue(warnings[0].message.startswith(
4284 self.ERROR_MESSAGE_FORMAT %
4285 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4286 self.assertTrue(("unlisted.grd appears to be translatable "
4287 "(because it contains <file> or <message> elements), "
4288 "but is not listed in the translation expectations."
4289 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124290
Daniel Cheng566634ff2024-06-29 14:56:534291 # Tests that the presubmit warns twice:
4292 # - for a non-existing file listed in expectations
4293 # - for an existing file not listed in expectations
4294 def testMultipleWarnings(self):
4295 # Mock input file list needs a grd or grdp file in order to run the
4296 # presubmit.
4297 input_api = MockInputApi()
4298 input_api.files = [
4299 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4300 ]
4301 # unlisted.grd is listed under tools/translation/testdata but is not
4302 # included in translation expectations.
4303 # test.grd is not listed under tools/translation/testdata but is included
4304 # in translation expectations.
4305 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4306 warnings = PRESUBMIT.CheckTranslationExpectations(
4307 input_api, MockOutputApi(), self.REPO_ROOT,
4308 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4309 self.assertEqual(1, len(warnings))
4310 self.assertTrue(warnings[0].message.startswith(
4311 self.ERROR_MESSAGE_FORMAT %
4312 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4313 self.assertTrue(("unlisted.grd appears to be translatable "
4314 "(because it contains <file> or <message> elements), "
4315 "but is not listed in the translation expectations."
4316 ) in warnings[0].message)
4317 self.assertTrue(
4318 ("test.grd is listed in the translation expectations, "
4319 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124320
4321
Dominic Battre033531052018-09-24 15:45:344322class DISABLETypoInTest(unittest.TestCase):
4323
Daniel Cheng566634ff2024-06-29 14:56:534324 def testPositive(self):
4325 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4326 # where the desire is to disable a test.
4327 tests = [
4328 # Disabled on one platform:
4329 '#if defined(OS_WIN)\n'
4330 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4331 '#else\n'
4332 '#define MAYBE_FoobarTest FoobarTest\n'
4333 '#endif\n',
4334 # Disabled on one platform spread cross lines:
4335 '#if defined(OS_WIN)\n'
4336 '#define MAYBE_FoobarTest \\\n'
4337 ' DISABLE_FoobarTest\n'
4338 '#else\n'
4339 '#define MAYBE_FoobarTest FoobarTest\n'
4340 '#endif\n',
4341 # Disabled on all platforms:
4342 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4343 # Disabled on all platforms but multiple lines
4344 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4345 ]
Dominic Battre033531052018-09-24 15:45:344346
Daniel Cheng566634ff2024-06-29 14:56:534347 for test in tests:
4348 mock_input_api = MockInputApi()
4349 mock_input_api.files = [
4350 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4351 ]
Dominic Battre033531052018-09-24 15:45:344352
Daniel Cheng566634ff2024-06-29 14:56:534353 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4354 mock_input_api, MockOutputApi())
4355 self.assertEqual(
4356 1,
4357 len(results),
4358 msg=('expected len(results) == 1 but got %d in test: %s' %
4359 (len(results), test)))
4360 self.assertTrue(
4361 'foo_unittest.cc' in results[0].message,
4362 msg=(
4363 'expected foo_unittest.cc in message but got %s in test %s'
4364 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344365
Daniel Cheng566634ff2024-06-29 14:56:534366 def testIgnoreNotTestFiles(self):
4367 mock_input_api = MockInputApi()
4368 mock_input_api.files = [
4369 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4370 ]
Dominic Battre033531052018-09-24 15:45:344371
Daniel Cheng566634ff2024-06-29 14:56:534372 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4373 MockOutputApi())
4374 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344375
Daniel Cheng566634ff2024-06-29 14:56:534376 def testIgnoreDeletedFiles(self):
4377 mock_input_api = MockInputApi()
4378 mock_input_api.files = [
4379 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4380 action='D'),
4381 ]
Katie Df13948e2018-09-25 07:33:444382
Daniel Cheng566634ff2024-06-29 14:56:534383 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4384 MockOutputApi())
4385 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344386
Nina Satragnof7660532021-09-20 18:03:354387class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354388
Daniel Cheng566634ff2024-06-29 14:56:534389 def testPositive(self):
4390 test = ('#if defined(HAS_ENERGY)\n'
4391 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4392 '#else\n'
4393 '#define MAYBE_CastExplosion CastExplosion\n'
4394 '#endif\n'
4395 'TEST_F(ArchWizard, CastExplosion) {\n'
4396 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4397 '#define MAYBE_ArchPriest ArchPriest\n'
4398 '#else\n'
4399 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4400 '#endif\n'
4401 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4402 '#if !defined(CRUSADER_IN_PARTY)\n'
4403 '#define MAYBE_Crusader \\\n'
4404 ' DISABLED_Crusader \n'
4405 '#else\n'
4406 '#define MAYBE_Crusader \\\n'
4407 ' Crusader\n'
4408 '#endif\n'
4409 ' TEST_F(\n'
4410 ' Crusader,\n'
4411 ' CastTaunt) { }\n'
4412 '#if defined(LEARNED_BASIC_SKILLS)\n'
4413 '#define MAYBE_CastSteal \\\n'
4414 ' DISABLED_CastSteal \n'
4415 '#else\n'
4416 '#define MAYBE_CastSteal \\\n'
4417 ' CastSteal\n'
4418 '#endif\n'
4419 ' TEST_F(\n'
4420 ' ThiefClass,\n'
4421 ' CastSteal) { }\n')
4422 mock_input_api = MockInputApi()
4423 mock_input_api.files = [
4424 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4425 ]
4426 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4427 mock_input_api, MockOutputApi())
4428 self.assertEqual(4, len(results))
4429 self.assertTrue('CastExplosion' in results[0].message)
4430 self.assertTrue(
4431 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4432 self.assertTrue('ArchPriest' in results[1].message)
4433 self.assertTrue(
4434 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4435 self.assertTrue('Crusader' in results[2].message)
4436 self.assertTrue(
4437 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4438 self.assertTrue('CastSteal' in results[3].message)
4439 self.assertTrue(
4440 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354441
Daniel Cheng566634ff2024-06-29 14:56:534442 def testNegative(self):
4443 test = ('#if defined(HAS_ENERGY)\n'
4444 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4445 '#else\n'
4446 '#define MAYBE_CastExplosion CastExplosion\n'
4447 '#endif\n'
4448 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4449 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4450 '#define MAYBE_ArchPriest ArchPriest\n'
4451 '#else\n'
4452 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4453 '#endif\n'
4454 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4455 '#if !defined(CRUSADER_IN_PARTY)\n'
4456 '#define MAYBE_Crusader \\\n'
4457 ' DISABLED_Crusader \n'
4458 '#else\n'
4459 '#define MAYBE_Crusader \\\n'
4460 ' Crusader\n'
4461 '#endif\n'
4462 ' TEST_F(\n'
4463 ' MAYBE_Crusader,\n'
4464 ' CastTaunt) { }\n'
4465 '#if defined(LEARNED_BASIC_SKILLS)\n'
4466 '#define MAYBE_CastSteal \\\n'
4467 ' DISABLED_CastSteal \n'
4468 '#else\n'
4469 '#define MAYBE_CastSteal \\\n'
4470 ' CastSteal\n'
4471 '#endif\n'
4472 ' TEST_F(\n'
4473 ' ThiefClass,\n'
4474 ' MAYBE_CastSteal) { }\n')
4475
4476 mock_input_api = MockInputApi()
4477 mock_input_api.files = [
4478 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4479 ]
4480 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4481 mock_input_api, MockOutputApi())
4482 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514483
Max Morozb47503b2019-08-08 21:03:274484class CheckFuzzTargetsTest(unittest.TestCase):
4485
Daniel Cheng566634ff2024-06-29 14:56:534486 def _check(self, files):
4487 mock_input_api = MockInputApi()
4488 mock_input_api.files = []
4489 for fname, contents in files.items():
4490 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4491 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4492 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274493
Daniel Cheng566634ff2024-06-29 14:56:534494 def testLibFuzzerSourcesIgnored(self):
4495 results = self._check({
4496 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4497 "LLVMFuzzerInitialize",
4498 })
4499 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274500
Daniel Cheng566634ff2024-06-29 14:56:534501 def testNonCodeFilesIgnored(self):
4502 results = self._check({
4503 "README.md": "LLVMFuzzerInitialize",
4504 })
4505 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274506
Daniel Cheng566634ff2024-06-29 14:56:534507 def testNoErrorHeaderPresent(self):
4508 results = self._check({
4509 "fuzzer.cc":
4510 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4511 "LLVMFuzzerInitialize")
4512 })
4513 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274514
Daniel Cheng566634ff2024-06-29 14:56:534515 def testErrorMissingHeader(self):
4516 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4517 self.assertEqual(len(results), 1)
4518 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274519
4520
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264521class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404522
Daniel Cheng566634ff2024-06-29 14:56:534523 def testSetNoParentTopLevelAllowed(self):
4524 mock_input_api = MockInputApi()
4525 mock_input_api.files = [
4526 MockAffectedFile('goat/OWNERS', [
4527 'set noparent',
4528 'jochen@chromium.org',
4529 ])
4530 ]
4531 mock_output_api = MockOutputApi()
4532 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4533 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264534
Daniel Cheng566634ff2024-06-29 14:56:534535 def testSetNoParentMissing(self):
4536 mock_input_api = MockInputApi()
4537 mock_input_api.files = [
4538 MockAffectedFile('services/goat/OWNERS', [
4539 'set noparent',
4540 'jochen@chromium.org',
4541 'per-file *.json=set noparent',
4542 'per-file *.json=jochen@chromium.org',
4543 ])
4544 ]
4545 mock_output_api = MockOutputApi()
4546 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4547 self.assertEqual(1, len(errors))
4548 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4549 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4550
4551 def testSetNoParentWithCorrectRule(self):
4552 mock_input_api = MockInputApi()
4553 mock_input_api.files = [
4554 MockAffectedFile('services/goat/OWNERS', [
4555 'set noparent',
4556 'file://ipc/SECURITY_OWNERS',
4557 'per-file *.json=set noparent',
4558 'per-file *.json=file://ipc/SECURITY_OWNERS',
4559 ])
4560 ]
4561 mock_output_api = MockOutputApi()
4562 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4563 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264564
4565
Ken Rockotc31f4832020-05-29 18:58:514566class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514567
Daniel Cheng566634ff2024-06-29 14:56:534568 def runTestWithAffectedFiles(self, affected_files):
4569 mock_input_api = MockInputApi()
4570 mock_input_api.files = affected_files
4571 mock_output_api = MockOutputApi()
4572 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4573 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514574
Daniel Cheng566634ff2024-06-29 14:56:534575 def testSafeChangePasses(self):
4576 errors = self.runTestWithAffectedFiles([
4577 MockAffectedFile(
4578 'foo/foo.mojom',
4579 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4580 old_contents=['[Stable] struct S {};'])
4581 ])
4582 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514583
Daniel Cheng566634ff2024-06-29 14:56:534584 def testBadChangeFails(self):
4585 errors = self.runTestWithAffectedFiles([
4586 MockAffectedFile('foo/foo.mojom',
4587 ['[Stable] struct S { int32 x; };'],
4588 old_contents=['[Stable] struct S {};'])
4589 ])
4590 self.assertEqual(1, len(errors))
4591 self.assertTrue('not backward-compatible' in errors[0].message)
4592
4593 def testDeletedFile(self):
4594 """Regression test for https://crbug.com/1091407."""
4595 errors = self.runTestWithAffectedFiles([
4596 MockAffectedFile('a.mojom', [],
4597 old_contents=['struct S {};'],
4598 action='D'),
4599 MockAffectedFile(
4600 'b.mojom', ['struct S {}; struct T { S s; };'],
4601 old_contents=['import "a.mojom"; struct T { S s; };'])
4602 ])
4603 self.assertEqual([], errors)
4604
Ken Rockotad7901f942020-06-04 20:17:094605
Jose Magana2b456f22021-03-09 23:26:404606class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4607
Daniel Cheng566634ff2024-06-29 14:56:534608 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404609
Daniel Cheng566634ff2024-06-29 14:56:534610 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404611
Daniel Cheng566634ff2024-06-29 14:56:534612 def testWarningNMF(self):
4613 mock_input_api = MockInputApi()
4614 mock_input_api.files = [
4615 MockAffectedFile(
4616 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4617 ['"program"', 'B'],
4618 scm_diff='\n'.join([
4619 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4620 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4621 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4622 ]),
4623 action='M')
4624 ]
4625 mock_output_api = MockOutputApi()
4626 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4627 mock_input_api, mock_output_api)
4628 self.assertEqual(1, len(errors))
4629 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4630 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404631
Daniel Cheng566634ff2024-06-29 14:56:534632 def testWarningManifest(self):
4633 mock_input_api = MockInputApi()
4634 mock_input_api.files = [
4635 MockAffectedFile(
4636 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4637 ['"app":"', 'B'],
4638 scm_diff='\n'.join([
4639 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4640 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4641 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4642 ]),
4643 action='M')
4644 ]
4645 mock_output_api = MockOutputApi()
4646 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4647 mock_input_api, mock_output_api)
4648 self.assertEqual(1, len(errors))
4649 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4650 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404651
Daniel Cheng566634ff2024-06-29 14:56:534652 def testOKWarningManifestWithoutApp(self):
4653 mock_input_api = MockInputApi()
4654 mock_input_api.files = [
4655 MockAffectedFile(
4656 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4657 ['"name":"', 'B'],
4658 scm_diff='\n'.join([
4659 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4660 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4661 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4662 ]),
4663 action='M')
4664 ]
4665 mock_output_api = MockOutputApi()
4666 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4667 mock_input_api, mock_output_api)
4668 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404669
Daniel Cheng566634ff2024-06-29 14:56:534670 def testWarningPPAPI(self):
4671 mock_input_api = MockInputApi()
4672 mock_input_api.files = [
4673 MockAffectedFile(
4674 'foo.hpp', ['A', '#include <ppapi.h>', 'B'], ['A', 'B'],
4675 scm_diff='\n'.join([
4676 '--- foo.hpp.old 2020-12-02 20:40:54.430676385 +0100',
4677 '+++ foo.hpp.new 2020-12-02 20:41:02.086700197 +0100',
4678 '@@ -1,2 +1,3 @@', ' A', '+#include <ppapi.h>', ' B'
4679 ]),
4680 action='M')
4681 ]
4682 mock_output_api = MockOutputApi()
4683 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4684 mock_input_api, mock_output_api)
4685 self.assertEqual(1, len(errors))
4686 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4687 self.assertTrue('foo.hpp' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404688
Daniel Cheng566634ff2024-06-29 14:56:534689 def testNoWarningPPAPI(self):
4690 mock_input_api = MockInputApi()
4691 mock_input_api.files = [
4692 MockAffectedFile(
4693 'foo.txt', ['A', 'Peppapig', 'B'], ['A', 'B'],
4694 scm_diff='\n'.join([
4695 '--- foo.txt.old 2020-12-02 20:40:54.430676385 +0100',
4696 '+++ foo.txt.new 2020-12-02 20:41:02.086700197 +0100',
4697 '@@ -1,2 +1,3 @@', ' A', '+Peppapig', ' B'
4698 ]),
4699 action='M')
4700 ]
4701 mock_output_api = MockOutputApi()
4702 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4703 mock_input_api, mock_output_api)
4704 self.assertEqual(0, len(errors))
4705
Jose Magana2b456f22021-03-09 23:26:404706
Dominic Battre645d42342020-12-04 16:14:104707class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534708 # Test that a warning is generated if a preference registration is removed
4709 # from a random file.
4710 def testWarning(self):
4711 mock_input_api = MockInputApi()
4712 mock_input_api.files = [
4713 MockAffectedFile(
4714 'foo.cc', ['A', 'B'],
4715 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4716 scm_diff='\n'.join([
4717 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4718 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4719 '@@ -1,3 +1,2 @@', ' A',
4720 '-prefs->RegisterStringPref("foo", "default");', ' B'
4721 ]),
4722 action='M')
4723 ]
4724 mock_output_api = MockOutputApi()
4725 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4726 mock_input_api, mock_output_api)
4727 self.assertEqual(1, len(errors))
4728 self.assertTrue(
4729 'Discovered possible removal of preference registrations' in
4730 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104731
Daniel Cheng566634ff2024-06-29 14:56:534732 # Test that a warning is inhibited if the preference registration was moved
4733 # to the deprecation functions in browser prefs.
4734 def testNoWarningForMigration(self):
4735 mock_input_api = MockInputApi()
4736 mock_input_api.files = [
4737 # RegisterStringPref was removed from foo.cc.
4738 MockAffectedFile(
4739 'foo.cc', ['A', 'B'],
4740 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4741 scm_diff='\n'.join([
4742 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4743 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4744 '@@ -1,3 +1,2 @@', ' A',
4745 '-prefs->RegisterStringPref("foo", "default");', ' B'
4746 ]),
4747 action='M'),
4748 # But the preference was properly migrated.
4749 MockAffectedFile(
4750 'chrome/browser/prefs/browser_prefs.cc', [
4751 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4752 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4753 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4754 'prefs->RegisterStringPref("foo", "default");',
4755 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4756 ], [
4757 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4758 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4759 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4760 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4761 ],
4762 scm_diff='\n'.join([
4763 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4764 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4765 '@@ -2,3 +2,4 @@',
4766 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4767 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4768 '+prefs->RegisterStringPref("foo", "default");',
4769 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4770 ]),
4771 action='M'),
4772 ]
4773 mock_output_api = MockOutputApi()
4774 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4775 mock_input_api, mock_output_api)
4776 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104777
Daniel Cheng566634ff2024-06-29 14:56:534778 # Test that a warning is NOT inhibited if the preference registration was
4779 # moved to a place outside of the migration functions in browser_prefs.cc
4780 def testWarningForImproperMigration(self):
4781 mock_input_api = MockInputApi()
4782 mock_input_api.files = [
4783 # RegisterStringPref was removed from foo.cc.
4784 MockAffectedFile(
4785 'foo.cc', ['A', 'B'],
4786 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4787 scm_diff='\n'.join([
4788 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4789 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4790 '@@ -1,3 +1,2 @@', ' A',
4791 '-prefs->RegisterStringPref("foo", "default");', ' B'
4792 ]),
4793 action='M'),
4794 # The registration call was moved to a place in browser_prefs.cc that
4795 # is outside the migration functions.
4796 MockAffectedFile(
4797 'chrome/browser/prefs/browser_prefs.cc', [
4798 'prefs->RegisterStringPref("foo", "default");',
4799 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4800 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4801 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4802 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4803 ], [
4804 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4805 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4806 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4807 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4808 ],
4809 scm_diff='\n'.join([
4810 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4811 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4812 '@@ -1,2 +1,3 @@',
4813 '+prefs->RegisterStringPref("foo", "default");',
4814 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4815 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4816 ]),
4817 action='M'),
4818 ]
4819 mock_output_api = MockOutputApi()
4820 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4821 mock_input_api, mock_output_api)
4822 self.assertEqual(1, len(errors))
4823 self.assertTrue(
4824 'Discovered possible removal of preference registrations' in
4825 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104826
Daniel Cheng566634ff2024-06-29 14:56:534827 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4828 # deleted.
4829 def testDeletedMarkerRaisesError(self):
4830 mock_input_api = MockInputApi()
4831 mock_input_api.files = [
4832 MockAffectedFile(
4833 'chrome/browser/prefs/browser_prefs.cc',
4834 [
4835 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4836 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4837 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4838 # The following line is deleted for this test
4839 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4840 ])
4841 ]
4842 mock_output_api = MockOutputApi()
4843 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4844 mock_input_api, mock_output_api)
4845 self.assertEqual(1, len(errors))
4846 self.assertEqual(
4847 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4848 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104849
Sven Zheng76a79ea2022-12-21 21:25:244850class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4851 def testWarning(self):
4852 mock_input_api = MockInputApi()
4853 mock_output_api = MockOutputApi()
4854 mock_input_api.files = [
4855 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4856 ]
4857 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4858 self.assertEqual(1, len(result))
4859 self.assertEqual(result[0].type, 'warning')
4860
4861 def testNoWarningWithBrowserTest(self):
4862 mock_input_api = MockInputApi()
4863 mock_output_api = MockOutputApi()
4864 mock_input_api.files = [
4865 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4866 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4867 ]
4868 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4869 self.assertEqual(0, len(result))
4870
4871 def testNoWarningModifyCrosapi(self):
4872 mock_input_api = MockInputApi()
4873 mock_output_api = MockOutputApi()
4874 mock_input_api.files = [
4875 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4876 ]
4877 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4878 self.assertEqual(0, len(result))
4879
4880 def testNoWarningAddNonMojomFile(self):
4881 mock_input_api = MockInputApi()
4882 mock_output_api = MockOutputApi()
4883 mock_input_api.files = [
4884 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4885 ]
4886 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4887 self.assertEqual(0, len(result))
4888
4889 def testNoWarningNoneRelatedMojom(self):
4890 mock_input_api = MockInputApi()
4891 mock_output_api = MockOutputApi()
4892 mock_input_api.files = [
4893 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4894 ]
4895 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4896 self.assertEqual(0, len(result))
4897
4898
Henrique Ferreiro2a4b55942021-11-29 23:45:364899class AssertAshOnlyCodeTest(unittest.TestCase):
4900 def testErrorsOnlyOnAshDirectories(self):
4901 files_in_ash = [
4902 MockFile('ash/BUILD.gn', []),
4903 MockFile('chrome/browser/ash/BUILD.gn', []),
4904 ]
4905 other_files = [
4906 MockFile('chrome/browser/BUILD.gn', []),
Georg Neis94f87f02024-10-22 08:20:134907 MockFile('chrome/browser/foo/BUILD.gn', ['assert(is_chromeos_ash)']),
Henrique Ferreiro2a4b55942021-11-29 23:45:364908 ]
4909 input_api = MockInputApi()
4910 input_api.files = files_in_ash
4911 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4912 self.assertEqual(2, len(errors))
4913
4914 input_api.files = other_files
4915 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4916 self.assertEqual(0, len(errors))
4917
4918 def testDoesNotErrorOnNonGNFiles(self):
4919 input_api = MockInputApi()
4920 input_api.files = [
4921 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4922 MockFile('chrome/browser/ash/test.cc',
4923 ['assert(is_chromeos_ash)']),
4924 ]
4925 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4926 self.assertEqual(0, len(errors))
4927
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214928 def testDeletedFile(self):
4929 input_api = MockInputApi()
4930 input_api.files = [
4931 MockFile('ash/BUILD.gn', []),
4932 MockFile('ash/foo/BUILD.gn', [], action='D'),
4933 ]
4934 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4935 self.assertEqual(1, len(errors))
4936
Henrique Ferreiro2a4b55942021-11-29 23:45:364937 def testDoesNotErrorWithAssertion(self):
4938 input_api = MockInputApi()
4939 input_api.files = [
4940 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4941 MockFile('chrome/browser/ash/BUILD.gn',
4942 ['assert(is_chromeos_ash)']),
Georg Neis94f87f02024-10-22 08:20:134943 MockFile('chrome/browser/ash/1/BUILD.gn',
4944 ['assert(is_chromeos)']),
4945 MockFile('chrome/browser/ash/2/BUILD.gn',
4946 ['assert(is_chromeos_ash)']),
4947 MockFile('chrome/browser/ash/3/BUILD.gn',
4948 ['assert(is_chromeos, "test")']),
4949 MockFile('chrome/browser/ash/4/BUILD.gn',
Henrique Ferreiro2a4b55942021-11-29 23:45:364950 ['assert(is_chromeos_ash, "test")']),
4951 ]
4952 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4953 self.assertEqual(0, len(errors))
4954
4955
Lukasz Anforowicz7016d05e2021-11-30 03:56:274956class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274957
Daniel Cheng566634ff2024-06-29 14:56:534958 def testAllowedCases(self):
4959 mock_input_api = MockInputApi()
4960 mock_input_api.files = [
4961 # Browser-side files are allowed.
4962 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4963 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4964 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4965 MockAffectedFile('test13/blink/public/common/foo.cc',
4966 ['raw_ptr<int>']),
4967 MockAffectedFile('test14/blink/public/platform/foo.cc',
4968 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274969
Daniel Cheng566634ff2024-06-29 14:56:534970 # Non-C++ files are allowed.
4971 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274972
Daniel Cheng566634ff2024-06-29 14:56:534973 # Renderer code is generally allowed (except specifically
4974 # disallowed directories).
4975 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
4976 ]
4977 mock_output_api = MockOutputApi()
4978 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4979 self.assertFalse(errors)
4980
4981 def testDisallowedCases(self):
4982 mock_input_api = MockInputApi()
4983 mock_input_api.files = [
4984 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
4985 ['raw_ptr<int>']),
4986 MockAffectedFile(
4987 'test2/third_party/blink/renderer/platform/heap/foo.cc',
4988 ['raw_ptr<int>']),
4989 MockAffectedFile(
4990 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
4991 ['raw_ptr<int>']),
4992 MockAffectedFile(
4993 'test4/third_party/blink/renderer/platform/fonts/foo.h',
4994 ['raw_ptr<int>']),
4995 MockAffectedFile(
4996 'test5/third_party/blink/renderer/core/paint/foo.cc',
4997 ['raw_ptr<int>']),
4998 MockAffectedFile(
4999 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
5000 ['raw_ptr<int>']),
5001 MockAffectedFile(
5002 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
5003 ['raw_ptr<int>']),
5004 ]
5005 mock_output_api = MockOutputApi()
5006 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
5007 self.assertEqual(len(mock_input_api.files), len(errors))
5008 for error in errors:
5009 self.assertTrue(
5010 'raw_ptr<T> should not be used in this renderer code' in
5011 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275012
mikt9337567c2023-09-08 18:38:175013class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:175014
Daniel Cheng566634ff2024-06-29 14:56:535015 def testAllowedCases(self):
5016 mock_input_api = MockInputApi()
5017 mock_input_api.files = [
5018 # Non-C++ files are allowed.
5019 MockAffectedFile('test20/renderer/foo.md',
5020 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:175021
Daniel Cheng566634ff2024-06-29 14:56:535022 # Mentions in a comment are allowed.
5023 MockAffectedFile('test30/renderer/foo.cc',
5024 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
5025 ]
5026 mock_output_api = MockOutputApi()
5027 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5028 mock_input_api, mock_output_api)
5029 self.assertFalse(errors)
5030
5031 def testDisallowedCases(self):
5032 mock_input_api = MockInputApi()
5033 mock_input_api.files = [
5034 MockAffectedFile('test1/foo.h',
5035 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5036 MockAffectedFile('test2/foo.cc',
5037 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5038 ]
5039 mock_output_api = MockOutputApi()
5040 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5041 mock_input_api, mock_output_api)
5042 self.assertEqual(1, len(errors))
5043 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
5044 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275045
Henrique Ferreirof9819f2e32021-11-30 13:31:565046class AssertPythonShebangTest(unittest.TestCase):
5047 def testError(self):
5048 input_api = MockInputApi()
5049 input_api.files = [
5050 MockFile('ash/test.py', ['#!/usr/bin/python']),
5051 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
5052 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:275053 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:565054 ]
5055 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5056 self.assertEqual(3, len(errors))
5057
5058 def testNonError(self):
5059 input_api = MockInputApi()
5060 input_api.files = [
5061 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
5062 MockFile('third_party/blink/web_tests/external/test.py',
5063 ['#!/usr/bin/python2']),
5064 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
5065 ]
5066 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5067 self.assertEqual(0, len(errors))
5068
Kalvin Lee4a3b79de2022-05-26 16:00:165069class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:165070
Daniel Cheng566634ff2024-06-29 14:56:535071 def testPermissibleUsage(self):
5072 input_api = MockInputApi()
5073 input_api.files = [
5074 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
5075 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:165076
Daniel Cheng566634ff2024-06-29 14:56:535077 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
5078 # own thing at their own risk.
5079 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
5080 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
5081 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
5082 ]
5083 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5084 MockOutputApi())
5085 self.assertEqual(0, len(errors))
5086
5087 def testMissingParentheses(self):
5088 input_api = MockInputApi()
5089 input_api.files = [
5090 MockFile('bad1.cc', ['DCHECK_IS_ON']),
5091 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
5092 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
5093 ]
5094 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5095 MockOutputApi())
5096 self.assertEqual(3, len(errors))
5097 for error in errors:
5098 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:565099
Sam Maier4cef9242022-10-03 14:21:245100
Andrew Grieve5a66ae72024-12-13 15:21:535101class CheckAndroidTestAnnotations(unittest.TestCase):
5102 """Test the CheckAndroidTestAnnotations presubmit check."""
James Shen81cc0e22022-06-15 21:10:455103
Andrew Grieve5a66ae72024-12-13 15:21:535104 def testBatchTruePositives(self):
Daniel Cheng566634ff2024-06-29 14:56:535105 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455106"""
Daniel Cheng566634ff2024-06-29 14:56:535107 mock_input = MockInputApi()
5108 mock_input.files = [
5109 MockFile('path/OneTest.java', ['public class OneTest']),
5110 MockFile('path/TwoTest.java', ['public class TwoTest']),
5111 MockFile('path/ThreeTest.java', [
5112 '@Batch(Batch.PER_CLASS)',
Andrew Grieve5a66ae72024-12-13 15:21:535113 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535114 'public class Three {'
5115 ]),
5116 MockFile('path/FourTest.java', [
5117 '@DoNotBatch(reason = "placeholder reason 1")',
Andrew Grieve5a66ae72024-12-13 15:21:535118 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535119 'public class Four {'
5120 ]),
5121 ]
Andrew Grieve5a66ae72024-12-13 15:21:535122 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535123 self.assertEqual(2, len(errors))
5124 self.assertEqual(2, len(errors[0].items))
5125 self.assertIn('OneTest.java', errors[0].items[0])
5126 self.assertIn('TwoTest.java', errors[0].items[1])
5127 self.assertEqual(2, len(errors[1].items))
5128 self.assertIn('ThreeTest.java', errors[1].items[0])
5129 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385130
Andrew Grieve5a66ae72024-12-13 15:21:535131 def testBatchAnnotationsPresent(self):
Daniel Cheng566634ff2024-06-29 14:56:535132 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5133 mock_input = MockInputApi()
5134 mock_input.files = [
5135 MockFile('path/OneTest.java',
5136 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5137 MockFile('path/TwoTest.java', [
5138 '@DoNotBatch(reason = "placeholder reasons.")',
5139 'public class Two {'
5140 ]),
5141 MockFile('path/ThreeTest.java', [
5142 '@Batch(Batch.PER_CLASS)',
5143 'public class Three extends BaseTestA {'
5144 ], [
5145 '@Batch(Batch.PER_CLASS)',
5146 'public class Three extends BaseTestB {'
5147 ]),
5148 MockFile('path/FourTest.java', [
5149 '@DoNotBatch(reason = "placeholder reason 1")',
5150 'public class Four extends BaseTestA {'
5151 ], [
5152 '@DoNotBatch(reason = "placeholder reason 2")',
5153 'public class Four extends BaseTestB {'
5154 ]),
5155 MockFile('path/FiveTest.java', [
5156 'import androidx.test.uiautomator.UiDevice;',
5157 'public class Five extends BaseTestA {'
5158 ], [
5159 'import androidx.test.uiautomator.UiDevice;',
5160 'public class Five extends BaseTestB {'
5161 ]),
5162 MockFile('path/SixTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535163 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535164 'public class Six extends BaseTestA {'
5165 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535166 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535167 'public class Six extends BaseTestB {'
5168 ]),
5169 MockFile('path/SevenTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535170 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535171 'public class Seven extends BaseTestA {'
5172 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535173 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535174 'public class Seven extends BaseTestB {'
5175 ]),
5176 MockFile(
5177 'path/OtherClass.java',
5178 ['public class OtherClass {'],
5179 ),
5180 MockFile('path/PRESUBMIT.py', [
5181 '@Batch(Batch.PER_CLASS)',
5182 '@DoNotBatch(reason = "placeholder reason)'
5183 ]),
5184 MockFile(
5185 'path/AnnotationTest.java',
5186 ['public @interface SomeAnnotation {'],
5187 ),
5188 ]
Andrew Grieve5a66ae72024-12-13 15:21:535189 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535190 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455191
Andrew Grieve5a66ae72024-12-13 15:21:535192 def testWrongRobolectricTestRunner(self):
5193 mock_input = MockInputApi()
5194 mock_input.files = [
5195 MockFile('path/OneTest.java', [
5196 '@RunWith(RobolectricTestRunner.class)',
5197 'public class ThreeTest {'
5198 ]),
5199 MockFile('path/TwoTest.java', [
5200 'import org.chromium.base.test.BaseRobolectricTestRule;',
5201 '@RunWith(RobolectricTestRunner.class)',
5202 'public class TwoTest {'
5203 ]),
5204 MockFile('path/ThreeTest.java', [
5205 '@RunWith(FooRobolectricTestRunner.class)',
5206 'public class ThreeTest {'
5207 ]),
5208 MockFile('webapks/FourTest.java', [
5209 '@RunWith(RobolectricTestRunner.class)',
5210 'public class ThreeTest {'
5211 ]),
5212 ]
5213 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
5214 self.assertEqual(1, len(errors))
5215 self.assertEqual(1, len(errors[0].items))
5216 self.assertIn('OneTest.java', errors[0].items[0])
5217
Sam Maier4cef9242022-10-03 14:21:245218
Henrique Nakashima224ee2482025-03-21 18:35:025219class CheckAndroidNullAwayAnnotatedClasses(unittest.TestCase):
5220 """Test the _CheckAndroidNullAwayAnnotatedClasses presubmit check."""
5221
5222 def testDetectsInClasses(self):
5223 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in classes."""
5224 mock_input = MockInputApi()
5225 mock_input.files = [
5226 MockFile('path/OneMissing.java', ['public class OneMissing']),
5227 MockFile('path/TwoMarked.java', [
5228 '@NullMarked',
5229 'public class TwoMarked {',
5230 ]),
5231 MockFile('path/ThreeMarked.java', [
5232 '@NullUnmarked',
5233 'public class ThreeMarked {',
5234 ]),
5235 MockFile('path/FourMissing.java', ['class FourMissing']),
5236 ]
5237 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5238 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425239 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025240 self.assertEqual(2, len(results[0].items))
5241 self.assertIn('OneMissing.java', results[0].items[0])
5242 self.assertIn('FourMissing.java', results[0].items[1])
5243
5244 def testDetectsInAnnotations(self):
5245 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in annotations."""
5246 mock_input = MockInputApi()
5247 mock_input.files = [
5248 MockFile('path/OneMissing.java', ['@interface OneMissing']),
5249 MockFile('path/TwoMarked.java', [
5250 '@NullMarked',
5251 '@interface TwoMarked {',
5252 ]),
5253 ]
5254 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5255 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425256 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025257 self.assertEqual(1, len(results[0].items))
5258 self.assertIn('OneMissing.java', results[0].items[0])
5259
5260 def testDetectsInInterfaces(self):
5261 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in interfaces."""
5262 mock_input = MockInputApi()
5263 mock_input.files = [
5264 MockFile('path/OneMissing.java', ['interface OneMissing']),
5265 MockFile('path/TwoMarked.java', [
5266 '@NullMarked',
5267 'interface TwoMarked {',
5268 ]),
5269 ]
5270 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5271 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425272 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025273 self.assertEqual(1, len(results[0].items))
5274 self.assertIn('OneMissing.java', results[0].items[0])
5275
Henrique Nakashimac6605432025-04-24 18:11:595276 def testOnlyChecksAddedFiles(self):
5277 """Tests that missing @NullMarked or @NullUnmarked is only flagged in newly added files."""
5278 mock_input = MockInputApi()
5279 mock_input.files = [
5280 MockFile('path/OneMissing.java', ['public class OneMissing'], action='M'),
5281 ]
5282 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5283 self.assertEqual(0, len(results))
5284
Henrique Nakashima224ee2482025-03-21 18:35:025285 def testExcludesTests(self):
5286 """Tests that missing @NullMarked or @NullUnmarked are not flagged in tests."""
5287 mock_input = MockInputApi()
5288 mock_input.files = [
5289 MockFile('path/OneTest.java', ['public class OneTest']),
5290 ]
5291 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5292 self.assertEqual(0, len(results))
5293
5294 def testExcludesTestSupport(self):
5295 """Tests that missing @NullMarked or @NullUnmarked are not flagged in test support classes."""
5296 mock_input = MockInputApi()
5297 mock_input.files = [
5298 MockFile('path/test/Two.java', [
5299 'public class Two'
5300 ]),
5301 ]
5302 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5303 self.assertEqual(0, len(results))
5304
5305
Mike Dougherty1b8be712022-10-20 00:15:135306class AssertNoJsInIosTest(unittest.TestCase):
5307 def testErrorJs(self):
5308 input_api = MockInputApi()
5309 input_api.files = [
5310 MockFile('components/feature/ios/resources/script.js', []),
5311 MockFile('ios/chrome/feature/resources/script.js', []),
5312 ]
5313 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5314 self.assertEqual(1, len(results))
5315 self.assertEqual('error', results[0].type)
5316 self.assertEqual(2, len(results[0].items))
5317
5318 def testNonError(self):
5319 input_api = MockInputApi()
5320 input_api.files = [
5321 MockFile('chrome/resources/script.js', []),
5322 MockFile('components/feature/ios/resources/script.ts', []),
5323 MockFile('ios/chrome/feature/resources/script.ts', []),
5324 MockFile('ios/web/feature/resources/script.ts', []),
5325 MockFile('ios/third_party/script.js', []),
5326 MockFile('third_party/ios/script.js', []),
5327 ]
5328 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5329 self.assertEqual(0, len(results))
5330
5331 def testExistingFilesWarningOnly(self):
5332 input_api = MockInputApi()
5333 input_api.files = [
5334 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5335 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5336 ]
5337 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5338 self.assertEqual(1, len(results))
5339 self.assertEqual('warning', results[0].type)
5340 self.assertEqual(1, len(results[0].items))
5341
Mike Dougherty4d1050b2023-03-14 15:59:535342 def testMovedScriptWarningOnly(self):
5343 input_api = MockInputApi()
5344 input_api.files = [
5345 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5346 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5347 ]
5348 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5349 self.assertEqual(1, len(results))
5350 self.assertEqual('warning', results[0].type)
5351 self.assertEqual(1, len(results[0].items))
5352
Yuanqing Zhu9eef02832022-12-04 14:42:175353class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175354
Daniel Cheng566634ff2024-06-29 14:56:535355 def testHasAbbreviation(self):
5356 """test png file names with abbreviation that fails the check"""
5357 input_api = MockInputApi()
5358 input_api.files = [
5359 MockFile('image_a.png', [], action='A'),
5360 MockFile('image_a_.png', [], action='A'),
5361 MockFile('image_a_name.png', [], action='A'),
5362 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5363 action='A'),
5364 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5365 action='A'),
5366 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5367 action='A'),
5368 ]
5369 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5370 input_api, MockOutputApi())
5371 self.assertEqual(1, len(results))
5372 self.assertEqual('error', results[0].type)
5373 self.assertEqual(len(input_api.files), len(results[0].items))
5374
5375 def testNoAbbreviation(self):
5376 """test png file names without abbreviation that passes the check"""
5377 input_api = MockInputApi()
5378 input_api.files = [
5379 MockFile('a.png', [], action='A'),
5380 MockFile('_a.png', [], action='A'),
5381 MockFile('image.png', [], action='A'),
5382 MockFile('image_ab_.png', [], action='A'),
5383 MockFile('image_ab_name.png', [], action='A'),
5384 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5385 # They should pass now because the path components ahead of the file name are ignored in the check.
5386 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5387 action='A'),
5388 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5389 action='A'),
5390 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5391 action='A'),
5392 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5393 action='A'),
5394 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5395 [],
5396 action='A'),
5397 ]
5398 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5399 input_api, MockOutputApi())
5400 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175401
Arthur Sonzogni7109bd32023-10-03 10:34:425402class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425403
Daniel Cheng566634ff2024-06-29 14:56:535404 def testError(self):
5405 """Test patch adding dangling pointers are reported"""
5406 mock_input_api = MockInputApi()
5407 mock_output_api = MockOutputApi()
5408
5409 mock_input_api.change.DescriptionText = lambda: "description"
5410 mock_input_api.files = [
5411 MockAffectedFile(
5412 local_path="foo/foo.cc",
5413 old_contents=["raw_ptr<T>"],
5414 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5415 )
5416 ]
5417 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5418 mock_output_api)
5419 self.assertEqual(len(msgs), 1)
5420 self.assertEqual(len(msgs[0].message), 10)
5421 self.assertEqual(
5422 msgs[0].message[0],
5423 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5424 )
Arthur Sonzogni7109bd32023-10-03 10:34:425425
5426class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425427
Daniel Cheng566634ff2024-06-29 14:56:535428 def testError(self):
5429 """Test patch adding dangling pointers are reported"""
5430 mock_input_api = MockInputApi()
5431 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425432
Daniel Cheng566634ff2024-06-29 14:56:535433 mock_input_api.change.DescriptionText = lambda: "description"
5434 mock_input_api.files = [
5435 MockAffectedFile(
5436 local_path="foo/foo.cc",
5437 old_contents=["raw_ptr<T>"],
5438 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5439 )
5440 ]
5441 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5442 mock_output_api)
5443 self.assertEqual(len(msgs), 1)
5444 self.assertTrue(
5445 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5446 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425447
Daniel Cheng566634ff2024-06-29 14:56:535448 def testNonCppFile(self):
5449 """Test patch adding dangling pointers are not reported in non C++ files"""
5450 mock_input_api = MockInputApi()
5451 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425452
Daniel Cheng566634ff2024-06-29 14:56:535453 mock_input_api.change.DescriptionText = lambda: "description"
5454 mock_input_api.files = [
5455 MockAffectedFile(
5456 local_path="foo/README.md",
5457 old_contents=[""],
5458 new_contents=["The DanglingUntriaged annotation means"],
5459 )
5460 ]
5461 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5462 mock_output_api)
5463 self.assertEqual(len(msgs), 0)
5464
5465 def testDeveloperAcknowledgeInCommitDescription(self):
5466 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425467 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535468 mock_input_api = MockInputApi()
5469 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425470
Daniel Cheng566634ff2024-06-29 14:56:535471 mock_input_api.files = [
5472 MockAffectedFile(
5473 local_path="foo/foo.cc",
5474 old_contents=["raw_ptr<T>"],
5475 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5476 )
5477 ]
5478 mock_input_api.change.DescriptionText = lambda: (
5479 "DanglingUntriaged-notes: Sorry about this!")
5480 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5481 mock_output_api)
5482 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425483
Daniel Cheng566634ff2024-06-29 14:56:535484 def testDeveloperAcknowledgeInCommitFooter(self):
5485 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425486 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535487 mock_input_api = MockInputApi()
5488 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425489
Daniel Cheng566634ff2024-06-29 14:56:535490 mock_input_api.files = [
5491 MockAffectedFile(
5492 local_path="foo/foo.cc",
5493 old_contents=["raw_ptr<T>"],
5494 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5495 )
5496 ]
5497 mock_input_api.change.DescriptionText = lambda: "description"
5498 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5499 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5500 mock_output_api)
5501 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425502
Daniel Cheng566634ff2024-06-29 14:56:535503 def testCongrats(self):
5504 """Test the presubmit congrats users removing dangling pointers"""
5505 mock_input_api = MockInputApi()
5506 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425507
Daniel Cheng566634ff2024-06-29 14:56:535508 mock_input_api.files = [
5509 MockAffectedFile(
5510 local_path="foo/foo.cc",
5511 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5512 new_contents=["raw_ptr<T>"],
5513 )
5514 ]
5515 mock_input_api.change.DescriptionText = lambda: (
5516 "This patch fixes some DanglingUntriaged pointers!")
5517 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5518 mock_output_api)
5519 self.assertEqual(len(msgs), 1)
5520 self.assertTrue(
5521 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5522 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425523
Daniel Cheng566634ff2024-06-29 14:56:535524 def testRenameFile(self):
5525 """Patch that we do not warn about DanglingUntriaged when moving files"""
5526 mock_input_api = MockInputApi()
5527 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425528
Daniel Cheng566634ff2024-06-29 14:56:535529 mock_input_api.files = [
5530 MockAffectedFile(
5531 local_path="foo/foo.cc",
5532 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5533 new_contents=[""],
5534 action="D",
5535 ),
5536 MockAffectedFile(
5537 local_path="foo/foo.cc",
5538 old_contents=[""],
5539 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5540 action="A",
5541 ),
5542 ]
5543 mock_input_api.change.DescriptionText = lambda: (
5544 "This patch moves files")
5545 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5546 mock_output_api)
5547 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425548
Jan Keitel77be7522023-10-12 20:40:495549class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495550
Daniel Cheng566634ff2024-06-29 14:56:535551 def testNoInlineConstexprInHeaderFile(self):
5552 """Tests that non-inlined constexpr variables in headers fail the test."""
5553 input_api = MockInputApi()
5554 input_api.files = [
5555 MockAffectedFile('src/constants.h',
5556 ['constexpr int kVersion = 5;'])
5557 ]
5558 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5559 input_api, MockOutputApi())
5560 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495561
Daniel Cheng566634ff2024-06-29 14:56:535562 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5563 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5564 input_api = MockInputApi()
5565 input_api.files = [
5566 MockAffectedFile('src/constants.h',
5567 ['constexpr int kVersion = GetVersion();'])
5568 ]
5569 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5570 input_api, MockOutputApi())
5571 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495572
Daniel Cheng566634ff2024-06-29 14:56:535573 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5574 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5575 input_api = MockInputApi()
5576 input_api.files = [
5577 MockAffectedFile('src/constants.h',
5578 ['constexpr int kVersion = (4 + 5)*3;'])
5579 ]
5580 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5581 input_api, MockOutputApi())
5582 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495583
Daniel Cheng566634ff2024-06-29 14:56:535584 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5585 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5586 input_api = MockInputApi()
5587 input_api.files = [
5588 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5589 ]
5590 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5591 input_api, MockOutputApi())
5592 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495593
Daniel Cheng566634ff2024-06-29 14:56:535594 def testNoInlineConstexprInHeaderWithAttribute(self):
5595 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5596 input_api = MockInputApi()
5597 input_api.files = [
5598 MockAffectedFile('src/constants.h',
5599 ['constexpr [[maybe_unused]] int kVersion{5};'])
5600 ]
5601 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5602 input_api, MockOutputApi())
5603 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495604
Daniel Cheng566634ff2024-06-29 14:56:535605 def testInlineConstexprInHeaderWithAttribute(self):
5606 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5607 input_api = MockInputApi()
5608 input_api.files = [
5609 MockAffectedFile(
5610 'src/constants.h',
5611 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5612 MockAffectedFile(
5613 'src/constants.h',
5614 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5615 MockAffectedFile(
5616 'src/constants.h',
5617 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5618 ]
5619 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5620 input_api, MockOutputApi())
5621 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495622
Daniel Cheng566634ff2024-06-29 14:56:535623 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5624 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5625 input_api = MockInputApi()
5626 lines = [
5627 'constexpr char kLongName =',
5628 ' "This is a very long name of something.";'
5629 ]
5630 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5631 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5632 input_api, MockOutputApi())
5633 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495634
Daniel Cheng566634ff2024-06-29 14:56:535635 def testNoInlineConstexprInCCFile(self):
5636 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5637 input_api = MockInputApi()
5638 input_api.files = [
5639 MockAffectedFile('src/implementation.cc',
5640 ['constexpr int kVersion = 5;'])
5641 ]
5642 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5643 input_api, MockOutputApi())
5644 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495645
Daniel Cheng566634ff2024-06-29 14:56:535646 def testInlineConstexprInHeaderFile(self):
5647 """Tests that inlined constexpr variables in header files pass the test."""
5648 input_api = MockInputApi()
5649 input_api.files = [
5650 MockAffectedFile('src/constants.h',
5651 ['constexpr inline int kX = 5;']),
5652 MockAffectedFile('src/version.h',
5653 ['inline constexpr float kY = 5.0f;'])
5654 ]
5655 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5656 input_api, MockOutputApi())
5657 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495658
Daniel Cheng566634ff2024-06-29 14:56:535659 def testConstexprStandaloneFunctionInHeaderFile(self):
5660 """Tests that non-inlined constexpr functions in headers pass the test."""
5661 input_api = MockInputApi()
5662 input_api.files = [
5663 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5664 ]
5665 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5666 input_api, MockOutputApi())
5667 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495668
Daniel Cheng566634ff2024-06-29 14:56:535669 def testConstexprWithAbseilAttributeInHeader(self):
5670 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5671 input_api = MockInputApi()
5672 input_api.files = [
5673 MockAffectedFile('src/helpers.h',
5674 ['ABSL_FOOFOO constexpr int i = 5;'])
5675 ]
5676 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5677 input_api, MockOutputApi())
5678 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495679
Daniel Cheng566634ff2024-06-29 14:56:535680 def testInlineConstexprWithAbseilAttributeInHeader(self):
5681 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5682 input_api = MockInputApi()
5683 input_api.files = [
5684 MockAffectedFile('src/helpers.h',
5685 ['constexpr ABSL_FOO inline int i = 5;'])
5686 ]
5687 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5688 input_api, MockOutputApi())
5689 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495690
Daniel Cheng566634ff2024-06-29 14:56:535691 def testConstexprWithClangAttributeInHeader(self):
5692 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5693 input_api = MockInputApi()
5694 input_api.files = [
5695 MockAffectedFile('src/helpers.h',
5696 ['[[clang::someattribute]] constexpr int i = 5;'])
5697 ]
5698 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5699 input_api, MockOutputApi())
5700 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495701
Daniel Cheng566634ff2024-06-29 14:56:535702 def testInlineConstexprWithClangAttributeInHeader(self):
5703 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5704 input_api = MockInputApi()
5705 input_api.files = [
5706 MockAffectedFile(
5707 'src/helpers.h',
5708 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5709 ]
5710 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5711 input_api, MockOutputApi())
5712 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425713
Daniel Cheng566634ff2024-06-29 14:56:535714 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5715 """Tests that non-inlined constexpr class members pass the test."""
5716 input_api = MockInputApi()
5717 lines = [
5718 'class SomeClass {', ' public:',
5719 ' static constexpr kVersion = 5;', '};'
5720 ]
5721 input_api.files = [MockAffectedFile('src/class.h', lines)]
5722 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5723 input_api, MockOutputApi())
5724 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045725
Daniel Cheng566634ff2024-06-29 14:56:535726 def testTodoBugReferencesWithOldBugId(self):
5727 """Tests that an old monorail bug ID in a TODO fails."""
5728 input_api = MockInputApi()
5729 input_api.files = [
5730 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5731 ]
5732 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5733 self.assertEqual(1, len(warnings))
5734
5735 def testTodoBugReferencesWithUpdatedBugId(self):
5736 """Tests that a new issue tracker bug ID in a TODO passes."""
5737 input_api = MockInputApi()
5738 input_api.files = [
5739 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5740 ]
5741 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5742 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045743
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155744class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535745 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155746
Daniel Cheng566634ff2024-06-29 14:56:535747 def testCppMobilePlatformPath(self):
5748 input_api = MockInputApi()
5749 input_api.files = [
5750 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5751 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5752 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5753 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5754 MockFile('components/foo/delegate_android.cc',
5755 ['IsSyncFeatureActive']),
5756 MockFile('components/foo/delegate_ios.cc',
5757 ['IsSyncFeatureActive']),
5758 MockFile('components/foo/android_delegate.cc',
5759 ['IsSyncFeatureActive']),
5760 MockFile('components/foo/ios_delegate.cc',
5761 ['IsSyncFeatureActive']),
5762 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155763
Daniel Cheng566634ff2024-06-29 14:56:535764 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155765
Ben Pastenee79d66112025-04-23 19:46:155766 self.assertEqual(7, len(results))
5767 self.assertTrue(all('chrome/browser/android/file.cc' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535768 self.assertTrue('chrome/android/file.cc' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155769 self.assertTrue('ios/file.mm' in results[1].message),
5770 self.assertTrue('components/foo/ios/file.cc' in results[2].message),
Daniel Cheng566634ff2024-06-29 14:56:535771 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155772 'components/foo/delegate_android.cc' in results[3].message),
Daniel Cheng566634ff2024-06-29 14:56:535773 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155774 'components/foo/delegate_ios.cc' in results[4].message),
Daniel Cheng566634ff2024-06-29 14:56:535775 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155776 'components/foo/android_delegate.cc' in results[5].message),
Daniel Cheng566634ff2024-06-29 14:56:535777 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155778 'components/foo/ios_delegate.cc' in results[6].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155779
Daniel Cheng566634ff2024-06-29 14:56:535780 def testCppNonMobilePlatformPath(self):
5781 input_api = MockInputApi()
5782 input_api.files = [
5783 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5784 MockFile('bios/file.cc', ['HasSyncConsent']),
5785 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5786 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155787
Daniel Cheng566634ff2024-06-29 14:56:535788 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155789
Daniel Cheng566634ff2024-06-29 14:56:535790 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155791
Daniel Cheng566634ff2024-06-29 14:56:535792 def testJavaPath(self):
5793 input_api = MockInputApi()
5794 input_api.files = [
5795 MockFile('components/foo/file1.java', ['otherFunction']),
5796 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5797 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5798 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5799 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5800 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155801
Daniel Cheng566634ff2024-06-29 14:56:535802 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155803
Ben Pastenee79d66112025-04-23 19:46:155804 self.assertEqual(4, len(results))
5805 self.assertTrue(all('components/foo/file1.java' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535806 self.assertTrue('components/foo/file2.java' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155807 self.assertTrue('chrome/foo/file3.java' in results[1].message),
5808 self.assertTrue('chrome/foo/file4.java' in results[2].message),
5809 self.assertTrue('chrome/foo/file5.java' in results[3].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155810
5811
Erik Chen1396bbe2025-01-27 23:39:365812class CheckAnonymousNamespaceTest(unittest.TestCase):
5813 """Test the presubmit for anonymous namespaces."""
5814
5815 def testAnonymousNamespace(self):
5816 input_api = MockInputApi()
5817 input_api.files = [
5818 MockFile('chrome/test.h', ['namespace {']),
5819 MockFile('chrome/test.cc', ['namespace {']),
5820 MockFile('chrome/test.java', ['namespace {']),
5821 MockFile('chrome/test.cpp', ['namespace {']),
5822 MockFile('chrome/test.txt', ['namespace {']),
5823 ]
5824
5825 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
5826
5827 self.assertEqual(1, len(results))
5828 self.assertTrue(
5829 'chrome/test.h' in results[0].message),
5830 self.assertFalse(
5831 'chrome/test.cc' in results[0].message),
5832 self.assertFalse(
5833 'chrome/test.java' in results[0].message),
5834 self.assertFalse(
5835 'chrome/test.cpp' in results[0].message),
5836 self.assertFalse(
5837 'chrome/test.txt' in results[0].message),
5838
5839
marja@chromium.org2299dcf2012-11-15 19:56:245840if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535841 unittest.main()