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

blob: 9ada4b69903d8c163f1884764e9f85733d0daa1b [file] [log] [blame]
Andrew Grieve3f9b9662022-02-02 19:07:551#!/usr/bin/env python3
Avi Drissman24976592022-09-12 15:24:312# Copyright 2012 The Chromium Authors
[email protected]2299dcf2012-11-15 19:56:243# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Andrew Grieve4deedb12022-02-03 21:34:506import io
Daniel Cheng4dcdb6b2017-04-13 08:30:177import os.path
[email protected]99171a92014-06-03 08:44:478import subprocess
Min Qinbc44383c2023-02-22 17:25:269import textwrap
[email protected]2299dcf2012-11-15 19:56:2410import unittest
11
12import PRESUBMIT
Saagar Sanghavifceeaae2020-08-12 16:40:3613
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3914from PRESUBMIT_test_mocks import MockFile, MockAffectedFile
gayane3dff8c22014-12-04 17:09:5115from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
[email protected]2299dcf2012-11-15 19:56:2416
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3917
[email protected]99171a92014-06-03 08:44:4718_TEST_DATA_DIR = 'base/test/data/presubmit'
19
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3920
[email protected]b00342e7f2013-03-26 16:21:5421class VersionControlConflictsTest(unittest.TestCase):
[email protected]70ca77752012-11-20 03:45:0322
Daniel Cheng566634ff2024-06-29 14:56:5323 def testTypicalConflict(self):
24 lines = [
25 '<<<<<<< HEAD', ' base::ScopedTempDir temp_dir_;', '=======',
26 ' ScopedTempDir temp_dir_;', '>>>>>>> master'
27 ]
28 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
29 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
30 self.assertEqual(3, len(errors))
31 self.assertTrue('1' in errors[0])
32 self.assertTrue('3' in errors[1])
33 self.assertTrue('5' in errors[2])
34
35 def testIgnoresReadmes(self):
36 lines = [
37 'A First Level Header', '====================', '',
38 'A Second Level Header', '---------------------'
39 ]
40 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
41 MockInputApi(), MockFile('some/polymer/README.md', lines))
42 self.assertEqual(0, len(errors))
dbeam95c35a2f2015-06-02 01:40:2343
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3944
[email protected]b8079ae4a2012-12-05 19:56:4945class BadExtensionsTest(unittest.TestCase):
[email protected]b8079ae4a2012-12-05 19:56:4946
Daniel Cheng566634ff2024-06-29 14:56:5347 def testBadRejFile(self):
48 mock_input_api = MockInputApi()
49 mock_input_api.files = [
50 MockFile('some/path/foo.cc', ''),
51 MockFile('some/path/foo.cc.rej', ''),
52 MockFile('some/path2/bar.h.rej', ''),
53 ]
[email protected]b8079ae4a2012-12-05 19:56:4954
Daniel Cheng566634ff2024-06-29 14:56:5355 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
56 self.assertEqual(1, len(results))
57 self.assertEqual(2, len(results[0].items))
58 self.assertTrue('foo.cc.rej' in results[0].items[0])
59 self.assertTrue('bar.h.rej' in results[0].items[1])
[email protected]b8079ae4a2012-12-05 19:56:4960
Daniel Cheng566634ff2024-06-29 14:56:5361 def testBadOrigFile(self):
62 mock_input_api = MockInputApi()
63 mock_input_api.files = [
64 MockFile('other/path/qux.h.orig', ''),
65 MockFile('other/path/qux.h', ''),
66 MockFile('other/path/qux.cc', ''),
67 ]
[email protected]b8079ae4a2012-12-05 19:56:4968
Daniel Cheng566634ff2024-06-29 14:56:5369 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
70 self.assertEqual(1, len(results))
71 self.assertEqual(1, len(results[0].items))
72 self.assertTrue('qux.h.orig' in results[0].items[0])
73
74 def testGoodFiles(self):
75 mock_input_api = MockInputApi()
76 mock_input_api.files = [
77 MockFile('other/path/qux.h', ''),
78 MockFile('other/path/qux.cc', ''),
79 ]
80 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
81 self.assertEqual(0, len(results))
[email protected]b8079ae4a2012-12-05 19:56:4982
83
Lei Zhang1c12a22f2021-05-12 11:28:4584class CheckForSuperfluousStlIncludesInHeadersTest(unittest.TestCase):
Lei Zhang1c12a22f2021-05-12 11:28:4585
Daniel Cheng566634ff2024-06-29 14:56:5386 def testGoodFiles(self):
87 mock_input_api = MockInputApi()
88 mock_input_api.files = [
89 # The check is not smart enough to figure out which definitions correspond
90 # to which header.
91 MockFile('other/path/foo.h', ['#include <string>', 'std::vector']),
92 # The check is not smart enough to do IWYU.
93 MockFile('other/path/bar.h',
94 ['#include "base/check.h"', 'std::vector']),
95 MockFile('other/path/qux.h',
96 ['#include "base/stl_util.h"', 'foobar']),
97 MockFile('other/path/baz.h',
98 ['#include "set/vector.h"', 'bazzab']),
99 # The check is only for header files.
100 MockFile('other/path/not_checked.cc',
101 ['#include <vector>', 'bazbaz']),
102 ]
103 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
104 mock_input_api, MockOutputApi())
105 self.assertEqual(0, len(results))
106
107 def testBadFiles(self):
108 mock_input_api = MockInputApi()
109 mock_input_api.files = [
110 MockFile('other/path/foo.h', ['#include <vector>', 'vector']),
111 MockFile(
112 'other/path/bar.h',
113 ['#include <limits>', '#include <set>', 'no_std_namespace']),
114 ]
115 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
116 mock_input_api, MockOutputApi())
117 self.assertEqual(1, len(results))
118 self.assertTrue('foo.h: Includes STL' in results[0].message)
119 self.assertTrue('bar.h: Includes STL' in results[0].message)
Lei Zhang1c12a22f2021-05-12 11:28:45120
121
glidere61efad2015-02-18 17:39:43122class CheckSingletonInHeadersTest(unittest.TestCase):
glidere61efad2015-02-18 17:39:43123
Daniel Cheng566634ff2024-06-29 14:56:53124 def testSingletonInArbitraryHeader(self):
125 diff_singleton_h = [
126 'base::subtle::AtomicWord '
127 'base::Singleton<Type, Traits, DifferentiatingType>::'
128 ]
129 diff_foo_h = [
130 '// base::Singleton<Foo> in comment.',
131 'friend class base::Singleton<Foo>'
132 ]
133 diff_foo2_h = [' //Foo* bar = base::Singleton<Foo>::get();']
134 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
135 mock_input_api = MockInputApi()
136 mock_input_api.files = [
137 MockAffectedFile('base/memory/singleton.h', diff_singleton_h),
138 MockAffectedFile('foo.h', diff_foo_h),
139 MockAffectedFile('foo2.h', diff_foo2_h),
140 MockAffectedFile('bad.h', diff_bad_h)
141 ]
142 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
143 MockOutputApi())
144 self.assertEqual(1, len(warnings))
145 self.assertEqual(1, len(warnings[0].items))
146 self.assertEqual('error', warnings[0].type)
147 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
148
149 def testSingletonInCC(self):
150 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
151 mock_input_api = MockInputApi()
152 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
153 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
154 MockOutputApi())
155 self.assertEqual(0, len(warnings))
glidere61efad2015-02-18 17:39:43156
157
Xiaohan Wang42d96c22022-01-20 17:23:11158class DeprecatedOSMacroNamesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:53159
160 def testDeprecatedOSMacroNames(self):
161 lines = [
162 '#if defined(OS_WIN)', ' #elif defined(OS_WINDOW)',
163 ' # if defined(OS_MAC) || defined(OS_CHROME)'
164 ]
165 errors = PRESUBMIT._CheckForDeprecatedOSMacrosInFile(
166 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
167 self.assertEqual(len(lines) + 1, len(errors))
168 self.assertTrue(
169 ':1: defined(OS_WIN) -> BUILDFLAG(IS_WIN)' in errors[0])
[email protected]b00342e7f2013-03-26 16:21:54170
171
lliabraa35bab3932014-10-01 12:16:44172class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
lliabraa35bab3932014-10-01 12:16:44173
Daniel Cheng566634ff2024-06-29 14:56:53174 def testInvalidIfDefinedMacroNames(self):
175 lines = [
176 '#if defined(TARGET_IPHONE_SIMULATOR)',
177 '#if !defined(TARGET_IPHONE_SIMULATOR)',
178 '#elif defined(TARGET_IPHONE_SIMULATOR)',
179 '#ifdef TARGET_IPHONE_SIMULATOR',
180 ' # ifdef TARGET_IPHONE_SIMULATOR',
181 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
182 '# else // defined(TARGET_IPHONE_SIMULATOR)',
183 '#endif // defined(TARGET_IPHONE_SIMULATOR)'
184 ]
185 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
186 MockInputApi(), MockFile('some/path/source.mm', lines))
187 self.assertEqual(len(lines), len(errors))
188
189 def testValidIfDefinedMacroNames(self):
190 lines = [
191 '#if defined(FOO)', '#ifdef BAR', '#if TARGET_IPHONE_SIMULATOR'
192 ]
193 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
194 MockInputApi(), MockFile('some/path/source.cc', lines))
195 self.assertEqual(0, len(errors))
lliabraa35bab3932014-10-01 12:16:44196
197
Andrew Williamsc9f69b482023-07-10 16:07:36198class CheckNoUNIT_TESTInSourceFilesTest(unittest.TestCase):
Andrew Williamsc9f69b482023-07-10 16:07:36199
Daniel Cheng566634ff2024-06-29 14:56:53200 def testUnitTestMacros(self):
201 lines = [
202 '#if defined(UNIT_TEST)', '#if defined UNIT_TEST',
203 '#if !defined(UNIT_TEST)', '#elif defined(UNIT_TEST)',
204 '#ifdef UNIT_TEST', ' # ifdef UNIT_TEST', '#ifndef UNIT_TEST',
205 '# if defined(VALID) || defined(UNIT_TEST)',
206 '# if defined(UNIT_TEST) && defined(VALID)',
207 '# else // defined(UNIT_TEST)', '#endif // defined(UNIT_TEST)'
208 ]
209 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
210 MockInputApi(), MockFile('some/path/source.cc', lines))
211 self.assertEqual(len(lines), len(errors))
212
213 def testNotUnitTestMacros(self):
214 lines = [
215 '// Comment about "#if defined(UNIT_TEST)"',
216 '/* Comment about #if defined(UNIT_TEST)" */',
217 '#ifndef UNIT_TEST_H', '#define UNIT_TEST_H',
218 '#ifndef TEST_UNIT_TEST', '#define TEST_UNIT_TEST',
219 '#if defined(_UNIT_TEST)', '#if defined(UNIT_TEST_)',
220 '#ifdef _UNIT_TEST', '#ifdef UNIT_TEST_', '#ifndef _UNIT_TEST',
221 '#ifndef UNIT_TEST_'
222 ]
223 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
224 MockInputApi(), MockFile('some/path/source.cc', lines))
225 self.assertEqual(0, len(errors))
Andrew Williamsc9f69b482023-07-10 16:07:36226
Rasika Navarangec2d33d22024-05-23 15:19:02227
228class CheckEachPerfettoTestDataFileHasDepsEntry(unittest.TestCase):
229
Daniel Cheng566634ff2024-06-29 14:56:53230 def testNewSha256FileNoDEPS(self):
231 input_api = MockInputApi()
232 input_api.files = [
233 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', []),
234 ]
235 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
236 input_api, MockOutputApi())
237 self.assertEqual(
238 ('You must update the DEPS file when you update a .sha256 file '
239 'in base/tracing/test/data_sha256'), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02240
Daniel Cheng566634ff2024-06-29 14:56:53241 def testNewSha256FileSuccess(self):
242 input_api = MockInputApi()
243 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02244 'src/base/tracing/test/data': {
245 'bucket': 'perfetto',
246 'objects': [
247 {
248 'object_name': 'test_data/new.pftrace-a1b2c3f4',
249 'sha256sum': 'a1b2c3f4',
250 'size_bytes': 1,
251 'generation': 1,
252 'output_file': 'new.pftrace'
253 },
254 ],
255 'dep_type': 'gcs'
256 },
257 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53258 input_api.files = [
259 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
260 ['a1b2c3f4']),
261 MockFile('DEPS', new_deps,
262 ["deps={'src/base/tracing/test/data':{}}"]),
263 ]
264 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
265 input_api, MockOutputApi())
266 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02267
Daniel Cheng566634ff2024-06-29 14:56:53268 def testNewSha256FileWrongSha256(self):
269 input_api = MockInputApi()
270 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02271 'src/base/tracing/test/data': {
272 'bucket': 'perfetto',
273 'objects': [
274 {
275 'object_name': 'test_data/new.pftrace-a1b2c3f4',
276 'sha256sum': 'wrong_hash',
277 'size_bytes': 1,
278 'generation': 1,
279 'output_file': 'new.pftrace'
280 },
281 ],
282 'dep_type': 'gcs'
283 },
284 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53285 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
286 ['a1b2c3f4'])
287 input_api.files = [
288 f,
289 MockFile('DEPS', new_deps,
290 ["deps={'src/base/tracing/test/data':{}}"]),
291 ]
292 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
293 input_api, MockOutputApi())
294 self.assertEqual(
295 ('No corresponding DEPS entry found for %s. '
296 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
297 'to generate the DEPS entry.' % (f.LocalPath(), f.LocalPath())),
298 results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02299
Daniel Cheng566634ff2024-06-29 14:56:53300 def testDeleteSha256File(self):
301 input_api = MockInputApi()
302 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02303 'src/base/tracing/test/data': {
304 'bucket': 'perfetto',
305 'objects': [
306 {
307 'object_name': 'test_data/new.pftrace-a1b2c3f4',
308 'sha256sum': 'a1b2c3f4',
309 'size_bytes': 1,
310 'generation': 1,
311 'output_file': 'new.pftrace'
312 },
313 ],
314 'dep_type': 'gcs'
315 },
316 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53317 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
318 ['a1b2c3f4'],
319 action='D')
320 input_api.files = [
321 f,
322 MockFile('DEPS', old_deps, old_deps),
323 ]
324 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
325 input_api, MockOutputApi())
326 self.assertEqual((
327 'You deleted %s so you must also remove the corresponding DEPS entry.'
328 % f.LocalPath()), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02329
Daniel Cheng566634ff2024-06-29 14:56:53330 def testDeleteSha256Success(self):
331 input_api = MockInputApi()
332 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02333 'src/base/tracing/test/data': {
334 'bucket': 'perfetto',
335 'objects': [],
336 'dep_type': 'gcs'
337 },
338 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53339 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02340 'src/base/tracing/test/data': {
341 'bucket': 'perfetto',
342 'objects': [
343 {
344 'object_name': 'test_data/new.pftrace-a1b2c3f4',
345 'sha256sum': 'a1b2c3f4',
346 'size_bytes': 1,
347 'generation': 1,
348 'output_file': 'new.pftrace'
349 },
350 ],
351 'dep_type': 'gcs'
352 },
353 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53354 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
355 ['a1b2c3f4'],
356 action='D')
357 input_api.files = [
358 f,
359 MockFile('DEPS', new_deps, old_deps),
360 ]
361 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
362 input_api, MockOutputApi())
363 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02364
365
Samuel Huang0db2ea22019-12-09 16:42:47366class CheckAddedDepsHaveTestApprovalsTest(unittest.TestCase):
Daniel Cheng4dcdb6b2017-04-13 08:30:17367
Andrew Grieve713b89b2024-10-15 20:20:08368 def setUp(self):
369 self.input_api = input_api = MockInputApi()
370 input_api.environ = {}
371 input_api.owners_client = self.FakeOwnersClient()
372 input_api.gerrit = self.fakeGerrit()
373 input_api.change.issue = 123
374 self.mockOwnersAndReviewers("owner", set(["reviewer"]))
375 self.mockListSubmodules([])
376
Daniel Cheng566634ff2024-06-29 14:56:53377 def calculate(self, old_include_rules, old_specific_include_rules,
378 new_include_rules, new_specific_include_rules):
379 return PRESUBMIT._CalculateAddedDeps(
380 os.path, 'include_rules = %r\nspecific_include_rules = %r' %
381 (old_include_rules, old_specific_include_rules),
382 'include_rules = %r\nspecific_include_rules = %r' %
383 (new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17384
Daniel Cheng566634ff2024-06-29 14:56:53385 def testCalculateAddedDeps(self):
386 old_include_rules = [
387 '+base',
388 '-chrome',
389 '+content',
390 '-grit',
391 '-grit/",',
392 '+jni/fooblat.h',
393 '!sandbox',
394 ]
395 old_specific_include_rules = {
Justin Lulejiana2fc7882025-04-01 18:34:47396 r'compositor\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53397 '+cc',
398 },
399 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17400
Daniel Cheng566634ff2024-06-29 14:56:53401 new_include_rules = [
402 '-ash',
403 '+base',
404 '+chrome',
405 '+components',
406 '+content',
407 '+grit',
408 '+grit/generated_resources.h",',
409 '+grit/",',
410 '+jni/fooblat.h',
411 '+policy',
412 '+' + os.path.join('third_party', 'WebKit'),
413 ]
414 new_specific_include_rules = {
Justin Lulejiana2fc7882025-04-01 18:34:47415 r'compositor\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53416 '+cc',
417 },
Justin Lulejiana2fc7882025-04-01 18:34:47418 r'widget\.*': {
Daniel Cheng566634ff2024-06-29 14:56:53419 '+gpu',
420 },
421 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17422
Daniel Cheng566634ff2024-06-29 14:56:53423 expected = set([
424 os.path.join('chrome', 'DEPS'),
425 os.path.join('gpu', 'DEPS'),
426 os.path.join('components', 'DEPS'),
427 os.path.join('policy', 'DEPS'),
428 os.path.join('third_party', 'WebKit', 'DEPS'),
429 ])
430 self.assertEqual(
431 expected,
432 self.calculate(old_include_rules, old_specific_include_rules,
433 new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17434
Daniel Cheng566634ff2024-06-29 14:56:53435 def testCalculateAddedDepsIgnoresPermutations(self):
436 old_include_rules = [
437 '+base',
438 '+chrome',
439 ]
440 new_include_rules = [
441 '+chrome',
442 '+base',
443 ]
444 self.assertEqual(
445 set(), self.calculate(old_include_rules, {}, new_include_rules,
446 {}))
[email protected]f32e2d1e2013-07-26 21:39:08447
Andrew Grieveb77ac76d2024-11-29 15:01:48448 def testFindAddedDepsThatRequireReview(self):
449 caring = ['new_usages_require_review = True']
450 self.input_api.InitFiles([
451 MockAffectedFile('cares/DEPS', caring),
452 MockAffectedFile('cares/inherits/DEPS', []),
453 MockAffectedFile('willynilly/DEPS', []),
454 MockAffectedFile('willynilly/butactually/DEPS', caring),
455 ])
456
457 expected = {
458 'cares': True,
459 'cares/sub/sub': True,
460 'cares/inherits': True,
461 'cares/inherits/sub': True,
462 'willynilly': False,
463 'willynilly/butactually': True,
464 'willynilly/butactually/sub': True,
465 }
466 results = PRESUBMIT._FindAddedDepsThatRequireReview(
467 self.input_api, set(expected))
468 actual = {k: k in results for k in expected}
469 self.assertEqual(expected, actual)
470
Daniel Cheng566634ff2024-06-29 14:56:53471 class FakeOwnersClient(object):
472 APPROVED = "APPROVED"
473 PENDING = "PENDING"
474 returns = {}
Scott Leebf6a0942024-06-26 22:59:39475
Daniel Cheng566634ff2024-06-29 14:56:53476 def ListOwners(self, *args, **kwargs):
477 return self.returns.get(self.ListOwners.__name__, "")
Scott Leebf6a0942024-06-26 22:59:39478
Daniel Cheng566634ff2024-06-29 14:56:53479 def mockListOwners(self, owners):
480 self.returns[self.ListOwners.__name__] = owners
Scott Leebf6a0942024-06-26 22:59:39481
Daniel Cheng566634ff2024-06-29 14:56:53482 def GetFilesApprovalStatus(self, *args, **kwargs):
483 return self.returns.get(self.GetFilesApprovalStatus.__name__, {})
Scott Leebf6a0942024-06-26 22:59:39484
Daniel Cheng566634ff2024-06-29 14:56:53485 def mockGetFilesApprovalStatus(self, status):
486 self.returns[self.GetFilesApprovalStatus.__name__] = status
Scott Leebf6a0942024-06-26 22:59:39487
Daniel Cheng566634ff2024-06-29 14:56:53488 def SuggestOwners(self, *args, **kwargs):
489 return ["eng1", "eng2", "eng3"]
Scott Leebf6a0942024-06-26 22:59:39490
Daniel Cheng566634ff2024-06-29 14:56:53491 class fakeGerrit(object):
Scott Leebf6a0942024-06-26 22:59:39492
Daniel Cheng566634ff2024-06-29 14:56:53493 def IsOwnersOverrideApproved(self, issue):
494 return False
Scott Leebf6a0942024-06-26 22:59:39495
Daniel Cheng566634ff2024-06-29 14:56:53496 def mockOwnersAndReviewers(self, owner, reviewers):
Scott Leebf6a0942024-06-26 22:59:39497
Daniel Cheng566634ff2024-06-29 14:56:53498 def mock(*args, **kwargs):
499 return [owner, reviewers]
Scott Leebf6a0942024-06-26 22:59:39500
Daniel Cheng566634ff2024-06-29 14:56:53501 self.input_api.canned_checks.GetCodereviewOwnerAndReviewers = mock
Scott Leebf6a0942024-06-26 22:59:39502
Daniel Cheng566634ff2024-06-29 14:56:53503 def mockListSubmodules(self, paths):
Scott Leebf6a0942024-06-26 22:59:39504
Daniel Cheng566634ff2024-06-29 14:56:53505 def mock(*args, **kwargs):
506 return paths
Scott Leebf6a0942024-06-26 22:59:39507
Daniel Cheng566634ff2024-06-29 14:56:53508 self.input_api.ListSubmodules = mock
509
510 def testApprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08511 self.input_api.InitFiles([
Joanna Wang130e7bdd2024-12-10 17:39:03512 MockAffectedFile('pdf/DEPS',
513 ['include_rules=["+v8/123", "+foo/bar"]']),
Andrew Grieveb77ac76d2024-11-29 15:01:48514 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Joanna Wang130e7bdd2024-12-10 17:39:03515 # Check that we ignore "DEPS" directories. Note there are real cases
516 # of directories named "deps/" and, especially for case-insensitive file
517 # systems we should prevent these from being considered.
518 MockAffectedFile('foo/bar/DEPS/boofar', ['boofar file contents']),
Andrew Grieve713b89b2024-10-15 20:20:08519 ])
Daniel Cheng566634ff2024-06-29 14:56:53520
521 # mark the additional dep as approved.
522 os_path = self.input_api.os_path
523 self.input_api.owners_client.mockGetFilesApprovalStatus(
524 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.APPROVED})
525 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
526 self.input_api, MockOutputApi())
527 # Then, the check should pass.
528 self.assertEqual([], results)
529
530 def testUnapprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08531 self.input_api.InitFiles([
532 MockAffectedFile('pdf/DEPS', ['include_rules=["+v8/123"]']),
Andrew Grieveb77ac76d2024-11-29 15:01:48533 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Andrew Grieve713b89b2024-10-15 20:20:08534 ])
Daniel Cheng566634ff2024-06-29 14:56:53535
536 # pending.
537 os_path = self.input_api.os_path
538 self.input_api.owners_client.mockGetFilesApprovalStatus(
539 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.PENDING})
540 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
541 self.input_api, MockOutputApi())
542 # the check should fail
543 self.assertIn('You need LGTM', results[0].message)
544 self.assertIn('+v8/123', results[0].message)
545
546 # unless the added dep is from a submodule.
547 self.mockListSubmodules(['v8'])
548 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
549 self.input_api, MockOutputApi())
550 self.assertEqual([], results)
Scott Leebf6a0942024-06-26 22:59:39551
[email protected]f32e2d1e2013-07-26 21:39:08552
[email protected]99171a92014-06-03 08:44:47553class JSONParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47554
Daniel Cheng566634ff2024-06-29 14:56:53555 def testSuccess(self):
556 input_api = MockInputApi()
557 filename = 'valid_json.json'
558 contents = [
559 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
560 ' "key2": 3 // This is an inline comment.', '}'
561 ]
562 input_api.files = [MockFile(filename, contents)]
563 self.assertEqual(None,
564 PRESUBMIT._GetJSONParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47565
Daniel Cheng566634ff2024-06-29 14:56:53566 def testFailure(self):
567 input_api = MockInputApi()
568 test_data = [
569 ('invalid_json_1.json', ['{ x }'], 'Expecting property name'),
570 ('invalid_json_2.json', ['// Hello world!', '{ "hello": "world }'],
571 'Unterminated string starting at:'),
572 ('invalid_json_3.json', ['{ "a": "b", "c": "d", }'],
573 'Expecting property name'),
574 ('invalid_json_4.json', ['{ "a": "b" "c": "d" }'],
575 "Expecting ',' delimiter:"),
576 ]
[email protected]99171a92014-06-03 08:44:47577
Daniel Cheng566634ff2024-06-29 14:56:53578 input_api.files = [
579 MockFile(filename, contents)
580 for (filename, contents, _) in test_data
581 ]
[email protected]99171a92014-06-03 08:44:47582
Daniel Cheng566634ff2024-06-29 14:56:53583 for (filename, _, expected_error) in test_data:
584 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
585 self.assertTrue(
586 expected_error in str(actual_error),
587 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47588
Daniel Cheng566634ff2024-06-29 14:56:53589 def testNoEatComments(self):
590 input_api = MockInputApi()
591 file_with_comments = 'file_with_comments.json'
592 contents_with_comments = [
593 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
594 ' "key2": 3 // This is an inline comment.', '}'
595 ]
596 file_without_comments = 'file_without_comments.json'
597 contents_without_comments = [
598 '{', ' "key1": ["value1", "value2"],', ' "key2": 3', '}'
599 ]
600 input_api.files = [
601 MockFile(file_with_comments, contents_with_comments),
602 MockFile(file_without_comments, contents_without_comments)
603 ]
604
605 self.assertNotEqual(
606 None,
607 str(
608 PRESUBMIT._GetJSONParseError(input_api,
609 file_with_comments,
610 eat_comments=False)))
611 self.assertEqual(
612 None,
613 PRESUBMIT._GetJSONParseError(input_api,
614 file_without_comments,
615 eat_comments=False))
[email protected]99171a92014-06-03 08:44:47616
617
618class IDLParsingTest(unittest.TestCase):
[email protected]99171a92014-06-03 08:44:47619
Daniel Cheng566634ff2024-06-29 14:56:53620 def testSuccess(self):
621 input_api = MockInputApi()
622 filename = 'valid_idl_basics.idl'
623 contents = [
624 '// Tests a valid IDL file.', 'namespace idl_basics {',
625 ' enum EnumType {', ' name1,', ' name2', ' };', '',
626 ' dictionary MyType1 {', ' DOMString a;', ' };', '',
627 ' callback Callback1 = void();',
628 ' callback Callback2 = void(long x);',
629 ' callback Callback3 = void(MyType1 arg);',
630 ' callback Callback4 = void(EnumType type);', '',
631 ' interface Functions {', ' static void function1();',
632 ' static void function2(long x);',
633 ' static void function3(MyType1 arg);',
634 ' static void function4(Callback1 cb);',
635 ' static void function5(Callback2 cb);',
636 ' static void function6(Callback3 cb);',
637 ' static void function7(Callback4 cb);', ' };', '',
638 ' interface Events {', ' static void onFoo1();',
639 ' static void onFoo2(long x);',
640 ' static void onFoo2(MyType1 arg);',
641 ' static void onFoo3(EnumType type);', ' };', '};'
642 ]
643 input_api.files = [MockFile(filename, contents)]
644 self.assertEqual(None,
645 PRESUBMIT._GetIDLParseError(input_api, filename))
[email protected]99171a92014-06-03 08:44:47646
Daniel Cheng566634ff2024-06-29 14:56:53647 def testFailure(self):
648 input_api = MockInputApi()
649 test_data = [
650 ('invalid_idl_1.idl', [
651 '//', 'namespace test {', ' dictionary {', ' DOMString s;',
652 ' };', '};'
653 ], 'Unexpected "{" after keyword "dictionary".\n'),
654 # TODO(yoz): Disabled because it causes the IDL parser to hang.
655 # See crbug.com/363830.
656 # ('invalid_idl_2.idl',
657 # (['namespace test {',
658 # ' dictionary MissingSemicolon {',
659 # ' DOMString a',
660 # ' DOMString b;',
661 # ' };',
662 # '};'],
663 # 'Unexpected symbol DOMString after symbol a.'),
664 ('invalid_idl_3.idl', [
665 '//', 'namespace test {', ' enum MissingComma {', ' name1',
666 ' name2', ' };', '};'
667 ], 'Unexpected symbol name2 after symbol name1.'),
668 ('invalid_idl_4.idl', [
669 '//', 'namespace test {', ' enum TrailingComma {',
670 ' name1,', ' name2,', ' };', '};'
671 ], 'Trailing comma in block.'),
672 ('invalid_idl_5.idl',
673 ['//', 'namespace test {', ' callback Callback1 = void(;',
674 '};'], 'Unexpected ";" after "(".'),
675 ('invalid_idl_6.idl', [
676 '//', 'namespace test {',
677 ' callback Callback1 = void(long );', '};'
678 ], 'Unexpected ")" after symbol long.'),
679 ('invalid_idl_7.idl', [
680 '//', 'namespace test {', ' interace Events {',
681 ' static void onFoo1();', ' };', '};'
682 ], 'Unexpected symbol Events after symbol interace.'),
683 ('invalid_idl_8.idl', [
684 '//', 'namespace test {', ' interface NotEvent {',
685 ' static void onFoo1();', ' };', '};'
686 ], 'Did not process Interface Interface(NotEvent)'),
687 ('invalid_idl_9.idl', [
688 '//', 'namespace test {', ' interface {',
689 ' static void function1();', ' };', '};'
690 ], 'Interface missing name.'),
691 ]
[email protected]99171a92014-06-03 08:44:47692
Daniel Cheng566634ff2024-06-29 14:56:53693 input_api.files = [
694 MockFile(filename, contents)
695 for (filename, contents, _) in test_data
696 ]
697
698 for (filename, _, expected_error) in test_data:
699 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
700 self.assertTrue(
701 expected_error in str(actual_error),
702 "'%s' not found in '%s'" % (expected_error, actual_error))
[email protected]99171a92014-06-03 08:44:47703
704
davileene0426252015-03-02 21:10:41705class UserMetricsActionTest(unittest.TestCase):
davileene0426252015-03-02 21:10:41706
Daniel Cheng566634ff2024-06-29 14:56:53707 def testUserMetricsActionInActions(self):
708 input_api = MockInputApi()
709 file_with_user_action = 'file_with_user_action.cc'
710 contents_with_user_action = ['base::UserMetricsAction("AboutChrome")']
davileene0426252015-03-02 21:10:41711
Daniel Cheng566634ff2024-06-29 14:56:53712 input_api.files = [
713 MockFile(file_with_user_action, contents_with_user_action)
714 ]
davileene0426252015-03-02 21:10:41715
Daniel Cheng566634ff2024-06-29 14:56:53716 self.assertEqual([],
717 PRESUBMIT.CheckUserActionUpdate(
718 input_api, MockOutputApi()))
davileene0426252015-03-02 21:10:41719
Daniel Cheng566634ff2024-06-29 14:56:53720 def testUserMetricsActionNotAddedToActions(self):
721 input_api = MockInputApi()
722 file_with_user_action = 'file_with_user_action.cc'
723 contents_with_user_action = [
724 'base::UserMetricsAction("NotInActionsXml")'
725 ]
davileene0426252015-03-02 21:10:41726
Daniel Cheng566634ff2024-06-29 14:56:53727 input_api.files = [
728 MockFile(file_with_user_action, contents_with_user_action)
729 ]
davileene0426252015-03-02 21:10:41730
Daniel Cheng566634ff2024-06-29 14:56:53731 output = PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi())
732 self.assertEqual(
733 ('File %s line %d: %s is missing in '
734 'tools/metrics/actions/actions.xml. Please run '
735 'tools/metrics/actions/extract_actions.py to update.' %
736 (file_with_user_action, 1, 'NotInActionsXml')), output[0].message)
Alexei Svitkine64505a92021-03-11 22:00:54737
Daniel Cheng566634ff2024-06-29 14:56:53738 def testUserMetricsActionInTestFile(self):
739 input_api = MockInputApi()
740 file_with_user_action = 'file_with_user_action_unittest.cc'
741 contents_with_user_action = [
742 'base::UserMetricsAction("NotInActionsXml")'
743 ]
Alexei Svitkine64505a92021-03-11 22:00:54744
Daniel Cheng566634ff2024-06-29 14:56:53745 input_api.files = [
746 MockFile(file_with_user_action, contents_with_user_action)
747 ]
748
749 self.assertEqual([],
750 PRESUBMIT.CheckUserActionUpdate(
751 input_api, MockOutputApi()))
Alexei Svitkine64505a92021-03-11 22:00:54752
davileene0426252015-03-02 21:10:41753
agrievef32bcc72016-04-04 14:57:40754class PydepsNeedsUpdatingTest(unittest.TestCase):
755
Daniel Cheng566634ff2024-06-29 14:56:53756 class MockPopen:
Andrew Grieve4deedb12022-02-03 21:34:50757
Daniel Cheng566634ff2024-06-29 14:56:53758 def __init__(self, stdout):
759 self.stdout = io.StringIO(stdout)
Andrew Grieve4deedb12022-02-03 21:34:50760
Daniel Cheng566634ff2024-06-29 14:56:53761 def wait(self):
762 return 0
Andrew Grieve4deedb12022-02-03 21:34:50763
Daniel Cheng566634ff2024-06-29 14:56:53764 class MockSubprocess:
765 CalledProcessError = subprocess.CalledProcessError
766 PIPE = 0
Andrew Grieve4deedb12022-02-03 21:34:50767
Daniel Cheng566634ff2024-06-29 14:56:53768 def __init__(self):
769 self._popen_func = None
agrievef32bcc72016-04-04 14:57:40770
Daniel Cheng566634ff2024-06-29 14:56:53771 def SetPopenCallback(self, func):
772 self._popen_func = func
Mohamed Heikal7cd4d8312020-06-16 16:49:40773
Daniel Cheng566634ff2024-06-29 14:56:53774 def Popen(self, cmd, *args, **kwargs):
775 return PydepsNeedsUpdatingTest.MockPopen(self._popen_func(cmd))
agrievef32bcc72016-04-04 14:57:40776
Daniel Cheng566634ff2024-06-29 14:56:53777 def _MockParseGclientArgs(self, is_android=True):
778 return lambda: {'checkout_android': 'true' if is_android else 'false'}
agrievef32bcc72016-04-04 14:57:40779
Daniel Cheng566634ff2024-06-29 14:56:53780 def setUp(self):
781 mock_all_pydeps = ['A.pydeps', 'B.pydeps', 'D.pydeps']
782 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
783 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
784 mock_android_pydeps = ['D.pydeps']
785 self.old_ANDROID_SPECIFIC_PYDEPS_FILES = (
786 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES)
787 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = mock_android_pydeps
788 self.old_ParseGclientArgs = PRESUBMIT._ParseGclientArgs
789 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs()
790 self.mock_input_api = MockInputApi()
791 self.mock_output_api = MockOutputApi()
792 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess(
793 )
794 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api,
795 mock_all_pydeps)
796 self.checker._file_cache = {
797 'A.pydeps':
798 '# Generated by:\n# CMD --output A.pydeps A\nA.py\nC.py\n',
799 'B.pydeps':
800 '# Generated by:\n# CMD --output B.pydeps B\nB.py\nC.py\n',
801 'D.pydeps': '# Generated by:\n# CMD --output D.pydeps D\nD.py\n',
802 }
agrievef32bcc72016-04-04 14:57:40803
Daniel Cheng566634ff2024-06-29 14:56:53804 def tearDown(self):
805 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
806 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = (
807 self.old_ANDROID_SPECIFIC_PYDEPS_FILES)
808 PRESUBMIT._ParseGclientArgs = self.old_ParseGclientArgs
pastarmovj89f7ee12016-09-20 14:58:13809
Daniel Cheng566634ff2024-06-29 14:56:53810 def _RunCheck(self):
811 return PRESUBMIT.CheckPydepsNeedsUpdating(
812 self.mock_input_api,
813 self.mock_output_api,
814 checker_for_tests=self.checker)
agrievef32bcc72016-04-04 14:57:40815
Daniel Cheng566634ff2024-06-29 14:56:53816 def testAddedPydep(self):
817 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
818 if not self.mock_input_api.platform.startswith('linux'):
819 return []
agrievef32bcc72016-04-04 14:57:40820
Andrew Grieve713b89b2024-10-15 20:20:08821 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53822 MockAffectedFile('new.pydeps', [], action='A'),
Sophey Dong58cf9bbd2024-10-09 00:08:10823 ])
Andrew Grieve713b89b2024-10-15 20:20:08824
Daniel Cheng566634ff2024-06-29 14:56:53825 results = self._RunCheck()
826 self.assertEqual(1, len(results))
827 self.assertIn('PYDEPS_FILES', str(results[0]))
pastarmovj89f7ee12016-09-20 14:58:13828
Daniel Cheng566634ff2024-06-29 14:56:53829 def testPydepNotInSrc(self):
Andrew Grieve713b89b2024-10-15 20:20:08830 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53831 MockAffectedFile('new.pydeps', [], action='A'),
Andrew Grieve713b89b2024-10-15 20:20:08832 ])
833 self.mock_input_api.os_path.exists = lambda x: False
Daniel Cheng566634ff2024-06-29 14:56:53834 results = self._RunCheck()
835 self.assertEqual(0, len(results))
agrievef32bcc72016-04-04 14:57:40836
Daniel Cheng566634ff2024-06-29 14:56:53837 def testRemovedPydep(self):
838 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
839 if not self.mock_input_api.platform.startswith('linux'):
840 return []
pastarmovj89f7ee12016-09-20 14:58:13841
Andrew Grieve713b89b2024-10-15 20:20:08842 self.mock_input_api.InitFiles([
Daniel Cheng566634ff2024-06-29 14:56:53843 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
Daniel Cheng566634ff2024-06-29 14:56:53844 ])
845 results = self._RunCheck()
846 self.assertEqual(1, len(results))
847 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40848
Daniel Cheng566634ff2024-06-29 14:56:53849 def testRandomPyIgnored(self):
850 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
851 if not self.mock_input_api.platform.startswith('linux'):
852 return []
agrievef32bcc72016-04-04 14:57:40853
Daniel Cheng566634ff2024-06-29 14:56:53854 self.mock_input_api.files = [
855 MockAffectedFile('random.py', []),
856 ]
pastarmovj89f7ee12016-09-20 14:58:13857
Daniel Cheng566634ff2024-06-29 14:56:53858 results = self._RunCheck()
859 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40860
Daniel Cheng566634ff2024-06-29 14:56:53861 def testRelevantPyNoChange(self):
862 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
863 if not self.mock_input_api.platform.startswith('linux'):
864 return []
agrievef32bcc72016-04-04 14:57:40865
Daniel Cheng566634ff2024-06-29 14:56:53866 self.mock_input_api.files = [
867 MockAffectedFile('A.py', []),
868 ]
agrievef32bcc72016-04-04 14:57:40869
Daniel Cheng566634ff2024-06-29 14:56:53870 def popen_callback(cmd):
871 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
872 return self.checker._file_cache['A.pydeps']
agrievef32bcc72016-04-04 14:57:40873
Daniel Cheng566634ff2024-06-29 14:56:53874 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13875
Daniel Cheng566634ff2024-06-29 14:56:53876 results = self._RunCheck()
877 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40878
Daniel Cheng566634ff2024-06-29 14:56:53879 def testRelevantPyOneChange(self):
880 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
881 if not self.mock_input_api.platform.startswith('linux'):
882 return []
agrievef32bcc72016-04-04 14:57:40883
Daniel Cheng566634ff2024-06-29 14:56:53884 self.mock_input_api.files = [
885 MockAffectedFile('A.py', []),
886 ]
agrievef32bcc72016-04-04 14:57:40887
Daniel Cheng566634ff2024-06-29 14:56:53888 def popen_callback(cmd):
889 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
890 return 'changed data'
agrievef32bcc72016-04-04 14:57:40891
Daniel Cheng566634ff2024-06-29 14:56:53892 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
pastarmovj89f7ee12016-09-20 14:58:13893
Daniel Cheng566634ff2024-06-29 14:56:53894 results = self._RunCheck()
895 self.assertEqual(1, len(results))
896 # Check that --output "" is not included.
897 self.assertNotIn('""', str(results[0]))
898 self.assertIn('File is stale', str(results[0]))
agrievef32bcc72016-04-04 14:57:40899
Daniel Cheng566634ff2024-06-29 14:56:53900 def testRelevantPyTwoChanges(self):
901 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
902 if not self.mock_input_api.platform.startswith('linux'):
903 return []
agrievef32bcc72016-04-04 14:57:40904
Daniel Cheng566634ff2024-06-29 14:56:53905 self.mock_input_api.files = [
906 MockAffectedFile('C.py', []),
907 ]
agrievef32bcc72016-04-04 14:57:40908
Daniel Cheng566634ff2024-06-29 14:56:53909 def popen_callback(cmd):
910 return 'changed data'
agrievef32bcc72016-04-04 14:57:40911
Daniel Cheng566634ff2024-06-29 14:56:53912 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Mohamed Heikal7cd4d8312020-06-16 16:49:40913
Daniel Cheng566634ff2024-06-29 14:56:53914 results = self._RunCheck()
915 self.assertEqual(2, len(results))
916 self.assertIn('File is stale', str(results[0]))
917 self.assertIn('File is stale', str(results[1]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40918
Daniel Cheng566634ff2024-06-29 14:56:53919 def testRelevantAndroidPyInNonAndroidCheckout(self):
920 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
921 if not self.mock_input_api.platform.startswith('linux'):
922 return []
Mohamed Heikal7cd4d8312020-06-16 16:49:40923
Daniel Cheng566634ff2024-06-29 14:56:53924 self.mock_input_api.files = [
925 MockAffectedFile('D.py', []),
926 ]
Mohamed Heikal7cd4d8312020-06-16 16:49:40927
Daniel Cheng566634ff2024-06-29 14:56:53928 def popen_callback(cmd):
929 self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
930 return 'changed data'
Andrew Grieve5bb4cf702020-10-22 20:21:39931
Daniel Cheng566634ff2024-06-29 14:56:53932 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
933 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(
934 is_android=False)
Andrew Grieve5bb4cf702020-10-22 20:21:39935
Daniel Cheng566634ff2024-06-29 14:56:53936 results = self._RunCheck()
937 self.assertEqual(1, len(results))
938 self.assertIn('Android', str(results[0]))
939 self.assertIn('D.pydeps', str(results[0]))
Andrew Grieve5bb4cf702020-10-22 20:21:39940
Daniel Cheng566634ff2024-06-29 14:56:53941 def testGnPathsAndMissingOutputFlag(self):
942 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
943 if not self.mock_input_api.platform.startswith('linux'):
944 return []
Andrew Grieve5bb4cf702020-10-22 20:21:39945
Daniel Cheng566634ff2024-06-29 14:56:53946 self.checker._file_cache = {
947 'A.pydeps':
948 '# Generated by:\n# CMD --gn-paths A\n//A.py\n//C.py\n',
949 'B.pydeps':
950 '# Generated by:\n# CMD --gn-paths B\n//B.py\n//C.py\n',
951 'D.pydeps': '# Generated by:\n# CMD --gn-paths D\n//D.py\n',
952 }
Andrew Grieve5bb4cf702020-10-22 20:21:39953
Daniel Cheng566634ff2024-06-29 14:56:53954 self.mock_input_api.files = [
955 MockAffectedFile('A.py', []),
956 ]
Andrew Grieve5bb4cf702020-10-22 20:21:39957
Daniel Cheng566634ff2024-06-29 14:56:53958 def popen_callback(cmd):
959 self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""',
960 cmd)
961 return 'changed data'
962
963 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
964
965 results = self._RunCheck()
966 self.assertEqual(1, len(results))
967 self.assertIn('File is stale', str(results[0]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40968
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39969
Daniel Bratell8ba52722018-03-02 16:06:14970class IncludeGuardTest(unittest.TestCase):
Daniel Bratell8ba52722018-03-02 16:06:14971
Daniel Cheng566634ff2024-06-29 14:56:53972 def testIncludeGuardChecks(self):
973 mock_input_api = MockInputApi()
974 mock_output_api = MockOutputApi()
975 mock_input_api.files = [
976 MockAffectedFile('content/browser/thing/foo.h', [
977 '// Comment',
978 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
979 '#define CONTENT_BROWSER_THING_FOO_H_',
980 'struct McBoatFace;',
981 '#endif // CONTENT_BROWSER_THING_FOO_H_',
982 ]),
983 MockAffectedFile('content/browser/thing/bar.h', [
984 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
985 '#define CONTENT_BROWSER_THING_BAR_H_',
986 'namespace content {',
987 '#endif // CONTENT_BROWSER_THING_BAR_H_',
988 '} // namespace content',
989 ]),
990 MockAffectedFile('content/browser/test1.h', [
991 'namespace content {',
992 '} // namespace content',
993 ]),
994 MockAffectedFile('content\\browser\\win.h', [
995 '#ifndef CONTENT_BROWSER_WIN_H_',
996 '#define CONTENT_BROWSER_WIN_H_',
997 'struct McBoatFace;',
998 '#endif // CONTENT_BROWSER_WIN_H_',
999 ]),
1000 MockAffectedFile('content/browser/test2.h', [
1001 '// Comment',
1002 '#ifndef CONTENT_BROWSER_TEST2_H_',
1003 'struct McBoatFace;',
1004 '#endif // CONTENT_BROWSER_TEST2_H_',
1005 ]),
1006 MockAffectedFile('content/browser/internal.h', [
1007 '// Comment',
1008 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
1009 '#define CONTENT_BROWSER_INTERNAL_H_',
1010 '// Comment',
1011 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1012 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
1013 'namespace internal {',
1014 '} // namespace internal',
1015 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
1016 'namespace content {',
1017 '} // namespace content',
1018 '#endif // CONTENT_BROWSER_THING_BAR_H_',
1019 ]),
1020 MockAffectedFile('content/browser/thing/foo.cc', [
1021 '// This is a non-header.',
1022 ]),
1023 MockAffectedFile('content/browser/disabled.h', [
1024 '// no-include-guard-because-multiply-included',
1025 'struct McBoatFace;',
1026 ]),
1027 # New files don't allow misspelled include guards.
1028 MockAffectedFile('content/browser/spleling.h', [
1029 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
1030 '#define CONTENT_BROWSER_SPLLEING_H_',
1031 'struct McBoatFace;',
1032 '#endif // CONTENT_BROWSER_SPLLEING_H_',
1033 ]),
1034 # New files don't allow + in include guards.
1035 MockAffectedFile('content/browser/foo+bar.h', [
1036 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
1037 '#define CONTENT_BROWSER_FOO+BAR_H_',
1038 'struct McBoatFace;',
1039 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
1040 ]),
1041 # Old files allow misspelled include guards (for now).
1042 MockAffectedFile('chrome/old.h', [
1043 '// New contents',
1044 '#ifndef CHROME_ODL_H_',
1045 '#define CHROME_ODL_H_',
1046 '#endif // CHROME_ODL_H_',
1047 ], [
1048 '// Old contents',
1049 '#ifndef CHROME_ODL_H_',
1050 '#define CHROME_ODL_H_',
1051 '#endif // CHROME_ODL_H_',
1052 ],
1053 action='M'),
1054 # Using a Blink style include guard outside Blink is wrong.
1055 MockAffectedFile('content/NotInBlink.h', [
1056 '#ifndef NotInBlink_h',
1057 '#define NotInBlink_h',
1058 'struct McBoatFace;',
1059 '#endif // NotInBlink_h',
1060 ]),
1061 # Using a Blink style include guard in Blink is no longer ok.
1062 MockAffectedFile('third_party/blink/InBlink.h', [
1063 '#ifndef InBlink_h',
1064 '#define InBlink_h',
1065 'struct McBoatFace;',
1066 '#endif // InBlink_h',
1067 ]),
1068 # Using a bad include guard in Blink is not ok.
1069 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
1070 '#ifndef WrongInBlink_h',
1071 '#define WrongInBlink_h',
1072 'struct McBoatFace;',
1073 '#endif // WrongInBlink_h',
1074 ]),
1075 # Using a bad include guard in Blink is not supposed to be accepted even
1076 # if it's an old file. However the current presubmit has accepted this
1077 # for a while.
1078 MockAffectedFile('third_party/blink/StillInBlink.h', [
1079 '// New contents',
1080 '#ifndef AcceptedInBlink_h',
1081 '#define AcceptedInBlink_h',
1082 'struct McBoatFace;',
1083 '#endif // AcceptedInBlink_h',
1084 ], [
1085 '// Old contents',
1086 '#ifndef AcceptedInBlink_h',
1087 '#define AcceptedInBlink_h',
1088 'struct McBoatFace;',
1089 '#endif // AcceptedInBlink_h',
1090 ],
1091 action='M'),
1092 # Using a non-Chromium include guard in third_party
1093 # (outside blink) is accepted.
1094 MockAffectedFile('third_party/foo/some_file.h', [
1095 '#ifndef REQUIRED_RPCNDR_H_',
1096 '#define REQUIRED_RPCNDR_H_',
1097 'struct SomeFileFoo;',
1098 '#endif // REQUIRED_RPCNDR_H_',
1099 ]),
1100 # Not having proper include guard in *_message_generator.h
1101 # for old IPC messages is allowed.
1102 MockAffectedFile('content/common/content_message_generator.h', [
1103 '#undef CONTENT_COMMON_FOO_MESSAGES_H_',
1104 '#include "content/common/foo_messages.h"',
1105 '#ifndef CONTENT_COMMON_FOO_MESSAGES_H_',
1106 '#error "Failed to include content/common/foo_messages.h"',
1107 '#endif',
1108 ]),
1109 MockAffectedFile('chrome/renderer/thing/qux.h', [
1110 '// Comment',
1111 '#ifndef CHROME_RENDERER_THING_QUX_H_',
1112 '#define CHROME_RENDERER_THING_QUX_H_',
1113 'struct Boaty;',
1114 '#endif',
1115 ]),
1116 ]
1117 msgs = PRESUBMIT.CheckForIncludeGuards(mock_input_api, mock_output_api)
1118 expected_fail_count = 10
1119 self.assertEqual(
1120 expected_fail_count, len(msgs), 'Expected %d items, found %d: %s' %
1121 (expected_fail_count, len(msgs), msgs))
1122 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
1123 self.assertEqual(
1124 msgs[0].message, 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
1125 'not covering the whole file')
Daniel Bratell8ba52722018-03-02 16:06:141126
Daniel Cheng566634ff2024-06-29 14:56:531127 self.assertIn('content/browser/test1.h', msgs[1].message)
1128 self.assertIn('Recommended name: CONTENT_BROWSER_TEST1_H_',
1129 msgs[1].message)
Daniel Bratell8ba52722018-03-02 16:06:141130
Daniel Cheng566634ff2024-06-29 14:56:531131 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
1132 self.assertEqual(
1133 msgs[2].message, 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
1134 'include guard')
Lei Zhangd84f9512024-05-28 19:43:301135
Daniel Cheng566634ff2024-06-29 14:56:531136 self.assertIn('content/browser/internal.h', msgs[3].message)
1137 self.assertIn(
1138 'Recommended #endif comment: // CONTENT_BROWSER_INTERNAL_H_',
1139 msgs[3].message)
Daniel Bratell8ba52722018-03-02 16:06:141140
Daniel Cheng566634ff2024-06-29 14:56:531141 self.assertEqual(msgs[4].items, ['content/browser/spleling.h:1'])
1142 self.assertEqual(
1143 msgs[4].message, 'Header using the wrong include guard name '
1144 'CONTENT_BROWSER_SPLLEING_H_')
Olivier Robinbba137492018-07-30 11:31:341145
Daniel Cheng566634ff2024-06-29 14:56:531146 self.assertIn('content/browser/foo+bar.h', msgs[5].message)
1147 self.assertIn('Recommended name: CONTENT_BROWSER_FOO_BAR_H_',
1148 msgs[5].message)
Daniel Bratell8ba52722018-03-02 16:06:141149
Daniel Cheng566634ff2024-06-29 14:56:531150 self.assertEqual(msgs[6].items, ['content/NotInBlink.h:1'])
1151 self.assertEqual(
1152 msgs[6].message, 'Header using the wrong include guard name '
1153 'NotInBlink_h')
Daniel Bratell39b5b062018-05-16 18:09:571154
Daniel Cheng566634ff2024-06-29 14:56:531155 self.assertEqual(msgs[7].items, ['third_party/blink/InBlink.h:1'])
1156 self.assertEqual(
1157 msgs[7].message, 'Header using the wrong include guard name '
1158 'InBlink_h')
Daniel Bratell8ba52722018-03-02 16:06:141159
Daniel Cheng566634ff2024-06-29 14:56:531160 self.assertEqual(msgs[8].items, ['third_party/blink/AlsoInBlink.h:1'])
1161 self.assertEqual(
1162 msgs[8].message, 'Header using the wrong include guard name '
1163 'WrongInBlink_h')
1164
1165 self.assertIn('chrome/renderer/thing/qux.h', msgs[9].message)
1166 self.assertIn(
1167 'Recommended #endif comment: // CHROME_RENDERER_THING_QUX_H_',
1168 msgs[9].message)
Lei Zhangd84f9512024-05-28 19:43:301169
1170
Chris Hall59f8d0c72020-05-01 07:31:191171class AccessibilityRelnotesFieldTest(unittest.TestCase):
Chris Hall59f8d0c72020-05-01 07:31:191172
Daniel Cheng566634ff2024-06-29 14:56:531173 def testRelnotesPresent(self):
1174 mock_input_api = MockInputApi()
1175 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191176
Daniel Cheng566634ff2024-06-29 14:56:531177 mock_input_api.files = [
1178 MockAffectedFile('ui/accessibility/foo.bar', [''])
1179 ]
1180 mock_input_api.change.DescriptionText = lambda: 'Commit description'
1181 mock_input_api.change.footers['AX-Relnotes'] = [
1182 'Important user facing change'
1183 ]
Chris Hall59f8d0c72020-05-01 07:31:191184
Daniel Cheng566634ff2024-06-29 14:56:531185 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1186 mock_input_api, mock_output_api)
1187 self.assertEqual(
1188 0, len(msgs),
1189 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191190
Daniel Cheng566634ff2024-06-29 14:56:531191 def testRelnotesMissingFromAccessibilityChange(self):
1192 mock_input_api = MockInputApi()
1193 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191194
Daniel Cheng566634ff2024-06-29 14:56:531195 mock_input_api.files = [
1196 MockAffectedFile('some/file', ['']),
1197 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1198 MockAffectedFile('some/other/file', [''])
1199 ]
1200 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191201
Daniel Cheng566634ff2024-06-29 14:56:531202 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1203 mock_input_api, mock_output_api)
1204 self.assertEqual(
1205 1, len(msgs),
1206 'Expected %d messages, found %d: %s' % (1, len(msgs), msgs))
1207 self.assertTrue(
1208 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1209 'Missing AX-Relnotes field message not found in errors')
Chris Hall59f8d0c72020-05-01 07:31:191210
Daniel Cheng566634ff2024-06-29 14:56:531211 # The relnotes footer is not required for changes which do not touch any
1212 # accessibility directories.
1213 def testIgnoresNonAccessibilityCode(self):
1214 mock_input_api = MockInputApi()
1215 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191216
Daniel Cheng566634ff2024-06-29 14:56:531217 mock_input_api.files = [
1218 MockAffectedFile('some/file', ['']),
1219 MockAffectedFile('some/other/file', [''])
1220 ]
1221 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191222
Daniel Cheng566634ff2024-06-29 14:56:531223 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1224 mock_input_api, mock_output_api)
1225 self.assertEqual(
1226 0, len(msgs),
1227 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191228
Daniel Cheng566634ff2024-06-29 14:56:531229 # Test that our presubmit correctly raises an error for a set of known paths.
1230 def testExpectedPaths(self):
1231 filesToTest = [
1232 "chrome/browser/accessibility/foo.py",
1233 "chrome/browser/ash/arc/accessibility/foo.cc",
1234 "chrome/browser/ui/views/accessibility/foo.h",
1235 "chrome/browser/extensions/api/automation/foo.h",
1236 "chrome/browser/extensions/api/automation_internal/foo.cc",
1237 "chrome/renderer/extensions/accessibility_foo.h",
1238 "chrome/tests/data/accessibility/foo.html",
1239 "content/browser/accessibility/foo.cc",
1240 "content/renderer/accessibility/foo.h",
1241 "content/tests/data/accessibility/foo.cc",
1242 "extensions/renderer/api/automation/foo.h",
1243 "ui/accessibility/foo/bar/baz.cc",
1244 "ui/views/accessibility/foo/bar/baz.h",
1245 ]
Chris Hall59f8d0c72020-05-01 07:31:191246
Daniel Cheng566634ff2024-06-29 14:56:531247 for testFile in filesToTest:
1248 mock_input_api = MockInputApi()
1249 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191250
Daniel Cheng566634ff2024-06-29 14:56:531251 mock_input_api.files = [MockAffectedFile(testFile, [''])]
1252 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391253
Daniel Cheng566634ff2024-06-29 14:56:531254 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1255 mock_input_api, mock_output_api)
1256 self.assertEqual(
1257 1, len(msgs),
1258 'Expected %d messages, found %d: %s, for file %s' %
1259 (1, len(msgs), msgs, testFile))
1260 self.assertTrue(
1261 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1262 ('Missing AX-Relnotes field message not found in errors '
1263 ' for file %s' % (testFile)))
Akihiro Ota08108e542020-05-20 15:30:531264
Daniel Cheng566634ff2024-06-29 14:56:531265 # Test that AX-Relnotes field can appear in the commit description (as long
1266 # as it appears at the beginning of a line).
1267 def testRelnotesInCommitDescription(self):
1268 mock_input_api = MockInputApi()
1269 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531270
Daniel Cheng566634ff2024-06-29 14:56:531271 mock_input_api.files = [
1272 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1273 ]
1274 mock_input_api.change.DescriptionText = lambda: (
1275 'Description:\n' +
1276 'AX-Relnotes: solves all accessibility issues forever')
Akihiro Ota08108e542020-05-20 15:30:531277
Daniel Cheng566634ff2024-06-29 14:56:531278 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1279 mock_input_api, mock_output_api)
1280 self.assertEqual(
1281 0, len(msgs),
1282 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Akihiro Ota08108e542020-05-20 15:30:531283
Daniel Cheng566634ff2024-06-29 14:56:531284 # Test that we don't match AX-Relnotes if it appears in the middle of a line.
1285 def testRelnotesMustAppearAtBeginningOfLine(self):
1286 mock_input_api = MockInputApi()
1287 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531288
Daniel Cheng566634ff2024-06-29 14:56:531289 mock_input_api.files = [
1290 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1291 ]
1292 mock_input_api.change.DescriptionText = lambda: (
1293 'Description:\n' +
1294 'This change has no AX-Relnotes: we should print a warning')
Akihiro Ota08108e542020-05-20 15:30:531295
Daniel Cheng566634ff2024-06-29 14:56:531296 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1297 mock_input_api, mock_output_api)
1298 self.assertTrue(
1299 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1300 'Missing AX-Relnotes field message not found in errors')
Akihiro Ota08108e542020-05-20 15:30:531301
Daniel Cheng566634ff2024-06-29 14:56:531302 # Tests that the AX-Relnotes field can be lowercase and use a '=' in place
1303 # of a ':'.
1304 def testRelnotesLowercaseWithEqualSign(self):
1305 mock_input_api = MockInputApi()
1306 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531307
Daniel Cheng566634ff2024-06-29 14:56:531308 mock_input_api.files = [
1309 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1310 ]
1311 mock_input_api.change.DescriptionText = lambda: (
1312 'Description:\n' +
1313 'ax-relnotes= this is a valid format for accessibility relnotes')
1314
1315 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1316 mock_input_api, mock_output_api)
1317 self.assertEqual(
1318 0, len(msgs),
1319 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1320
Akihiro Ota08108e542020-05-20 15:30:531321
Mark Schillaci44c90b42024-11-22 20:44:381322class AccessibilityAriaElementAttributeGettersTest(unittest.TestCase):
1323
1324 # Test warning is surfaced for various possible uses of bad methods.
1325 def testMatchingLines(self):
1326 mock_input_api = MockInputApi()
1327 mock_input_api.files = [
1328 MockFile(
1329 "third_party/blink/renderer/core/accessibility/ax_object.h",
1330 [
1331 "->getAttribute(html_names::kAriaCheckedAttr)",
1332 "node->hasAttribute(html_names::kRoleAttr)",
1333 "->FastHasAttribute(html_names::kAriaLabelAttr)",
1334 " .FastGetAttribute(html_names::kAriaCurrentAttr);",
1335
1336 ],
1337 action='M'
1338 ),
1339 MockFile(
1340 "third_party/blink/renderer/core/accessibility/ax_table.cc",
1341 [
1342 "bool result = node->hasAttribute(html_names::kFooAttr);",
1343 "foo->getAttribute(html_names::kAriaInvalidValueAttr)",
1344 "foo->GetAriaCurrentState(html_names::kAriaCurrentStateAttr)",
1345 ],
1346 action='M'
1347 ),
1348 ]
1349
1350 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1351 self.assertEqual(1, len(results))
1352 self.assertEqual(5, len(results[0].items))
1353 self.assertIn("ax_object.h:1", results[0].items[0])
1354 self.assertIn("ax_object.h:2", results[0].items[1])
1355 self.assertIn("ax_object.h:3", results[0].items[2])
1356 self.assertIn("ax_object.h:4", results[0].items[3])
1357 self.assertIn("ax_table.cc:2", results[0].items[4])
1358 self.assertIn("Please use ARIA-specific attribute access", results[0].message)
1359
1360 # Test no warnings for files that are not accessibility related.
1361 def testNonMatchingFiles(self):
1362 mock_input_api = MockInputApi()
1363 mock_input_api.files = [
1364 MockFile(
1365 "content/browser/foobar/foo.cc",
1366 ["->getAttribute(html_names::kAriaCheckedAttr)"],
1367 action='M'),
1368 MockFile(
1369 "third_party/blink/renderer/core/foo.cc",
1370 ["node->hasAttribute(html_names::kRoleAttr)"],
1371 action='M'),
1372 ]
1373 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1374 self.assertEqual(0, len(results))
1375
1376 # Test no warning when methods are used with different attribute params.
1377 def testNoBadParam(self):
1378 mock_input_api = MockInputApi()
1379 mock_input_api.files = [
1380 MockFile(
1381 "third_party/blink/renderer/core/accessibility/ax_object.h",
1382 [
1383 "->getAttribute(html_names::kCheckedAttr)",
1384 "->hasAttribute(html_names::kIdAttr)",
1385 ],
1386 action='M'
1387 )
1388 ]
1389
1390 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1391 self.assertEqual(0, len(results))
1392
1393 # Test no warning when attribute params are used for different methods.
1394 def testNoMethod(self):
1395 mock_input_api = MockInputApi()
1396 mock_input_api.files = [
1397 MockFile(
1398 "third_party/blink/renderer/core/accessibility/ax_object.cc",
1399 [
1400 "foo(html_names::kAriaCheckedAttr)",
1401 "bar(html_names::kRoleAttr)"
1402 ],
1403 action='M'
1404 )
1405 ]
1406
1407 results = PRESUBMIT.CheckAccessibilityAriaElementAttributeGetters(mock_input_api, MockOutputApi())
1408 self.assertEqual(0, len(results))
1409
1410
yolandyan45001472016-12-21 21:12:421411class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
yolandyan45001472016-12-21 21:12:421412
Daniel Cheng566634ff2024-06-29 14:56:531413 def testCheckAndroidTestAnnotationUsage(self):
1414 mock_input_api = MockInputApi()
1415 mock_output_api = MockOutputApi()
1416
1417 mock_input_api.files = [
1418 MockAffectedFile('LalaLand.java', ['random stuff']),
1419 MockAffectedFile('CorrectUsage.java', [
1420 'import androidx.test.filters.LargeTest;',
1421 'import androidx.test.filters.MediumTest;',
1422 'import androidx.test.filters.SmallTest;',
1423 ]),
1424 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1425 'import android.test.suitebuilder.annotation.LargeTest;',
1426 ]),
1427 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1428 'import android.test.suitebuilder.annotation.MediumTest;',
1429 ]),
1430 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1431 'import android.test.suitebuilder.annotation.SmallTest;',
1432 ]),
1433 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1434 'import android.test.suitebuilder.annotation.Smoke;',
1435 ])
1436 ]
1437 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1438 mock_input_api, mock_output_api)
1439 self.assertEqual(
1440 1, len(msgs),
1441 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1442 self.assertEqual(
1443 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1444 (4, len(msgs[0].items), msgs[0].items))
1445 self.assertTrue(
1446 'UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1447 'UsedDeprecatedLargeTestAnnotation not found in errors')
1448 self.assertTrue(
1449 'UsedDeprecatedMediumTestAnnotation.java:1' in msgs[0].items,
1450 'UsedDeprecatedMediumTestAnnotation not found in errors')
1451 self.assertTrue(
1452 'UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1453 'UsedDeprecatedSmallTestAnnotation not found in errors')
1454 self.assertTrue(
1455 'UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1456 'UsedDeprecatedSmokeAnnotation not found in errors')
1457
yolandyan45001472016-12-21 21:12:421458
Min Qinbc44383c2023-02-22 17:25:261459class AndroidBannedImportTest(unittest.TestCase):
Min Qinbc44383c2023-02-22 17:25:261460
Daniel Cheng566634ff2024-06-29 14:56:531461 def testCheckAndroidNoBannedImports(self):
1462 mock_input_api = MockInputApi()
1463 mock_output_api = MockOutputApi()
1464
1465 test_files = [
1466 MockAffectedFile('RandomStufff.java', ['random stuff']),
1467 MockAffectedFile('NoBannedImports.java', [
1468 'import androidx.test.filters.LargeTest;',
1469 'import androidx.test.filters.MediumTest;',
1470 'import androidx.test.filters.SmallTest;',
1471 ]),
1472 MockAffectedFile('BannedUri.java', [
1473 'import java.net.URI;',
1474 ]),
1475 MockAffectedFile('BannedTargetApi.java', [
1476 'import android.annotation.TargetApi;',
1477 ]),
Daniel Cheng566634ff2024-06-29 14:56:531478 MockAffectedFile('BannedActivityTestRule.java', [
1479 'import androidx.test.rule.ActivityTestRule;',
1480 ]),
1481 MockAffectedFile('BannedVectorDrawableCompat.java', [
1482 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
1483 ])
1484 ]
1485 msgs = []
1486 for file in test_files:
1487 mock_input_api.files = [file]
1488 msgs.append(
1489 PRESUBMIT._CheckAndroidNoBannedImports(mock_input_api,
1490 mock_output_api))
1491 self.assertEqual(0, len(msgs[0]))
1492 self.assertEqual(0, len(msgs[1]))
1493 self.assertTrue(msgs[2][0].message.startswith(
1494 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261495 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531496 BannedUri.java:1:""")))
1497 self.assertTrue(msgs[3][0].message.startswith(
1498 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261499 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531500 BannedTargetApi.java:1:""")))
1501 self.assertTrue(msgs[4][0].message.startswith(
1502 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261503 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531504 BannedActivityTestRule.java:1:""")))
Theo Cristea1d9a90a2024-11-14 13:31:301505 self.assertTrue(msgs[5][0].message.startswith(
Daniel Cheng566634ff2024-06-29 14:56:531506 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261507 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531508 BannedVectorDrawableCompat.java:1:""")))
1509
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391510
Mohamed Heikal5e5b7922020-10-29 18:57:591511class CheckNoDownstreamDepsTest(unittest.TestCase):
Mohamed Heikal5e5b7922020-10-29 18:57:591512
Daniel Cheng566634ff2024-06-29 14:56:531513 def testInvalidDepFromUpstream(self):
1514 mock_input_api = MockInputApi()
1515 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591516
Daniel Cheng566634ff2024-06-29 14:56:531517 mock_input_api.files = [
1518 MockAffectedFile('BUILD.gn',
1519 ['deps = [', ' "//clank/target:test",', ']']),
1520 MockAffectedFile('chrome/android/BUILD.gn',
1521 ['deps = [ "//clank/target:test" ]']),
1522 MockAffectedFile(
1523 'chrome/chrome_java_deps.gni',
1524 ['java_deps = [', ' "//clank/target:test",', ']']),
1525 ]
1526 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1527 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1528 mock_output_api)
1529 self.assertEqual(
1530 1, len(msgs),
1531 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1532 self.assertEqual(
1533 3, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1534 (3, len(msgs[0].items), msgs[0].items))
1535 self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
1536 'BUILD.gn not found in errors')
1537 self.assertTrue(
1538 any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
1539 'chrome/android/BUILD.gn:1 not found in errors')
1540 self.assertTrue(
1541 any('chrome/chrome_java_deps.gni:2' in item
1542 for item in msgs[0].items),
1543 'chrome/chrome_java_deps.gni:2 not found in errors')
Mohamed Heikal5e5b7922020-10-29 18:57:591544
Daniel Cheng566634ff2024-06-29 14:56:531545 def testAllowsComments(self):
1546 mock_input_api = MockInputApi()
1547 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591548
Daniel Cheng566634ff2024-06-29 14:56:531549 mock_input_api.files = [
1550 MockAffectedFile('BUILD.gn', [
1551 '# real implementation in //clank/target:test',
1552 ]),
1553 ]
1554 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1555 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1556 mock_output_api)
1557 self.assertEqual(
1558 0, len(msgs),
1559 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591560
Daniel Cheng566634ff2024-06-29 14:56:531561 def testOnlyChecksBuildFiles(self):
1562 mock_input_api = MockInputApi()
1563 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591564
Daniel Cheng566634ff2024-06-29 14:56:531565 mock_input_api.files = [
1566 MockAffectedFile('README.md',
1567 ['DEPS = [ "//clank/target:test" ]']),
1568 MockAffectedFile('chrome/android/java/file.java',
1569 ['//clank/ only function']),
1570 ]
1571 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1572 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1573 mock_output_api)
1574 self.assertEqual(
1575 0, len(msgs),
1576 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591577
Daniel Cheng566634ff2024-06-29 14:56:531578 def testValidDepFromDownstream(self):
1579 mock_input_api = MockInputApi()
1580 mock_output_api = MockOutputApi()
1581
1582 mock_input_api.files = [
1583 MockAffectedFile('BUILD.gn',
1584 ['DEPS = [', ' "//clank/target:test",', ']']),
1585 MockAffectedFile('java/BUILD.gn',
1586 ['DEPS = [ "//clank/target:test" ]']),
1587 ]
1588 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
1589 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1590 mock_output_api)
1591 self.assertEqual(
1592 0, len(msgs),
1593 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591594
yolandyan45001472016-12-21 21:12:421595
Jinsong Fan91ebbbd2019-04-16 14:57:171596class AndroidDebuggableBuildTest(unittest.TestCase):
1597
Daniel Cheng566634ff2024-06-29 14:56:531598 def testCheckAndroidDebuggableBuild(self):
1599 mock_input_api = MockInputApi()
1600 mock_output_api = MockOutputApi()
Jinsong Fan91ebbbd2019-04-16 14:57:171601
Daniel Cheng566634ff2024-06-29 14:56:531602 mock_input_api.files = [
1603 MockAffectedFile('RandomStuff.java', ['random stuff']),
1604 MockAffectedFile('CorrectUsage.java', [
1605 'import org.chromium.base.BuildInfo;',
1606 'some random stuff',
1607 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1608 ]),
1609 MockAffectedFile('JustCheckUserdebugBuild.java', [
1610 'import android.os.Build;',
1611 'some random stuff',
1612 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1613 ]),
1614 MockAffectedFile('JustCheckEngineeringBuild.java', [
1615 'import android.os.Build;',
1616 'some random stuff',
1617 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1618 ]),
1619 MockAffectedFile('UsedBuildType.java', [
1620 'import android.os.Build;',
1621 'some random stuff',
1622 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1623 '|| "eng".equals(Build.TYPE)',
1624 ]),
1625 MockAffectedFile('UsedExplicitBuildType.java', [
1626 'some random stuff',
1627 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1628 '|| "eng".equals(android.os.Build.TYPE)',
1629 ]),
1630 ]
Jinsong Fan91ebbbd2019-04-16 14:57:171631
Daniel Cheng566634ff2024-06-29 14:56:531632 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(mock_input_api,
1633 mock_output_api)
1634 self.assertEqual(
1635 1, len(msgs),
1636 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1637 self.assertEqual(
1638 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1639 (4, len(msgs[0].items), msgs[0].items))
1640 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1641 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1642 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1643 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
Jinsong Fan91ebbbd2019-04-16 14:57:171644
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391645
dgn4401aa52015-04-29 16:26:171646class LogUsageTest(unittest.TestCase):
1647
Daniel Cheng566634ff2024-06-29 14:56:531648 def testCheckAndroidCrLogUsage(self):
1649 mock_input_api = MockInputApi()
1650 mock_output_api = MockOutputApi()
dgnaa68d5e2015-06-10 10:08:221651
Daniel Cheng566634ff2024-06-29 14:56:531652 mock_input_api.files = [
1653 MockAffectedFile('RandomStuff.java', ['random stuff']),
1654 MockAffectedFile('HasAndroidLog.java', [
1655 'import android.util.Log;',
1656 'some random stuff',
1657 'Log.d("TAG", "foo");',
1658 ]),
1659 MockAffectedFile('HasExplicitUtilLog.java', [
1660 'some random stuff',
1661 'android.util.Log.d("TAG", "foo");',
1662 ]),
1663 MockAffectedFile('IsInBasePackage.java', [
1664 'package org.chromium.base;',
1665 'private static final String TAG = "cr_Foo";',
1666 'Log.d(TAG, "foo");',
1667 ]),
1668 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1669 'package org.chromium.base;',
1670 'import android.util.Log;',
1671 'private static final String TAG = "cr_Foo";',
1672 'Log.d(TAG, "foo");',
1673 ]),
1674 MockAffectedFile('HasBothLog.java', [
1675 'import org.chromium.base.Log;',
1676 'some random stuff',
1677 'private static final String TAG = "cr_Foo";',
1678 'Log.d(TAG, "foo");',
1679 'android.util.Log.d("TAG", "foo");',
1680 ]),
1681 MockAffectedFile('HasCorrectTag.java', [
1682 'import org.chromium.base.Log;',
1683 'some random stuff',
1684 'private static final String TAG = "cr_Foo";',
1685 'Log.d(TAG, "foo");',
1686 ]),
1687 MockAffectedFile('HasOldTag.java', [
1688 'import org.chromium.base.Log;',
1689 'some random stuff',
1690 'private static final String TAG = "cr.Foo";',
1691 'Log.d(TAG, "foo");',
1692 ]),
1693 MockAffectedFile('HasDottedTag.java', [
1694 'import org.chromium.base.Log;',
1695 'some random stuff',
1696 'private static final String TAG = "cr_foo.bar";',
1697 'Log.d(TAG, "foo");',
1698 ]),
1699 MockAffectedFile('HasDottedTagPublic.java', [
1700 'import org.chromium.base.Log;',
1701 'some random stuff',
1702 'public static final String TAG = "cr_foo.bar";',
1703 'Log.d(TAG, "foo");',
1704 ]),
1705 MockAffectedFile('HasNoTagDecl.java', [
1706 'import org.chromium.base.Log;',
1707 'some random stuff',
1708 'Log.d(TAG, "foo");',
1709 ]),
1710 MockAffectedFile('HasIncorrectTagDecl.java', [
1711 'import org.chromium.base.Log;',
1712 'private static final String TAHG = "cr_Foo";',
1713 'some random stuff',
1714 'Log.d(TAG, "foo");',
1715 ]),
1716 MockAffectedFile('HasInlineTag.java', [
1717 'import org.chromium.base.Log;',
1718 'some random stuff',
1719 'private static final String TAG = "cr_Foo";',
1720 'Log.d("TAG", "foo");',
1721 ]),
1722 MockAffectedFile('HasInlineTagWithSpace.java', [
1723 'import org.chromium.base.Log;',
1724 'some random stuff',
1725 'private static final String TAG = "cr_Foo";',
1726 'Log.d("log message", "foo");',
1727 ]),
1728 MockAffectedFile('HasUnprefixedTag.java', [
1729 'import org.chromium.base.Log;',
1730 'some random stuff',
1731 'private static final String TAG = "rubbish";',
1732 'Log.d(TAG, "foo");',
1733 ]),
1734 MockAffectedFile('HasTooLongTag.java', [
1735 'import org.chromium.base.Log;',
1736 'some random stuff',
1737 'private static final String TAG = "21_characters_long___";',
1738 'Log.d(TAG, "foo");',
1739 ]),
1740 MockAffectedFile('HasTooLongTagWithNoLogCallsInDiff.java', [
1741 'import org.chromium.base.Log;',
1742 'some random stuff',
1743 'private static final String TAG = "21_characters_long___";',
1744 ]),
1745 ]
dgnaa68d5e2015-06-10 10:08:221746
Daniel Cheng566634ff2024-06-29 14:56:531747 msgs = PRESUBMIT._CheckAndroidCrLogUsage(mock_input_api,
1748 mock_output_api)
dgnaa68d5e2015-06-10 10:08:221749
Daniel Cheng566634ff2024-06-29 14:56:531750 self.assertEqual(
1751 5, len(msgs),
1752 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
dgnaa68d5e2015-06-10 10:08:221753
Daniel Cheng566634ff2024-06-29 14:56:531754 # Declaration format
1755 nb = len(msgs[0].items)
1756 self.assertEqual(
1757 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
1758 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1759 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
dgnaa68d5e2015-06-10 10:08:221760
Daniel Cheng566634ff2024-06-29 14:56:531761 # Tag length
1762 nb = len(msgs[1].items)
1763 self.assertEqual(
1764 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[1].items))
1765 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
1766 self.assertTrue(
1767 'HasTooLongTagWithNoLogCallsInDiff.java' in msgs[1].items)
Geoff Huang77e3d6f2023-12-25 06:27:381768
Daniel Cheng566634ff2024-06-29 14:56:531769 # Tag must be a variable named TAG
1770 nb = len(msgs[2].items)
1771 self.assertEqual(
1772 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[2].items))
1773 self.assertTrue('HasBothLog.java:5' in msgs[2].items)
1774 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
1775 self.assertTrue('HasInlineTagWithSpace.java:4' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221776
Daniel Cheng566634ff2024-06-29 14:56:531777 # Util Log usage
1778 nb = len(msgs[3].items)
1779 self.assertEqual(
Sky Malice5766d282025-07-25 20:41:421780 5, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1781 self.assertTrue('HasAndroidLog.java:1' in msgs[3].items)
Daniel Cheng566634ff2024-06-29 14:56:531782 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1783 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
Sky Malice5766d282025-07-25 20:41:421784 self.assertTrue('IsInBasePackageButImportsLog.java:2' in msgs[3].items)
Daniel Cheng566634ff2024-06-29 14:56:531785 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381786
Daniel Cheng566634ff2024-06-29 14:56:531787 # Tag must not contain
1788 nb = len(msgs[4].items)
1789 self.assertEqual(
1790 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1791 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1792 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1793 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511794
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391795
estadee17314a02017-01-12 16:22:161796class GoogleAnswerUrlFormatTest(unittest.TestCase):
1797
Daniel Cheng566634ff2024-06-29 14:56:531798 def testCatchAnswerUrlId(self):
1799 input_api = MockInputApi()
1800 input_api.files = [
1801 MockFile('somewhere/file.cc', [
1802 'char* host = '
1803 ' "https://support.google.com/chrome/answer/123456";'
1804 ]),
1805 MockFile('somewhere_else/file.cc', [
1806 'char* host = '
1807 ' "https://support.google.com/chrome/a/answer/123456";'
1808 ]),
1809 ]
estadee17314a02017-01-12 16:22:161810
Daniel Cheng566634ff2024-06-29 14:56:531811 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1812 input_api, MockOutputApi())
1813 self.assertEqual(1, len(warnings))
1814 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161815
Daniel Cheng566634ff2024-06-29 14:56:531816 def testAllowAnswerUrlParam(self):
1817 input_api = MockInputApi()
1818 input_api.files = [
1819 MockFile('somewhere/file.cc', [
1820 'char* host = '
1821 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1822 ]),
1823 ]
estadee17314a02017-01-12 16:22:161824
Daniel Cheng566634ff2024-06-29 14:56:531825 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1826 input_api, MockOutputApi())
1827 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161828
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391829
reillyi38965732015-11-16 18:27:331830class HardcodedGoogleHostsTest(unittest.TestCase):
1831
Daniel Cheng566634ff2024-06-29 14:56:531832 def testWarnOnAssignedLiterals(self):
1833 input_api = MockInputApi()
1834 input_api.files = [
1835 MockFile('content/file.cc',
1836 ['char* host = "https://www.google.com";']),
1837 MockFile('content/file.cc',
1838 ['char* host = "https://www.googleapis.com";']),
1839 MockFile('content/file.cc',
1840 ['char* host = "https://clients1.google.com";']),
1841 ]
reillyi38965732015-11-16 18:27:331842
Daniel Cheng566634ff2024-06-29 14:56:531843 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1844 input_api, MockOutputApi())
1845 self.assertEqual(1, len(warnings))
1846 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331847
Daniel Cheng566634ff2024-06-29 14:56:531848 def testAllowInComment(self):
1849 input_api = MockInputApi()
1850 input_api.files = [
1851 MockFile('content/file.cc',
1852 ['char* host = "https://www.aol.com"; // google.com'])
1853 ]
reillyi38965732015-11-16 18:27:331854
Daniel Cheng566634ff2024-06-29 14:56:531855 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1856 input_api, MockOutputApi())
1857 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331858
dgn4401aa52015-04-29 16:26:171859
James Cook6b6597c2019-11-06 22:05:291860class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1861
Daniel Cheng566634ff2024-06-29 14:56:531862 def testWarnsOnChromeOsDirectories(self):
1863 files = [
1864 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1865 MockFile('chrome/browser/chromeos/file.cc',
1866 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1867 MockFile('chromeos/file.cc',
1868 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1869 MockFile('components/arc/file.cc',
1870 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1871 MockFile('components/exo/file.cc',
1872 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1873 ]
1874 input_api = MockInputApi()
1875 for file in files:
1876 input_api.files = [file]
1877 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1878 input_api, MockOutputApi())
1879 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291880
Daniel Cheng566634ff2024-06-29 14:56:531881 def testDoesNotWarnOnSyncOsPref(self):
1882 input_api = MockInputApi()
1883 input_api.files = [
1884 MockFile('chromeos/file.cc',
1885 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1886 ]
1887 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1888 input_api, MockOutputApi())
1889 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291890
Daniel Cheng566634ff2024-06-29 14:56:531891 def testDoesNotWarnOnOtherDirectories(self):
1892 input_api = MockInputApi()
1893 input_api.files = [
1894 MockFile('chrome/browser/ui/file.cc',
1895 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1896 MockFile('components/sync/file.cc',
1897 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1898 MockFile('content/browser/file.cc',
1899 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1900 MockFile('a/notchromeos/file.cc',
1901 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1902 ]
1903 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1904 input_api, MockOutputApi())
1905 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291906
Daniel Cheng566634ff2024-06-29 14:56:531907 def testSeparateWarningForPriorityPrefs(self):
1908 input_api = MockInputApi()
1909 input_api.files = [
1910 MockFile('chromeos/file.cc', [
1911 'PrefRegistrySyncable::SYNCABLE_PREF',
1912 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
1913 ]),
1914 ]
1915 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1916 input_api, MockOutputApi())
1917 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:291918
1919
jbriance9e12f162016-11-25 07:57:501920class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:501921
Daniel Cheng566634ff2024-06-29 14:56:531922 def testCheckHeadersOnlyOutsideThirdParty(self):
1923 mock_input_api = MockInputApi()
1924 mock_input_api.files = [
1925 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
1926 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
1927 ]
1928 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1929 mock_input_api, MockOutputApi())
1930 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501931
Daniel Cheng566634ff2024-06-29 14:56:531932 def testNoNestedDeclaration(self):
1933 mock_input_api = MockInputApi()
1934 mock_input_api.files = [
1935 MockAffectedFile('somewhere/header.h', [
1936 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
1937 ])
1938 ]
1939 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1940 mock_input_api, MockOutputApi())
1941 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501942
Daniel Cheng566634ff2024-06-29 14:56:531943 def testSubStrings(self):
1944 mock_input_api = MockInputApi()
1945 mock_input_api.files = [
1946 MockAffectedFile('somewhere/header.h', [
1947 'class NotUsefulClass;', 'struct SomeStruct;',
1948 'UsefulClass *p1;', 'SomeStructPtr *p2;'
1949 ])
1950 ]
1951 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1952 mock_input_api, MockOutputApi())
1953 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:501954
Daniel Cheng566634ff2024-06-29 14:56:531955 def testUselessForwardDeclaration(self):
1956 mock_input_api = MockInputApi()
1957 mock_input_api.files = [
1958 MockAffectedFile('somewhere/header.h', [
1959 'class DummyClass;', 'struct DummyStruct;',
1960 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
1961 ])
1962 ]
1963 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1964 mock_input_api, MockOutputApi())
1965 self.assertEqual(2, len(warnings))
1966
1967 def testBlinkHeaders(self):
1968 mock_input_api = MockInputApi()
1969 mock_input_api.files = [
1970 MockAffectedFile('third_party/blink/header.h', [
1971 'class DummyClass;',
1972 'struct DummyStruct;',
1973 ]),
1974 MockAffectedFile('third_party\\blink\\header.h', [
1975 'class DummyClass;',
1976 'struct DummyStruct;',
1977 ])
1978 ]
1979 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1980 mock_input_api, MockOutputApi())
1981 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:311982
jbriance9e12f162016-11-25 07:57:501983
rlanday6802cf632017-05-30 17:48:361984class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:361985
Daniel Cheng566634ff2024-06-29 14:56:531986 def testThirdPartyNotWebKitIgnored(self):
1987 mock_input_api = MockInputApi()
1988 mock_input_api.files = [
1989 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1990 MockAffectedFile('third_party/test/test.cpp',
1991 '#include "../header.h"'),
1992 ]
rlanday6802cf632017-05-30 17:48:361993
Daniel Cheng566634ff2024-06-29 14:56:531994 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:361995
Daniel Cheng566634ff2024-06-29 14:56:531996 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
1997 mock_output_api)
1998 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:361999
Daniel Cheng566634ff2024-06-29 14:56:532000 def testNonCppFileIgnored(self):
2001 mock_input_api = MockInputApi()
2002 mock_input_api.files = [
2003 MockAffectedFile('test.py', '#include "../header.h"'),
2004 ]
rlanday6802cf632017-05-30 17:48:362005
Daniel Cheng566634ff2024-06-29 14:56:532006 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362007
Daniel Cheng566634ff2024-06-29 14:56:532008 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2009 mock_output_api)
2010 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362011
Daniel Cheng566634ff2024-06-29 14:56:532012 def testInnocuousChangesAllowed(self):
2013 mock_input_api = MockInputApi()
2014 mock_input_api.files = [
2015 MockAffectedFile('test.cpp', '#include "header.h"'),
2016 MockAffectedFile('test2.cpp', '../'),
2017 ]
rlanday6802cf632017-05-30 17:48:362018
Daniel Cheng566634ff2024-06-29 14:56:532019 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362020
Daniel Cheng566634ff2024-06-29 14:56:532021 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2022 mock_output_api)
2023 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362024
Daniel Cheng566634ff2024-06-29 14:56:532025 def testRelativeIncludeNonWebKitProducesError(self):
2026 mock_input_api = MockInputApi()
2027 mock_input_api.files = [
2028 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2029 ]
rlanday6802cf632017-05-30 17:48:362030
Daniel Cheng566634ff2024-06-29 14:56:532031 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362032
Daniel Cheng566634ff2024-06-29 14:56:532033 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2034 mock_output_api)
2035 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362036
Daniel Cheng566634ff2024-06-29 14:56:532037 def testRelativeIncludeWebKitProducesError(self):
2038 mock_input_api = MockInputApi()
2039 mock_input_api.files = [
2040 MockAffectedFile('third_party/blink/test.cpp',
2041 ['#include "../header.h']),
2042 ]
rlanday6802cf632017-05-30 17:48:362043
Daniel Cheng566634ff2024-06-29 14:56:532044 mock_output_api = MockOutputApi()
2045
2046 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2047 mock_output_api)
2048 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242049
Daniel Cheng13ca61a882017-08-25 15:11:252050
Daniel Bratell65b033262019-04-23 08:17:062051class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062052
Daniel Cheng566634ff2024-06-29 14:56:532053 def testThirdPartyNotBlinkIgnored(self):
2054 mock_input_api = MockInputApi()
2055 mock_input_api.files = [
2056 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2057 ]
Daniel Bratell65b033262019-04-23 08:17:062058
Daniel Cheng566634ff2024-06-29 14:56:532059 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062060
Daniel Cheng566634ff2024-06-29 14:56:532061 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2062 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062063
Daniel Cheng566634ff2024-06-29 14:56:532064 def testPythonFileIgnored(self):
2065 mock_input_api = MockInputApi()
2066 mock_input_api.files = [
2067 MockAffectedFile('test.py', '#include "file.cc"'),
2068 ]
Daniel Bratell65b033262019-04-23 08:17:062069
Daniel Cheng566634ff2024-06-29 14:56:532070 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062071
Daniel Cheng566634ff2024-06-29 14:56:532072 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2073 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062074
Daniel Cheng566634ff2024-06-29 14:56:532075 def testIncFilesAccepted(self):
2076 mock_input_api = MockInputApi()
2077 mock_input_api.files = [
2078 MockAffectedFile('test.py', '#include "file.inc"'),
2079 ]
Daniel Bratell65b033262019-04-23 08:17:062080
Daniel Cheng566634ff2024-06-29 14:56:532081 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062082
Daniel Cheng566634ff2024-06-29 14:56:532083 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2084 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062085
Daniel Cheng566634ff2024-06-29 14:56:532086 def testInnocuousChangesAllowed(self):
2087 mock_input_api = MockInputApi()
2088 mock_input_api.files = [
2089 MockAffectedFile('test.cpp', '#include "header.h"'),
2090 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2091 ]
Daniel Bratell65b033262019-04-23 08:17:062092
Daniel Cheng566634ff2024-06-29 14:56:532093 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062094
Daniel Cheng566634ff2024-06-29 14:56:532095 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2096 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062097
Daniel Cheng566634ff2024-06-29 14:56:532098 def testCcIncludeNonBlinkProducesError(self):
2099 mock_input_api = MockInputApi()
2100 mock_input_api.files = [
2101 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2102 ]
Daniel Bratell65b033262019-04-23 08:17:062103
Daniel Cheng566634ff2024-06-29 14:56:532104 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062105
Daniel Cheng566634ff2024-06-29 14:56:532106 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2107 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062108
Daniel Cheng566634ff2024-06-29 14:56:532109 def testCppIncludeBlinkProducesError(self):
2110 mock_input_api = MockInputApi()
2111 mock_input_api.files = [
2112 MockAffectedFile('third_party/blink/test.cpp',
2113 ['#include "foo/file.cpp"']),
2114 ]
Daniel Bratell65b033262019-04-23 08:17:062115
Daniel Cheng566634ff2024-06-29 14:56:532116 mock_output_api = MockOutputApi()
2117
2118 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2119 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062120
2121
Andrew Grieve1b290e4a22020-11-24 20:07:012122class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012123
Daniel Cheng566634ff2024-06-29 14:56:532124 def testAddBareGlobs(self):
2125 mock_input_api = MockInputApi()
2126 mock_input_api.files = [
2127 MockAffectedFile('base/stuff.gni',
2128 ['forward_variables_from(invoker, "*")']),
2129 MockAffectedFile('base/BUILD.gn',
2130 ['forward_variables_from(invoker, "*")']),
2131 ]
2132 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2133 MockOutputApi())
2134 self.assertEqual(1, len(warnings))
2135 msg = '\n'.join(warnings[0].items)
2136 self.assertIn('base/stuff.gni', msg)
2137 # Should not check .gn files. Local templates don't need to care about
2138 # visibility / testonly.
2139 self.assertNotIn('base/BUILD.gn', msg)
2140
2141 def testValidUses(self):
2142 mock_input_api = MockInputApi()
2143 mock_input_api.files = [
2144 MockAffectedFile('base/stuff.gni',
2145 ['forward_variables_from(invoker, "*", [])']),
2146 MockAffectedFile('base/stuff2.gni', [
2147 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2148 ]),
2149 MockAffectedFile(
2150 'base/stuff3.gni',
2151 ['forward_variables_from(invoker, [ "testonly" ])']),
2152 ]
2153 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2154 MockOutputApi())
2155 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012156
2157
Sean Kaucb7c9b32022-10-25 21:25:522158class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522159
Daniel Cheng566634ff2024-06-29 14:56:532160 def testAddAbsolutePath(self):
2161 mock_input_api = MockInputApi()
2162 mock_input_api.files = [
2163 MockAffectedFile('base/BUILD.gn',
2164 ['rebase_path("$target_gen_dir", "//")']),
2165 MockAffectedFile('base/root/BUILD.gn',
2166 ['rebase_path("$target_gen_dir", "/")']),
2167 MockAffectedFile('base/variable/BUILD.gn',
2168 ['rebase_path(target_gen_dir, "/")']),
2169 ]
2170 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2171 self.assertEqual(1, len(warnings))
2172 msg = '\n'.join(warnings[0].items)
2173 self.assertIn('base/BUILD.gn', msg)
2174 self.assertIn('base/root/BUILD.gn', msg)
2175 self.assertIn('base/variable/BUILD.gn', msg)
2176 self.assertEqual(3, len(warnings[0].items))
2177
2178 def testValidUses(self):
2179 mock_input_api = MockInputApi()
2180 mock_input_api.files = [
2181 MockAffectedFile(
2182 'base/foo/BUILD.gn',
2183 ['rebase_path("$target_gen_dir", root_build_dir)']),
2184 MockAffectedFile(
2185 'base/bar/BUILD.gn',
2186 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2187 MockAffectedFile('base/baz/BUILD.gn',
2188 ['rebase_path(target_gen_dir, root_build_dir)']),
2189 MockAffectedFile(
2190 'base/baz/BUILD.gn',
2191 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2192 MockAffectedFile('base/okay_slash/BUILD.gn',
2193 ['rebase_path(".", "//")']),
2194 ]
2195 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2196 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522197
2198
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192199class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192200
Daniel Cheng566634ff2024-06-29 14:56:532201 def testAddHeaderWithoutGn(self):
2202 mock_input_api = MockInputApi()
2203 mock_input_api.files = [
2204 MockAffectedFile('base/stuff.h', ''),
2205 ]
2206 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2207 mock_input_api, MockOutputApi())
2208 self.assertEqual(1, len(warnings))
2209 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192210
Daniel Cheng566634ff2024-06-29 14:56:532211 def testModifyHeader(self):
2212 mock_input_api = MockInputApi()
2213 mock_input_api.files = [
2214 MockAffectedFile('base/stuff.h', '', action='M'),
2215 ]
2216 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2217 mock_input_api, MockOutputApi())
2218 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192219
Daniel Cheng566634ff2024-06-29 14:56:532220 def testDeleteHeader(self):
2221 mock_input_api = MockInputApi()
2222 mock_input_api.files = [
2223 MockAffectedFile('base/stuff.h', '', action='D'),
2224 ]
2225 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2226 mock_input_api, MockOutputApi())
2227 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192228
Daniel Cheng566634ff2024-06-29 14:56:532229 def testAddHeaderWithGn(self):
2230 mock_input_api = MockInputApi()
2231 mock_input_api.files = [
2232 MockAffectedFile('base/stuff.h', ''),
2233 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2234 ]
2235 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2236 mock_input_api, MockOutputApi())
2237 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192238
Daniel Cheng566634ff2024-06-29 14:56:532239 def testAddHeaderWithGni(self):
2240 mock_input_api = MockInputApi()
2241 mock_input_api.files = [
2242 MockAffectedFile('base/stuff.h', ''),
2243 MockAffectedFile('base/files.gni', 'stuff.h'),
2244 ]
2245 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2246 mock_input_api, MockOutputApi())
2247 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192248
Daniel Cheng566634ff2024-06-29 14:56:532249 def testAddHeaderWithOther(self):
2250 mock_input_api = MockInputApi()
2251 mock_input_api.files = [
2252 MockAffectedFile('base/stuff.h', ''),
2253 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2254 ]
2255 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2256 mock_input_api, MockOutputApi())
2257 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192258
Daniel Cheng566634ff2024-06-29 14:56:532259 def testAddHeaderWithWrongGn(self):
2260 mock_input_api = MockInputApi()
2261 mock_input_api.files = [
2262 MockAffectedFile('base/stuff.h', ''),
2263 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2264 ]
2265 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2266 mock_input_api, MockOutputApi())
2267 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192268
Daniel Cheng566634ff2024-06-29 14:56:532269 def testAddHeadersWithGn(self):
2270 mock_input_api = MockInputApi()
2271 mock_input_api.files = [
2272 MockAffectedFile('base/stuff.h', ''),
2273 MockAffectedFile('base/another.h', ''),
2274 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2275 ]
2276 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2277 mock_input_api, MockOutputApi())
2278 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192279
Daniel Cheng566634ff2024-06-29 14:56:532280 def testAddHeadersWithWrongGn(self):
2281 mock_input_api = MockInputApi()
2282 mock_input_api.files = [
2283 MockAffectedFile('base/stuff.h', ''),
2284 MockAffectedFile('base/another.h', ''),
2285 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2286 ]
2287 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2288 mock_input_api, MockOutputApi())
2289 self.assertEqual(1, len(warnings))
2290 self.assertFalse('base/stuff.h' in warnings[0].items)
2291 self.assertTrue('base/another.h' in warnings[0].items)
2292
2293 def testAddHeadersWithWrongGn2(self):
2294 mock_input_api = MockInputApi()
2295 mock_input_api.files = [
2296 MockAffectedFile('base/stuff.h', ''),
2297 MockAffectedFile('base/another.h', ''),
2298 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2299 ]
2300 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2301 mock_input_api, MockOutputApi())
2302 self.assertEqual(1, len(warnings))
2303 self.assertTrue('base/stuff.h' in warnings[0].items)
2304 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192305
2306
Michael Giuffridad3bc8672018-10-25 22:48:022307class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022308
Daniel Cheng566634ff2024-06-29 14:56:532309 def testProductNameInDesc(self):
2310 mock_input_api = MockInputApi()
2311 mock_input_api.files = [
2312 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2313 '<message name="Foo" desc="Welcome to Chrome">',
2314 ' Welcome to Chrome!',
2315 '</message>',
2316 ]),
2317 MockAffectedFile('chrome/app/chromium_strings.grd', [
2318 '<message name="Bar" desc="Welcome to Chrome">',
2319 ' Welcome to Chromium!',
2320 '</message>',
2321 ]),
2322 ]
2323 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2324 mock_input_api, MockOutputApi())
2325 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022326
Daniel Cheng566634ff2024-06-29 14:56:532327 def testChromeInChromium(self):
2328 mock_input_api = MockInputApi()
2329 mock_input_api.files = [
2330 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2331 '<message name="Foo" desc="Welcome to Chrome">',
2332 ' Welcome to Chrome!',
2333 '</message>',
2334 ]),
2335 MockAffectedFile('chrome/app/chromium_strings.grd', [
2336 '<message name="Bar" desc="Welcome to Chrome">',
2337 ' Welcome to Chrome!',
2338 '</message>',
2339 ]),
2340 ]
2341 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2342 mock_input_api, MockOutputApi())
2343 self.assertEqual(1, len(warnings))
2344 self.assertTrue(
2345 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022346
Daniel Cheng566634ff2024-06-29 14:56:532347 def testChromiumInChrome(self):
2348 mock_input_api = MockInputApi()
2349 mock_input_api.files = [
2350 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2351 '<message name="Foo" desc="Welcome to Chrome">',
2352 ' Welcome to Chromium!',
2353 '</message>',
2354 ]),
2355 MockAffectedFile('chrome/app/chromium_strings.grd', [
2356 '<message name="Bar" desc="Welcome to Chrome">',
2357 ' Welcome to Chromium!',
2358 '</message>',
2359 ]),
2360 ]
2361 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2362 mock_input_api, MockOutputApi())
2363 self.assertEqual(1, len(warnings))
2364 self.assertTrue(
2365 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202366
Daniel Cheng566634ff2024-06-29 14:56:532367 def testChromeForTestingInChromium(self):
2368 mock_input_api = MockInputApi()
2369 mock_input_api.files = [
2370 MockAffectedFile('chrome/app/chromium_strings.grd', [
2371 '<message name="Bar" desc="Welcome to Chrome">',
2372 ' Welcome to Chrome for Testing!',
2373 '</message>',
2374 ]),
2375 ]
2376 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2377 mock_input_api, MockOutputApi())
2378 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202379
Daniel Cheng566634ff2024-06-29 14:56:532380 def testChromeForTestingInChrome(self):
2381 mock_input_api = MockInputApi()
2382 mock_input_api.files = [
2383 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2384 '<message name="Bar" desc="Welcome to Chrome">',
2385 ' Welcome to Chrome for Testing!',
2386 '</message>',
2387 ]),
2388 ]
2389 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2390 mock_input_api, MockOutputApi())
2391 self.assertEqual(1, len(warnings))
2392 self.assertTrue(
2393 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022394
Daniel Cheng566634ff2024-06-29 14:56:532395 def testMultipleInstances(self):
2396 mock_input_api = MockInputApi()
2397 mock_input_api.files = [
2398 MockAffectedFile('chrome/app/chromium_strings.grd', [
2399 '<message name="Bar" desc="Welcome to Chrome">',
2400 ' Welcome to Chrome!',
2401 '</message>',
2402 '<message name="Baz" desc="A correct message">',
2403 ' Chromium is the software you are using.',
2404 '</message>',
2405 '<message name="Bat" desc="An incorrect message">',
2406 ' Google Chrome is the software you are using.',
2407 '</message>',
2408 ]),
2409 ]
2410 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2411 mock_input_api, MockOutputApi())
2412 self.assertEqual(1, len(warnings))
2413 self.assertTrue(
2414 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2415 self.assertTrue(
2416 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2417
2418 def testMultipleWarnings(self):
2419 mock_input_api = MockInputApi()
2420 mock_input_api.files = [
2421 MockAffectedFile('chrome/app/chromium_strings.grd', [
2422 '<message name="Bar" desc="Welcome to Chrome">',
2423 ' Welcome to Chrome!',
2424 '</message>',
2425 '<message name="Baz" desc="A correct message">',
2426 ' Chromium is the software you are using.',
2427 '</message>',
2428 '<message name="Bat" desc="An incorrect message">',
2429 ' Google Chrome is the software you are using.',
2430 '</message>',
2431 ]),
2432 MockAffectedFile(
2433 'components/components_google_chrome_strings.grd', [
2434 '<message name="Bar" desc="Welcome to Chrome">',
2435 ' Welcome to Chrome!',
2436 '</message>',
2437 '<message name="Baz" desc="A correct message">',
2438 ' Chromium is the software you are using.',
2439 '</message>',
2440 '<message name="Bat" desc="An incorrect message">',
2441 ' Google Chrome is the software you are using.',
2442 '</message>',
2443 ]),
2444 ]
2445 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2446 mock_input_api, MockOutputApi())
2447 self.assertEqual(2, len(warnings))
2448 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2449 warnings[0].items[0])
2450 self.assertTrue(
2451 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2452 self.assertTrue(
2453 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022454
2455
Daniel Chenga37c03db2022-05-12 17:20:342456class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252457
Daniel Cheng566634ff2024-06-29 14:56:532458 def _createMockInputApi(self):
2459 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472460
Daniel Cheng566634ff2024-06-29 14:56:532461 def FakeRepositoryRoot():
2462 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472463
Daniel Cheng566634ff2024-06-29 14:56:532464 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2465 self._injectFakeOwnersClient(
2466 mock_input_api, ['[email protected]', '[email protected]'])
2467 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342468
Daniel Cheng566634ff2024-06-29 14:56:532469 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342470
Daniel Cheng566634ff2024-06-29 14:56:532471 class FakeGerrit(object):
2472
2473 def IsOwnersOverrideApproved(self, issue):
2474 return False
2475
2476 input_api.change.issue = 123
2477 input_api.gerrit = FakeGerrit()
2478
2479 def _injectFakeOwnersClient(self, input_api, owners):
2480
2481 class FakeOwnersClient(object):
2482
2483 def ListOwners(self, f):
2484 return owners
2485
2486 input_api.owners_client = FakeOwnersClient()
2487
2488 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2489
2490 def MockOwnerAndReviewers(input_api,
2491 email_regexp,
2492 approval_needed=False):
2493 return [owner, reviewers]
2494
2495 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2496 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342497
2498
2499class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532500 _test_cases = [
2501 ('*_messages.cc', 'scary_messages.cc'),
2502 ('*_messages*.h', 'scary_messages.h'),
2503 ('*_messages*.h', 'scary_messages_android.h'),
2504 ('*_param_traits*.*', 'scary_param_traits.h'),
2505 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2506 ('*.mojom', 'scary.mojom'),
2507 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2508 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2509 ('*_type_converter*.*', 'scary_type_converter.h'),
Daniel Cheng566634ff2024-06-29 14:56:532510 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252511 ]
Daniel Cheng171dad8d2022-05-21 00:40:252512
Daniel Cheng566634ff2024-06-29 14:56:532513 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2514 mock_input_api = self._createMockInputApi()
2515 new_owners_file_path = mock_input_api.os_path.join(
2516 'services', 'goat', 'public', 'OWNERS')
2517 new_owners_file = [
2518 'per-file *.mojom=set noparent',
2519 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2520 ]
Daniel Cheng3008dc12022-05-13 04:02:112521
Daniel Cheng566634ff2024-06-29 14:56:532522 def FakeReadFile(filename):
2523 self.assertEqual(
2524 mock_input_api.os_path.join('chromium', 'src',
2525 new_owners_file_path), filename)
2526 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112527
Daniel Cheng566634ff2024-06-29 14:56:532528 mock_input_api.ReadFile = FakeReadFile
2529 mock_input_api.files = [
2530 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252531 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532532 mock_input_api.os_path.join('services', 'goat', 'public',
2533 'goat.mojom'),
2534 ['// Scary contents.'])
2535 ]
2536 self._setupFakeChange(mock_input_api)
2537 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2538 '[email protected]',
2539 ['[email protected]'])
2540 mock_input_api.is_committing = True
2541 mock_input_api.dry_run = False
2542 mock_output_api = MockOutputApi()
2543 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2544 mock_output_api)
2545 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342546
Daniel Cheng566634ff2024-06-29 14:56:532547 def testMissingSecurityReviewerAtUpload(self):
2548 mock_input_api = self._createMockInputApi()
2549 new_owners_file_path = mock_input_api.os_path.join(
2550 'services', 'goat', 'public', 'OWNERS')
2551 new_owners_file = [
2552 'per-file *.mojom=set noparent',
2553 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2554 ]
Daniel Chenga37c03db2022-05-12 17:20:342555
Daniel Cheng566634ff2024-06-29 14:56:532556 def FakeReadFile(filename):
2557 self.assertEqual(
2558 mock_input_api.os_path.join('chromium', 'src',
2559 new_owners_file_path), filename)
2560 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362561
Daniel Cheng566634ff2024-06-29 14:56:532562 mock_input_api.ReadFile = FakeReadFile
2563 mock_input_api.files = [
2564 MockAffectedFile(new_owners_file_path, new_owners_file),
2565 MockAffectedFile(
2566 mock_input_api.os_path.join('services', 'goat', 'public',
2567 'goat.mojom'),
2568 ['// Scary contents.'])
2569 ]
2570 self._setupFakeChange(mock_input_api)
2571 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2572 '[email protected]',
2573 ['[email protected]'])
2574 mock_input_api.is_committing = False
2575 mock_input_api.dry_run = False
2576 mock_output_api = MockOutputApi()
2577 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2578 mock_output_api)
2579 self.assertEqual(1, len(results))
2580 self.assertEqual('notify', results[0].type)
2581 self.assertEqual(
2582 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2583 'following newly-added files:', results[0].message)
2584
2585 def testMissingSecurityReviewerAtDryRunCommit(self):
2586 mock_input_api = self._createMockInputApi()
2587 new_owners_file_path = mock_input_api.os_path.join(
2588 'services', 'goat', 'public', 'OWNERS')
2589 new_owners_file = [
2590 'per-file *.mojom=set noparent',
2591 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2592 ]
2593
2594 def FakeReadFile(filename):
2595 self.assertEqual(
2596 mock_input_api.os_path.join('chromium', 'src',
2597 new_owners_file_path), filename)
2598 return '\n'.join(new_owners_file)
2599
2600 mock_input_api.ReadFile = FakeReadFile
2601 mock_input_api.files = [
2602 MockAffectedFile(new_owners_file_path, new_owners_file),
2603 MockAffectedFile(
2604 mock_input_api.os_path.join('services', 'goat', 'public',
2605 'goat.mojom'),
2606 ['// Scary contents.'])
2607 ]
2608 self._setupFakeChange(mock_input_api)
2609 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2610 '[email protected]',
2611 ['[email protected]'])
2612 mock_input_api.is_committing = True
2613 mock_input_api.dry_run = True
2614 mock_output_api = MockOutputApi()
2615 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2616 mock_output_api)
2617 self.assertEqual(1, len(results))
2618 self.assertEqual('error', results[0].type)
2619 self.assertEqual(
2620 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2621 'following newly-added files:', results[0].message)
2622
2623 def testMissingSecurityApprovalAtRealCommit(self):
2624 mock_input_api = self._createMockInputApi()
2625 new_owners_file_path = mock_input_api.os_path.join(
2626 'services', 'goat', 'public', 'OWNERS')
2627 new_owners_file = [
2628 'per-file *.mojom=set noparent',
2629 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2630 ]
2631
2632 def FakeReadFile(filename):
2633 self.assertEqual(
2634 mock_input_api.os_path.join('chromium', 'src',
2635 new_owners_file_path), filename)
2636 return '\n'.join(new_owners_file)
2637
2638 mock_input_api.ReadFile = FakeReadFile
2639 mock_input_api.files = [
2640 MockAffectedFile(new_owners_file_path, new_owners_file),
2641 MockAffectedFile(
2642 mock_input_api.os_path.join('services', 'goat', 'public',
2643 'goat.mojom'),
2644 ['// Scary contents.'])
2645 ]
2646 self._setupFakeChange(mock_input_api)
2647 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2648 '[email protected]',
2649 ['[email protected]'])
2650 mock_input_api.is_committing = True
2651 mock_input_api.dry_run = False
2652 mock_output_api = MockOutputApi()
2653 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2654 mock_output_api)
2655 self.assertEqual('error', results[0].type)
2656 self.assertEqual(
2657 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2658 'following newly-added files:', results[0].message)
2659
2660 def testIpcChangeNeedsSecurityOwner(self):
2661 for is_committing in [True, False]:
2662 for pattern, filename in self._test_cases:
2663 with self.subTest(
2664 line=
2665 f'is_committing={is_committing}, filename={filename}'):
2666 mock_input_api = self._createMockInputApi()
2667 mock_input_api.files = [
2668 MockAffectedFile(
2669 mock_input_api.os_path.join(
2670 'services', 'goat', 'public', filename),
2671 ['// Scary contents.'])
2672 ]
2673 self._setupFakeChange(mock_input_api)
2674 self._injectFakeChangeOwnerAndReviewers(
2675 mock_input_api, '[email protected]',
2676 ['[email protected]'])
2677 mock_input_api.is_committing = is_committing
2678 mock_input_api.dry_run = False
2679 mock_output_api = MockOutputApi()
2680 results = PRESUBMIT.CheckSecurityOwners(
2681 mock_input_api, mock_output_api)
2682 self.assertEqual(1, len(results))
2683 self.assertEqual('error', results[0].type)
2684 self.assertTrue(results[0].message.replace(
2685 '\\', '/'
2686 ).startswith(
2687 'Found missing OWNERS lines for security-sensitive files. '
2688 'Please add the following lines to services/goat/public/OWNERS:'
2689 ))
2690 self.assertEqual(['[email protected]'],
2691 mock_output_api.more_cc)
2692
2693 def testServiceManifestChangeNeedsSecurityOwner(self):
2694 mock_input_api = self._createMockInputApi()
2695 mock_input_api.files = [
2696 MockAffectedFile(
2697 mock_input_api.os_path.join('services', 'goat', 'public',
2698 'cpp', 'manifest.cc'),
2699 [
2700 '#include "services/goat/public/cpp/manifest.h"',
2701 'const service_manager::Manifest& GetManifest() {}',
2702 ])
2703 ]
2704 self._setupFakeChange(mock_input_api)
2705 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2706 '[email protected]',
2707 ['[email protected]'])
2708 mock_output_api = MockOutputApi()
2709 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2710 self.assertEqual(1, len(errors))
2711 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2712 'Found missing OWNERS lines for security-sensitive files. '
2713 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2714 ))
2715 self.assertEqual(['[email protected]'],
2716 mock_output_api.more_cc)
2717
2718 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2719 mock_input_api = self._createMockInputApi()
2720 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2721 '[email protected]',
2722 ['[email protected]'])
2723 mock_input_api.files = [
2724 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2725 'const char kNoEnforcement[] = "not a manifest!";',
2726 ])
2727 ]
2728 mock_output_api = MockOutputApi()
2729 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2730 self.assertEqual([], errors)
2731 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032732
2733
Daniel Chenga37c03db2022-05-12 17:20:342734class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032735
Daniel Cheng566634ff2024-06-29 14:56:532736 def testFidlChangeNeedsSecurityOwner(self):
2737 mock_input_api = self._createMockInputApi()
2738 mock_input_api.files = [
2739 MockAffectedFile('potentially/scary/ipc.fidl',
2740 ['library test.fidl'])
2741 ]
2742 self._setupFakeChange(mock_input_api)
2743 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2744 '[email protected]',
2745 ['[email protected]'])
2746 mock_output_api = MockOutputApi()
2747 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2748 self.assertEqual(1, len(errors))
2749 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2750 'Found missing OWNERS lines for security-sensitive files. '
2751 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032752
Daniel Cheng566634ff2024-06-29 14:56:532753 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2754 mock_input_api = self._createMockInputApi()
2755 mock_input_api.files = [
2756 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2757 ['{ "that is no": "manifest!" }'])
2758 ]
2759 self._setupFakeChange(mock_input_api)
2760 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2761 '[email protected]',
2762 ['[email protected]'])
2763 mock_output_api = MockOutputApi()
2764 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2765 self.assertEqual(1, len(errors))
2766 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2767 'Found missing OWNERS lines for security-sensitive files. '
2768 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032769
Daniel Cheng566634ff2024-06-29 14:56:532770 def testComponentManifestV2NeedsSecurityOwner(self):
2771 mock_input_api = self._createMockInputApi()
2772 mock_input_api.files = [
2773 MockAffectedFile('potentially/scary/v2_manifest.cml',
2774 ['{ "that is no": "manifest!" }'])
2775 ]
2776 self._setupFakeChange(mock_input_api)
2777 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2778 '[email protected]',
2779 ['[email protected]'])
2780 mock_output_api = MockOutputApi()
2781 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2782 self.assertEqual(1, len(errors))
2783 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2784 'Found missing OWNERS lines for security-sensitive files. '
2785 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092786
Daniel Cheng566634ff2024-06-29 14:56:532787 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2788 mock_input_api = MockInputApi()
2789 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2790 '[email protected]',
2791 ['[email protected]'])
2792 mock_input_api.files = [
2793 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2794 'const char kNoEnforcement[] = "Security?!? Pah!";',
2795 ])
2796 ]
2797 mock_output_api = MockOutputApi()
2798 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2799 self.assertEqual([], errors)
2800
2801 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2802 mock_input_api = MockInputApi()
2803 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2804 '[email protected]',
2805 ['[email protected]'])
2806 mock_input_api.files = [
2807 MockAffectedFile(
2808 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2809 'const char kNoEnforcement[] = "Security?!? Pah!";',
2810 ])
2811 ]
2812 mock_output_api = MockOutputApi()
2813 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2814 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362815
Daniel Cheng13ca61a882017-08-25 15:11:252816
Daniel Chenga37c03db2022-05-12 17:20:342817class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132818
Daniel Cheng566634ff2024-06-29 14:56:532819 def testDiffGetServiceSandboxType(self):
2820 mock_input_api = MockInputApi()
2821 mock_input_api.files = [
2822 MockAffectedFile('services/goat/teleporter_host.cc', [
2823 'template <>', 'inline content::SandboxType',
2824 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2825 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2826 '#else', ' return SandboxType::kNoSandbox;',
2827 '#endif // !defined(OS_WIN)', '}'
2828 ]),
2829 ]
2830 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2831 mock_input_api)
2832 self.assertEqual(
2833 {
2834 'services/goat/teleporter_host.cc':
2835 set(['content::GetServiceSandboxType<>()'])
2836 }, files_to_functions)
2837
2838 def testDiffRemovingLine(self):
2839 mock_input_api = MockInputApi()
2840 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2841 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132842+++ new 2020-05-04 14:08:32.000000000 -0400
2843@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372844 template <>
2845 inline content::SandboxType
2846-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2847 #if defined(OS_WIN)
2848 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132849"""
Daniel Cheng566634ff2024-06-29 14:56:532850 mock_input_api.files = [mock_file]
2851 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2852 mock_input_api)
2853 self.assertEqual(
2854 {
2855 'services/goat/teleporter_host.cc':
2856 set(['content::GetServiceSandboxType<>()'])
2857 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132858
Daniel Cheng566634ff2024-06-29 14:56:532859 def testChangeOwnersMissing(self):
2860 mock_input_api = self._createMockInputApi()
2861 self._setupFakeChange(mock_input_api)
2862 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2863 '[email protected]',
2864 ['[email protected]'])
2865 mock_input_api.is_committing = False
2866 mock_input_api.files = [
2867 MockAffectedFile('file.cc',
2868 ['GetServiceSandboxType<Goat>(Sandbox)'])
2869 ]
2870 mock_output_api = MockOutputApi()
2871 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2872 mock_output_api)
2873 self.assertEqual(1, len(result))
2874 self.assertEqual(result[0].type, 'notify')
2875 self.assertEqual(result[0].message,
2876 'The following files change calls to security-sensitive functions\n' \
2877 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2878 ' file.cc\n'
2879 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132880
Daniel Cheng566634ff2024-06-29 14:56:532881 def testChangeOwnersMissingAtCommit(self):
2882 mock_input_api = self._createMockInputApi()
2883 self._setupFakeChange(mock_input_api)
2884 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2885 '[email protected]',
2886 ['[email protected]'])
2887 mock_input_api.is_committing = True
2888 mock_input_api.dry_run = False
2889 mock_input_api.files = [
2890 MockAffectedFile('file.cc',
2891 ['GetServiceSandboxType<mojom::Goat>()'])
2892 ]
2893 mock_output_api = MockOutputApi()
2894 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2895 mock_output_api)
2896 self.assertEqual(1, len(result))
2897 self.assertEqual(result[0].type, 'error')
2898 self.assertEqual(result[0].message,
2899 'The following files change calls to security-sensitive functions\n' \
2900 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2901 ' file.cc\n'
2902 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132903
Daniel Cheng566634ff2024-06-29 14:56:532904 def testChangeOwnersPresent(self):
2905 mock_input_api = self._createMockInputApi()
2906 self._injectFakeChangeOwnerAndReviewers(
2907 mock_input_api, '[email protected]',
2908 ['[email protected]', '[email protected]'])
2909 mock_input_api.files = [
2910 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2911 ]
2912 mock_output_api = MockOutputApi()
2913 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2914 mock_output_api)
2915 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132916
Daniel Cheng566634ff2024-06-29 14:56:532917 def testChangeOwnerIsSecurityOwner(self):
2918 mock_input_api = self._createMockInputApi()
2919 self._setupFakeChange(mock_input_api)
2920 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2921 '[email protected]',
2922 ['[email protected]'])
2923 mock_input_api.files = [
2924 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
2925 ]
2926 mock_output_api = MockOutputApi()
2927 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2928 mock_output_api)
2929 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132930
2931
Mario Sanchez Prada2472cab2019-09-18 10:58:312932class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:292933
Daniel Cheng566634ff2024-06-29 14:56:532934 def testBannedJsFunctions(self):
2935 input_api = MockInputApi()
2936 input_api.files = [
2937 MockFile('ash/webui/file.js', ['chrome.send(something);']),
2938 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
2939 ]
Clement Yan9b330cb2022-11-17 05:25:292940
Daniel Cheng566634ff2024-06-29 14:56:532941 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542942
Daniel Cheng566634ff2024-06-29 14:56:532943 self.assertEqual(1, len(results))
2944 self.assertTrue('ash/webui/file.js' in results[0].message)
2945 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:262946
Daniel Cheng566634ff2024-06-29 14:56:532947 def testBannedJavaFunctions(self):
2948 input_api = MockInputApi()
2949 input_api.files = [
2950 MockFile('some/java/problematic/diskread.java',
2951 ['StrictMode.allowThreadDiskReads();']),
2952 MockFile('some/java/problematic/diskwrite.java',
2953 ['StrictMode.allowThreadDiskWrites();']),
2954 MockFile('some/java/ok/diskwrite.java',
2955 ['StrictModeContext.allowDiskWrites();']),
2956 MockFile('some/java/problematic/waitidleforsync.java',
2957 ['instrumentation.waitForIdleSync();']),
2958 MockFile('some/java/problematic/registerreceiver.java',
2959 ['context.registerReceiver();']),
2960 MockFile('some/java/problematic/property.java',
2961 ['new Property<abc, Integer>;']),
2962 MockFile('some/java/problematic/requestlayout.java',
2963 ['requestLayout();']),
2964 MockFile('some/java/problematic/lastprofile.java',
2965 ['ProfileManager.getLastUsedRegularProfile();']),
2966 MockFile('some/java/problematic/getdrawable1.java',
2967 ['ResourcesCompat.getDrawable();']),
2968 MockFile('some/java/problematic/getdrawable2.java',
2969 ['getResources().getDrawable();']),
Jenna Himawan859865d2025-02-25 22:22:312970 MockFile('some/java/problematic/announceForAccessibility.java',
2971 ['view.announceForAccessibility(accessibilityText);']),
2972 MockFile(
2973 'some/java/problematic/accessibilityTypeAnnouncement.java', [
2974 'accessibilityEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);'
2975 ]),
Sirisha Kavuluru042e4772025-07-03 02:41:092976 MockFile(
Nate Fischerd541ff82025-03-11 21:34:192977 'content/java/problematic/desktopandroid.java', [
Sirisha Kavuluru042e4772025-07-03 02:41:092978 'if (DeviceInfo.isDesktop()) {}'
Nate Fischerd541ff82025-03-11 21:34:192979 ]),
Sirisha Kavuluru67f07b3d2025-07-28 19:16:012980 MockFile(
2981 'content/java/problematic/desktopandroid1.java', [
2982 'if (PackageManager.FEATURE_PC) {}'
2983 ]),
2984 MockFile(
2985 'content/java/problematic/desktopandroid2.java', [
2986 'if (BuildConfig.IS_DESKTOP_ANDROID) {}'
2987 ]),
Daniel Cheng566634ff2024-06-29 14:56:532988 ]
Min Qinbc44383c2023-02-22 17:25:262989
Daniel Cheng566634ff2024-06-29 14:56:532990 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sirisha Kavuluru67f07b3d2025-07-28 19:16:012991 self.assertEqual(14, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:532992 self.assertTrue(
2993 'some/java/problematic/diskread.java' in errors[0].message)
2994 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152995 'some/java/problematic/diskwrite.java' in errors[1].message)
2996 self.assertTrue(all('some/java/ok/diskwrite.java' not in e.message for e in errors))
Daniel Cheng566634ff2024-06-29 14:56:532997 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152998 'some/java/problematic/waitidleforsync.java' in errors[2].message)
Daniel Cheng566634ff2024-06-29 14:56:532999 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153000 'some/java/problematic/registerreceiver.java' in errors[3].message)
Daniel Cheng566634ff2024-06-29 14:56:533001 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153002 'some/java/problematic/property.java' in errors[4].message)
Daniel Cheng566634ff2024-06-29 14:56:533003 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153004 'some/java/problematic/requestlayout.java' in errors[5].message)
Daniel Cheng566634ff2024-06-29 14:56:533005 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153006 'some/java/problematic/lastprofile.java' in errors[6].message)
Daniel Cheng566634ff2024-06-29 14:56:533007 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153008 'some/java/problematic/getdrawable1.java' in errors[7].message)
Daniel Cheng566634ff2024-06-29 14:56:533009 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153010 'some/java/problematic/getdrawable2.java' in errors[8].message)
Jenna Himawan859865d2025-02-25 22:22:313011 self.assertTrue('some/java/problematic/announceForAccessibility.java'
Ben Pastenee79d66112025-04-23 19:46:153012 in errors[9].message)
Jenna Himawan859865d2025-02-25 22:22:313013 self.assertTrue(
3014 'some/java/problematic/accessibilityTypeAnnouncement.java' in
Ben Pastenee79d66112025-04-23 19:46:153015 errors[10].message)
Nate Fischerd541ff82025-03-11 21:34:193016 self.assertTrue(
3017 'content/java/problematic/desktopandroid.java' in
Ben Pastenee79d66112025-04-23 19:46:153018 errors[11].message)
Sirisha Kavuluru67f07b3d2025-07-28 19:16:013019 self.assertTrue(
3020 'content/java/problematic/desktopandroid1.java' in
3021 errors[12].message)
3022 self.assertTrue(
3023 'content/java/problematic/desktopandroid2.java' in
3024 errors[13].message)
Jenna Himawan859865d2025-02-25 22:22:313025
Peter Kasting94a56c42019-10-25 21:54:043026
Daniel Cheng566634ff2024-06-29 14:56:533027 def testBannedCppFunctions(self):
3028 input_api = MockInputApi()
3029 input_api.files = [
3030 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
3031 MockFile('third_party/blink/problematic/file.cc',
3032 ['GetInterfaceProvider()']),
3033 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
Daniel Cheng566634ff2024-06-29 14:56:533034 MockFile('some/cpp/nocheck/file.cc',
3035 ['using namespace std; // nocheck']),
3036 MockFile('some/cpp/comment/file.cc',
3037 [' // A comment about `using namespace std;`']),
Peter Kasting13607932025-04-10 22:52:383038 MockFile('some/cpp/problematic/file2.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533039 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3040 ]),
Peter Kasting13607932025-04-10 22:52:383041 MockFile('some/cpp/problematic/file3.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533042 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3043 ]),
Peter Kasting13607932025-04-10 22:52:383044 MockFile('some/cpp/problematic/file4.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533045 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3046 ]),
Daniel Cheng70a35272025-05-06 16:41:343047 MockFile(
3048 'allowed_ranges_usage.cc',
3049 [
3050 'std::ranges::begin(vec);',
Michael Tang626d8982025-05-08 23:24:293051 'std::ranges::subrange(first, last);',
Daniel Cheng70a35272025-05-06 16:41:343052 # std::ranges::view is a concept and allowed, but the views
3053 # library itself is not (see below)
3054 'static_assert(std::ranges::view<SomeType>);'
3055 ]),
3056 MockFile(
3057 'banned_ranges_usage.cc',
3058 [
Michael Tang626d8982025-05-08 23:24:293059 'std::ranges::borrowed_subrange_t(subrange);',
Daniel Cheng70a35272025-05-06 16:41:343060 # Edge case: make sure std::ranges::views is disallowed,
3061 # even though std::ranges::view is allowed.
3062 'std::ranges::views::take(first, count);'
3063 ]),
Daniel Cheng89719222024-07-04 04:59:293064 MockFile('views_usage.cc', ['std::views::all(vec)']),
Daniel Cheng70a35272025-05-06 16:41:343065 MockFile('content/desktop_android.cc', [
3066 '// some first line',
3067 '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
3068 '// some third line',
3069 ]),
Daniel Cheng566634ff2024-06-29 14:56:533070 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163071
Daniel Cheng566634ff2024-06-29 14:56:533072 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043073
Ben Pastenee79d66112025-04-23 19:46:153074 # Each entry in results corresponds to a BanRule with a violation, in
3075 # the order they were encountered.
Daniel Cheng70a35272025-05-06 16:41:343076 self.assertEqual(9, len(results))
Ben Pastenee79d66112025-04-23 19:46:153077 self.assertTrue('some/cpp/problematic/file.cc' in results[0].message)
Daniel Cheng566634ff2024-06-29 14:56:533078 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153079 'third_party/blink/problematic/file.cc' in results[1].message)
3080 self.assertTrue(all('some/cpp/ok/file.cc' not in r.message for r in results))
3081 self.assertTrue('some/cpp/problematic/file2.cc' in results[2].message)
3082 self.assertTrue('some/cpp/problematic/file3.cc' in results[3].message)
3083 self.assertTrue('some/cpp/problematic/file4.cc' in results[4].message)
3084 self.assertTrue(all('some/cpp/nocheck/file.cc' not in r.message for r in results))
3085 self.assertTrue(all('some/cpp/comment/file.cc' not in r.message for r in results))
3086 self.assertTrue(all('allowed_ranges_usage.cc' not in r.message for r in results))
3087 self.assertTrue('banned_ranges_usage.cc' in results[5].message)
Daniel Cheng70a35272025-05-06 16:41:343088 self.assertTrue('banned_ranges_usage.cc' in results[6].message)
3089 self.assertTrue('views_usage.cc' in results[7].message)
3090 self.assertTrue('content/desktop_android.cc' in results[8].message)
Ben Pastenee79d66112025-04-23 19:46:153091
3092 # Check ResultLocation data. Line nums start at 1.
Daniel Cheng70a35272025-05-06 16:41:343093 self.assertEqual(results[8].locations[0].file_path,
3094 'content/desktop_android.cc')
3095 self.assertEqual(results[8].locations[0].start_line, 2)
3096 self.assertEqual(results[8].locations[0].end_line, 2)
Daniel Cheng192683f2022-11-01 20:52:443097
Daniel Cheng566634ff2024-06-29 14:56:533098 def testBannedCppRandomFunctions(self):
3099 banned_rngs = [
3100 'absl::BitGen',
3101 'absl::InsecureBitGen',
3102 'std::linear_congruential_engine',
3103 'std::mersenne_twister_engine',
3104 'std::subtract_with_carry_engine',
3105 'std::discard_block_engine',
3106 'std::independent_bits_engine',
3107 'std::shuffle_order_engine',
3108 'std::minstd_rand0',
3109 'std::minstd_rand',
3110 'std::mt19937',
3111 'std::mt19937_64',
3112 'std::ranlux24_base',
3113 'std::ranlux48_base',
3114 'std::ranlux24',
3115 'std::ranlux48',
3116 'std::knuth_b',
3117 'std::default_random_engine',
3118 'std::random_device',
3119 ]
3120 for banned_rng in banned_rngs:
3121 input_api = MockInputApi()
3122 input_api.files = [
3123 MockFile('some/cpp/problematic/file.cc',
3124 [f'{banned_rng} engine;']),
3125 MockFile('third_party/blink/problematic/file.cc',
3126 [f'{banned_rng} engine;']),
3127 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3128 ]
3129 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3130 MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153131 self.assertEqual(2, len(results), banned_rng)
Daniel Cheng566634ff2024-06-29 14:56:533132 self.assertTrue(
3133 'some/cpp/problematic/file.cc' in results[0].message,
3134 banned_rng)
3135 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153136 'third_party/blink/problematic/file.cc' in results[1].message,
Daniel Cheng566634ff2024-06-29 14:56:533137 banned_rng)
Ben Pastenee79d66112025-04-23 19:46:153138 self.assertTrue(all('third_party/ok/file.cc' not in r.message for r in results))
Sylvain Defresnea8b73d252018-02-28 15:45:543139
Daniel Cheng566634ff2024-06-29 14:56:533140 def testBannedIosObjcFunctions(self):
3141 input_api = MockInputApi()
3142 input_api.files = [
3143 MockFile('some/ios/file.mm',
3144 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3145 MockFile('some/mac/file.mm',
3146 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3147 MockFile('another/ios_file.mm',
3148 ['class SomeTest : public testing::Test {};']),
3149 MockFile(
3150 'some/ios/file_egtest.mm',
3151 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3152 MockFile('some/ios/file_unittest.mm', [
3153 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3154 ]),
3155 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543156
Daniel Cheng566634ff2024-06-29 14:56:533157 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153158 self.assertEqual(3, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:533159 self.assertTrue('some/ios/file.mm' in errors[0].message)
Ben Pastenee79d66112025-04-23 19:46:153160 self.assertTrue('another/ios_file.mm' in errors[1].message)
3161 self.assertTrue(all('some/mac/file.mm' not in e.message for e in errors))
3162 self.assertTrue('some/ios/file_egtest.mm' in errors[2].message)
3163 self.assertTrue(all('some/ios/file_unittest.mm' not in e.message for e in errors))
Carlos Knippschildab192b8c2019-04-08 20:02:383164
Daniel Cheng566634ff2024-06-29 14:56:533165 def testBannedMojoFunctions(self):
3166 input_api = MockInputApi()
3167 input_api.files = [
3168 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3169 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3170 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3171 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223172
Daniel Cheng566634ff2024-06-29 14:56:533173 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383174
Ben Pastenee79d66112025-04-23 19:46:153175 # Each entry in results corresponds to a BanRule with a violation, in
3176 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533177 self.assertEqual(1, len(results))
3178 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3179 self.assertTrue(
3180 'third_party/blink/ok/file3.cc' not in results[0].message)
3181 self.assertTrue(
3182 'content/renderer/ok/file3.cc' not in results[0].message)
3183
Justin Lulejian09fd06872025-04-01 22:03:283184 def testBannedMojomPatterns_SharedBuffer(self):
Daniel Cheng566634ff2024-06-29 14:56:533185 input_api = MockInputApi()
3186 input_api.files = [
3187 MockFile(
3188 'bad.mojom',
3189 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3190 MockFile('good.mojom', [
3191 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223192 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3193 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533194 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3195 ]),
3196 ]
Daniel Cheng92c15e32022-03-16 17:48:223197
Daniel Cheng566634ff2024-06-29 14:56:533198 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223199
Ben Pastenee79d66112025-04-23 19:46:153200 # Each entry in results corresponds to a BanRule with a violation, in
3201 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533202 self.assertEqual(1, len(results))
3203 self.assertTrue('bad.mojom' in results[0].message)
3204 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223205
Justin Lulejian09fd06872025-04-01 22:03:283206 def testBannedMojomPatterns_ExtensionId(self):
3207 input_api = MockInputApi()
3208 input_api.files = [
3209 # Pattern tests.
3210 MockFile('extensions/bad.mojom', ['string extension_id']),
3211 MockFile('extensions/bad_struct.mojom',
3212 ['struct Bad {', ' string extension_id;', '};']),
3213 MockFile('extensions/good.mojom', ['ExtensionId extension_id']),
3214 MockFile('extensions/good_struct.mojom',
3215 ['struct Bad {', ' ExtensionId extension_id;', '};']),
3216
3217 # Path exclusion tests.
3218 MockFile('some/included/extensions/path/bad_extension_id.mojom',
3219 ['string extension_id']),
3220 MockFile('some/excluded/path/bad_extension_id.mojom',
3221 ['string extension_id']),
3222 ]
3223
Ben Pastenee79d66112025-04-23 19:46:153224 # Each entry in results corresponds to a BanRule with a violation, in
3225 # the order they were encountered.
Justin Lulejian09fd06872025-04-01 22:03:283226 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3227
Ben Pastenee79d66112025-04-23 19:46:153228 self.assertEqual(3, len(results))
Justin Lulejian09fd06872025-04-01 22:03:283229
3230 # Pattern test assertions.
3231 self.assertTrue('bad.mojom' in results[0].message)
Ben Pastenee79d66112025-04-23 19:46:153232 self.assertTrue('bad_struct.mojom' in results[1].message)
3233 self.assertTrue(all('good.mojom' not in r.message for r in results))
3234 self.assertTrue(all('good_struct.mojom' not in r.message for r in results))
Justin Lulejian09fd06872025-04-01 22:03:283235
3236 # Path exclusion assertions.
3237 self.assertTrue('some/included/extensions/path/bad_extension_id.mojom'
Ben Pastenee79d66112025-04-23 19:46:153238 in results[2].message)
3239 self.assertTrue(all('some/excluded/path/bad_extension_id.mojom' not in r.message for r in results))
3240
Justin Lulejian09fd06872025-04-01 22:03:283241
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273242class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243243
Daniel Cheng566634ff2024-06-29 14:56:533244 def testTruePositives(self):
3245 mock_input_api = MockInputApi()
3246 mock_input_api.files = [
3247 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3248 MockFile('some/path/foo.mm', ['FooForTesting();']),
3249 MockFile('some/path/foo.cxx', ['FooForTests();']),
3250 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3251 ]
Vaclav Brozekf01ed502018-03-16 19:38:243252
Daniel Cheng566634ff2024-06-29 14:56:533253 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3254 mock_input_api, MockOutputApi())
3255 self.assertEqual(1, len(results))
3256 self.assertEqual(4, len(results[0].items))
3257 self.assertTrue('foo.cc' in results[0].items[0])
3258 self.assertTrue('foo.mm' in results[0].items[1])
3259 self.assertTrue('foo.cxx' in results[0].items[2])
3260 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243261
Daniel Cheng566634ff2024-06-29 14:56:533262 def testFalsePositives(self):
3263 mock_input_api = MockInputApi()
3264 mock_input_api.files = [
3265 MockFile('some/path/foo.h', ['foo_for_testing();']),
3266 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3267 MockFile('some/path/foo.cc', ['::FooForTests();']),
3268 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3269 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3270 ]
Vaclav Brozekf01ed502018-03-16 19:38:243271
Daniel Cheng566634ff2024-06-29 14:56:533272 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3273 mock_input_api, MockOutputApi())
3274 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133275
Daniel Cheng566634ff2024-06-29 14:56:533276 def testAllowedFiles(self):
3277 mock_input_api = MockInputApi()
3278 mock_input_api.files = [
3279 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3280 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3281 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3282 ]
3283
3284 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3285 mock_input_api, MockOutputApi())
3286 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133287
Vaclav Brozekf01ed502018-03-16 19:38:243288
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273289class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233290
Daniel Cheng566634ff2024-06-29 14:56:533291 def testTruePositives(self):
3292 mock_input_api = MockInputApi()
3293 mock_input_api.files = [
3294 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3295 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3296 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3297 MockFile('dir/java/src/mult.java', [
3298 'int x = SomethingLongHere()',
3299 ' * SomethingLongHereForTesting();'
3300 ])
3301 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233302
Daniel Cheng566634ff2024-06-29 14:56:533303 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3304 mock_input_api, MockOutputApi())
3305 self.assertEqual(1, len(results))
3306 self.assertEqual(4, len(results[0].items))
3307 self.assertTrue('foo.java' in results[0].items[0])
3308 self.assertTrue('bar.java' in results[0].items[1])
3309 self.assertTrue('baz.java' in results[0].items[2])
3310 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233311
Daniel Cheng566634ff2024-06-29 14:56:533312 def testFalsePositives(self):
3313 mock_input_api = MockInputApi()
3314 mock_input_api.files = [
3315 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3316 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3317 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3318 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3319 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3320 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3321 MockFile('dir/java/src/bar5.java', [
3322 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3323 ]),
3324 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3325 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3326 MockFile('dir/junit/src/javadoc.java',
3327 ['/** Use FooForTest(); to obtain foo in tests.'
3328 ' */']),
3329 MockFile(
3330 'dir/junit/src/javadoc2.java',
3331 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3332 ' */']),
3333 MockFile('dir/java/src/bar6.java',
3334 ['FooForTesting(); // IN-TEST']),
3335 ]
3336
3337 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3338 mock_input_api, MockOutputApi())
3339 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233340
3341
Mohamed Heikald048240a2019-11-12 16:57:373342class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373343
Daniel Cheng566634ff2024-06-29 14:56:533344 def testTruePositives(self):
3345 mock_input_api = MockInputApi()
3346 mock_input_api.files = [
3347 MockFile('dir/android/res/drawable/foo.png', []),
3348 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3349 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3350 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3351 ]
Mohamed Heikald048240a2019-11-12 16:57:373352
Daniel Cheng566634ff2024-06-29 14:56:533353 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3354 MockOutputApi())
3355 self.assertEqual(1, len(results))
3356 self.assertEqual(4, len(results[0].items))
3357 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3358 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3359 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3360 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373361
Daniel Cheng566634ff2024-06-29 14:56:533362 def testFalsePositives(self):
3363 mock_input_api = MockInputApi()
3364 mock_input_api.files = [
3365 MockFile('dir/pngs/README.md', []),
3366 MockFile('java/test/res/drawable/foo.png', []),
3367 MockFile('third_party/blink/foo.png', []),
3368 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3369 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3370 ]
3371
3372 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3373 MockOutputApi())
3374 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373375
Evan Stade7cd4a2c2022-08-04 23:37:253376class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253377
Daniel Cheng566634ff2024-06-29 14:56:533378 def test(self):
3379 mock_input_api = MockInputApi()
3380 mock_input_api.files = [
3381 MockFile('components/vector_icons/google_jetpack.icon', []),
3382 MockFile('components/vector_icons/generic_jetpack.icon', []),
3383 ]
3384
3385 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3386 mock_input_api, MockOutputApi())
3387 self.assertEqual(1, len(results))
3388 self.assertEqual(1, len(results[0].items))
3389 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373390
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273391class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053392
Daniel Cheng566634ff2024-06-29 14:56:533393 def testTruePositivesNullptr(self):
3394 mock_input_api = MockInputApi()
3395 mock_input_api.files = [
3396 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3397 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3398 ]
Vaclav Brozek851d9602018-04-04 16:13:053399
Daniel Cheng566634ff2024-06-29 14:56:533400 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3401 MockOutputApi())
3402 self.assertEqual(1, len(results))
3403 self.assertTrue('nullptr' in results[0].message)
3404 self.assertEqual(2, len(results[0].items))
3405 self.assertTrue('baz.cc' in results[0].items[0])
3406 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243407
Daniel Cheng566634ff2024-06-29 14:56:533408 def testTruePositivesConstructor(self):
3409 mock_input_api = MockInputApi()
3410 mock_input_api.files = [
3411 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3412 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3413 MockFile('dir/mult.cc', [
3414 'return',
3415 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3416 ]),
3417 MockFile('dir/mult2.cc', [
3418 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3419 ' std::unique_ptr<T>(foo);'
3420 ]),
3421 MockFile('dir/mult3.cc', [
3422 'bar = std::unique_ptr<T>(',
3423 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3424 ]),
3425 MockFile('dir/multi_arg.cc', [
3426 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3427 ]),
3428 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243429
Daniel Cheng566634ff2024-06-29 14:56:533430 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3431 MockOutputApi())
3432 self.assertEqual(1, len(results))
3433 self.assertTrue('std::make_unique' in results[0].message)
3434 self.assertEqual(6, len(results[0].items))
3435 self.assertTrue('foo.cc' in results[0].items[0])
3436 self.assertTrue('bar.mm' in results[0].items[1])
3437 self.assertTrue('mult.cc' in results[0].items[2])
3438 self.assertTrue('mult2.cc' in results[0].items[3])
3439 self.assertTrue('mult3.cc' in results[0].items[4])
3440 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533441
Daniel Cheng566634ff2024-06-29 14:56:533442 def testFalsePositives(self):
3443 mock_input_api = MockInputApi()
3444 mock_input_api.files = [
3445 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3446 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3447 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3448 MockFile('dir/baz.cc',
3449 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3450 MockFile('dir/baz2.cc',
3451 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3452 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3453 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3454 # Changed line is inside a multiline template block.
3455 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3456 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243457
Daniel Cheng566634ff2024-06-29 14:56:533458 # Two-argument invocation of std::unique_ptr is exempt because there is
3459 # no equivalent using std::make_unique.
3460 MockFile('dir/multi_arg.cc',
3461 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3462 ]
3463
3464 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3465 MockOutputApi())
3466 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243467
Danil Chapovalov3518f362018-08-11 16:13:433468class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433469
Daniel Cheng566634ff2024-06-29 14:56:533470 def testBlocksDirectIncludes(self):
3471 mock_input_api = MockInputApi()
3472 mock_input_api.files = [
3473 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3474 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3475 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3476 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3477 ]
3478 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3479 MockOutputApi())
3480 self.assertEqual(1, len(results))
3481 self.assertEqual(4, len(results[0].items))
3482 self.assertTrue('StrCat' in results[0].message)
3483 self.assertTrue('foo_win.cc' in results[0].items[0])
3484 self.assertTrue('bar.h' in results[0].items[1])
3485 self.assertTrue('baz.h' in results[0].items[2])
3486 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433487
Daniel Cheng566634ff2024-06-29 14:56:533488 def testAllowsToIncludeWrapper(self):
3489 mock_input_api = MockInputApi()
3490 mock_input_api.files = [
3491 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3492 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3493 ]
3494 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3495 MockOutputApi())
3496 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323497
Daniel Cheng566634ff2024-06-29 14:56:533498 def testAllowsToCreateWrapper(self):
3499 mock_input_api = MockInputApi()
3500 mock_input_api.files = [
3501 MockFile('base/win/shlwapi.h', [
3502 '#include <shlwapi.h>',
3503 '#include "base/win/windows_defines.inc"'
3504 ]),
3505 ]
3506 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3507 MockOutputApi())
3508 self.assertEqual(0, len(results))
3509
3510 def testIgnoresNonImplAndHeaders(self):
3511 mock_input_api = MockInputApi()
3512 mock_input_api.files = [
3513 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3514 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3515 ]
3516 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3517 MockOutputApi())
3518 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243519
Mustafa Emre Acer51f2f742020-03-09 19:41:123520
Rainhard Findlingfc31844c52020-05-15 09:58:263521class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533522 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263523
Daniel Cheng566634ff2024-06-29 14:56:533524 # An empty grd file.
3525 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143526 <grit latest_public_release="1" current_release="1">
3527 <release seq="1">
3528 <messages></messages>
3529 </release>
3530 </grit>
3531 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533532 # A grd file with a single message.
3533 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143534 <grit latest_public_release="1" current_release="1">
3535 <release seq="1">
3536 <messages>
3537 <message name="IDS_TEST1">
3538 Test string 1
3539 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483540 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3541 translateable="false">
3542 Non translateable message 1, should be ignored
3543 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393544 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343545 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393546 Accessibility label 1, should be ignored
3547 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143548 </messages>
3549 </release>
3550 </grit>
3551 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533552 # A grd file with two messages.
3553 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143554 <grit latest_public_release="1" current_release="1">
3555 <release seq="1">
3556 <messages>
3557 <message name="IDS_TEST1">
3558 Test string 1
3559 </message>
3560 <message name="IDS_TEST2">
3561 Test string 2
3562 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483563 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3564 translateable="false">
3565 Non translateable message 2, should be ignored
3566 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143567 </messages>
3568 </release>
3569 </grit>
3570 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533571 # A grd file with one ICU syntax message without syntax errors.
3572 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263573 <grit latest_public_release="1" current_release="1">
3574 <release seq="1">
3575 <messages>
3576 <message name="IDS_TEST1">
3577 {NUM, plural,
3578 =1 {Test text for numeric one}
3579 other {Test text for plural with {NUM} as number}}
3580 </message>
3581 </messages>
3582 </release>
3583 </grit>
3584 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533585 # A grd file with one ICU syntax message without syntax errors.
3586 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263587 <grit latest_public_release="1" current_release="1">
3588 <release seq="1">
3589 <messages>
3590 <message name="IDS_TEST1">
3591 {NUM, plural,
3592 =1 {Different test text for numeric one}
3593 other {Different test text for plural with {NUM} as number}}
3594 </message>
3595 </messages>
3596 </release>
3597 </grit>
3598 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533599 # A grd file with multiple ICU syntax messages without syntax errors.
3600 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323601 <grit latest_public_release="1" current_release="1">
3602 <release seq="1">
3603 <messages>
3604 <message name="IDS_TEST1">
3605 {NUM, plural,
3606 =0 {New test text for numeric zero}
3607 =1 {Different test text for numeric one}
3608 =2 {New test text for numeric two}
3609 =3 {New test text for numeric three}
3610 other {Different test text for plural with {NUM} as number}}
3611 </message>
3612 </messages>
3613 </release>
3614 </grit>
3615 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533616 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3617 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263618 <grit latest_public_release="1" current_release="1">
3619 <release seq="1">
3620 <messages>
3621 <message name="IDS_TEST1">
3622 {NUM, plural
3623 =1 {Test text for numeric one}
3624 other {Test text for plural with {NUM} as number}}
3625 </message>
3626 </messages>
3627 </release>
3628 </grit>
3629 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143630
Daniel Cheng566634ff2024-06-29 14:56:533631 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3632 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583633
Daniel Cheng566634ff2024-06-29 14:56:533634 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3635 '<grit-part>', '<message name="IDS_PART_TEST1">',
3636 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583637
Daniel Cheng566634ff2024-06-29 14:56:533638 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3639 '<grit-part>', '<message name="IDS_PART_TEST1">',
3640 'Part string 1', '</message>',
3641 '<message name="IDS_PART_TEST2">', 'Part string 2',
3642 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583643
Daniel Cheng566634ff2024-06-29 14:56:533644 NEW_GRDP_CONTENTS3 = (
3645 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093646 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533647 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093648
Daniel Cheng566634ff2024-06-29 14:56:533649 NEW_GRDP_CONTENTS4 = (
3650 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093651 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533652 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093653
Daniel Cheng566634ff2024-06-29 14:56:533654 NEW_GRDP_CONTENTS5 = (
3655 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353656 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533657 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353658
Daniel Cheng566634ff2024-06-29 14:56:533659 NEW_GRDP_CONTENTS6 = (
3660 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353661 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533662 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353663
Daniel Cheng566634ff2024-06-29 14:56:533664 # A grdp file with one ICU syntax message without syntax errors.
3665 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3666 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3667 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3668 '=1 {Test text for numeric one}',
3669 'other {Test text for plural with {NUM} as number}}', '</message>',
3670 '</grit-part>')
3671 # A grdp file with one ICU syntax message without syntax errors.
3672 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3673 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3674 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3675 '=1 {Different test text for numeric one}',
3676 'other {Different test text for plural with {NUM} as number}}',
3677 '</message>', '</grit-part>')
3678 # A grdp file with multiple ICU syntax messages without syntax errors.
3679 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3680 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3681 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3682 '=0 {New test text for numeric zero}',
3683 '=1 {Different test text for numeric one}',
3684 '=2 {New test text for numeric two}',
3685 '=3 {New test text for numeric three}',
3686 'other {Different test text for plural with {NUM} as number}}',
3687 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263688
Daniel Cheng566634ff2024-06-29 14:56:533689 # A grdp file with one ICU syntax message with syntax errors (superfluous
3690 # space).
3691 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3692 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3693 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3694 '= 1 {Test text for numeric one}',
3695 'other {Test text for plural with {NUM} as number}}', '</message>',
3696 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263697
Daniel Cheng566634ff2024-06-29 14:56:533698 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3699 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3700 'changelist. Run '
3701 'tools/translate/upload_screenshots.py to '
3702 'upload them instead:')
3703 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3704 'To ensure the best translations, take '
3705 'screenshots of the relevant UI '
3706 '(https://g.co/chrome/translation) and add '
3707 'these files to your changelist:')
3708 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3709 'files. Remove:')
3710 ICU_SYNTAX_ERROR_MESSAGE = (
3711 'ICU syntax errors were found in the following '
3712 'strings (problems or feedback? Contact '
3713 '[email protected]):')
3714 SHA1_FORMAT_MESSAGE = (
3715 'The following files do not seem to contain valid sha1 '
3716 'hashes. Make sure they contain hashes created by '
3717 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143718
Daniel Cheng566634ff2024-06-29 14:56:533719 def makeInputApi(self, files):
3720 input_api = MockInputApi()
Andrew Grieve713b89b2024-10-15 20:20:083721 input_api.InitFiles(files)
Daniel Cheng566634ff2024-06-29 14:56:533722 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143723
Daniel Cheng566634ff2024-06-29 14:56:533724 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583725
Daniel Cheng566634ff2024-06-29 14:56:533726 def testNoScreenshots(self):
3727 # No new strings (file contents same). Should not warn.
3728 input_api = self.makeInputApi([
3729 MockAffectedFile('test.grd',
3730 self.NEW_GRD_CONTENTS1,
3731 self.NEW_GRD_CONTENTS1,
3732 action='M'),
3733 MockAffectedFile('part.grdp',
3734 self.NEW_GRDP_CONTENTS1,
3735 self.NEW_GRDP_CONTENTS1,
3736 action='M')
3737 ])
3738 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3739 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343740
Daniel Cheng566634ff2024-06-29 14:56:533741 # Add two new strings. Should have two warnings.
3742 input_api = self.makeInputApi([
3743 MockAffectedFile('test.grd',
3744 self.NEW_GRD_CONTENTS2,
3745 self.NEW_GRD_CONTENTS1,
3746 action='M'),
3747 MockAffectedFile('part.grdp',
3748 self.NEW_GRDP_CONTENTS2,
3749 self.NEW_GRDP_CONTENTS1,
3750 action='M')
3751 ])
3752 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3753 self.assertEqual(1, len(warnings))
3754 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3755 self.assertEqual('error', warnings[0].type)
3756 self.assertEqual([
3757 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3758 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3759 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213760
Daniel Cheng566634ff2024-06-29 14:56:533761 # Add four new strings. Should have four warnings.
3762 input_api = self.makeInputApi([
3763 MockAffectedFile('test.grd',
3764 self.NEW_GRD_CONTENTS2,
3765 self.OLD_GRD_CONTENTS,
3766 action='M'),
3767 MockAffectedFile('part.grdp',
3768 self.NEW_GRDP_CONTENTS2,
3769 self.OLD_GRDP_CONTENTS,
3770 action='M')
3771 ])
3772 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3773 self.assertEqual(1, len(warnings))
3774 self.assertEqual('error', warnings[0].type)
3775 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3776 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583777 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583778 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303779 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303780 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533781 ], warnings[0].items)
3782
3783 def testModifiedMessageDescription(self):
3784 # CL modified a message description for a message that does not yet have a
3785 # screenshot. Should not warn.
3786 input_api = self.makeInputApi([
3787 MockAffectedFile('part.grdp',
3788 self.NEW_GRDP_CONTENTS3,
3789 self.NEW_GRDP_CONTENTS4,
3790 action='M')
3791 ])
3792 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3793 self.assertEqual(0, len(warnings))
3794
3795 # CL modified a message description for a message that already has a
3796 # screenshot. Should not warn.
3797 input_api = self.makeInputApi([
3798 MockAffectedFile('part.grdp',
3799 self.NEW_GRDP_CONTENTS3,
3800 self.NEW_GRDP_CONTENTS4,
3801 action='M'),
3802 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3803 self.VALID_SHA1,
3804 action='A')
3805 ])
3806 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3807 self.assertEqual(0, len(warnings))
3808
3809 def testModifiedMessageMeaning(self):
3810 # CL modified a message meaning for a message that does not yet have a
3811 # screenshot. Should warn.
3812 input_api = self.makeInputApi([
3813 MockAffectedFile('part.grdp',
3814 self.NEW_GRDP_CONTENTS5,
3815 self.NEW_GRDP_CONTENTS6,
3816 action='M')
3817 ])
3818 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3819 self.assertEqual(1, len(warnings))
3820
3821 # CL modified a message meaning for a message that already has a
3822 # screenshot. Should not warn.
3823 input_api = self.makeInputApi([
3824 MockAffectedFile('part.grdp',
3825 self.NEW_GRDP_CONTENTS5,
3826 self.NEW_GRDP_CONTENTS6,
3827 action='M'),
3828 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3829 self.VALID_SHA1,
3830 action='A')
3831 ])
3832 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3833 self.assertEqual(0, len(warnings))
3834
3835 def testModifiedIntroducedInvalidSha1(self):
3836 # CL modified a message and the sha1 file changed to invalid
3837 input_api = self.makeInputApi([
3838 MockAffectedFile('part.grdp',
3839 self.NEW_GRDP_CONTENTS5,
3840 self.NEW_GRDP_CONTENTS6,
3841 action='M'),
3842 MockAffectedFile(os.path.join('part_grdp',
3843 'IDS_PART_TEST1.png.sha1'),
3844 ('some invalid sha1', ),
3845 self.VALID_SHA1,
3846 action='M')
3847 ])
3848 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3849 self.assertEqual(1, len(warnings))
3850
3851 def testPngAddedSha1NotAdded(self):
3852 # CL added one new message in a grd file and added the png file associated
3853 # with it, but did not add the corresponding sha1 file. This should warn
3854 # twice:
3855 # - Once for the added png file (because we don't want developers to upload
3856 # actual images)
3857 # - Once for the missing .sha1 file
3858 input_api = self.makeInputApi([
3859 MockAffectedFile('test.grd',
3860 self.NEW_GRD_CONTENTS1,
3861 self.OLD_GRD_CONTENTS,
3862 action='M'),
3863 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3864 'binary',
3865 action='A')
3866 ])
3867 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3868 self.assertEqual(2, len(warnings))
3869 self.assertEqual('error', warnings[0].type)
3870 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3871 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3872 warnings[0].items)
3873 self.assertEqual('error', warnings[1].type)
3874 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3875 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3876 warnings[1].items)
3877
3878 # CL added two messages (one in grd, one in grdp) and added the png files
3879 # associated with the messages, but did not add the corresponding sha1
3880 # files. This should warn twice:
3881 # - Once for the added png files (because we don't want developers to upload
3882 # actual images)
3883 # - Once for the missing .sha1 files
3884 input_api = self.makeInputApi([
3885 # Modified files:
3886 MockAffectedFile('test.grd',
3887 self.NEW_GRD_CONTENTS1,
3888 self.OLD_GRD_CONTENTS,
3889 action='M'),
3890 MockAffectedFile('part.grdp',
3891 self.NEW_GRDP_CONTENTS1,
3892 self.OLD_GRDP_CONTENTS,
3893 action='M'),
3894 # Added files:
3895 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3896 'binary',
3897 action='A'),
3898 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3899 'binary',
3900 action='A')
3901 ])
3902 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3903 self.assertEqual(2, len(warnings))
3904 self.assertEqual('error', warnings[0].type)
3905 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3906 self.assertEqual([
3907 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3908 os.path.join('test_grd', 'IDS_TEST1.png')
3909 ], warnings[0].items)
3910 self.assertEqual('error', warnings[0].type)
3911 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3912 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303913 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533914 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3915 ], warnings[1].items)
3916
3917 def testScreenshotsWithSha1(self):
3918 # CL added four messages (two each in a grd and grdp) and their
3919 # corresponding .sha1 files. No warnings.
3920 input_api = self.makeInputApi([
3921 # Modified files:
3922 MockAffectedFile('test.grd',
3923 self.NEW_GRD_CONTENTS2,
3924 self.OLD_GRD_CONTENTS,
3925 action='M'),
3926 MockAffectedFile('part.grdp',
3927 self.NEW_GRDP_CONTENTS2,
3928 self.OLD_GRDP_CONTENTS,
3929 action='M'),
3930 # Added files:
3931 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3932 self.VALID_SHA1,
3933 action='A'),
3934 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3935 ('0000000000000000000000000000000000000000', ''),
3936 action='A'),
3937 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3938 self.VALID_SHA1,
3939 action='A'),
3940 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3941 self.VALID_SHA1,
3942 action='A'),
3943 ])
3944 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3945 self.assertEqual([], warnings)
3946
3947 def testScreenshotsWithInvalidSha1(self):
3948 input_api = self.makeInputApi([
3949 # Modified files:
3950 MockAffectedFile('test.grd',
3951 self.NEW_GRD_CONTENTS2,
3952 self.OLD_GRD_CONTENTS,
3953 action='M'),
3954 MockAffectedFile('part.grdp',
3955 self.NEW_GRDP_CONTENTS2,
3956 self.OLD_GRDP_CONTENTS,
3957 action='M'),
3958 # Added files:
3959 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3960 self.VALID_SHA1,
3961 action='A'),
3962 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3963 ('‰PNG', 'test'),
3964 action='A'),
3965 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3966 self.VALID_SHA1,
3967 action='A'),
3968 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3969 self.VALID_SHA1,
3970 action='A'),
3971 ])
3972 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3973 self.assertEqual(1, len(warnings))
3974 self.assertEqual('error', warnings[0].type)
3975 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
3976 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3977 warnings[0].items)
3978
3979 def testScreenshotsRemovedWithSha1(self):
3980 # Replace new contents with old contents in grd and grp files, removing
3981 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3982 # Should warn to remove the sha1 files associated with these strings.
3983 input_api = self.makeInputApi([
3984 # Modified files:
3985 MockAffectedFile(
3986 'test.grd',
3987 self.OLD_GRD_CONTENTS, # new_contents
3988 self.NEW_GRD_CONTENTS2, # old_contents
3989 action='M'),
3990 MockAffectedFile(
3991 'part.grdp',
3992 self.OLD_GRDP_CONTENTS, # new_contents
3993 self.NEW_GRDP_CONTENTS2, # old_contents
3994 action='M'),
3995 # Unmodified files:
3996 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3997 self.VALID_SHA1, ''),
3998 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3999 self.VALID_SHA1, ''),
4000 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4001 self.VALID_SHA1, ''),
4002 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4003 self.VALID_SHA1, '')
4004 ])
4005 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4006 self.assertEqual(1, len(warnings))
4007 self.assertEqual('error', warnings[0].type)
4008 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4009 self.assertEqual([
4010 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:304011 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:014012 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534013 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
4014 ], warnings[0].items)
4015
4016 # Same as above, but this time one of the .sha1 files is also removed.
4017 input_api = self.makeInputApi([
4018 # Modified files:
4019 MockAffectedFile(
4020 'test.grd',
4021 self.OLD_GRD_CONTENTS, # new_contents
4022 self.NEW_GRD_CONTENTS2, # old_contents
4023 action='M'),
4024 MockAffectedFile(
4025 'part.grdp',
4026 self.OLD_GRDP_CONTENTS, # new_contents
4027 self.NEW_GRDP_CONTENTS2, # old_contents
4028 action='M'),
4029 # Unmodified files:
4030 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4031 self.VALID_SHA1, ''),
4032 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4033 self.VALID_SHA1, ''),
4034 # Deleted files:
4035 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4036 '',
4037 'old_contents',
4038 action='D'),
4039 MockAffectedFile(os.path.join('part_grdp',
4040 'IDS_PART_TEST2.png.sha1'),
4041 '',
4042 'old_contents',
4043 action='D')
4044 ])
4045 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4046 self.assertEqual(1, len(warnings))
4047 self.assertEqual('error', warnings[0].type)
4048 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4049 self.assertEqual([
meacerff8a9b62019-12-10 19:43:584050 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534051 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
4052 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144053
Daniel Cheng566634ff2024-06-29 14:56:534054 # Remove all sha1 files. There should be no warnings.
4055 input_api = self.makeInputApi([
4056 # Modified files:
4057 MockAffectedFile('test.grd',
4058 self.OLD_GRD_CONTENTS,
4059 self.NEW_GRD_CONTENTS2,
4060 action='M'),
4061 MockAffectedFile('part.grdp',
4062 self.OLD_GRDP_CONTENTS,
4063 self.NEW_GRDP_CONTENTS2,
4064 action='M'),
4065 # Deleted files:
4066 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4067 self.VALID_SHA1,
4068 action='D'),
4069 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4070 self.VALID_SHA1,
4071 action='D'),
4072 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4073 self.VALID_SHA1,
4074 action='D'),
4075 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4076 self.VALID_SHA1,
4077 action='D')
4078 ])
4079 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4080 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:264081
Daniel Cheng566634ff2024-06-29 14:56:534082 def testIcuSyntax(self):
4083 # Add valid ICU syntax string. Should not raise an error.
4084 input_api = self.makeInputApi([
4085 MockAffectedFile('test.grd',
4086 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4087 self.NEW_GRD_CONTENTS1,
4088 action='M'),
4089 MockAffectedFile('part.grdp',
4090 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4091 self.NEW_GRDP_CONTENTS1,
4092 action='M')
4093 ])
4094 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4095 # We expect no ICU syntax errors.
4096 icu_errors = [
4097 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4098 ]
4099 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264100
Daniel Cheng566634ff2024-06-29 14:56:534101 # Valid changes in ICU syntax. Should not raise an error.
4102 input_api = self.makeInputApi([
4103 MockAffectedFile('test.grd',
4104 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4105 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4106 action='M'),
4107 MockAffectedFile('part.grdp',
4108 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4109 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4110 action='M')
4111 ])
4112 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4113 # We expect no ICU syntax errors.
4114 icu_errors = [
4115 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4116 ]
4117 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324118
Daniel Cheng566634ff2024-06-29 14:56:534119 # Valid changes in ICU syntax. Should not raise an error.
4120 input_api = self.makeInputApi([
4121 MockAffectedFile('test.grd',
4122 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4123 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4124 action='M'),
4125 MockAffectedFile('part.grdp',
4126 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4127 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4128 action='M')
4129 ])
4130 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4131 # We expect no ICU syntax errors.
4132 icu_errors = [
4133 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4134 ]
4135 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264136
Daniel Cheng566634ff2024-06-29 14:56:534137 # Add invalid ICU syntax strings. Should raise two errors.
4138 input_api = self.makeInputApi([
4139 MockAffectedFile('test.grd',
4140 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4141 self.NEW_GRD_CONTENTS1,
4142 action='M'),
4143 MockAffectedFile('part.grdp',
4144 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4145 self.NEW_GRD_CONTENTS1,
4146 action='M')
4147 ])
4148 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4149 # We expect 2 ICU syntax errors.
4150 icu_errors = [
4151 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4152 ]
4153 self.assertEqual(1, len(icu_errors))
4154 self.assertEqual([
4155 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4156 'ICU syntax.',
4157 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4158 ], icu_errors[0].items)
4159
4160 # Change two strings to have ICU syntax errors. Should raise two errors.
4161 input_api = self.makeInputApi([
4162 MockAffectedFile('test.grd',
4163 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4164 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4165 action='M'),
4166 MockAffectedFile('part.grdp',
4167 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4168 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4169 action='M')
4170 ])
4171 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4172 # We expect 2 ICU syntax errors.
4173 icu_errors = [
4174 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4175 ]
4176 self.assertEqual(1, len(icu_errors))
4177 self.assertEqual([
4178 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4179 'ICU syntax.',
4180 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4181 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264182
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144183
Mustafa Emre Acer51f2f742020-03-09 19:41:124184class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534185 ERROR_MESSAGE_FORMAT = (
4186 "Failed to get a list of translatable grd files. "
4187 "This happens when:\n"
4188 " - One of the modified grd or grdp files cannot be parsed or\n"
4189 " - %s is not updated.\n"
4190 "Stack:\n")
4191 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4192 # This lists all .grd files under REPO_ROOT.
4193 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4194 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4195 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4196 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124197
Daniel Cheng566634ff2024-06-29 14:56:534198 # Tests that the presubmit doesn't return when no grd or grdp files are
4199 # modified.
4200 def testExpectationsNoModifiedGrd(self):
4201 input_api = MockInputApi()
4202 input_api.files = [
4203 MockAffectedFile('not_used.txt',
4204 'not used',
4205 'not used',
4206 action='M')
4207 ]
4208 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4209 # under tools/translation/testdata. This is OK because the presubmit won't
4210 # run in the first place since there are no modified grd/grps in input_api.
4211 grd_files = ['doesnt_exist_doesnt_matter.grd']
4212 warnings = PRESUBMIT.CheckTranslationExpectations(
4213 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4214 grd_files)
4215 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124216
Daniel Cheng566634ff2024-06-29 14:56:534217 # Tests that the list of files passed to the presubmit matches the list of
4218 # files in the expectations.
4219 def testExpectationsSuccess(self):
4220 # Mock input file list needs a grd or grdp file in order to run the
4221 # presubmit. The file itself doesn't matter.
4222 input_api = MockInputApi()
4223 input_api.files = [
4224 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4225 ]
4226 # List of all grd files in the repo.
4227 grd_files = [
4228 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4229 ]
4230 warnings = PRESUBMIT.CheckTranslationExpectations(
4231 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4232 grd_files)
4233 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124234
Ben Mason5d4c3242025-04-15 20:28:374235 # Tests that the list of files passed to the presubmit does not
4236 # contain duplicate basenames.
4237 def testExpectationsSuccess(self):
4238 # Mock input file list needs a grd or grdp file in order to run the
4239 # presubmit. The file itself doesn't matter.
4240 input_api = MockInputApi()
4241 input_api.files = [
4242 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4243 ]
4244 # List of all grd files in the repo.
4245 grd_files = [
4246 'dir1/test.grd', 'unlisted.grd', 'not_translated.grd',
4247 'internal.grd', 'dir2/test.grd'
4248 ]
4249 warnings = PRESUBMIT.CheckTranslationExpectations(
4250 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4251 grd_files)
4252 self.assertEqual(1, len(warnings))
4253 self.assertTrue(
4254 ("Multiple string files have the same basename. "
4255 "This will result in missing translations. "
4256 "Files: dir1/test.grd, dir2/test.grd") in warnings[0].message)
4257
Daniel Cheng566634ff2024-06-29 14:56:534258 # Tests that the presubmit warns when a file is listed in expectations, but
4259 # does not actually exist.
4260 def testExpectationsMissingFile(self):
4261 # Mock input file list needs a grd or grdp file in order to run the
4262 # presubmit.
4263 input_api = MockInputApi()
4264 input_api.files = [
4265 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4266 ]
4267 # unlisted.grd is listed under tools/translation/testdata but is not
4268 # included in translation expectations.
4269 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4270 warnings = PRESUBMIT.CheckTranslationExpectations(
4271 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4272 grd_files)
4273 self.assertEqual(1, len(warnings))
4274 self.assertTrue(warnings[0].message.startswith(
4275 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4276 self.assertTrue(
4277 ("test.grd is listed in the translation expectations, "
4278 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124279
Daniel Cheng566634ff2024-06-29 14:56:534280 # Tests that the presubmit warns when a file is not listed in expectations but
4281 # does actually exist.
4282 def testExpectationsUnlistedFile(self):
4283 # Mock input file list needs a grd or grdp file in order to run the
4284 # presubmit.
4285 input_api = MockInputApi()
4286 input_api.files = [
4287 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4288 ]
4289 # unlisted.grd is listed under tools/translation/testdata but is not
4290 # included in translation expectations.
4291 grd_files = [
4292 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4293 ]
4294 warnings = PRESUBMIT.CheckTranslationExpectations(
4295 input_api, MockOutputApi(), self.REPO_ROOT,
4296 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4297 self.assertEqual(1, len(warnings))
4298 self.assertTrue(warnings[0].message.startswith(
4299 self.ERROR_MESSAGE_FORMAT %
4300 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4301 self.assertTrue(("unlisted.grd appears to be translatable "
4302 "(because it contains <file> or <message> elements), "
4303 "but is not listed in the translation expectations."
4304 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124305
Daniel Cheng566634ff2024-06-29 14:56:534306 # Tests that the presubmit warns twice:
4307 # - for a non-existing file listed in expectations
4308 # - for an existing file not listed in expectations
4309 def testMultipleWarnings(self):
4310 # Mock input file list needs a grd or grdp file in order to run the
4311 # presubmit.
4312 input_api = MockInputApi()
4313 input_api.files = [
4314 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4315 ]
4316 # unlisted.grd is listed under tools/translation/testdata but is not
4317 # included in translation expectations.
4318 # test.grd is not listed under tools/translation/testdata but is included
4319 # in translation expectations.
4320 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4321 warnings = PRESUBMIT.CheckTranslationExpectations(
4322 input_api, MockOutputApi(), self.REPO_ROOT,
4323 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4324 self.assertEqual(1, len(warnings))
4325 self.assertTrue(warnings[0].message.startswith(
4326 self.ERROR_MESSAGE_FORMAT %
4327 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4328 self.assertTrue(("unlisted.grd appears to be translatable "
4329 "(because it contains <file> or <message> elements), "
4330 "but is not listed in the translation expectations."
4331 ) in warnings[0].message)
4332 self.assertTrue(
4333 ("test.grd is listed in the translation expectations, "
4334 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124335
4336
Dominic Battre033531052018-09-24 15:45:344337class DISABLETypoInTest(unittest.TestCase):
4338
Daniel Cheng566634ff2024-06-29 14:56:534339 def testPositive(self):
4340 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4341 # where the desire is to disable a test.
4342 tests = [
4343 # Disabled on one platform:
4344 '#if defined(OS_WIN)\n'
4345 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4346 '#else\n'
4347 '#define MAYBE_FoobarTest FoobarTest\n'
4348 '#endif\n',
4349 # Disabled on one platform spread cross lines:
4350 '#if defined(OS_WIN)\n'
4351 '#define MAYBE_FoobarTest \\\n'
4352 ' DISABLE_FoobarTest\n'
4353 '#else\n'
4354 '#define MAYBE_FoobarTest FoobarTest\n'
4355 '#endif\n',
4356 # Disabled on all platforms:
4357 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4358 # Disabled on all platforms but multiple lines
4359 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4360 ]
Dominic Battre033531052018-09-24 15:45:344361
Daniel Cheng566634ff2024-06-29 14:56:534362 for test in tests:
4363 mock_input_api = MockInputApi()
4364 mock_input_api.files = [
4365 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4366 ]
Dominic Battre033531052018-09-24 15:45:344367
Daniel Cheng566634ff2024-06-29 14:56:534368 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4369 mock_input_api, MockOutputApi())
4370 self.assertEqual(
4371 1,
4372 len(results),
4373 msg=('expected len(results) == 1 but got %d in test: %s' %
4374 (len(results), test)))
4375 self.assertTrue(
4376 'foo_unittest.cc' in results[0].message,
4377 msg=(
4378 'expected foo_unittest.cc in message but got %s in test %s'
4379 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344380
Daniel Cheng566634ff2024-06-29 14:56:534381 def testIgnoreNotTestFiles(self):
4382 mock_input_api = MockInputApi()
4383 mock_input_api.files = [
4384 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4385 ]
Dominic Battre033531052018-09-24 15:45:344386
Daniel Cheng566634ff2024-06-29 14:56:534387 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4388 MockOutputApi())
4389 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344390
Daniel Cheng566634ff2024-06-29 14:56:534391 def testIgnoreDeletedFiles(self):
4392 mock_input_api = MockInputApi()
4393 mock_input_api.files = [
4394 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4395 action='D'),
4396 ]
Katie Df13948e2018-09-25 07:33:444397
Daniel Cheng566634ff2024-06-29 14:56:534398 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4399 MockOutputApi())
4400 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344401
Nina Satragnof7660532021-09-20 18:03:354402class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354403
Daniel Cheng566634ff2024-06-29 14:56:534404 def testPositive(self):
4405 test = ('#if defined(HAS_ENERGY)\n'
4406 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4407 '#else\n'
4408 '#define MAYBE_CastExplosion CastExplosion\n'
4409 '#endif\n'
4410 'TEST_F(ArchWizard, CastExplosion) {\n'
4411 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4412 '#define MAYBE_ArchPriest ArchPriest\n'
4413 '#else\n'
4414 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4415 '#endif\n'
4416 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4417 '#if !defined(CRUSADER_IN_PARTY)\n'
4418 '#define MAYBE_Crusader \\\n'
4419 ' DISABLED_Crusader \n'
4420 '#else\n'
4421 '#define MAYBE_Crusader \\\n'
4422 ' Crusader\n'
4423 '#endif\n'
4424 ' TEST_F(\n'
4425 ' Crusader,\n'
4426 ' CastTaunt) { }\n'
4427 '#if defined(LEARNED_BASIC_SKILLS)\n'
4428 '#define MAYBE_CastSteal \\\n'
4429 ' DISABLED_CastSteal \n'
4430 '#else\n'
4431 '#define MAYBE_CastSteal \\\n'
4432 ' CastSteal\n'
4433 '#endif\n'
4434 ' TEST_F(\n'
4435 ' ThiefClass,\n'
4436 ' CastSteal) { }\n')
4437 mock_input_api = MockInputApi()
4438 mock_input_api.files = [
4439 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4440 ]
4441 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4442 mock_input_api, MockOutputApi())
4443 self.assertEqual(4, len(results))
4444 self.assertTrue('CastExplosion' in results[0].message)
4445 self.assertTrue(
4446 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4447 self.assertTrue('ArchPriest' in results[1].message)
4448 self.assertTrue(
4449 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4450 self.assertTrue('Crusader' in results[2].message)
4451 self.assertTrue(
4452 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4453 self.assertTrue('CastSteal' in results[3].message)
4454 self.assertTrue(
4455 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354456
Daniel Cheng566634ff2024-06-29 14:56:534457 def testNegative(self):
4458 test = ('#if defined(HAS_ENERGY)\n'
4459 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4460 '#else\n'
4461 '#define MAYBE_CastExplosion CastExplosion\n'
4462 '#endif\n'
4463 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4464 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4465 '#define MAYBE_ArchPriest ArchPriest\n'
4466 '#else\n'
4467 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4468 '#endif\n'
4469 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4470 '#if !defined(CRUSADER_IN_PARTY)\n'
4471 '#define MAYBE_Crusader \\\n'
4472 ' DISABLED_Crusader \n'
4473 '#else\n'
4474 '#define MAYBE_Crusader \\\n'
4475 ' Crusader\n'
4476 '#endif\n'
4477 ' TEST_F(\n'
4478 ' MAYBE_Crusader,\n'
4479 ' CastTaunt) { }\n'
4480 '#if defined(LEARNED_BASIC_SKILLS)\n'
4481 '#define MAYBE_CastSteal \\\n'
4482 ' DISABLED_CastSteal \n'
4483 '#else\n'
4484 '#define MAYBE_CastSteal \\\n'
4485 ' CastSteal\n'
4486 '#endif\n'
4487 ' TEST_F(\n'
4488 ' ThiefClass,\n'
4489 ' MAYBE_CastSteal) { }\n')
4490
4491 mock_input_api = MockInputApi()
4492 mock_input_api.files = [
4493 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4494 ]
4495 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4496 mock_input_api, MockOutputApi())
4497 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514498
Max Morozb47503b2019-08-08 21:03:274499class CheckFuzzTargetsTest(unittest.TestCase):
4500
Daniel Cheng566634ff2024-06-29 14:56:534501 def _check(self, files):
4502 mock_input_api = MockInputApi()
4503 mock_input_api.files = []
4504 for fname, contents in files.items():
4505 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4506 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4507 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274508
Daniel Cheng566634ff2024-06-29 14:56:534509 def testLibFuzzerSourcesIgnored(self):
4510 results = self._check({
4511 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4512 "LLVMFuzzerInitialize",
4513 })
4514 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274515
Daniel Cheng566634ff2024-06-29 14:56:534516 def testNonCodeFilesIgnored(self):
4517 results = self._check({
4518 "README.md": "LLVMFuzzerInitialize",
4519 })
4520 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274521
Daniel Cheng566634ff2024-06-29 14:56:534522 def testNoErrorHeaderPresent(self):
4523 results = self._check({
4524 "fuzzer.cc":
4525 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4526 "LLVMFuzzerInitialize")
4527 })
4528 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274529
Daniel Cheng566634ff2024-06-29 14:56:534530 def testErrorMissingHeader(self):
4531 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4532 self.assertEqual(len(results), 1)
4533 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274534
4535
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264536class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404537
Daniel Cheng566634ff2024-06-29 14:56:534538 def testSetNoParentTopLevelAllowed(self):
4539 mock_input_api = MockInputApi()
4540 mock_input_api.files = [
4541 MockAffectedFile('goat/OWNERS', [
4542 'set noparent',
4543 '[email protected]',
4544 ])
4545 ]
4546 mock_output_api = MockOutputApi()
4547 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4548 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264549
Daniel Cheng566634ff2024-06-29 14:56:534550 def testSetNoParentMissing(self):
4551 mock_input_api = MockInputApi()
4552 mock_input_api.files = [
4553 MockAffectedFile('services/goat/OWNERS', [
4554 'set noparent',
4555 '[email protected]',
4556 'per-file *.json=set noparent',
4557 'per-file *[email protected]',
4558 ])
4559 ]
4560 mock_output_api = MockOutputApi()
4561 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4562 self.assertEqual(1, len(errors))
4563 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4564 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4565
4566 def testSetNoParentWithCorrectRule(self):
4567 mock_input_api = MockInputApi()
4568 mock_input_api.files = [
4569 MockAffectedFile('services/goat/OWNERS', [
4570 'set noparent',
4571 'file://ipc/SECURITY_OWNERS',
4572 'per-file *.json=set noparent',
4573 'per-file *.json=file://ipc/SECURITY_OWNERS',
4574 ])
4575 ]
4576 mock_output_api = MockOutputApi()
4577 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4578 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264579
4580
Ken Rockotc31f4832020-05-29 18:58:514581class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514582
Daniel Chengbdb67a22025-07-30 16:30:234583 def runTestWithAffectedFiles(self, affected_files, footers={}):
Daniel Cheng566634ff2024-06-29 14:56:534584 mock_input_api = MockInputApi()
4585 mock_input_api.files = affected_files
Daniel Chengbdb67a22025-07-30 16:30:234586 mock_input_api.change.footers = footers
Daniel Cheng566634ff2024-06-29 14:56:534587 mock_output_api = MockOutputApi()
4588 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4589 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514590
Daniel Chengbdb67a22025-07-30 16:30:234591 def testNoMojomChangePasses(self):
4592 errors = self.runTestWithAffectedFiles([
4593 MockAffectedFile('foo/foo.cc', ['// world'],
4594 old_contents=['// Hello'])
4595 ])
4596 self.assertEqual([], errors)
4597
4598 def testNoMojomChangeWithUnnecessaryFooterFails(self):
4599 errors = self.runTestWithAffectedFiles([
4600 MockAffectedFile('foo/foo.cc', ['// world'],
4601 old_contents=['// Hello'])
4602 ],
4603 footers={
4604 'No-Stable-Mojom-Checks':
Daniel Cheng32bde7d2025-07-31 00:25:344605 ['true'],
Daniel Chengbdb67a22025-07-30 16:30:234606 })
4607 self.assertEqual(1, len(errors))
4608 self.assertTrue('unnecessary git footer' in errors[0].message)
4609
Daniel Cheng566634ff2024-06-29 14:56:534610 def testSafeChangePasses(self):
4611 errors = self.runTestWithAffectedFiles([
4612 MockAffectedFile(
4613 'foo/foo.mojom',
4614 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4615 old_contents=['[Stable] struct S {};'])
4616 ])
4617 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514618
Daniel Chengbdb67a22025-07-30 16:30:234619 def testSafeChangeWithUnnecessaryFooterFails(self):
4620 errors = self.runTestWithAffectedFiles([
4621 MockAffectedFile('foo/foo.mojom',
4622 ['[Stable] struct S { int32 x; };'],
4623 old_contents=['[Stable] struct S { int32 y; };'])
4624 ],
4625 footers={
4626 'No-Stable-Mojom-Checks':
Daniel Cheng32bde7d2025-07-31 00:25:344627 ['true'],
Daniel Chengbdb67a22025-07-30 16:30:234628 })
4629 self.assertEqual(1, len(errors))
4630 self.assertTrue('unnecessary git footer' in errors[0].message)
4631
Daniel Cheng566634ff2024-06-29 14:56:534632 def testBadChangeFails(self):
4633 errors = self.runTestWithAffectedFiles([
4634 MockAffectedFile('foo/foo.mojom',
4635 ['[Stable] struct S { int32 x; };'],
4636 old_contents=['[Stable] struct S {};'])
4637 ])
4638 self.assertEqual(1, len(errors))
Daniel Chengbdb67a22025-07-30 16:30:234639 self.assertTrue('changed in a way that breaks backward compatibility.'
4640 in errors[0].message)
4641
4642 def testBadChangeButExplicitlyAllowed(self):
4643 errors = self.runTestWithAffectedFiles([
4644 MockAffectedFile('foo/foo.mojom',
4645 ['[Stable] struct S { int32 x; };'],
4646 old_contents=['[Stable] struct S {};'])
4647 ],
4648 footers={
4649 'No-Stable-Mojom-Checks':
Daniel Cheng32bde7d2025-07-31 00:25:344650 ['true'],
Daniel Chengbdb67a22025-07-30 16:30:234651 })
4652 self.assertEqual([], errors)
4653
4654 def testBadChangeButExplicitlyAllowedWithWrongValue(self):
4655 errors = self.runTestWithAffectedFiles([
4656 MockAffectedFile('foo/foo.mojom',
4657 ['[Stable] struct S { int32 x; };'],
4658 old_contents=['[Stable] struct S {};'])
4659 ],
4660 footers={
4661 'No-Stable-Mojom-Checks':
Daniel Cheng32bde7d2025-07-31 00:25:344662 ['🐮'],
Daniel Chengbdb67a22025-07-30 16:30:234663 })
4664 self.assertEqual(1, len(errors))
4665 self.assertTrue('only accepts the value "true"' in errors[0].message)
Daniel Cheng566634ff2024-06-29 14:56:534666
4667 def testDeletedFile(self):
4668 """Regression test for https://crbug.com/1091407."""
4669 errors = self.runTestWithAffectedFiles([
4670 MockAffectedFile('a.mojom', [],
4671 old_contents=['struct S {};'],
4672 action='D'),
4673 MockAffectedFile(
4674 'b.mojom', ['struct S {}; struct T { S s; };'],
4675 old_contents=['import "a.mojom"; struct T { S s; };'])
4676 ])
4677 self.assertEqual([], errors)
4678
Ken Rockotad7901f942020-06-04 20:17:094679
Jose Magana2b456f22021-03-09 23:26:404680class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4681
Daniel Cheng566634ff2024-06-29 14:56:534682 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404683
Daniel Cheng566634ff2024-06-29 14:56:534684 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404685
Daniel Cheng566634ff2024-06-29 14:56:534686 def testWarningNMF(self):
4687 mock_input_api = MockInputApi()
4688 mock_input_api.files = [
4689 MockAffectedFile(
4690 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4691 ['"program"', 'B'],
4692 scm_diff='\n'.join([
4693 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4694 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4695 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4696 ]),
4697 action='M')
4698 ]
4699 mock_output_api = MockOutputApi()
4700 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4701 mock_input_api, mock_output_api)
4702 self.assertEqual(1, len(errors))
4703 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4704 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404705
Daniel Cheng566634ff2024-06-29 14:56:534706 def testWarningManifest(self):
4707 mock_input_api = MockInputApi()
4708 mock_input_api.files = [
4709 MockAffectedFile(
4710 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4711 ['"app":"', 'B'],
4712 scm_diff='\n'.join([
4713 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4714 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4715 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4716 ]),
4717 action='M')
4718 ]
4719 mock_output_api = MockOutputApi()
4720 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4721 mock_input_api, mock_output_api)
4722 self.assertEqual(1, len(errors))
4723 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4724 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404725
Daniel Cheng566634ff2024-06-29 14:56:534726 def testOKWarningManifestWithoutApp(self):
4727 mock_input_api = MockInputApi()
4728 mock_input_api.files = [
4729 MockAffectedFile(
4730 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4731 ['"name":"', 'B'],
4732 scm_diff='\n'.join([
4733 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4734 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4735 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4736 ]),
4737 action='M')
4738 ]
4739 mock_output_api = MockOutputApi()
4740 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4741 mock_input_api, mock_output_api)
4742 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404743
Jose Magana2b456f22021-03-09 23:26:404744
Dominic Battre645d42342020-12-04 16:14:104745class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534746 # Test that a warning is generated if a preference registration is removed
4747 # from a random file.
4748 def testWarning(self):
4749 mock_input_api = MockInputApi()
4750 mock_input_api.files = [
4751 MockAffectedFile(
4752 'foo.cc', ['A', 'B'],
4753 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4754 scm_diff='\n'.join([
4755 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4756 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4757 '@@ -1,3 +1,2 @@', ' A',
4758 '-prefs->RegisterStringPref("foo", "default");', ' B'
4759 ]),
4760 action='M')
4761 ]
4762 mock_output_api = MockOutputApi()
4763 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4764 mock_input_api, mock_output_api)
4765 self.assertEqual(1, len(errors))
4766 self.assertTrue(
4767 'Discovered possible removal of preference registrations' in
4768 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104769
Daniel Cheng566634ff2024-06-29 14:56:534770 # Test that a warning is inhibited if the preference registration was moved
4771 # to the deprecation functions in browser prefs.
4772 def testNoWarningForMigration(self):
4773 mock_input_api = MockInputApi()
4774 mock_input_api.files = [
4775 # RegisterStringPref was removed from foo.cc.
4776 MockAffectedFile(
4777 'foo.cc', ['A', 'B'],
4778 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4779 scm_diff='\n'.join([
4780 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4781 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4782 '@@ -1,3 +1,2 @@', ' A',
4783 '-prefs->RegisterStringPref("foo", "default");', ' B'
4784 ]),
4785 action='M'),
4786 # But the preference was properly migrated.
4787 MockAffectedFile(
4788 'chrome/browser/prefs/browser_prefs.cc', [
4789 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4790 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4791 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4792 'prefs->RegisterStringPref("foo", "default");',
4793 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4794 ], [
4795 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4796 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4797 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4798 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4799 ],
4800 scm_diff='\n'.join([
4801 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4802 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4803 '@@ -2,3 +2,4 @@',
4804 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4805 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4806 '+prefs->RegisterStringPref("foo", "default");',
4807 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4808 ]),
4809 action='M'),
4810 ]
4811 mock_output_api = MockOutputApi()
4812 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4813 mock_input_api, mock_output_api)
4814 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104815
Daniel Cheng566634ff2024-06-29 14:56:534816 # Test that a warning is NOT inhibited if the preference registration was
4817 # moved to a place outside of the migration functions in browser_prefs.cc
4818 def testWarningForImproperMigration(self):
4819 mock_input_api = MockInputApi()
4820 mock_input_api.files = [
4821 # RegisterStringPref was removed from foo.cc.
4822 MockAffectedFile(
4823 'foo.cc', ['A', 'B'],
4824 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4825 scm_diff='\n'.join([
4826 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4827 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4828 '@@ -1,3 +1,2 @@', ' A',
4829 '-prefs->RegisterStringPref("foo", "default");', ' B'
4830 ]),
4831 action='M'),
4832 # The registration call was moved to a place in browser_prefs.cc that
4833 # is outside the migration functions.
4834 MockAffectedFile(
4835 'chrome/browser/prefs/browser_prefs.cc', [
4836 'prefs->RegisterStringPref("foo", "default");',
4837 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4838 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4839 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4840 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4841 ], [
4842 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4843 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4844 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4845 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4846 ],
4847 scm_diff='\n'.join([
4848 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4849 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4850 '@@ -1,2 +1,3 @@',
4851 '+prefs->RegisterStringPref("foo", "default");',
4852 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4853 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4854 ]),
4855 action='M'),
4856 ]
4857 mock_output_api = MockOutputApi()
4858 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4859 mock_input_api, mock_output_api)
4860 self.assertEqual(1, len(errors))
4861 self.assertTrue(
4862 'Discovered possible removal of preference registrations' in
4863 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104864
Daniel Cheng566634ff2024-06-29 14:56:534865 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4866 # deleted.
4867 def testDeletedMarkerRaisesError(self):
4868 mock_input_api = MockInputApi()
4869 mock_input_api.files = [
4870 MockAffectedFile(
4871 'chrome/browser/prefs/browser_prefs.cc',
4872 [
4873 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4874 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4875 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4876 # The following line is deleted for this test
4877 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4878 ])
4879 ]
4880 mock_output_api = MockOutputApi()
4881 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4882 mock_input_api, mock_output_api)
4883 self.assertEqual(1, len(errors))
4884 self.assertEqual(
4885 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4886 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104887
Sven Zheng76a79ea2022-12-21 21:25:244888class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4889 def testWarning(self):
4890 mock_input_api = MockInputApi()
4891 mock_output_api = MockOutputApi()
4892 mock_input_api.files = [
4893 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4894 ]
4895 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4896 self.assertEqual(1, len(result))
4897 self.assertEqual(result[0].type, 'warning')
4898
4899 def testNoWarningWithBrowserTest(self):
4900 mock_input_api = MockInputApi()
4901 mock_output_api = MockOutputApi()
4902 mock_input_api.files = [
4903 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4904 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4905 ]
4906 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4907 self.assertEqual(0, len(result))
4908
4909 def testNoWarningModifyCrosapi(self):
4910 mock_input_api = MockInputApi()
4911 mock_output_api = MockOutputApi()
4912 mock_input_api.files = [
4913 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4914 ]
4915 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4916 self.assertEqual(0, len(result))
4917
4918 def testNoWarningAddNonMojomFile(self):
4919 mock_input_api = MockInputApi()
4920 mock_output_api = MockOutputApi()
4921 mock_input_api.files = [
4922 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4923 ]
4924 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4925 self.assertEqual(0, len(result))
4926
4927 def testNoWarningNoneRelatedMojom(self):
4928 mock_input_api = MockInputApi()
4929 mock_output_api = MockOutputApi()
4930 mock_input_api.files = [
4931 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4932 ]
4933 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4934 self.assertEqual(0, len(result))
4935
4936
Henrique Ferreiro2a4b55942021-11-29 23:45:364937class AssertAshOnlyCodeTest(unittest.TestCase):
4938 def testErrorsOnlyOnAshDirectories(self):
4939 files_in_ash = [
4940 MockFile('ash/BUILD.gn', []),
4941 MockFile('chrome/browser/ash/BUILD.gn', []),
4942 ]
4943 other_files = [
4944 MockFile('chrome/browser/BUILD.gn', []),
Georg Neis94f87f02024-10-22 08:20:134945 MockFile('chrome/browser/foo/BUILD.gn', ['assert(is_chromeos_ash)']),
Henrique Ferreiro2a4b55942021-11-29 23:45:364946 ]
4947 input_api = MockInputApi()
4948 input_api.files = files_in_ash
4949 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4950 self.assertEqual(2, len(errors))
4951
4952 input_api.files = other_files
4953 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4954 self.assertEqual(0, len(errors))
4955
4956 def testDoesNotErrorOnNonGNFiles(self):
4957 input_api = MockInputApi()
4958 input_api.files = [
4959 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4960 MockFile('chrome/browser/ash/test.cc',
4961 ['assert(is_chromeos_ash)']),
4962 ]
4963 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4964 self.assertEqual(0, len(errors))
4965
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214966 def testDeletedFile(self):
4967 input_api = MockInputApi()
4968 input_api.files = [
4969 MockFile('ash/BUILD.gn', []),
4970 MockFile('ash/foo/BUILD.gn', [], action='D'),
4971 ]
4972 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4973 self.assertEqual(1, len(errors))
4974
Henrique Ferreiro2a4b55942021-11-29 23:45:364975 def testDoesNotErrorWithAssertion(self):
4976 input_api = MockInputApi()
4977 input_api.files = [
4978 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4979 MockFile('chrome/browser/ash/BUILD.gn',
4980 ['assert(is_chromeos_ash)']),
Georg Neis94f87f02024-10-22 08:20:134981 MockFile('chrome/browser/ash/1/BUILD.gn',
4982 ['assert(is_chromeos)']),
4983 MockFile('chrome/browser/ash/2/BUILD.gn',
4984 ['assert(is_chromeos_ash)']),
4985 MockFile('chrome/browser/ash/3/BUILD.gn',
4986 ['assert(is_chromeos, "test")']),
4987 MockFile('chrome/browser/ash/4/BUILD.gn',
Henrique Ferreiro2a4b55942021-11-29 23:45:364988 ['assert(is_chromeos_ash, "test")']),
4989 ]
4990 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4991 self.assertEqual(0, len(errors))
4992
4993
Lukasz Anforowicz7016d05e2021-11-30 03:56:274994class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274995
Daniel Cheng566634ff2024-06-29 14:56:534996 def testAllowedCases(self):
4997 mock_input_api = MockInputApi()
4998 mock_input_api.files = [
4999 # Browser-side files are allowed.
5000 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
5001 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
5002 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
5003 MockAffectedFile('test13/blink/public/common/foo.cc',
5004 ['raw_ptr<int>']),
5005 MockAffectedFile('test14/blink/public/platform/foo.cc',
5006 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:275007
Daniel Cheng566634ff2024-06-29 14:56:535008 # Non-C++ files are allowed.
5009 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:275010
Daniel Cheng566634ff2024-06-29 14:56:535011 # Renderer code is generally allowed (except specifically
5012 # disallowed directories).
5013 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
5014 ]
5015 mock_output_api = MockOutputApi()
5016 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
5017 self.assertFalse(errors)
5018
5019 def testDisallowedCases(self):
5020 mock_input_api = MockInputApi()
5021 mock_input_api.files = [
5022 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
5023 ['raw_ptr<int>']),
5024 MockAffectedFile(
5025 'test2/third_party/blink/renderer/platform/heap/foo.cc',
5026 ['raw_ptr<int>']),
5027 MockAffectedFile(
5028 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
5029 ['raw_ptr<int>']),
5030 MockAffectedFile(
5031 'test4/third_party/blink/renderer/platform/fonts/foo.h',
5032 ['raw_ptr<int>']),
5033 MockAffectedFile(
5034 'test5/third_party/blink/renderer/core/paint/foo.cc',
5035 ['raw_ptr<int>']),
5036 MockAffectedFile(
5037 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
5038 ['raw_ptr<int>']),
5039 MockAffectedFile(
5040 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
5041 ['raw_ptr<int>']),
5042 ]
5043 mock_output_api = MockOutputApi()
5044 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
5045 self.assertEqual(len(mock_input_api.files), len(errors))
5046 for error in errors:
5047 self.assertTrue(
5048 'raw_ptr<T> should not be used in this renderer code' in
5049 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275050
mikt9337567c2023-09-08 18:38:175051class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:175052
Daniel Cheng566634ff2024-06-29 14:56:535053 def testAllowedCases(self):
5054 mock_input_api = MockInputApi()
5055 mock_input_api.files = [
5056 # Non-C++ files are allowed.
5057 MockAffectedFile('test20/renderer/foo.md',
5058 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:175059
Daniel Cheng566634ff2024-06-29 14:56:535060 # Mentions in a comment are allowed.
5061 MockAffectedFile('test30/renderer/foo.cc',
5062 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
5063 ]
5064 mock_output_api = MockOutputApi()
5065 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5066 mock_input_api, mock_output_api)
5067 self.assertFalse(errors)
5068
5069 def testDisallowedCases(self):
5070 mock_input_api = MockInputApi()
5071 mock_input_api.files = [
5072 MockAffectedFile('test1/foo.h',
5073 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5074 MockAffectedFile('test2/foo.cc',
5075 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5076 ]
5077 mock_output_api = MockOutputApi()
5078 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5079 mock_input_api, mock_output_api)
5080 self.assertEqual(1, len(errors))
5081 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
5082 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275083
Henrique Ferreirof9819f2e32021-11-30 13:31:565084class AssertPythonShebangTest(unittest.TestCase):
5085 def testError(self):
5086 input_api = MockInputApi()
5087 input_api.files = [
5088 MockFile('ash/test.py', ['#!/usr/bin/python']),
5089 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
5090 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:275091 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:565092 ]
5093 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5094 self.assertEqual(3, len(errors))
5095
5096 def testNonError(self):
5097 input_api = MockInputApi()
5098 input_api.files = [
5099 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
5100 MockFile('third_party/blink/web_tests/external/test.py',
5101 ['#!/usr/bin/python2']),
5102 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
5103 ]
5104 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5105 self.assertEqual(0, len(errors))
5106
Kalvin Lee4a3b79de2022-05-26 16:00:165107class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:165108
Daniel Cheng566634ff2024-06-29 14:56:535109 def testPermissibleUsage(self):
5110 input_api = MockInputApi()
5111 input_api.files = [
5112 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
5113 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:165114
Daniel Cheng566634ff2024-06-29 14:56:535115 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
5116 # own thing at their own risk.
5117 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
5118 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
5119 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
5120 ]
5121 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5122 MockOutputApi())
5123 self.assertEqual(0, len(errors))
5124
5125 def testMissingParentheses(self):
5126 input_api = MockInputApi()
5127 input_api.files = [
5128 MockFile('bad1.cc', ['DCHECK_IS_ON']),
5129 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
5130 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
5131 ]
5132 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5133 MockOutputApi())
5134 self.assertEqual(3, len(errors))
5135 for error in errors:
5136 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:565137
Sam Maier4cef9242022-10-03 14:21:245138
Andrew Grieve5a66ae72024-12-13 15:21:535139class CheckAndroidTestAnnotations(unittest.TestCase):
5140 """Test the CheckAndroidTestAnnotations presubmit check."""
James Shen81cc0e22022-06-15 21:10:455141
Andrew Grieve5a66ae72024-12-13 15:21:535142 def testBatchTruePositives(self):
Daniel Cheng566634ff2024-06-29 14:56:535143 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455144"""
Daniel Cheng566634ff2024-06-29 14:56:535145 mock_input = MockInputApi()
5146 mock_input.files = [
5147 MockFile('path/OneTest.java', ['public class OneTest']),
5148 MockFile('path/TwoTest.java', ['public class TwoTest']),
5149 MockFile('path/ThreeTest.java', [
5150 '@Batch(Batch.PER_CLASS)',
Andrew Grieve5a66ae72024-12-13 15:21:535151 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535152 'public class Three {'
5153 ]),
5154 MockFile('path/FourTest.java', [
5155 '@DoNotBatch(reason = "placeholder reason 1")',
Andrew Grieve5a66ae72024-12-13 15:21:535156 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535157 'public class Four {'
5158 ]),
5159 ]
Andrew Grieve5a66ae72024-12-13 15:21:535160 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535161 self.assertEqual(2, len(errors))
5162 self.assertEqual(2, len(errors[0].items))
5163 self.assertIn('OneTest.java', errors[0].items[0])
5164 self.assertIn('TwoTest.java', errors[0].items[1])
5165 self.assertEqual(2, len(errors[1].items))
5166 self.assertIn('ThreeTest.java', errors[1].items[0])
5167 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385168
Andrew Grieve5a66ae72024-12-13 15:21:535169 def testBatchAnnotationsPresent(self):
Daniel Cheng566634ff2024-06-29 14:56:535170 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5171 mock_input = MockInputApi()
5172 mock_input.files = [
5173 MockFile('path/OneTest.java',
5174 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5175 MockFile('path/TwoTest.java', [
5176 '@DoNotBatch(reason = "placeholder reasons.")',
5177 'public class Two {'
5178 ]),
5179 MockFile('path/ThreeTest.java', [
5180 '@Batch(Batch.PER_CLASS)',
5181 'public class Three extends BaseTestA {'
5182 ], [
5183 '@Batch(Batch.PER_CLASS)',
5184 'public class Three extends BaseTestB {'
5185 ]),
5186 MockFile('path/FourTest.java', [
5187 '@DoNotBatch(reason = "placeholder reason 1")',
5188 'public class Four extends BaseTestA {'
5189 ], [
5190 '@DoNotBatch(reason = "placeholder reason 2")',
5191 'public class Four extends BaseTestB {'
5192 ]),
5193 MockFile('path/FiveTest.java', [
5194 'import androidx.test.uiautomator.UiDevice;',
5195 'public class Five extends BaseTestA {'
5196 ], [
5197 'import androidx.test.uiautomator.UiDevice;',
5198 'public class Five extends BaseTestB {'
5199 ]),
5200 MockFile('path/SixTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535201 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535202 'public class Six extends BaseTestA {'
5203 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535204 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535205 'public class Six extends BaseTestB {'
5206 ]),
5207 MockFile('path/SevenTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535208 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535209 'public class Seven extends BaseTestA {'
5210 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535211 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535212 'public class Seven extends BaseTestB {'
5213 ]),
5214 MockFile(
5215 'path/OtherClass.java',
5216 ['public class OtherClass {'],
5217 ),
5218 MockFile('path/PRESUBMIT.py', [
5219 '@Batch(Batch.PER_CLASS)',
5220 '@DoNotBatch(reason = "placeholder reason)'
5221 ]),
5222 MockFile(
5223 'path/AnnotationTest.java',
5224 ['public @interface SomeAnnotation {'],
5225 ),
5226 ]
Andrew Grieve5a66ae72024-12-13 15:21:535227 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535228 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455229
Andrew Grieve5a66ae72024-12-13 15:21:535230 def testWrongRobolectricTestRunner(self):
5231 mock_input = MockInputApi()
5232 mock_input.files = [
5233 MockFile('path/OneTest.java', [
5234 '@RunWith(RobolectricTestRunner.class)',
5235 'public class ThreeTest {'
5236 ]),
5237 MockFile('path/TwoTest.java', [
5238 'import org.chromium.base.test.BaseRobolectricTestRule;',
5239 '@RunWith(RobolectricTestRunner.class)',
5240 'public class TwoTest {'
5241 ]),
5242 MockFile('path/ThreeTest.java', [
5243 '@RunWith(FooRobolectricTestRunner.class)',
5244 'public class ThreeTest {'
5245 ]),
5246 MockFile('webapks/FourTest.java', [
5247 '@RunWith(RobolectricTestRunner.class)',
5248 'public class ThreeTest {'
5249 ]),
5250 ]
5251 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
5252 self.assertEqual(1, len(errors))
5253 self.assertEqual(1, len(errors[0].items))
5254 self.assertIn('OneTest.java', errors[0].items[0])
5255
Sam Maier4cef9242022-10-03 14:21:245256
Henrique Nakashima224ee2482025-03-21 18:35:025257class CheckAndroidNullAwayAnnotatedClasses(unittest.TestCase):
5258 """Test the _CheckAndroidNullAwayAnnotatedClasses presubmit check."""
5259
5260 def testDetectsInClasses(self):
5261 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in classes."""
5262 mock_input = MockInputApi()
5263 mock_input.files = [
5264 MockFile('path/OneMissing.java', ['public class OneMissing']),
5265 MockFile('path/TwoMarked.java', [
5266 '@NullMarked',
5267 'public class TwoMarked {',
5268 ]),
5269 MockFile('path/ThreeMarked.java', [
5270 '@NullUnmarked',
5271 'public class ThreeMarked {',
5272 ]),
5273 MockFile('path/FourMissing.java', ['class FourMissing']),
5274 ]
5275 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5276 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425277 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025278 self.assertEqual(2, len(results[0].items))
5279 self.assertIn('OneMissing.java', results[0].items[0])
5280 self.assertIn('FourMissing.java', results[0].items[1])
5281
5282 def testDetectsInAnnotations(self):
5283 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in annotations."""
5284 mock_input = MockInputApi()
5285 mock_input.files = [
5286 MockFile('path/OneMissing.java', ['@interface OneMissing']),
5287 MockFile('path/TwoMarked.java', [
5288 '@NullMarked',
5289 '@interface TwoMarked {',
5290 ]),
5291 ]
5292 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5293 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425294 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025295 self.assertEqual(1, len(results[0].items))
5296 self.assertIn('OneMissing.java', results[0].items[0])
5297
5298 def testDetectsInInterfaces(self):
5299 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in interfaces."""
5300 mock_input = MockInputApi()
5301 mock_input.files = [
5302 MockFile('path/OneMissing.java', ['interface OneMissing']),
5303 MockFile('path/TwoMarked.java', [
5304 '@NullMarked',
5305 'interface TwoMarked {',
5306 ]),
5307 ]
5308 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5309 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425310 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025311 self.assertEqual(1, len(results[0].items))
5312 self.assertIn('OneMissing.java', results[0].items[0])
5313
Henrique Nakashimac6605432025-04-24 18:11:595314 def testOnlyChecksAddedFiles(self):
5315 """Tests that missing @NullMarked or @NullUnmarked is only flagged in newly added files."""
5316 mock_input = MockInputApi()
5317 mock_input.files = [
5318 MockFile('path/OneMissing.java', ['public class OneMissing'], action='M'),
5319 ]
5320 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5321 self.assertEqual(0, len(results))
5322
Henrique Nakashima224ee2482025-03-21 18:35:025323 def testExcludesTests(self):
5324 """Tests that missing @NullMarked or @NullUnmarked are not flagged in tests."""
5325 mock_input = MockInputApi()
5326 mock_input.files = [
5327 MockFile('path/OneTest.java', ['public class OneTest']),
5328 ]
5329 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5330 self.assertEqual(0, len(results))
5331
5332 def testExcludesTestSupport(self):
5333 """Tests that missing @NullMarked or @NullUnmarked are not flagged in test support classes."""
5334 mock_input = MockInputApi()
5335 mock_input.files = [
5336 MockFile('path/test/Two.java', [
5337 'public class Two'
5338 ]),
5339 ]
5340 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5341 self.assertEqual(0, len(results))
5342
5343
Mike Dougherty1b8be712022-10-20 00:15:135344class AssertNoJsInIosTest(unittest.TestCase):
5345 def testErrorJs(self):
5346 input_api = MockInputApi()
5347 input_api.files = [
5348 MockFile('components/feature/ios/resources/script.js', []),
5349 MockFile('ios/chrome/feature/resources/script.js', []),
5350 ]
5351 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5352 self.assertEqual(1, len(results))
5353 self.assertEqual('error', results[0].type)
5354 self.assertEqual(2, len(results[0].items))
5355
5356 def testNonError(self):
5357 input_api = MockInputApi()
5358 input_api.files = [
5359 MockFile('chrome/resources/script.js', []),
5360 MockFile('components/feature/ios/resources/script.ts', []),
5361 MockFile('ios/chrome/feature/resources/script.ts', []),
5362 MockFile('ios/web/feature/resources/script.ts', []),
5363 MockFile('ios/third_party/script.js', []),
5364 MockFile('third_party/ios/script.js', []),
5365 ]
5366 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5367 self.assertEqual(0, len(results))
5368
5369 def testExistingFilesWarningOnly(self):
5370 input_api = MockInputApi()
5371 input_api.files = [
5372 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5373 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5374 ]
5375 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5376 self.assertEqual(1, len(results))
5377 self.assertEqual('warning', results[0].type)
5378 self.assertEqual(1, len(results[0].items))
5379
Mike Dougherty4d1050b2023-03-14 15:59:535380 def testMovedScriptWarningOnly(self):
5381 input_api = MockInputApi()
5382 input_api.files = [
5383 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5384 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5385 ]
5386 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5387 self.assertEqual(1, len(results))
5388 self.assertEqual('warning', results[0].type)
5389 self.assertEqual(1, len(results[0].items))
5390
Yuanqing Zhu9eef02832022-12-04 14:42:175391class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175392
Daniel Cheng566634ff2024-06-29 14:56:535393 def testHasAbbreviation(self):
5394 """test png file names with abbreviation that fails the check"""
5395 input_api = MockInputApi()
5396 input_api.files = [
5397 MockFile('image_a.png', [], action='A'),
5398 MockFile('image_a_.png', [], action='A'),
5399 MockFile('image_a_name.png', [], action='A'),
5400 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5401 action='A'),
5402 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5403 action='A'),
5404 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5405 action='A'),
5406 ]
5407 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5408 input_api, MockOutputApi())
5409 self.assertEqual(1, len(results))
5410 self.assertEqual('error', results[0].type)
5411 self.assertEqual(len(input_api.files), len(results[0].items))
5412
5413 def testNoAbbreviation(self):
5414 """test png file names without abbreviation that passes the check"""
5415 input_api = MockInputApi()
5416 input_api.files = [
5417 MockFile('a.png', [], action='A'),
5418 MockFile('_a.png', [], action='A'),
5419 MockFile('image.png', [], action='A'),
5420 MockFile('image_ab_.png', [], action='A'),
5421 MockFile('image_ab_name.png', [], action='A'),
5422 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5423 # They should pass now because the path components ahead of the file name are ignored in the check.
5424 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5425 action='A'),
5426 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5427 action='A'),
5428 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5429 action='A'),
5430 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5431 action='A'),
5432 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5433 [],
5434 action='A'),
5435 ]
5436 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5437 input_api, MockOutputApi())
5438 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175439
Arthur Sonzogni7109bd32023-10-03 10:34:425440class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425441
Daniel Cheng566634ff2024-06-29 14:56:535442 def testError(self):
5443 """Test patch adding dangling pointers are reported"""
5444 mock_input_api = MockInputApi()
5445 mock_output_api = MockOutputApi()
5446
5447 mock_input_api.change.DescriptionText = lambda: "description"
5448 mock_input_api.files = [
5449 MockAffectedFile(
5450 local_path="foo/foo.cc",
5451 old_contents=["raw_ptr<T>"],
5452 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5453 )
5454 ]
5455 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5456 mock_output_api)
5457 self.assertEqual(len(msgs), 1)
5458 self.assertEqual(len(msgs[0].message), 10)
5459 self.assertEqual(
5460 msgs[0].message[0],
5461 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5462 )
Arthur Sonzogni7109bd32023-10-03 10:34:425463
5464class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425465
Daniel Cheng566634ff2024-06-29 14:56:535466 def testError(self):
5467 """Test patch adding dangling pointers are reported"""
5468 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.change.DescriptionText = lambda: "description"
5472 mock_input_api.files = [
5473 MockAffectedFile(
5474 local_path="foo/foo.cc",
5475 old_contents=["raw_ptr<T>"],
5476 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5477 )
5478 ]
5479 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5480 mock_output_api)
5481 self.assertEqual(len(msgs), 1)
5482 self.assertTrue(
5483 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5484 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425485
Daniel Cheng566634ff2024-06-29 14:56:535486 def testNonCppFile(self):
5487 """Test patch adding dangling pointers are not reported in non C++ files"""
5488 mock_input_api = MockInputApi()
5489 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425490
Daniel Cheng566634ff2024-06-29 14:56:535491 mock_input_api.change.DescriptionText = lambda: "description"
5492 mock_input_api.files = [
5493 MockAffectedFile(
5494 local_path="foo/README.md",
5495 old_contents=[""],
5496 new_contents=["The DanglingUntriaged annotation means"],
5497 )
5498 ]
5499 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5500 mock_output_api)
5501 self.assertEqual(len(msgs), 0)
5502
5503 def testDeveloperAcknowledgeInCommitDescription(self):
5504 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425505 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535506 mock_input_api = MockInputApi()
5507 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425508
Daniel Cheng566634ff2024-06-29 14:56:535509 mock_input_api.files = [
5510 MockAffectedFile(
5511 local_path="foo/foo.cc",
5512 old_contents=["raw_ptr<T>"],
5513 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5514 )
5515 ]
5516 mock_input_api.change.DescriptionText = lambda: (
5517 "DanglingUntriaged-notes: Sorry about this!")
5518 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5519 mock_output_api)
5520 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425521
Daniel Cheng566634ff2024-06-29 14:56:535522 def testDeveloperAcknowledgeInCommitFooter(self):
5523 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425524 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535525 mock_input_api = MockInputApi()
5526 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425527
Daniel Cheng566634ff2024-06-29 14:56:535528 mock_input_api.files = [
5529 MockAffectedFile(
5530 local_path="foo/foo.cc",
5531 old_contents=["raw_ptr<T>"],
5532 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5533 )
5534 ]
5535 mock_input_api.change.DescriptionText = lambda: "description"
5536 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5537 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5538 mock_output_api)
5539 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425540
Daniel Cheng566634ff2024-06-29 14:56:535541 def testCongrats(self):
5542 """Test the presubmit congrats users removing dangling pointers"""
5543 mock_input_api = MockInputApi()
5544 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425545
Daniel Cheng566634ff2024-06-29 14:56:535546 mock_input_api.files = [
5547 MockAffectedFile(
5548 local_path="foo/foo.cc",
5549 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5550 new_contents=["raw_ptr<T>"],
5551 )
5552 ]
5553 mock_input_api.change.DescriptionText = lambda: (
5554 "This patch fixes some DanglingUntriaged pointers!")
5555 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5556 mock_output_api)
5557 self.assertEqual(len(msgs), 1)
5558 self.assertTrue(
5559 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5560 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425561
Daniel Cheng566634ff2024-06-29 14:56:535562 def testRenameFile(self):
5563 """Patch that we do not warn about DanglingUntriaged when moving files"""
5564 mock_input_api = MockInputApi()
5565 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425566
Daniel Cheng566634ff2024-06-29 14:56:535567 mock_input_api.files = [
5568 MockAffectedFile(
5569 local_path="foo/foo.cc",
5570 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5571 new_contents=[""],
5572 action="D",
5573 ),
5574 MockAffectedFile(
5575 local_path="foo/foo.cc",
5576 old_contents=[""],
5577 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5578 action="A",
5579 ),
5580 ]
5581 mock_input_api.change.DescriptionText = lambda: (
5582 "This patch moves files")
5583 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5584 mock_output_api)
5585 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425586
Jan Keitel77be7522023-10-12 20:40:495587class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495588
Daniel Cheng566634ff2024-06-29 14:56:535589 def testNoInlineConstexprInHeaderFile(self):
5590 """Tests that non-inlined constexpr variables in headers fail the test."""
5591 input_api = MockInputApi()
5592 input_api.files = [
5593 MockAffectedFile('src/constants.h',
5594 ['constexpr int kVersion = 5;'])
5595 ]
5596 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5597 input_api, MockOutputApi())
5598 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495599
Daniel Cheng566634ff2024-06-29 14:56:535600 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5601 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5602 input_api = MockInputApi()
5603 input_api.files = [
5604 MockAffectedFile('src/constants.h',
5605 ['constexpr int kVersion = GetVersion();'])
5606 ]
5607 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5608 input_api, MockOutputApi())
5609 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495610
Daniel Cheng566634ff2024-06-29 14:56:535611 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5612 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5613 input_api = MockInputApi()
5614 input_api.files = [
5615 MockAffectedFile('src/constants.h',
5616 ['constexpr int kVersion = (4 + 5)*3;'])
5617 ]
5618 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5619 input_api, MockOutputApi())
5620 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495621
Daniel Cheng566634ff2024-06-29 14:56:535622 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5623 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5624 input_api = MockInputApi()
5625 input_api.files = [
5626 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5627 ]
5628 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5629 input_api, MockOutputApi())
5630 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495631
Daniel Cheng566634ff2024-06-29 14:56:535632 def testNoInlineConstexprInHeaderWithAttribute(self):
5633 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5634 input_api = MockInputApi()
5635 input_api.files = [
5636 MockAffectedFile('src/constants.h',
5637 ['constexpr [[maybe_unused]] int kVersion{5};'])
5638 ]
5639 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5640 input_api, MockOutputApi())
5641 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495642
Daniel Cheng566634ff2024-06-29 14:56:535643 def testInlineConstexprInHeaderWithAttribute(self):
5644 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5645 input_api = MockInputApi()
5646 input_api.files = [
5647 MockAffectedFile(
5648 'src/constants.h',
5649 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5650 MockAffectedFile(
5651 'src/constants.h',
5652 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5653 MockAffectedFile(
5654 'src/constants.h',
5655 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5656 ]
5657 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5658 input_api, MockOutputApi())
5659 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495660
Daniel Cheng566634ff2024-06-29 14:56:535661 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5662 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5663 input_api = MockInputApi()
5664 lines = [
5665 'constexpr char kLongName =',
5666 ' "This is a very long name of something.";'
5667 ]
5668 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5669 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5670 input_api, MockOutputApi())
5671 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495672
Daniel Cheng566634ff2024-06-29 14:56:535673 def testNoInlineConstexprInCCFile(self):
5674 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5675 input_api = MockInputApi()
5676 input_api.files = [
5677 MockAffectedFile('src/implementation.cc',
5678 ['constexpr int kVersion = 5;'])
5679 ]
5680 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5681 input_api, MockOutputApi())
5682 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495683
Daniel Cheng566634ff2024-06-29 14:56:535684 def testInlineConstexprInHeaderFile(self):
5685 """Tests that inlined constexpr variables in header files pass the test."""
5686 input_api = MockInputApi()
5687 input_api.files = [
5688 MockAffectedFile('src/constants.h',
5689 ['constexpr inline int kX = 5;']),
5690 MockAffectedFile('src/version.h',
5691 ['inline constexpr float kY = 5.0f;'])
5692 ]
5693 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5694 input_api, MockOutputApi())
5695 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495696
Daniel Cheng566634ff2024-06-29 14:56:535697 def testConstexprStandaloneFunctionInHeaderFile(self):
5698 """Tests that non-inlined constexpr functions in headers pass the test."""
5699 input_api = MockInputApi()
5700 input_api.files = [
5701 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5702 ]
5703 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5704 input_api, MockOutputApi())
5705 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495706
Daniel Cheng566634ff2024-06-29 14:56:535707 def testConstexprWithAbseilAttributeInHeader(self):
5708 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5709 input_api = MockInputApi()
5710 input_api.files = [
5711 MockAffectedFile('src/helpers.h',
5712 ['ABSL_FOOFOO constexpr int i = 5;'])
5713 ]
5714 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5715 input_api, MockOutputApi())
5716 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495717
Daniel Cheng566634ff2024-06-29 14:56:535718 def testInlineConstexprWithAbseilAttributeInHeader(self):
5719 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5720 input_api = MockInputApi()
5721 input_api.files = [
5722 MockAffectedFile('src/helpers.h',
5723 ['constexpr ABSL_FOO inline int i = 5;'])
5724 ]
5725 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5726 input_api, MockOutputApi())
5727 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495728
Daniel Cheng566634ff2024-06-29 14:56:535729 def testConstexprWithClangAttributeInHeader(self):
5730 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5731 input_api = MockInputApi()
5732 input_api.files = [
5733 MockAffectedFile('src/helpers.h',
5734 ['[[clang::someattribute]] constexpr int i = 5;'])
5735 ]
5736 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5737 input_api, MockOutputApi())
5738 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495739
Daniel Cheng566634ff2024-06-29 14:56:535740 def testInlineConstexprWithClangAttributeInHeader(self):
5741 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5742 input_api = MockInputApi()
5743 input_api.files = [
5744 MockAffectedFile(
5745 'src/helpers.h',
5746 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5747 ]
5748 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5749 input_api, MockOutputApi())
5750 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425751
Daniel Cheng566634ff2024-06-29 14:56:535752 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5753 """Tests that non-inlined constexpr class members pass the test."""
5754 input_api = MockInputApi()
5755 lines = [
5756 'class SomeClass {', ' public:',
5757 ' static constexpr kVersion = 5;', '};'
5758 ]
5759 input_api.files = [MockAffectedFile('src/class.h', lines)]
5760 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5761 input_api, MockOutputApi())
5762 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045763
Daniel Cheng566634ff2024-06-29 14:56:535764 def testTodoBugReferencesWithOldBugId(self):
5765 """Tests that an old monorail bug ID in a TODO fails."""
5766 input_api = MockInputApi()
5767 input_api.files = [
5768 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5769 ]
5770 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5771 self.assertEqual(1, len(warnings))
5772
5773 def testTodoBugReferencesWithUpdatedBugId(self):
5774 """Tests that a new issue tracker bug ID in a TODO passes."""
5775 input_api = MockInputApi()
5776 input_api.files = [
5777 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5778 ]
5779 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5780 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045781
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155782class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535783 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155784
Daniel Cheng566634ff2024-06-29 14:56:535785 def testCppMobilePlatformPath(self):
5786 input_api = MockInputApi()
5787 input_api.files = [
5788 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5789 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5790 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5791 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5792 MockFile('components/foo/delegate_android.cc',
5793 ['IsSyncFeatureActive']),
5794 MockFile('components/foo/delegate_ios.cc',
5795 ['IsSyncFeatureActive']),
5796 MockFile('components/foo/android_delegate.cc',
5797 ['IsSyncFeatureActive']),
5798 MockFile('components/foo/ios_delegate.cc',
5799 ['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(7, len(results))
5805 self.assertTrue(all('chrome/browser/android/file.cc' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535806 self.assertTrue('chrome/android/file.cc' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155807 self.assertTrue('ios/file.mm' in results[1].message),
5808 self.assertTrue('components/foo/ios/file.cc' in results[2].message),
Daniel Cheng566634ff2024-06-29 14:56:535809 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155810 'components/foo/delegate_android.cc' in results[3].message),
Daniel Cheng566634ff2024-06-29 14:56:535811 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155812 'components/foo/delegate_ios.cc' in results[4].message),
Daniel Cheng566634ff2024-06-29 14:56:535813 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155814 'components/foo/android_delegate.cc' in results[5].message),
Daniel Cheng566634ff2024-06-29 14:56:535815 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155816 'components/foo/ios_delegate.cc' in results[6].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155817
Daniel Cheng566634ff2024-06-29 14:56:535818 def testCppNonMobilePlatformPath(self):
5819 input_api = MockInputApi()
5820 input_api.files = [
5821 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5822 MockFile('bios/file.cc', ['HasSyncConsent']),
5823 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5824 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155825
Daniel Cheng566634ff2024-06-29 14:56:535826 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155827
Daniel Cheng566634ff2024-06-29 14:56:535828 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155829
Daniel Cheng566634ff2024-06-29 14:56:535830 def testJavaPath(self):
5831 input_api = MockInputApi()
5832 input_api.files = [
5833 MockFile('components/foo/file1.java', ['otherFunction']),
5834 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5835 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5836 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5837 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5838 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155839
Daniel Cheng566634ff2024-06-29 14:56:535840 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155841
Ben Pastenee79d66112025-04-23 19:46:155842 self.assertEqual(4, len(results))
5843 self.assertTrue(all('components/foo/file1.java' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535844 self.assertTrue('components/foo/file2.java' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155845 self.assertTrue('chrome/foo/file3.java' in results[1].message),
5846 self.assertTrue('chrome/foo/file4.java' in results[2].message),
5847 self.assertTrue('chrome/foo/file5.java' in results[3].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155848
5849
Erik Chen1396bbe2025-01-27 23:39:365850class CheckAnonymousNamespaceTest(unittest.TestCase):
5851 """Test the presubmit for anonymous namespaces."""
5852
5853 def testAnonymousNamespace(self):
5854 input_api = MockInputApi()
5855 input_api.files = [
5856 MockFile('chrome/test.h', ['namespace {']),
5857 MockFile('chrome/test.cc', ['namespace {']),
5858 MockFile('chrome/test.java', ['namespace {']),
5859 MockFile('chrome/test.cpp', ['namespace {']),
5860 MockFile('chrome/test.txt', ['namespace {']),
5861 ]
5862
5863 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
5864
5865 self.assertEqual(1, len(results))
5866 self.assertTrue(
5867 'chrome/test.h' in results[0].message),
5868 self.assertFalse(
5869 'chrome/test.cc' in results[0].message),
5870 self.assertFalse(
5871 'chrome/test.java' in results[0].message),
5872 self.assertFalse(
5873 'chrome/test.cpp' in results[0].message),
5874 self.assertFalse(
5875 'chrome/test.txt' in results[0].message),
5876
5877
[email protected]2299dcf2012-11-15 19:56:245878if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535879 unittest.main()