blob: e82fda59f6fdef63658bd9c0240b2f30ba22a8d0 [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 Grieveb77ac762024-11-29 15:01:48448 def testFindAddedDepsThatRequireReview(self):
449 caring = ['new_usages_require_review = True']
450 self.input_api.InitFiles([
451 MockAffectedFile('cares/DEPS', caring),
452 MockAffectedFile('cares/inherits/DEPS', []),
453 MockAffectedFile('willynilly/DEPS', []),
454 MockAffectedFile('willynilly/butactually/DEPS', caring),
455 ])
456
457 expected = {
458 'cares': True,
459 'cares/sub/sub': True,
460 'cares/inherits': True,
461 'cares/inherits/sub': True,
462 'willynilly': False,
463 'willynilly/butactually': True,
464 'willynilly/butactually/sub': True,
465 }
466 results = PRESUBMIT._FindAddedDepsThatRequireReview(
467 self.input_api, set(expected))
468 actual = {k: k in results for k in expected}
469 self.assertEqual(expected, actual)
470
Daniel Cheng566634ff2024-06-29 14:56:53471 class FakeOwnersClient(object):
472 APPROVED = "APPROVED"
473 PENDING = "PENDING"
474 returns = {}
Scott Leebf6a0942024-06-26 22:59:39475
Daniel Cheng566634ff2024-06-29 14:56:53476 def ListOwners(self, *args, **kwargs):
477 return self.returns.get(self.ListOwners.__name__, "")
Scott Leebf6a0942024-06-26 22:59:39478
Daniel Cheng566634ff2024-06-29 14:56:53479 def mockListOwners(self, owners):
480 self.returns[self.ListOwners.__name__] = owners
Scott Leebf6a0942024-06-26 22:59:39481
Daniel Cheng566634ff2024-06-29 14:56:53482 def GetFilesApprovalStatus(self, *args, **kwargs):
483 return self.returns.get(self.GetFilesApprovalStatus.__name__, {})
Scott Leebf6a0942024-06-26 22:59:39484
Daniel Cheng566634ff2024-06-29 14:56:53485 def mockGetFilesApprovalStatus(self, status):
486 self.returns[self.GetFilesApprovalStatus.__name__] = status
Scott Leebf6a0942024-06-26 22:59:39487
Daniel Cheng566634ff2024-06-29 14:56:53488 def SuggestOwners(self, *args, **kwargs):
489 return ["eng1", "eng2", "eng3"]
Scott Leebf6a0942024-06-26 22:59:39490
Daniel Cheng566634ff2024-06-29 14:56:53491 class fakeGerrit(object):
Scott Leebf6a0942024-06-26 22:59:39492
Daniel Cheng566634ff2024-06-29 14:56:53493 def IsOwnersOverrideApproved(self, issue):
494 return False
Scott Leebf6a0942024-06-26 22:59:39495
Daniel Cheng566634ff2024-06-29 14:56:53496 def mockOwnersAndReviewers(self, owner, reviewers):
Scott Leebf6a0942024-06-26 22:59:39497
Daniel Cheng566634ff2024-06-29 14:56:53498 def mock(*args, **kwargs):
499 return [owner, reviewers]
Scott Leebf6a0942024-06-26 22:59:39500
Daniel Cheng566634ff2024-06-29 14:56:53501 self.input_api.canned_checks.GetCodereviewOwnerAndReviewers = mock
Scott Leebf6a0942024-06-26 22:59:39502
Daniel Cheng566634ff2024-06-29 14:56:53503 def mockListSubmodules(self, paths):
Scott Leebf6a0942024-06-26 22:59:39504
Daniel Cheng566634ff2024-06-29 14:56:53505 def mock(*args, **kwargs):
506 return paths
Scott Leebf6a0942024-06-26 22:59:39507
Daniel Cheng566634ff2024-06-29 14:56:53508 self.input_api.ListSubmodules = mock
509
510 def testApprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08511 self.input_api.InitFiles([
Joanna Wang130e7bdd2024-12-10 17:39:03512 MockAffectedFile('pdf/DEPS',
513 ['include_rules=["+v8/123", "+foo/bar"]']),
Andrew Grieveb77ac762024-11-29 15:01:48514 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Joanna Wang130e7bdd2024-12-10 17:39:03515 # Check that we ignore "DEPS" directories. Note there are real cases
516 # of directories named "deps/" and, especially for case-insensitive file
517 # systems we should prevent these from being considered.
518 MockAffectedFile('foo/bar/DEPS/boofar', ['boofar file contents']),
Andrew Grieve713b89b2024-10-15 20:20:08519 ])
Daniel Cheng566634ff2024-06-29 14:56:53520
521 # mark the additional dep as approved.
522 os_path = self.input_api.os_path
523 self.input_api.owners_client.mockGetFilesApprovalStatus(
524 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.APPROVED})
525 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
526 self.input_api, MockOutputApi())
527 # Then, the check should pass.
528 self.assertEqual([], results)
529
530 def testUnapprovedAdditionalDep(self):
Andrew Grieve713b89b2024-10-15 20:20:08531 self.input_api.InitFiles([
532 MockAffectedFile('pdf/DEPS', ['include_rules=["+v8/123"]']),
Andrew Grieveb77ac762024-11-29 15:01:48533 MockAffectedFile('v8/DEPS', ['new_usages_require_review=True']),
Andrew Grieve713b89b2024-10-15 20:20:08534 ])
Daniel Cheng566634ff2024-06-29 14:56:53535
536 # pending.
537 os_path = self.input_api.os_path
538 self.input_api.owners_client.mockGetFilesApprovalStatus(
539 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.PENDING})
540 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
541 self.input_api, MockOutputApi())
542 # the check should fail
543 self.assertIn('You need LGTM', results[0].message)
544 self.assertIn('+v8/123', results[0].message)
545
546 # unless the added dep is from a submodule.
547 self.mockListSubmodules(['v8'])
548 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
549 self.input_api, MockOutputApi())
550 self.assertEqual([], results)
Scott Leebf6a0942024-06-26 22:59:39551
[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(
1780 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1781 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1782 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
1783 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381784
Daniel Cheng566634ff2024-06-29 14:56:531785 # Tag must not contain
1786 nb = len(msgs[4].items)
1787 self.assertEqual(
1788 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1789 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1790 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1791 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511792
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391793
estadee17314a02017-01-12 16:22:161794class GoogleAnswerUrlFormatTest(unittest.TestCase):
1795
Daniel Cheng566634ff2024-06-29 14:56:531796 def testCatchAnswerUrlId(self):
1797 input_api = MockInputApi()
1798 input_api.files = [
1799 MockFile('somewhere/file.cc', [
1800 'char* host = '
1801 ' "https://support.google.com/chrome/answer/123456";'
1802 ]),
1803 MockFile('somewhere_else/file.cc', [
1804 'char* host = '
1805 ' "https://support.google.com/chrome/a/answer/123456";'
1806 ]),
1807 ]
estadee17314a02017-01-12 16:22:161808
Daniel Cheng566634ff2024-06-29 14:56:531809 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1810 input_api, MockOutputApi())
1811 self.assertEqual(1, len(warnings))
1812 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161813
Daniel Cheng566634ff2024-06-29 14:56:531814 def testAllowAnswerUrlParam(self):
1815 input_api = MockInputApi()
1816 input_api.files = [
1817 MockFile('somewhere/file.cc', [
1818 'char* host = '
1819 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1820 ]),
1821 ]
estadee17314a02017-01-12 16:22:161822
Daniel Cheng566634ff2024-06-29 14:56:531823 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1824 input_api, MockOutputApi())
1825 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161826
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391827
reillyi38965732015-11-16 18:27:331828class HardcodedGoogleHostsTest(unittest.TestCase):
1829
Daniel Cheng566634ff2024-06-29 14:56:531830 def testWarnOnAssignedLiterals(self):
1831 input_api = MockInputApi()
1832 input_api.files = [
1833 MockFile('content/file.cc',
1834 ['char* host = "https://www.google.com";']),
1835 MockFile('content/file.cc',
1836 ['char* host = "https://www.googleapis.com";']),
1837 MockFile('content/file.cc',
1838 ['char* host = "https://clients1.google.com";']),
1839 ]
reillyi38965732015-11-16 18:27:331840
Daniel Cheng566634ff2024-06-29 14:56:531841 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1842 input_api, MockOutputApi())
1843 self.assertEqual(1, len(warnings))
1844 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331845
Daniel Cheng566634ff2024-06-29 14:56:531846 def testAllowInComment(self):
1847 input_api = MockInputApi()
1848 input_api.files = [
1849 MockFile('content/file.cc',
1850 ['char* host = "https://www.aol.com"; // google.com'])
1851 ]
reillyi38965732015-11-16 18:27:331852
Daniel Cheng566634ff2024-06-29 14:56:531853 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1854 input_api, MockOutputApi())
1855 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331856
dgn4401aa52015-04-29 16:26:171857
James Cook6b6597c2019-11-06 22:05:291858class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1859
Daniel Cheng566634ff2024-06-29 14:56:531860 def testWarnsOnChromeOsDirectories(self):
1861 files = [
1862 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1863 MockFile('chrome/browser/chromeos/file.cc',
1864 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1865 MockFile('chromeos/file.cc',
1866 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1867 MockFile('components/arc/file.cc',
1868 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1869 MockFile('components/exo/file.cc',
1870 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1871 ]
1872 input_api = MockInputApi()
1873 for file in files:
1874 input_api.files = [file]
1875 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1876 input_api, MockOutputApi())
1877 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291878
Daniel Cheng566634ff2024-06-29 14:56:531879 def testDoesNotWarnOnSyncOsPref(self):
1880 input_api = MockInputApi()
1881 input_api.files = [
1882 MockFile('chromeos/file.cc',
1883 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
1884 ]
1885 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1886 input_api, MockOutputApi())
1887 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291888
Daniel Cheng566634ff2024-06-29 14:56:531889 def testDoesNotWarnOnOtherDirectories(self):
1890 input_api = MockInputApi()
1891 input_api.files = [
1892 MockFile('chrome/browser/ui/file.cc',
1893 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1894 MockFile('components/sync/file.cc',
1895 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1896 MockFile('content/browser/file.cc',
1897 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1898 MockFile('a/notchromeos/file.cc',
1899 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1900 ]
1901 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1902 input_api, MockOutputApi())
1903 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:291904
Daniel Cheng566634ff2024-06-29 14:56:531905 def testSeparateWarningForPriorityPrefs(self):
1906 input_api = MockInputApi()
1907 input_api.files = [
1908 MockFile('chromeos/file.cc', [
1909 'PrefRegistrySyncable::SYNCABLE_PREF',
1910 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
1911 ]),
1912 ]
1913 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1914 input_api, MockOutputApi())
1915 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:291916
1917
jbriance9e12f162016-11-25 07:57:501918class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:501919
Daniel Cheng566634ff2024-06-29 14:56:531920 def testCheckHeadersOnlyOutsideThirdParty(self):
1921 mock_input_api = MockInputApi()
1922 mock_input_api.files = [
1923 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
1924 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
1925 ]
1926 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1927 mock_input_api, MockOutputApi())
1928 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501929
Daniel Cheng566634ff2024-06-29 14:56:531930 def testNoNestedDeclaration(self):
1931 mock_input_api = MockInputApi()
1932 mock_input_api.files = [
1933 MockAffectedFile('somewhere/header.h', [
1934 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
1935 ])
1936 ]
1937 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1938 mock_input_api, MockOutputApi())
1939 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:501940
Daniel Cheng566634ff2024-06-29 14:56:531941 def testSubStrings(self):
1942 mock_input_api = MockInputApi()
1943 mock_input_api.files = [
1944 MockAffectedFile('somewhere/header.h', [
1945 'class NotUsefulClass;', 'struct SomeStruct;',
1946 'UsefulClass *p1;', 'SomeStructPtr *p2;'
1947 ])
1948 ]
1949 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1950 mock_input_api, MockOutputApi())
1951 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:501952
Daniel Cheng566634ff2024-06-29 14:56:531953 def testUselessForwardDeclaration(self):
1954 mock_input_api = MockInputApi()
1955 mock_input_api.files = [
1956 MockAffectedFile('somewhere/header.h', [
1957 'class DummyClass;', 'struct DummyStruct;',
1958 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
1959 ])
1960 ]
1961 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1962 mock_input_api, MockOutputApi())
1963 self.assertEqual(2, len(warnings))
1964
1965 def testBlinkHeaders(self):
1966 mock_input_api = MockInputApi()
1967 mock_input_api.files = [
1968 MockAffectedFile('third_party/blink/header.h', [
1969 'class DummyClass;',
1970 'struct DummyStruct;',
1971 ]),
1972 MockAffectedFile('third_party\\blink\\header.h', [
1973 'class DummyClass;',
1974 'struct DummyStruct;',
1975 ])
1976 ]
1977 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
1978 mock_input_api, MockOutputApi())
1979 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:311980
jbriance9e12f162016-11-25 07:57:501981
rlanday6802cf632017-05-30 17:48:361982class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:361983
Daniel Cheng566634ff2024-06-29 14:56:531984 def testThirdPartyNotWebKitIgnored(self):
1985 mock_input_api = MockInputApi()
1986 mock_input_api.files = [
1987 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
1988 MockAffectedFile('third_party/test/test.cpp',
1989 '#include "../header.h"'),
1990 ]
rlanday6802cf632017-05-30 17:48:361991
Daniel Cheng566634ff2024-06-29 14:56:531992 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:361993
Daniel Cheng566634ff2024-06-29 14:56:531994 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
1995 mock_output_api)
1996 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:361997
Daniel Cheng566634ff2024-06-29 14:56:531998 def testNonCppFileIgnored(self):
1999 mock_input_api = MockInputApi()
2000 mock_input_api.files = [
2001 MockAffectedFile('test.py', '#include "../header.h"'),
2002 ]
rlanday6802cf632017-05-30 17:48:362003
Daniel Cheng566634ff2024-06-29 14:56:532004 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362005
Daniel Cheng566634ff2024-06-29 14:56:532006 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2007 mock_output_api)
2008 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362009
Daniel Cheng566634ff2024-06-29 14:56:532010 def testInnocuousChangesAllowed(self):
2011 mock_input_api = MockInputApi()
2012 mock_input_api.files = [
2013 MockAffectedFile('test.cpp', '#include "header.h"'),
2014 MockAffectedFile('test2.cpp', '../'),
2015 ]
rlanday6802cf632017-05-30 17:48:362016
Daniel Cheng566634ff2024-06-29 14:56:532017 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362018
Daniel Cheng566634ff2024-06-29 14:56:532019 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2020 mock_output_api)
2021 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362022
Daniel Cheng566634ff2024-06-29 14:56:532023 def testRelativeIncludeNonWebKitProducesError(self):
2024 mock_input_api = MockInputApi()
2025 mock_input_api.files = [
2026 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2027 ]
rlanday6802cf632017-05-30 17:48:362028
Daniel Cheng566634ff2024-06-29 14:56:532029 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362030
Daniel Cheng566634ff2024-06-29 14:56:532031 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2032 mock_output_api)
2033 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362034
Daniel Cheng566634ff2024-06-29 14:56:532035 def testRelativeIncludeWebKitProducesError(self):
2036 mock_input_api = MockInputApi()
2037 mock_input_api.files = [
2038 MockAffectedFile('third_party/blink/test.cpp',
2039 ['#include "../header.h']),
2040 ]
rlanday6802cf632017-05-30 17:48:362041
Daniel Cheng566634ff2024-06-29 14:56:532042 mock_output_api = MockOutputApi()
2043
2044 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2045 mock_output_api)
2046 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242047
Daniel Cheng13ca61a882017-08-25 15:11:252048
Daniel Bratell65b033262019-04-23 08:17:062049class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062050
Daniel Cheng566634ff2024-06-29 14:56:532051 def testThirdPartyNotBlinkIgnored(self):
2052 mock_input_api = MockInputApi()
2053 mock_input_api.files = [
2054 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2055 ]
Daniel Bratell65b033262019-04-23 08:17:062056
Daniel Cheng566634ff2024-06-29 14:56:532057 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062058
Daniel Cheng566634ff2024-06-29 14:56:532059 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2060 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062061
Daniel Cheng566634ff2024-06-29 14:56:532062 def testPythonFileIgnored(self):
2063 mock_input_api = MockInputApi()
2064 mock_input_api.files = [
2065 MockAffectedFile('test.py', '#include "file.cc"'),
2066 ]
Daniel Bratell65b033262019-04-23 08:17:062067
Daniel Cheng566634ff2024-06-29 14:56:532068 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062069
Daniel Cheng566634ff2024-06-29 14:56:532070 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2071 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062072
Daniel Cheng566634ff2024-06-29 14:56:532073 def testIncFilesAccepted(self):
2074 mock_input_api = MockInputApi()
2075 mock_input_api.files = [
2076 MockAffectedFile('test.py', '#include "file.inc"'),
2077 ]
Daniel Bratell65b033262019-04-23 08:17:062078
Daniel Cheng566634ff2024-06-29 14:56:532079 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062080
Daniel Cheng566634ff2024-06-29 14:56:532081 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2082 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062083
Daniel Cheng566634ff2024-06-29 14:56:532084 def testInnocuousChangesAllowed(self):
2085 mock_input_api = MockInputApi()
2086 mock_input_api.files = [
2087 MockAffectedFile('test.cpp', '#include "header.h"'),
2088 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2089 ]
Daniel Bratell65b033262019-04-23 08:17:062090
Daniel Cheng566634ff2024-06-29 14:56:532091 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062092
Daniel Cheng566634ff2024-06-29 14:56:532093 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2094 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062095
Daniel Cheng566634ff2024-06-29 14:56:532096 def testCcIncludeNonBlinkProducesError(self):
2097 mock_input_api = MockInputApi()
2098 mock_input_api.files = [
2099 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2100 ]
Daniel Bratell65b033262019-04-23 08:17:062101
Daniel Cheng566634ff2024-06-29 14:56:532102 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062103
Daniel Cheng566634ff2024-06-29 14:56:532104 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2105 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062106
Daniel Cheng566634ff2024-06-29 14:56:532107 def testCppIncludeBlinkProducesError(self):
2108 mock_input_api = MockInputApi()
2109 mock_input_api.files = [
2110 MockAffectedFile('third_party/blink/test.cpp',
2111 ['#include "foo/file.cpp"']),
2112 ]
Daniel Bratell65b033262019-04-23 08:17:062113
Daniel Cheng566634ff2024-06-29 14:56:532114 mock_output_api = MockOutputApi()
2115
2116 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2117 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062118
2119
Andrew Grieve1b290e4a22020-11-24 20:07:012120class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012121
Daniel Cheng566634ff2024-06-29 14:56:532122 def testAddBareGlobs(self):
2123 mock_input_api = MockInputApi()
2124 mock_input_api.files = [
2125 MockAffectedFile('base/stuff.gni',
2126 ['forward_variables_from(invoker, "*")']),
2127 MockAffectedFile('base/BUILD.gn',
2128 ['forward_variables_from(invoker, "*")']),
2129 ]
2130 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2131 MockOutputApi())
2132 self.assertEqual(1, len(warnings))
2133 msg = '\n'.join(warnings[0].items)
2134 self.assertIn('base/stuff.gni', msg)
2135 # Should not check .gn files. Local templates don't need to care about
2136 # visibility / testonly.
2137 self.assertNotIn('base/BUILD.gn', msg)
2138
2139 def testValidUses(self):
2140 mock_input_api = MockInputApi()
2141 mock_input_api.files = [
2142 MockAffectedFile('base/stuff.gni',
2143 ['forward_variables_from(invoker, "*", [])']),
2144 MockAffectedFile('base/stuff2.gni', [
2145 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2146 ]),
2147 MockAffectedFile(
2148 'base/stuff3.gni',
2149 ['forward_variables_from(invoker, [ "testonly" ])']),
2150 ]
2151 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2152 MockOutputApi())
2153 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012154
2155
Sean Kaucb7c9b32022-10-25 21:25:522156class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522157
Daniel Cheng566634ff2024-06-29 14:56:532158 def testAddAbsolutePath(self):
2159 mock_input_api = MockInputApi()
2160 mock_input_api.files = [
2161 MockAffectedFile('base/BUILD.gn',
2162 ['rebase_path("$target_gen_dir", "//")']),
2163 MockAffectedFile('base/root/BUILD.gn',
2164 ['rebase_path("$target_gen_dir", "/")']),
2165 MockAffectedFile('base/variable/BUILD.gn',
2166 ['rebase_path(target_gen_dir, "/")']),
2167 ]
2168 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2169 self.assertEqual(1, len(warnings))
2170 msg = '\n'.join(warnings[0].items)
2171 self.assertIn('base/BUILD.gn', msg)
2172 self.assertIn('base/root/BUILD.gn', msg)
2173 self.assertIn('base/variable/BUILD.gn', msg)
2174 self.assertEqual(3, len(warnings[0].items))
2175
2176 def testValidUses(self):
2177 mock_input_api = MockInputApi()
2178 mock_input_api.files = [
2179 MockAffectedFile(
2180 'base/foo/BUILD.gn',
2181 ['rebase_path("$target_gen_dir", root_build_dir)']),
2182 MockAffectedFile(
2183 'base/bar/BUILD.gn',
2184 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2185 MockAffectedFile('base/baz/BUILD.gn',
2186 ['rebase_path(target_gen_dir, root_build_dir)']),
2187 MockAffectedFile(
2188 'base/baz/BUILD.gn',
2189 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2190 MockAffectedFile('base/okay_slash/BUILD.gn',
2191 ['rebase_path(".", "//")']),
2192 ]
2193 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2194 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522195
2196
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192197class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192198
Daniel Cheng566634ff2024-06-29 14:56:532199 def testAddHeaderWithoutGn(self):
2200 mock_input_api = MockInputApi()
2201 mock_input_api.files = [
2202 MockAffectedFile('base/stuff.h', ''),
2203 ]
2204 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2205 mock_input_api, MockOutputApi())
2206 self.assertEqual(1, len(warnings))
2207 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192208
Daniel Cheng566634ff2024-06-29 14:56:532209 def testModifyHeader(self):
2210 mock_input_api = MockInputApi()
2211 mock_input_api.files = [
2212 MockAffectedFile('base/stuff.h', '', action='M'),
2213 ]
2214 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2215 mock_input_api, MockOutputApi())
2216 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192217
Daniel Cheng566634ff2024-06-29 14:56:532218 def testDeleteHeader(self):
2219 mock_input_api = MockInputApi()
2220 mock_input_api.files = [
2221 MockAffectedFile('base/stuff.h', '', action='D'),
2222 ]
2223 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2224 mock_input_api, MockOutputApi())
2225 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192226
Daniel Cheng566634ff2024-06-29 14:56:532227 def testAddHeaderWithGn(self):
2228 mock_input_api = MockInputApi()
2229 mock_input_api.files = [
2230 MockAffectedFile('base/stuff.h', ''),
2231 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2232 ]
2233 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2234 mock_input_api, MockOutputApi())
2235 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192236
Daniel Cheng566634ff2024-06-29 14:56:532237 def testAddHeaderWithGni(self):
2238 mock_input_api = MockInputApi()
2239 mock_input_api.files = [
2240 MockAffectedFile('base/stuff.h', ''),
2241 MockAffectedFile('base/files.gni', 'stuff.h'),
2242 ]
2243 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2244 mock_input_api, MockOutputApi())
2245 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192246
Daniel Cheng566634ff2024-06-29 14:56:532247 def testAddHeaderWithOther(self):
2248 mock_input_api = MockInputApi()
2249 mock_input_api.files = [
2250 MockAffectedFile('base/stuff.h', ''),
2251 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2252 ]
2253 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2254 mock_input_api, MockOutputApi())
2255 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192256
Daniel Cheng566634ff2024-06-29 14:56:532257 def testAddHeaderWithWrongGn(self):
2258 mock_input_api = MockInputApi()
2259 mock_input_api.files = [
2260 MockAffectedFile('base/stuff.h', ''),
2261 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2262 ]
2263 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2264 mock_input_api, MockOutputApi())
2265 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192266
Daniel Cheng566634ff2024-06-29 14:56:532267 def testAddHeadersWithGn(self):
2268 mock_input_api = MockInputApi()
2269 mock_input_api.files = [
2270 MockAffectedFile('base/stuff.h', ''),
2271 MockAffectedFile('base/another.h', ''),
2272 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2273 ]
2274 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2275 mock_input_api, MockOutputApi())
2276 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192277
Daniel Cheng566634ff2024-06-29 14:56:532278 def testAddHeadersWithWrongGn(self):
2279 mock_input_api = MockInputApi()
2280 mock_input_api.files = [
2281 MockAffectedFile('base/stuff.h', ''),
2282 MockAffectedFile('base/another.h', ''),
2283 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2284 ]
2285 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2286 mock_input_api, MockOutputApi())
2287 self.assertEqual(1, len(warnings))
2288 self.assertFalse('base/stuff.h' in warnings[0].items)
2289 self.assertTrue('base/another.h' in warnings[0].items)
2290
2291 def testAddHeadersWithWrongGn2(self):
2292 mock_input_api = MockInputApi()
2293 mock_input_api.files = [
2294 MockAffectedFile('base/stuff.h', ''),
2295 MockAffectedFile('base/another.h', ''),
2296 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2297 ]
2298 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2299 mock_input_api, MockOutputApi())
2300 self.assertEqual(1, len(warnings))
2301 self.assertTrue('base/stuff.h' in warnings[0].items)
2302 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192303
2304
Michael Giuffridad3bc8672018-10-25 22:48:022305class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022306
Daniel Cheng566634ff2024-06-29 14:56:532307 def testProductNameInDesc(self):
2308 mock_input_api = MockInputApi()
2309 mock_input_api.files = [
2310 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2311 '<message name="Foo" desc="Welcome to Chrome">',
2312 ' Welcome to Chrome!',
2313 '</message>',
2314 ]),
2315 MockAffectedFile('chrome/app/chromium_strings.grd', [
2316 '<message name="Bar" desc="Welcome to Chrome">',
2317 ' Welcome to Chromium!',
2318 '</message>',
2319 ]),
2320 ]
2321 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2322 mock_input_api, MockOutputApi())
2323 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022324
Daniel Cheng566634ff2024-06-29 14:56:532325 def testChromeInChromium(self):
2326 mock_input_api = MockInputApi()
2327 mock_input_api.files = [
2328 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2329 '<message name="Foo" desc="Welcome to Chrome">',
2330 ' Welcome to Chrome!',
2331 '</message>',
2332 ]),
2333 MockAffectedFile('chrome/app/chromium_strings.grd', [
2334 '<message name="Bar" desc="Welcome to Chrome">',
2335 ' Welcome to Chrome!',
2336 '</message>',
2337 ]),
2338 ]
2339 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2340 mock_input_api, MockOutputApi())
2341 self.assertEqual(1, len(warnings))
2342 self.assertTrue(
2343 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022344
Daniel Cheng566634ff2024-06-29 14:56:532345 def testChromiumInChrome(self):
2346 mock_input_api = MockInputApi()
2347 mock_input_api.files = [
2348 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2349 '<message name="Foo" desc="Welcome to Chrome">',
2350 ' Welcome to Chromium!',
2351 '</message>',
2352 ]),
2353 MockAffectedFile('chrome/app/chromium_strings.grd', [
2354 '<message name="Bar" desc="Welcome to Chrome">',
2355 ' Welcome to Chromium!',
2356 '</message>',
2357 ]),
2358 ]
2359 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2360 mock_input_api, MockOutputApi())
2361 self.assertEqual(1, len(warnings))
2362 self.assertTrue(
2363 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202364
Daniel Cheng566634ff2024-06-29 14:56:532365 def testChromeForTestingInChromium(self):
2366 mock_input_api = MockInputApi()
2367 mock_input_api.files = [
2368 MockAffectedFile('chrome/app/chromium_strings.grd', [
2369 '<message name="Bar" desc="Welcome to Chrome">',
2370 ' Welcome to Chrome for Testing!',
2371 '</message>',
2372 ]),
2373 ]
2374 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2375 mock_input_api, MockOutputApi())
2376 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202377
Daniel Cheng566634ff2024-06-29 14:56:532378 def testChromeForTestingInChrome(self):
2379 mock_input_api = MockInputApi()
2380 mock_input_api.files = [
2381 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2382 '<message name="Bar" desc="Welcome to Chrome">',
2383 ' Welcome to Chrome for Testing!',
2384 '</message>',
2385 ]),
2386 ]
2387 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2388 mock_input_api, MockOutputApi())
2389 self.assertEqual(1, len(warnings))
2390 self.assertTrue(
2391 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022392
Daniel Cheng566634ff2024-06-29 14:56:532393 def testMultipleInstances(self):
2394 mock_input_api = MockInputApi()
2395 mock_input_api.files = [
2396 MockAffectedFile('chrome/app/chromium_strings.grd', [
2397 '<message name="Bar" desc="Welcome to Chrome">',
2398 ' Welcome to Chrome!',
2399 '</message>',
2400 '<message name="Baz" desc="A correct message">',
2401 ' Chromium is the software you are using.',
2402 '</message>',
2403 '<message name="Bat" desc="An incorrect message">',
2404 ' Google Chrome is the software you are using.',
2405 '</message>',
2406 ]),
2407 ]
2408 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2409 mock_input_api, MockOutputApi())
2410 self.assertEqual(1, len(warnings))
2411 self.assertTrue(
2412 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2413 self.assertTrue(
2414 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2415
2416 def testMultipleWarnings(self):
2417 mock_input_api = MockInputApi()
2418 mock_input_api.files = [
2419 MockAffectedFile('chrome/app/chromium_strings.grd', [
2420 '<message name="Bar" desc="Welcome to Chrome">',
2421 ' Welcome to Chrome!',
2422 '</message>',
2423 '<message name="Baz" desc="A correct message">',
2424 ' Chromium is the software you are using.',
2425 '</message>',
2426 '<message name="Bat" desc="An incorrect message">',
2427 ' Google Chrome is the software you are using.',
2428 '</message>',
2429 ]),
2430 MockAffectedFile(
2431 'components/components_google_chrome_strings.grd', [
2432 '<message name="Bar" desc="Welcome to Chrome">',
2433 ' Welcome to Chrome!',
2434 '</message>',
2435 '<message name="Baz" desc="A correct message">',
2436 ' Chromium is the software you are using.',
2437 '</message>',
2438 '<message name="Bat" desc="An incorrect message">',
2439 ' Google Chrome is the software you are using.',
2440 '</message>',
2441 ]),
2442 ]
2443 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2444 mock_input_api, MockOutputApi())
2445 self.assertEqual(2, len(warnings))
2446 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2447 warnings[0].items[0])
2448 self.assertTrue(
2449 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2450 self.assertTrue(
2451 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022452
2453
Daniel Chenga37c03db2022-05-12 17:20:342454class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252455
Daniel Cheng566634ff2024-06-29 14:56:532456 def _createMockInputApi(self):
2457 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472458
Daniel Cheng566634ff2024-06-29 14:56:532459 def FakeRepositoryRoot():
2460 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472461
Daniel Cheng566634ff2024-06-29 14:56:532462 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2463 self._injectFakeOwnersClient(
2464 mock_input_api, ['[email protected]', '[email protected]'])
2465 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342466
Daniel Cheng566634ff2024-06-29 14:56:532467 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342468
Daniel Cheng566634ff2024-06-29 14:56:532469 class FakeGerrit(object):
2470
2471 def IsOwnersOverrideApproved(self, issue):
2472 return False
2473
2474 input_api.change.issue = 123
2475 input_api.gerrit = FakeGerrit()
2476
2477 def _injectFakeOwnersClient(self, input_api, owners):
2478
2479 class FakeOwnersClient(object):
2480
2481 def ListOwners(self, f):
2482 return owners
2483
2484 input_api.owners_client = FakeOwnersClient()
2485
2486 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2487
2488 def MockOwnerAndReviewers(input_api,
2489 email_regexp,
2490 approval_needed=False):
2491 return [owner, reviewers]
2492
2493 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2494 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342495
2496
2497class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532498 _test_cases = [
2499 ('*_messages.cc', 'scary_messages.cc'),
2500 ('*_messages*.h', 'scary_messages.h'),
2501 ('*_messages*.h', 'scary_messages_android.h'),
2502 ('*_param_traits*.*', 'scary_param_traits.h'),
2503 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2504 ('*.mojom', 'scary.mojom'),
2505 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2506 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2507 ('*_type_converter*.*', 'scary_type_converter.h'),
2508 ('*_type_converter*.*', 'scary_type_converter_nacl.h'),
2509 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252510 ]
Daniel Cheng171dad8d2022-05-21 00:40:252511
Daniel Cheng566634ff2024-06-29 14:56:532512 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2513 mock_input_api = self._createMockInputApi()
2514 new_owners_file_path = mock_input_api.os_path.join(
2515 'services', 'goat', 'public', 'OWNERS')
2516 new_owners_file = [
2517 'per-file *.mojom=set noparent',
2518 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2519 ]
Daniel Cheng3008dc12022-05-13 04:02:112520
Daniel Cheng566634ff2024-06-29 14:56:532521 def FakeReadFile(filename):
2522 self.assertEqual(
2523 mock_input_api.os_path.join('chromium', 'src',
2524 new_owners_file_path), filename)
2525 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112526
Daniel Cheng566634ff2024-06-29 14:56:532527 mock_input_api.ReadFile = FakeReadFile
2528 mock_input_api.files = [
2529 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252530 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532531 mock_input_api.os_path.join('services', 'goat', 'public',
2532 'goat.mojom'),
2533 ['// Scary contents.'])
2534 ]
2535 self._setupFakeChange(mock_input_api)
2536 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2537 '[email protected]',
2538 ['[email protected]'])
2539 mock_input_api.is_committing = True
2540 mock_input_api.dry_run = False
2541 mock_output_api = MockOutputApi()
2542 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2543 mock_output_api)
2544 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342545
Daniel Cheng566634ff2024-06-29 14:56:532546 def testMissingSecurityReviewerAtUpload(self):
2547 mock_input_api = self._createMockInputApi()
2548 new_owners_file_path = mock_input_api.os_path.join(
2549 'services', 'goat', 'public', 'OWNERS')
2550 new_owners_file = [
2551 'per-file *.mojom=set noparent',
2552 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2553 ]
Daniel Chenga37c03db2022-05-12 17:20:342554
Daniel Cheng566634ff2024-06-29 14:56:532555 def FakeReadFile(filename):
2556 self.assertEqual(
2557 mock_input_api.os_path.join('chromium', 'src',
2558 new_owners_file_path), filename)
2559 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362560
Daniel Cheng566634ff2024-06-29 14:56:532561 mock_input_api.ReadFile = FakeReadFile
2562 mock_input_api.files = [
2563 MockAffectedFile(new_owners_file_path, new_owners_file),
2564 MockAffectedFile(
2565 mock_input_api.os_path.join('services', 'goat', 'public',
2566 'goat.mojom'),
2567 ['// Scary contents.'])
2568 ]
2569 self._setupFakeChange(mock_input_api)
2570 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2571 '[email protected]',
2572 ['[email protected]'])
2573 mock_input_api.is_committing = False
2574 mock_input_api.dry_run = False
2575 mock_output_api = MockOutputApi()
2576 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2577 mock_output_api)
2578 self.assertEqual(1, len(results))
2579 self.assertEqual('notify', results[0].type)
2580 self.assertEqual(
2581 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2582 'following newly-added files:', results[0].message)
2583
2584 def testMissingSecurityReviewerAtDryRunCommit(self):
2585 mock_input_api = self._createMockInputApi()
2586 new_owners_file_path = mock_input_api.os_path.join(
2587 'services', 'goat', 'public', 'OWNERS')
2588 new_owners_file = [
2589 'per-file *.mojom=set noparent',
2590 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2591 ]
2592
2593 def FakeReadFile(filename):
2594 self.assertEqual(
2595 mock_input_api.os_path.join('chromium', 'src',
2596 new_owners_file_path), filename)
2597 return '\n'.join(new_owners_file)
2598
2599 mock_input_api.ReadFile = FakeReadFile
2600 mock_input_api.files = [
2601 MockAffectedFile(new_owners_file_path, new_owners_file),
2602 MockAffectedFile(
2603 mock_input_api.os_path.join('services', 'goat', 'public',
2604 'goat.mojom'),
2605 ['// Scary contents.'])
2606 ]
2607 self._setupFakeChange(mock_input_api)
2608 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2609 '[email protected]',
2610 ['[email protected]'])
2611 mock_input_api.is_committing = True
2612 mock_input_api.dry_run = True
2613 mock_output_api = MockOutputApi()
2614 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2615 mock_output_api)
2616 self.assertEqual(1, len(results))
2617 self.assertEqual('error', results[0].type)
2618 self.assertEqual(
2619 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2620 'following newly-added files:', results[0].message)
2621
2622 def testMissingSecurityApprovalAtRealCommit(self):
2623 mock_input_api = self._createMockInputApi()
2624 new_owners_file_path = mock_input_api.os_path.join(
2625 'services', 'goat', 'public', 'OWNERS')
2626 new_owners_file = [
2627 'per-file *.mojom=set noparent',
2628 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2629 ]
2630
2631 def FakeReadFile(filename):
2632 self.assertEqual(
2633 mock_input_api.os_path.join('chromium', 'src',
2634 new_owners_file_path), filename)
2635 return '\n'.join(new_owners_file)
2636
2637 mock_input_api.ReadFile = FakeReadFile
2638 mock_input_api.files = [
2639 MockAffectedFile(new_owners_file_path, new_owners_file),
2640 MockAffectedFile(
2641 mock_input_api.os_path.join('services', 'goat', 'public',
2642 'goat.mojom'),
2643 ['// Scary contents.'])
2644 ]
2645 self._setupFakeChange(mock_input_api)
2646 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2647 '[email protected]',
2648 ['[email protected]'])
2649 mock_input_api.is_committing = True
2650 mock_input_api.dry_run = False
2651 mock_output_api = MockOutputApi()
2652 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2653 mock_output_api)
2654 self.assertEqual('error', results[0].type)
2655 self.assertEqual(
2656 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2657 'following newly-added files:', results[0].message)
2658
2659 def testIpcChangeNeedsSecurityOwner(self):
2660 for is_committing in [True, False]:
2661 for pattern, filename in self._test_cases:
2662 with self.subTest(
2663 line=
2664 f'is_committing={is_committing}, filename={filename}'):
2665 mock_input_api = self._createMockInputApi()
2666 mock_input_api.files = [
2667 MockAffectedFile(
2668 mock_input_api.os_path.join(
2669 'services', 'goat', 'public', filename),
2670 ['// Scary contents.'])
2671 ]
2672 self._setupFakeChange(mock_input_api)
2673 self._injectFakeChangeOwnerAndReviewers(
2674 mock_input_api, '[email protected]',
2675 ['[email protected]'])
2676 mock_input_api.is_committing = is_committing
2677 mock_input_api.dry_run = False
2678 mock_output_api = MockOutputApi()
2679 results = PRESUBMIT.CheckSecurityOwners(
2680 mock_input_api, mock_output_api)
2681 self.assertEqual(1, len(results))
2682 self.assertEqual('error', results[0].type)
2683 self.assertTrue(results[0].message.replace(
2684 '\\', '/'
2685 ).startswith(
2686 'Found missing OWNERS lines for security-sensitive files. '
2687 'Please add the following lines to services/goat/public/OWNERS:'
2688 ))
2689 self.assertEqual(['[email protected]'],
2690 mock_output_api.more_cc)
2691
2692 def testServiceManifestChangeNeedsSecurityOwner(self):
2693 mock_input_api = self._createMockInputApi()
2694 mock_input_api.files = [
2695 MockAffectedFile(
2696 mock_input_api.os_path.join('services', 'goat', 'public',
2697 'cpp', 'manifest.cc'),
2698 [
2699 '#include "services/goat/public/cpp/manifest.h"',
2700 'const service_manager::Manifest& GetManifest() {}',
2701 ])
2702 ]
2703 self._setupFakeChange(mock_input_api)
2704 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2705 '[email protected]',
2706 ['[email protected]'])
2707 mock_output_api = MockOutputApi()
2708 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2709 self.assertEqual(1, len(errors))
2710 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2711 'Found missing OWNERS lines for security-sensitive files. '
2712 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2713 ))
2714 self.assertEqual(['[email protected]'],
2715 mock_output_api.more_cc)
2716
2717 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2718 mock_input_api = self._createMockInputApi()
2719 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2720 '[email protected]',
2721 ['[email protected]'])
2722 mock_input_api.files = [
2723 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2724 'const char kNoEnforcement[] = "not a manifest!";',
2725 ])
2726 ]
2727 mock_output_api = MockOutputApi()
2728 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2729 self.assertEqual([], errors)
2730 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032731
2732
Daniel Chenga37c03db2022-05-12 17:20:342733class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032734
Daniel Cheng566634ff2024-06-29 14:56:532735 def testFidlChangeNeedsSecurityOwner(self):
2736 mock_input_api = self._createMockInputApi()
2737 mock_input_api.files = [
2738 MockAffectedFile('potentially/scary/ipc.fidl',
2739 ['library test.fidl'])
2740 ]
2741 self._setupFakeChange(mock_input_api)
2742 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2743 '[email protected]',
2744 ['[email protected]'])
2745 mock_output_api = MockOutputApi()
2746 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2747 self.assertEqual(1, len(errors))
2748 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2749 'Found missing OWNERS lines for security-sensitive files. '
2750 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032751
Daniel Cheng566634ff2024-06-29 14:56:532752 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2753 mock_input_api = self._createMockInputApi()
2754 mock_input_api.files = [
2755 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2756 ['{ "that is no": "manifest!" }'])
2757 ]
2758 self._setupFakeChange(mock_input_api)
2759 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2760 '[email protected]',
2761 ['[email protected]'])
2762 mock_output_api = MockOutputApi()
2763 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2764 self.assertEqual(1, len(errors))
2765 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2766 'Found missing OWNERS lines for security-sensitive files. '
2767 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032768
Daniel Cheng566634ff2024-06-29 14:56:532769 def testComponentManifestV2NeedsSecurityOwner(self):
2770 mock_input_api = self._createMockInputApi()
2771 mock_input_api.files = [
2772 MockAffectedFile('potentially/scary/v2_manifest.cml',
2773 ['{ "that is no": "manifest!" }'])
2774 ]
2775 self._setupFakeChange(mock_input_api)
2776 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2777 '[email protected]',
2778 ['[email protected]'])
2779 mock_output_api = MockOutputApi()
2780 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2781 self.assertEqual(1, len(errors))
2782 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2783 'Found missing OWNERS lines for security-sensitive files. '
2784 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092785
Daniel Cheng566634ff2024-06-29 14:56:532786 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2787 mock_input_api = MockInputApi()
2788 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2789 '[email protected]',
2790 ['[email protected]'])
2791 mock_input_api.files = [
2792 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2793 'const char kNoEnforcement[] = "Security?!? Pah!";',
2794 ])
2795 ]
2796 mock_output_api = MockOutputApi()
2797 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2798 self.assertEqual([], errors)
2799
2800 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2801 mock_input_api = MockInputApi()
2802 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2803 '[email protected]',
2804 ['[email protected]'])
2805 mock_input_api.files = [
2806 MockAffectedFile(
2807 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2808 'const char kNoEnforcement[] = "Security?!? Pah!";',
2809 ])
2810 ]
2811 mock_output_api = MockOutputApi()
2812 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2813 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362814
Daniel Cheng13ca61a882017-08-25 15:11:252815
Daniel Chenga37c03db2022-05-12 17:20:342816class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132817
Daniel Cheng566634ff2024-06-29 14:56:532818 def testDiffGetServiceSandboxType(self):
2819 mock_input_api = MockInputApi()
2820 mock_input_api.files = [
2821 MockAffectedFile('services/goat/teleporter_host.cc', [
2822 'template <>', 'inline content::SandboxType',
2823 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2824 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2825 '#else', ' return SandboxType::kNoSandbox;',
2826 '#endif // !defined(OS_WIN)', '}'
2827 ]),
2828 ]
2829 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2830 mock_input_api)
2831 self.assertEqual(
2832 {
2833 'services/goat/teleporter_host.cc':
2834 set(['content::GetServiceSandboxType<>()'])
2835 }, files_to_functions)
2836
2837 def testDiffRemovingLine(self):
2838 mock_input_api = MockInputApi()
2839 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2840 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132841+++ new 2020-05-04 14:08:32.000000000 -0400
2842@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372843 template <>
2844 inline content::SandboxType
2845-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2846 #if defined(OS_WIN)
2847 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132848"""
Daniel Cheng566634ff2024-06-29 14:56:532849 mock_input_api.files = [mock_file]
2850 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2851 mock_input_api)
2852 self.assertEqual(
2853 {
2854 'services/goat/teleporter_host.cc':
2855 set(['content::GetServiceSandboxType<>()'])
2856 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132857
Daniel Cheng566634ff2024-06-29 14:56:532858 def testChangeOwnersMissing(self):
2859 mock_input_api = self._createMockInputApi()
2860 self._setupFakeChange(mock_input_api)
2861 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2862 '[email protected]',
2863 ['[email protected]'])
2864 mock_input_api.is_committing = False
2865 mock_input_api.files = [
2866 MockAffectedFile('file.cc',
2867 ['GetServiceSandboxType<Goat>(Sandbox)'])
2868 ]
2869 mock_output_api = MockOutputApi()
2870 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2871 mock_output_api)
2872 self.assertEqual(1, len(result))
2873 self.assertEqual(result[0].type, 'notify')
2874 self.assertEqual(result[0].message,
2875 'The following files change calls to security-sensitive functions\n' \
2876 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2877 ' file.cc\n'
2878 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132879
Daniel Cheng566634ff2024-06-29 14:56:532880 def testChangeOwnersMissingAtCommit(self):
2881 mock_input_api = self._createMockInputApi()
2882 self._setupFakeChange(mock_input_api)
2883 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2884 '[email protected]',
2885 ['[email protected]'])
2886 mock_input_api.is_committing = True
2887 mock_input_api.dry_run = False
2888 mock_input_api.files = [
2889 MockAffectedFile('file.cc',
2890 ['GetServiceSandboxType<mojom::Goat>()'])
2891 ]
2892 mock_output_api = MockOutputApi()
2893 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2894 mock_output_api)
2895 self.assertEqual(1, len(result))
2896 self.assertEqual(result[0].type, 'error')
2897 self.assertEqual(result[0].message,
2898 'The following files change calls to security-sensitive functions\n' \
2899 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2900 ' file.cc\n'
2901 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:132902
Daniel Cheng566634ff2024-06-29 14:56:532903 def testChangeOwnersPresent(self):
2904 mock_input_api = self._createMockInputApi()
2905 self._injectFakeChangeOwnerAndReviewers(
2906 mock_input_api, '[email protected]',
2907 ['[email protected]', '[email protected]'])
2908 mock_input_api.files = [
2909 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
2910 ]
2911 mock_output_api = MockOutputApi()
2912 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2913 mock_output_api)
2914 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:132915
Daniel Cheng566634ff2024-06-29 14:56:532916 def testChangeOwnerIsSecurityOwner(self):
2917 mock_input_api = self._createMockInputApi()
2918 self._setupFakeChange(mock_input_api)
2919 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2920 '[email protected]',
2921 ['[email protected]'])
2922 mock_input_api.files = [
2923 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
2924 ]
2925 mock_output_api = MockOutputApi()
2926 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2927 mock_output_api)
2928 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:132929
2930
Mario Sanchez Prada2472cab2019-09-18 10:58:312931class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:292932
Daniel Cheng566634ff2024-06-29 14:56:532933 def testBannedJsFunctions(self):
2934 input_api = MockInputApi()
2935 input_api.files = [
2936 MockFile('ash/webui/file.js', ['chrome.send(something);']),
2937 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
2938 ]
Clement Yan9b330cb2022-11-17 05:25:292939
Daniel Cheng566634ff2024-06-29 14:56:532940 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:542941
Daniel Cheng566634ff2024-06-29 14:56:532942 self.assertEqual(1, len(results))
2943 self.assertTrue('ash/webui/file.js' in results[0].message)
2944 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:262945
Daniel Cheng566634ff2024-06-29 14:56:532946 def testBannedJavaFunctions(self):
2947 input_api = MockInputApi()
2948 input_api.files = [
2949 MockFile('some/java/problematic/diskread.java',
2950 ['StrictMode.allowThreadDiskReads();']),
2951 MockFile('some/java/problematic/diskwrite.java',
2952 ['StrictMode.allowThreadDiskWrites();']),
2953 MockFile('some/java/ok/diskwrite.java',
2954 ['StrictModeContext.allowDiskWrites();']),
2955 MockFile('some/java/problematic/waitidleforsync.java',
2956 ['instrumentation.waitForIdleSync();']),
2957 MockFile('some/java/problematic/registerreceiver.java',
2958 ['context.registerReceiver();']),
2959 MockFile('some/java/problematic/property.java',
2960 ['new Property<abc, Integer>;']),
2961 MockFile('some/java/problematic/requestlayout.java',
2962 ['requestLayout();']),
2963 MockFile('some/java/problematic/lastprofile.java',
2964 ['ProfileManager.getLastUsedRegularProfile();']),
2965 MockFile('some/java/problematic/getdrawable1.java',
2966 ['ResourcesCompat.getDrawable();']),
2967 MockFile('some/java/problematic/getdrawable2.java',
2968 ['getResources().getDrawable();']),
Jenna Himawan859865d2025-02-25 22:22:312969 MockFile('some/java/problematic/announceForAccessibility.java',
2970 ['view.announceForAccessibility(accessibilityText);']),
2971 MockFile(
2972 'some/java/problematic/accessibilityTypeAnnouncement.java', [
2973 'accessibilityEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);'
2974 ]),
Nate Fischerd541ff82025-03-11 21:34:192975 MockFile(
2976 'content/java/problematic/desktopandroid.java', [
2977 'if (BuildConfig.IS_DESKTOP_ANDROID) {}'
2978 ]),
Daniel Cheng566634ff2024-06-29 14:56:532979 ]
Min Qinbc44383c2023-02-22 17:25:262980
Daniel Cheng566634ff2024-06-29 14:56:532981 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:152982 self.assertEqual(12, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:532983 self.assertTrue(
2984 'some/java/problematic/diskread.java' in errors[0].message)
2985 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152986 'some/java/problematic/diskwrite.java' in errors[1].message)
2987 self.assertTrue(all('some/java/ok/diskwrite.java' not in e.message for e in errors))
Daniel Cheng566634ff2024-06-29 14:56:532988 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152989 'some/java/problematic/waitidleforsync.java' in errors[2].message)
Daniel Cheng566634ff2024-06-29 14:56:532990 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152991 'some/java/problematic/registerreceiver.java' in errors[3].message)
Daniel Cheng566634ff2024-06-29 14:56:532992 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152993 'some/java/problematic/property.java' in errors[4].message)
Daniel Cheng566634ff2024-06-29 14:56:532994 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152995 'some/java/problematic/requestlayout.java' in errors[5].message)
Daniel Cheng566634ff2024-06-29 14:56:532996 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152997 'some/java/problematic/lastprofile.java' in errors[6].message)
Daniel Cheng566634ff2024-06-29 14:56:532998 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:152999 'some/java/problematic/getdrawable1.java' in errors[7].message)
Daniel Cheng566634ff2024-06-29 14:56:533000 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153001 'some/java/problematic/getdrawable2.java' in errors[8].message)
Jenna Himawan859865d2025-02-25 22:22:313002 self.assertTrue('some/java/problematic/announceForAccessibility.java'
Ben Pastenee79d66112025-04-23 19:46:153003 in errors[9].message)
Jenna Himawan859865d2025-02-25 22:22:313004 self.assertTrue(
3005 'some/java/problematic/accessibilityTypeAnnouncement.java' in
Ben Pastenee79d66112025-04-23 19:46:153006 errors[10].message)
Nate Fischerd541ff82025-03-11 21:34:193007 self.assertTrue(
3008 'content/java/problematic/desktopandroid.java' in
Ben Pastenee79d66112025-04-23 19:46:153009 errors[11].message)
Jenna Himawan859865d2025-02-25 22:22:313010
Peter Kasting94a56c42019-10-25 21:54:043011
Daniel Cheng566634ff2024-06-29 14:56:533012 def testBannedCppFunctions(self):
3013 input_api = MockInputApi()
3014 input_api.files = [
3015 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
3016 MockFile('third_party/blink/problematic/file.cc',
3017 ['GetInterfaceProvider()']),
3018 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
Daniel Cheng566634ff2024-06-29 14:56:533019 MockFile('some/cpp/nocheck/file.cc',
3020 ['using namespace std; // nocheck']),
3021 MockFile('some/cpp/comment/file.cc',
3022 [' // A comment about `using namespace std;`']),
Peter Kasting13607932025-04-10 22:52:383023 MockFile('some/cpp/problematic/file2.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533024 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3025 ]),
Peter Kasting13607932025-04-10 22:52:383026 MockFile('some/cpp/problematic/file3.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533027 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3028 ]),
Peter Kasting13607932025-04-10 22:52:383029 MockFile('some/cpp/problematic/file4.cc', [
Daniel Cheng566634ff2024-06-29 14:56:533030 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3031 ]),
Daniel Cheng89719222024-07-04 04:59:293032 MockFile('allowed_ranges_usage.cc', ['std::ranges::begin(vec)']),
3033 MockFile('banned_ranges_usage.cc',
3034 ['std::ranges::subrange(first, last)']),
3035 MockFile('views_usage.cc', ['std::views::all(vec)']),
Nate Fischerd541ff82025-03-11 21:34:193036 MockFile('content/desktop_android.cc',
Ben Pastenee79d66112025-04-23 19:46:153037 [
3038 '// some first line',
3039 '#if BUILDFLAG(IS_DESKTOP_ANDROID)',
3040 '// some third line',
3041 ]),
Daniel Cheng566634ff2024-06-29 14:56:533042 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163043
Daniel Cheng566634ff2024-06-29 14:56:533044 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043045
Ben Pastenee79d66112025-04-23 19:46:153046 # Each entry in results corresponds to a BanRule with a violation, in
3047 # the order they were encountered.
3048 self.assertEqual(8, len(results))
3049 self.assertTrue('some/cpp/problematic/file.cc' in results[0].message)
Daniel Cheng566634ff2024-06-29 14:56:533050 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153051 'third_party/blink/problematic/file.cc' in results[1].message)
3052 self.assertTrue(all('some/cpp/ok/file.cc' not in r.message for r in results))
3053 self.assertTrue('some/cpp/problematic/file2.cc' in results[2].message)
3054 self.assertTrue('some/cpp/problematic/file3.cc' in results[3].message)
3055 self.assertTrue('some/cpp/problematic/file4.cc' in results[4].message)
3056 self.assertTrue(all('some/cpp/nocheck/file.cc' not in r.message for r in results))
3057 self.assertTrue(all('some/cpp/comment/file.cc' not in r.message for r in results))
3058 self.assertTrue(all('allowed_ranges_usage.cc' not in r.message for r in results))
3059 self.assertTrue('banned_ranges_usage.cc' in results[5].message)
3060 self.assertTrue('views_usage.cc' in results[6].message)
3061 self.assertTrue('content/desktop_android.cc' in results[7].message)
3062
3063 # Check ResultLocation data. Line nums start at 1.
3064 self.assertEqual(results[7].locations[0].file_path, 'content/desktop_android.cc')
3065 self.assertEqual(results[7].locations[0].start_line, 2)
3066 self.assertEqual(results[7].locations[0].end_line, 2)
Daniel Cheng192683f2022-11-01 20:52:443067
Daniel Cheng566634ff2024-06-29 14:56:533068 def testBannedCppRandomFunctions(self):
3069 banned_rngs = [
3070 'absl::BitGen',
3071 'absl::InsecureBitGen',
3072 'std::linear_congruential_engine',
3073 'std::mersenne_twister_engine',
3074 'std::subtract_with_carry_engine',
3075 'std::discard_block_engine',
3076 'std::independent_bits_engine',
3077 'std::shuffle_order_engine',
3078 'std::minstd_rand0',
3079 'std::minstd_rand',
3080 'std::mt19937',
3081 'std::mt19937_64',
3082 'std::ranlux24_base',
3083 'std::ranlux48_base',
3084 'std::ranlux24',
3085 'std::ranlux48',
3086 'std::knuth_b',
3087 'std::default_random_engine',
3088 'std::random_device',
3089 ]
3090 for banned_rng in banned_rngs:
3091 input_api = MockInputApi()
3092 input_api.files = [
3093 MockFile('some/cpp/problematic/file.cc',
3094 [f'{banned_rng} engine;']),
3095 MockFile('third_party/blink/problematic/file.cc',
3096 [f'{banned_rng} engine;']),
3097 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3098 ]
3099 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3100 MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153101 self.assertEqual(2, len(results), banned_rng)
Daniel Cheng566634ff2024-06-29 14:56:533102 self.assertTrue(
3103 'some/cpp/problematic/file.cc' in results[0].message,
3104 banned_rng)
3105 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:153106 'third_party/blink/problematic/file.cc' in results[1].message,
Daniel Cheng566634ff2024-06-29 14:56:533107 banned_rng)
Ben Pastenee79d66112025-04-23 19:46:153108 self.assertTrue(all('third_party/ok/file.cc' not in r.message for r in results))
Sylvain Defresnea8b73d252018-02-28 15:45:543109
Daniel Cheng566634ff2024-06-29 14:56:533110 def testBannedIosObjcFunctions(self):
3111 input_api = MockInputApi()
3112 input_api.files = [
3113 MockFile('some/ios/file.mm',
3114 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3115 MockFile('some/mac/file.mm',
3116 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3117 MockFile('another/ios_file.mm',
3118 ['class SomeTest : public testing::Test {};']),
3119 MockFile(
3120 'some/ios/file_egtest.mm',
3121 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3122 MockFile('some/ios/file_unittest.mm', [
3123 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3124 ]),
3125 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543126
Daniel Cheng566634ff2024-06-29 14:56:533127 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Ben Pastenee79d66112025-04-23 19:46:153128 self.assertEqual(3, len(errors))
Daniel Cheng566634ff2024-06-29 14:56:533129 self.assertTrue('some/ios/file.mm' in errors[0].message)
Ben Pastenee79d66112025-04-23 19:46:153130 self.assertTrue('another/ios_file.mm' in errors[1].message)
3131 self.assertTrue(all('some/mac/file.mm' not in e.message for e in errors))
3132 self.assertTrue('some/ios/file_egtest.mm' in errors[2].message)
3133 self.assertTrue(all('some/ios/file_unittest.mm' not in e.message for e in errors))
Carlos Knippschildab192b8c2019-04-08 20:02:383134
Daniel Cheng566634ff2024-06-29 14:56:533135 def testBannedMojoFunctions(self):
3136 input_api = MockInputApi()
3137 input_api.files = [
3138 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3139 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3140 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3141 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223142
Daniel Cheng566634ff2024-06-29 14:56:533143 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383144
Ben Pastenee79d66112025-04-23 19:46:153145 # Each entry in results corresponds to a BanRule with a violation, in
3146 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533147 self.assertEqual(1, len(results))
3148 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3149 self.assertTrue(
3150 'third_party/blink/ok/file3.cc' not in results[0].message)
3151 self.assertTrue(
3152 'content/renderer/ok/file3.cc' not in results[0].message)
3153
Justin Lulejian09fd06872025-04-01 22:03:283154 def testBannedMojomPatterns_SharedBuffer(self):
Daniel Cheng566634ff2024-06-29 14:56:533155 input_api = MockInputApi()
3156 input_api.files = [
3157 MockFile(
3158 'bad.mojom',
3159 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3160 MockFile('good.mojom', [
3161 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223162 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3163 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533164 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3165 ]),
3166 ]
Daniel Cheng92c15e32022-03-16 17:48:223167
Daniel Cheng566634ff2024-06-29 14:56:533168 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223169
Ben Pastenee79d66112025-04-23 19:46:153170 # Each entry in results corresponds to a BanRule with a violation, in
3171 # the order they were encountered.
Daniel Cheng566634ff2024-06-29 14:56:533172 self.assertEqual(1, len(results))
3173 self.assertTrue('bad.mojom' in results[0].message)
3174 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223175
Justin Lulejian09fd06872025-04-01 22:03:283176 def testBannedMojomPatterns_ExtensionId(self):
3177 input_api = MockInputApi()
3178 input_api.files = [
3179 # Pattern tests.
3180 MockFile('extensions/bad.mojom', ['string extension_id']),
3181 MockFile('extensions/bad_struct.mojom',
3182 ['struct Bad {', ' string extension_id;', '};']),
3183 MockFile('extensions/good.mojom', ['ExtensionId extension_id']),
3184 MockFile('extensions/good_struct.mojom',
3185 ['struct Bad {', ' ExtensionId extension_id;', '};']),
3186
3187 # Path exclusion tests.
3188 MockFile('some/included/extensions/path/bad_extension_id.mojom',
3189 ['string extension_id']),
3190 MockFile('some/excluded/path/bad_extension_id.mojom',
3191 ['string extension_id']),
3192 ]
3193
Ben Pastenee79d66112025-04-23 19:46:153194 # Each entry in results corresponds to a BanRule with a violation, in
3195 # the order they were encountered.
Justin Lulejian09fd06872025-04-01 22:03:283196 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3197
Ben Pastenee79d66112025-04-23 19:46:153198 self.assertEqual(3, len(results))
Justin Lulejian09fd06872025-04-01 22:03:283199
3200 # Pattern test assertions.
3201 self.assertTrue('bad.mojom' in results[0].message)
Ben Pastenee79d66112025-04-23 19:46:153202 self.assertTrue('bad_struct.mojom' in results[1].message)
3203 self.assertTrue(all('good.mojom' not in r.message for r in results))
3204 self.assertTrue(all('good_struct.mojom' not in r.message for r in results))
Justin Lulejian09fd06872025-04-01 22:03:283205
3206 # Path exclusion assertions.
3207 self.assertTrue('some/included/extensions/path/bad_extension_id.mojom'
Ben Pastenee79d66112025-04-23 19:46:153208 in results[2].message)
3209 self.assertTrue(all('some/excluded/path/bad_extension_id.mojom' not in r.message for r in results))
3210
Justin Lulejian09fd06872025-04-01 22:03:283211
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273212class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243213
Daniel Cheng566634ff2024-06-29 14:56:533214 def testTruePositives(self):
3215 mock_input_api = MockInputApi()
3216 mock_input_api.files = [
3217 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3218 MockFile('some/path/foo.mm', ['FooForTesting();']),
3219 MockFile('some/path/foo.cxx', ['FooForTests();']),
3220 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3221 ]
Vaclav Brozekf01ed502018-03-16 19:38:243222
Daniel Cheng566634ff2024-06-29 14:56:533223 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3224 mock_input_api, MockOutputApi())
3225 self.assertEqual(1, len(results))
3226 self.assertEqual(4, len(results[0].items))
3227 self.assertTrue('foo.cc' in results[0].items[0])
3228 self.assertTrue('foo.mm' in results[0].items[1])
3229 self.assertTrue('foo.cxx' in results[0].items[2])
3230 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243231
Daniel Cheng566634ff2024-06-29 14:56:533232 def testFalsePositives(self):
3233 mock_input_api = MockInputApi()
3234 mock_input_api.files = [
3235 MockFile('some/path/foo.h', ['foo_for_testing();']),
3236 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3237 MockFile('some/path/foo.cc', ['::FooForTests();']),
3238 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3239 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3240 ]
Vaclav Brozekf01ed502018-03-16 19:38:243241
Daniel Cheng566634ff2024-06-29 14:56:533242 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3243 mock_input_api, MockOutputApi())
3244 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133245
Daniel Cheng566634ff2024-06-29 14:56:533246 def testAllowedFiles(self):
3247 mock_input_api = MockInputApi()
3248 mock_input_api.files = [
3249 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3250 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3251 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3252 ]
3253
3254 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3255 mock_input_api, MockOutputApi())
3256 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133257
Vaclav Brozekf01ed502018-03-16 19:38:243258
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273259class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233260
Daniel Cheng566634ff2024-06-29 14:56:533261 def testTruePositives(self):
3262 mock_input_api = MockInputApi()
3263 mock_input_api.files = [
3264 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3265 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3266 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3267 MockFile('dir/java/src/mult.java', [
3268 'int x = SomethingLongHere()',
3269 ' * SomethingLongHereForTesting();'
3270 ])
3271 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233272
Daniel Cheng566634ff2024-06-29 14:56:533273 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3274 mock_input_api, MockOutputApi())
3275 self.assertEqual(1, len(results))
3276 self.assertEqual(4, len(results[0].items))
3277 self.assertTrue('foo.java' in results[0].items[0])
3278 self.assertTrue('bar.java' in results[0].items[1])
3279 self.assertTrue('baz.java' in results[0].items[2])
3280 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233281
Daniel Cheng566634ff2024-06-29 14:56:533282 def testFalsePositives(self):
3283 mock_input_api = MockInputApi()
3284 mock_input_api.files = [
3285 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3286 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3287 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3288 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3289 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3290 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3291 MockFile('dir/java/src/bar5.java', [
3292 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3293 ]),
3294 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3295 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3296 MockFile('dir/junit/src/javadoc.java',
3297 ['/** Use FooForTest(); to obtain foo in tests.'
3298 ' */']),
3299 MockFile(
3300 'dir/junit/src/javadoc2.java',
3301 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3302 ' */']),
3303 MockFile('dir/java/src/bar6.java',
3304 ['FooForTesting(); // IN-TEST']),
3305 ]
3306
3307 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3308 mock_input_api, MockOutputApi())
3309 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233310
3311
Mohamed Heikald048240a2019-11-12 16:57:373312class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373313
Daniel Cheng566634ff2024-06-29 14:56:533314 def testTruePositives(self):
3315 mock_input_api = MockInputApi()
3316 mock_input_api.files = [
3317 MockFile('dir/android/res/drawable/foo.png', []),
3318 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3319 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3320 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3321 ]
Mohamed Heikald048240a2019-11-12 16:57:373322
Daniel Cheng566634ff2024-06-29 14:56:533323 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3324 MockOutputApi())
3325 self.assertEqual(1, len(results))
3326 self.assertEqual(4, len(results[0].items))
3327 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3328 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3329 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3330 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373331
Daniel Cheng566634ff2024-06-29 14:56:533332 def testFalsePositives(self):
3333 mock_input_api = MockInputApi()
3334 mock_input_api.files = [
3335 MockFile('dir/pngs/README.md', []),
3336 MockFile('java/test/res/drawable/foo.png', []),
3337 MockFile('third_party/blink/foo.png', []),
3338 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3339 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3340 ]
3341
3342 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3343 MockOutputApi())
3344 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373345
Evan Stade7cd4a2c2022-08-04 23:37:253346class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253347
Daniel Cheng566634ff2024-06-29 14:56:533348 def test(self):
3349 mock_input_api = MockInputApi()
3350 mock_input_api.files = [
3351 MockFile('components/vector_icons/google_jetpack.icon', []),
3352 MockFile('components/vector_icons/generic_jetpack.icon', []),
3353 ]
3354
3355 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3356 mock_input_api, MockOutputApi())
3357 self.assertEqual(1, len(results))
3358 self.assertEqual(1, len(results[0].items))
3359 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373360
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273361class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053362
Daniel Cheng566634ff2024-06-29 14:56:533363 def testTruePositivesNullptr(self):
3364 mock_input_api = MockInputApi()
3365 mock_input_api.files = [
3366 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3367 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3368 ]
Vaclav Brozek851d9602018-04-04 16:13:053369
Daniel Cheng566634ff2024-06-29 14:56:533370 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3371 MockOutputApi())
3372 self.assertEqual(1, len(results))
3373 self.assertTrue('nullptr' in results[0].message)
3374 self.assertEqual(2, len(results[0].items))
3375 self.assertTrue('baz.cc' in results[0].items[0])
3376 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243377
Daniel Cheng566634ff2024-06-29 14:56:533378 def testTruePositivesConstructor(self):
3379 mock_input_api = MockInputApi()
3380 mock_input_api.files = [
3381 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3382 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3383 MockFile('dir/mult.cc', [
3384 'return',
3385 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3386 ]),
3387 MockFile('dir/mult2.cc', [
3388 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3389 ' std::unique_ptr<T>(foo);'
3390 ]),
3391 MockFile('dir/mult3.cc', [
3392 'bar = std::unique_ptr<T>(',
3393 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3394 ]),
3395 MockFile('dir/multi_arg.cc', [
3396 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3397 ]),
3398 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243399
Daniel Cheng566634ff2024-06-29 14:56:533400 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3401 MockOutputApi())
3402 self.assertEqual(1, len(results))
3403 self.assertTrue('std::make_unique' in results[0].message)
3404 self.assertEqual(6, len(results[0].items))
3405 self.assertTrue('foo.cc' in results[0].items[0])
3406 self.assertTrue('bar.mm' in results[0].items[1])
3407 self.assertTrue('mult.cc' in results[0].items[2])
3408 self.assertTrue('mult2.cc' in results[0].items[3])
3409 self.assertTrue('mult3.cc' in results[0].items[4])
3410 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533411
Daniel Cheng566634ff2024-06-29 14:56:533412 def testFalsePositives(self):
3413 mock_input_api = MockInputApi()
3414 mock_input_api.files = [
3415 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3416 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3417 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3418 MockFile('dir/baz.cc',
3419 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3420 MockFile('dir/baz2.cc',
3421 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3422 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3423 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3424 # Changed line is inside a multiline template block.
3425 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3426 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243427
Daniel Cheng566634ff2024-06-29 14:56:533428 # Two-argument invocation of std::unique_ptr is exempt because there is
3429 # no equivalent using std::make_unique.
3430 MockFile('dir/multi_arg.cc',
3431 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3432 ]
3433
3434 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3435 MockOutputApi())
3436 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243437
Danil Chapovalov3518f362018-08-11 16:13:433438class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433439
Daniel Cheng566634ff2024-06-29 14:56:533440 def testBlocksDirectIncludes(self):
3441 mock_input_api = MockInputApi()
3442 mock_input_api.files = [
3443 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3444 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3445 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3446 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3447 ]
3448 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3449 MockOutputApi())
3450 self.assertEqual(1, len(results))
3451 self.assertEqual(4, len(results[0].items))
3452 self.assertTrue('StrCat' in results[0].message)
3453 self.assertTrue('foo_win.cc' in results[0].items[0])
3454 self.assertTrue('bar.h' in results[0].items[1])
3455 self.assertTrue('baz.h' in results[0].items[2])
3456 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433457
Daniel Cheng566634ff2024-06-29 14:56:533458 def testAllowsToIncludeWrapper(self):
3459 mock_input_api = MockInputApi()
3460 mock_input_api.files = [
3461 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3462 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3463 ]
3464 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3465 MockOutputApi())
3466 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323467
Daniel Cheng566634ff2024-06-29 14:56:533468 def testAllowsToCreateWrapper(self):
3469 mock_input_api = MockInputApi()
3470 mock_input_api.files = [
3471 MockFile('base/win/shlwapi.h', [
3472 '#include <shlwapi.h>',
3473 '#include "base/win/windows_defines.inc"'
3474 ]),
3475 ]
3476 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3477 MockOutputApi())
3478 self.assertEqual(0, len(results))
3479
3480 def testIgnoresNonImplAndHeaders(self):
3481 mock_input_api = MockInputApi()
3482 mock_input_api.files = [
3483 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3484 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3485 ]
3486 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3487 MockOutputApi())
3488 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243489
Mustafa Emre Acer51f2f742020-03-09 19:41:123490
Rainhard Findlingfc31844c52020-05-15 09:58:263491class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533492 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263493
Daniel Cheng566634ff2024-06-29 14:56:533494 # An empty grd file.
3495 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143496 <grit latest_public_release="1" current_release="1">
3497 <release seq="1">
3498 <messages></messages>
3499 </release>
3500 </grit>
3501 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533502 # A grd file with a single message.
3503 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143504 <grit latest_public_release="1" current_release="1">
3505 <release seq="1">
3506 <messages>
3507 <message name="IDS_TEST1">
3508 Test string 1
3509 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483510 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3511 translateable="false">
3512 Non translateable message 1, should be ignored
3513 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393514 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343515 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393516 Accessibility label 1, should be ignored
3517 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143518 </messages>
3519 </release>
3520 </grit>
3521 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533522 # A grd file with two messages.
3523 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143524 <grit latest_public_release="1" current_release="1">
3525 <release seq="1">
3526 <messages>
3527 <message name="IDS_TEST1">
3528 Test string 1
3529 </message>
3530 <message name="IDS_TEST2">
3531 Test string 2
3532 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483533 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3534 translateable="false">
3535 Non translateable message 2, should be ignored
3536 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143537 </messages>
3538 </release>
3539 </grit>
3540 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533541 # A grd file with one ICU syntax message without syntax errors.
3542 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263543 <grit latest_public_release="1" current_release="1">
3544 <release seq="1">
3545 <messages>
3546 <message name="IDS_TEST1">
3547 {NUM, plural,
3548 =1 {Test text for numeric one}
3549 other {Test text for plural with {NUM} as number}}
3550 </message>
3551 </messages>
3552 </release>
3553 </grit>
3554 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533555 # A grd file with one ICU syntax message without syntax errors.
3556 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263557 <grit latest_public_release="1" current_release="1">
3558 <release seq="1">
3559 <messages>
3560 <message name="IDS_TEST1">
3561 {NUM, plural,
3562 =1 {Different test text for numeric one}
3563 other {Different test text for plural with {NUM} as number}}
3564 </message>
3565 </messages>
3566 </release>
3567 </grit>
3568 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533569 # A grd file with multiple ICU syntax messages without syntax errors.
3570 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323571 <grit latest_public_release="1" current_release="1">
3572 <release seq="1">
3573 <messages>
3574 <message name="IDS_TEST1">
3575 {NUM, plural,
3576 =0 {New test text for numeric zero}
3577 =1 {Different test text for numeric one}
3578 =2 {New test text for numeric two}
3579 =3 {New test text for numeric three}
3580 other {Different test text for plural with {NUM} as number}}
3581 </message>
3582 </messages>
3583 </release>
3584 </grit>
3585 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533586 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3587 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263588 <grit latest_public_release="1" current_release="1">
3589 <release seq="1">
3590 <messages>
3591 <message name="IDS_TEST1">
3592 {NUM, plural
3593 =1 {Test text for numeric one}
3594 other {Test text for plural with {NUM} as number}}
3595 </message>
3596 </messages>
3597 </release>
3598 </grit>
3599 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143600
Daniel Cheng566634ff2024-06-29 14:56:533601 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3602 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583603
Daniel Cheng566634ff2024-06-29 14:56:533604 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3605 '<grit-part>', '<message name="IDS_PART_TEST1">',
3606 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583607
Daniel Cheng566634ff2024-06-29 14:56:533608 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3609 '<grit-part>', '<message name="IDS_PART_TEST1">',
3610 'Part string 1', '</message>',
3611 '<message name="IDS_PART_TEST2">', 'Part string 2',
3612 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583613
Daniel Cheng566634ff2024-06-29 14:56:533614 NEW_GRDP_CONTENTS3 = (
3615 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093616 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533617 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093618
Daniel Cheng566634ff2024-06-29 14:56:533619 NEW_GRDP_CONTENTS4 = (
3620 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093621 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533622 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093623
Daniel Cheng566634ff2024-06-29 14:56:533624 NEW_GRDP_CONTENTS5 = (
3625 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353626 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533627 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353628
Daniel Cheng566634ff2024-06-29 14:56:533629 NEW_GRDP_CONTENTS6 = (
3630 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353631 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533632 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353633
Daniel Cheng566634ff2024-06-29 14:56:533634 # A grdp file with one ICU syntax message without syntax errors.
3635 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3636 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3637 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3638 '=1 {Test text for numeric one}',
3639 'other {Test text for plural with {NUM} as number}}', '</message>',
3640 '</grit-part>')
3641 # A grdp file with one ICU syntax message without syntax errors.
3642 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3643 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3644 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3645 '=1 {Different test text for numeric one}',
3646 'other {Different test text for plural with {NUM} as number}}',
3647 '</message>', '</grit-part>')
3648 # A grdp file with multiple ICU syntax messages without syntax errors.
3649 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3650 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3651 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3652 '=0 {New test text for numeric zero}',
3653 '=1 {Different test text for numeric one}',
3654 '=2 {New test text for numeric two}',
3655 '=3 {New test text for numeric three}',
3656 'other {Different test text for plural with {NUM} as number}}',
3657 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263658
Daniel Cheng566634ff2024-06-29 14:56:533659 # A grdp file with one ICU syntax message with syntax errors (superfluous
3660 # space).
3661 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3662 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3663 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3664 '= 1 {Test text for numeric one}',
3665 'other {Test text for plural with {NUM} as number}}', '</message>',
3666 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263667
Daniel Cheng566634ff2024-06-29 14:56:533668 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3669 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3670 'changelist. Run '
3671 'tools/translate/upload_screenshots.py to '
3672 'upload them instead:')
3673 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3674 'To ensure the best translations, take '
3675 'screenshots of the relevant UI '
3676 '(https://g.co/chrome/translation) and add '
3677 'these files to your changelist:')
3678 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3679 'files. Remove:')
3680 ICU_SYNTAX_ERROR_MESSAGE = (
3681 'ICU syntax errors were found in the following '
3682 'strings (problems or feedback? Contact '
3683 '[email protected]):')
3684 SHA1_FORMAT_MESSAGE = (
3685 'The following files do not seem to contain valid sha1 '
3686 'hashes. Make sure they contain hashes created by '
3687 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143688
Daniel Cheng566634ff2024-06-29 14:56:533689 def makeInputApi(self, files):
3690 input_api = MockInputApi()
Andrew Grieve713b89b2024-10-15 20:20:083691 input_api.InitFiles(files)
Daniel Cheng566634ff2024-06-29 14:56:533692 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143693
Daniel Cheng566634ff2024-06-29 14:56:533694 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583695
Daniel Cheng566634ff2024-06-29 14:56:533696 def testNoScreenshots(self):
3697 # No new strings (file contents same). Should not warn.
3698 input_api = self.makeInputApi([
3699 MockAffectedFile('test.grd',
3700 self.NEW_GRD_CONTENTS1,
3701 self.NEW_GRD_CONTENTS1,
3702 action='M'),
3703 MockAffectedFile('part.grdp',
3704 self.NEW_GRDP_CONTENTS1,
3705 self.NEW_GRDP_CONTENTS1,
3706 action='M')
3707 ])
3708 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3709 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343710
Daniel Cheng566634ff2024-06-29 14:56:533711 # Add two new strings. Should have two warnings.
3712 input_api = self.makeInputApi([
3713 MockAffectedFile('test.grd',
3714 self.NEW_GRD_CONTENTS2,
3715 self.NEW_GRD_CONTENTS1,
3716 action='M'),
3717 MockAffectedFile('part.grdp',
3718 self.NEW_GRDP_CONTENTS2,
3719 self.NEW_GRDP_CONTENTS1,
3720 action='M')
3721 ])
3722 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3723 self.assertEqual(1, len(warnings))
3724 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3725 self.assertEqual('error', warnings[0].type)
3726 self.assertEqual([
3727 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3728 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3729 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213730
Daniel Cheng566634ff2024-06-29 14:56:533731 # Add four new strings. Should have four warnings.
3732 input_api = self.makeInputApi([
3733 MockAffectedFile('test.grd',
3734 self.NEW_GRD_CONTENTS2,
3735 self.OLD_GRD_CONTENTS,
3736 action='M'),
3737 MockAffectedFile('part.grdp',
3738 self.NEW_GRDP_CONTENTS2,
3739 self.OLD_GRDP_CONTENTS,
3740 action='M')
3741 ])
3742 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3743 self.assertEqual(1, len(warnings))
3744 self.assertEqual('error', warnings[0].type)
3745 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3746 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583747 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583748 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303749 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303750 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533751 ], warnings[0].items)
3752
3753 def testModifiedMessageDescription(self):
3754 # CL modified a message description for a message that does not yet have a
3755 # screenshot. Should not warn.
3756 input_api = self.makeInputApi([
3757 MockAffectedFile('part.grdp',
3758 self.NEW_GRDP_CONTENTS3,
3759 self.NEW_GRDP_CONTENTS4,
3760 action='M')
3761 ])
3762 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3763 self.assertEqual(0, len(warnings))
3764
3765 # CL modified a message description for a message that already has a
3766 # screenshot. Should not warn.
3767 input_api = self.makeInputApi([
3768 MockAffectedFile('part.grdp',
3769 self.NEW_GRDP_CONTENTS3,
3770 self.NEW_GRDP_CONTENTS4,
3771 action='M'),
3772 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3773 self.VALID_SHA1,
3774 action='A')
3775 ])
3776 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3777 self.assertEqual(0, len(warnings))
3778
3779 def testModifiedMessageMeaning(self):
3780 # CL modified a message meaning for a message that does not yet have a
3781 # screenshot. Should warn.
3782 input_api = self.makeInputApi([
3783 MockAffectedFile('part.grdp',
3784 self.NEW_GRDP_CONTENTS5,
3785 self.NEW_GRDP_CONTENTS6,
3786 action='M')
3787 ])
3788 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3789 self.assertEqual(1, len(warnings))
3790
3791 # CL modified a message meaning for a message that already has a
3792 # screenshot. Should not warn.
3793 input_api = self.makeInputApi([
3794 MockAffectedFile('part.grdp',
3795 self.NEW_GRDP_CONTENTS5,
3796 self.NEW_GRDP_CONTENTS6,
3797 action='M'),
3798 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3799 self.VALID_SHA1,
3800 action='A')
3801 ])
3802 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3803 self.assertEqual(0, len(warnings))
3804
3805 def testModifiedIntroducedInvalidSha1(self):
3806 # CL modified a message and the sha1 file changed to invalid
3807 input_api = self.makeInputApi([
3808 MockAffectedFile('part.grdp',
3809 self.NEW_GRDP_CONTENTS5,
3810 self.NEW_GRDP_CONTENTS6,
3811 action='M'),
3812 MockAffectedFile(os.path.join('part_grdp',
3813 'IDS_PART_TEST1.png.sha1'),
3814 ('some invalid sha1', ),
3815 self.VALID_SHA1,
3816 action='M')
3817 ])
3818 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3819 self.assertEqual(1, len(warnings))
3820
3821 def testPngAddedSha1NotAdded(self):
3822 # CL added one new message in a grd file and added the png file associated
3823 # with it, but did not add the corresponding sha1 file. This should warn
3824 # twice:
3825 # - Once for the added png file (because we don't want developers to upload
3826 # actual images)
3827 # - Once for the missing .sha1 file
3828 input_api = self.makeInputApi([
3829 MockAffectedFile('test.grd',
3830 self.NEW_GRD_CONTENTS1,
3831 self.OLD_GRD_CONTENTS,
3832 action='M'),
3833 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3834 'binary',
3835 action='A')
3836 ])
3837 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3838 self.assertEqual(2, len(warnings))
3839 self.assertEqual('error', warnings[0].type)
3840 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3841 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3842 warnings[0].items)
3843 self.assertEqual('error', warnings[1].type)
3844 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3845 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3846 warnings[1].items)
3847
3848 # CL added two messages (one in grd, one in grdp) and added the png files
3849 # associated with the messages, but did not add the corresponding sha1
3850 # files. This should warn twice:
3851 # - Once for the added png files (because we don't want developers to upload
3852 # actual images)
3853 # - Once for the missing .sha1 files
3854 input_api = self.makeInputApi([
3855 # Modified files:
3856 MockAffectedFile('test.grd',
3857 self.NEW_GRD_CONTENTS1,
3858 self.OLD_GRD_CONTENTS,
3859 action='M'),
3860 MockAffectedFile('part.grdp',
3861 self.NEW_GRDP_CONTENTS1,
3862 self.OLD_GRDP_CONTENTS,
3863 action='M'),
3864 # Added files:
3865 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3866 'binary',
3867 action='A'),
3868 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3869 'binary',
3870 action='A')
3871 ])
3872 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3873 self.assertEqual(2, len(warnings))
3874 self.assertEqual('error', warnings[0].type)
3875 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3876 self.assertEqual([
3877 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3878 os.path.join('test_grd', 'IDS_TEST1.png')
3879 ], warnings[0].items)
3880 self.assertEqual('error', warnings[0].type)
3881 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3882 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303883 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533884 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3885 ], warnings[1].items)
3886
3887 def testScreenshotsWithSha1(self):
3888 # CL added four messages (two each in a grd and grdp) and their
3889 # corresponding .sha1 files. No warnings.
3890 input_api = self.makeInputApi([
3891 # Modified files:
3892 MockAffectedFile('test.grd',
3893 self.NEW_GRD_CONTENTS2,
3894 self.OLD_GRD_CONTENTS,
3895 action='M'),
3896 MockAffectedFile('part.grdp',
3897 self.NEW_GRDP_CONTENTS2,
3898 self.OLD_GRDP_CONTENTS,
3899 action='M'),
3900 # Added files:
3901 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3902 self.VALID_SHA1,
3903 action='A'),
3904 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3905 ('0000000000000000000000000000000000000000', ''),
3906 action='A'),
3907 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3908 self.VALID_SHA1,
3909 action='A'),
3910 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3911 self.VALID_SHA1,
3912 action='A'),
3913 ])
3914 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3915 self.assertEqual([], warnings)
3916
3917 def testScreenshotsWithInvalidSha1(self):
3918 input_api = self.makeInputApi([
3919 # Modified files:
3920 MockAffectedFile('test.grd',
3921 self.NEW_GRD_CONTENTS2,
3922 self.OLD_GRD_CONTENTS,
3923 action='M'),
3924 MockAffectedFile('part.grdp',
3925 self.NEW_GRDP_CONTENTS2,
3926 self.OLD_GRDP_CONTENTS,
3927 action='M'),
3928 # Added files:
3929 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3930 self.VALID_SHA1,
3931 action='A'),
3932 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3933 ('‰PNG', 'test'),
3934 action='A'),
3935 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3936 self.VALID_SHA1,
3937 action='A'),
3938 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3939 self.VALID_SHA1,
3940 action='A'),
3941 ])
3942 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3943 self.assertEqual(1, len(warnings))
3944 self.assertEqual('error', warnings[0].type)
3945 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
3946 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
3947 warnings[0].items)
3948
3949 def testScreenshotsRemovedWithSha1(self):
3950 # Replace new contents with old contents in grd and grp files, removing
3951 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
3952 # Should warn to remove the sha1 files associated with these strings.
3953 input_api = self.makeInputApi([
3954 # Modified files:
3955 MockAffectedFile(
3956 'test.grd',
3957 self.OLD_GRD_CONTENTS, # new_contents
3958 self.NEW_GRD_CONTENTS2, # old_contents
3959 action='M'),
3960 MockAffectedFile(
3961 'part.grdp',
3962 self.OLD_GRDP_CONTENTS, # new_contents
3963 self.NEW_GRDP_CONTENTS2, # old_contents
3964 action='M'),
3965 # Unmodified files:
3966 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3967 self.VALID_SHA1, ''),
3968 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3969 self.VALID_SHA1, ''),
3970 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3971 self.VALID_SHA1, ''),
3972 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3973 self.VALID_SHA1, '')
3974 ])
3975 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3976 self.assertEqual(1, len(warnings))
3977 self.assertEqual('error', warnings[0].type)
3978 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
3979 self.assertEqual([
3980 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303981 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:013982 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533983 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3984 ], warnings[0].items)
3985
3986 # Same as above, but this time one of the .sha1 files is also removed.
3987 input_api = self.makeInputApi([
3988 # Modified files:
3989 MockAffectedFile(
3990 'test.grd',
3991 self.OLD_GRD_CONTENTS, # new_contents
3992 self.NEW_GRD_CONTENTS2, # old_contents
3993 action='M'),
3994 MockAffectedFile(
3995 'part.grdp',
3996 self.OLD_GRDP_CONTENTS, # new_contents
3997 self.NEW_GRDP_CONTENTS2, # old_contents
3998 action='M'),
3999 # Unmodified files:
4000 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4001 self.VALID_SHA1, ''),
4002 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4003 self.VALID_SHA1, ''),
4004 # Deleted files:
4005 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4006 '',
4007 'old_contents',
4008 action='D'),
4009 MockAffectedFile(os.path.join('part_grdp',
4010 'IDS_PART_TEST2.png.sha1'),
4011 '',
4012 'old_contents',
4013 action='D')
4014 ])
4015 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4016 self.assertEqual(1, len(warnings))
4017 self.assertEqual('error', warnings[0].type)
4018 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4019 self.assertEqual([
meacerff8a9b62019-12-10 19:43:584020 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534021 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
4022 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144023
Daniel Cheng566634ff2024-06-29 14:56:534024 # Remove all sha1 files. There should be no warnings.
4025 input_api = self.makeInputApi([
4026 # Modified files:
4027 MockAffectedFile('test.grd',
4028 self.OLD_GRD_CONTENTS,
4029 self.NEW_GRD_CONTENTS2,
4030 action='M'),
4031 MockAffectedFile('part.grdp',
4032 self.OLD_GRDP_CONTENTS,
4033 self.NEW_GRDP_CONTENTS2,
4034 action='M'),
4035 # Deleted files:
4036 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4037 self.VALID_SHA1,
4038 action='D'),
4039 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4040 self.VALID_SHA1,
4041 action='D'),
4042 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4043 self.VALID_SHA1,
4044 action='D'),
4045 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4046 self.VALID_SHA1,
4047 action='D')
4048 ])
4049 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4050 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:264051
Daniel Cheng566634ff2024-06-29 14:56:534052 def testIcuSyntax(self):
4053 # Add valid ICU syntax string. Should not raise an error.
4054 input_api = self.makeInputApi([
4055 MockAffectedFile('test.grd',
4056 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4057 self.NEW_GRD_CONTENTS1,
4058 action='M'),
4059 MockAffectedFile('part.grdp',
4060 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4061 self.NEW_GRDP_CONTENTS1,
4062 action='M')
4063 ])
4064 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4065 # We expect no ICU syntax errors.
4066 icu_errors = [
4067 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4068 ]
4069 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264070
Daniel Cheng566634ff2024-06-29 14:56:534071 # Valid changes in ICU syntax. Should not raise an error.
4072 input_api = self.makeInputApi([
4073 MockAffectedFile('test.grd',
4074 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4075 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4076 action='M'),
4077 MockAffectedFile('part.grdp',
4078 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4079 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4080 action='M')
4081 ])
4082 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4083 # We expect no ICU syntax errors.
4084 icu_errors = [
4085 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4086 ]
4087 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324088
Daniel Cheng566634ff2024-06-29 14:56:534089 # Valid changes in ICU syntax. Should not raise an error.
4090 input_api = self.makeInputApi([
4091 MockAffectedFile('test.grd',
4092 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4093 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4094 action='M'),
4095 MockAffectedFile('part.grdp',
4096 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4097 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4098 action='M')
4099 ])
4100 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4101 # We expect no ICU syntax errors.
4102 icu_errors = [
4103 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4104 ]
4105 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264106
Daniel Cheng566634ff2024-06-29 14:56:534107 # Add invalid ICU syntax strings. Should raise two errors.
4108 input_api = self.makeInputApi([
4109 MockAffectedFile('test.grd',
4110 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4111 self.NEW_GRD_CONTENTS1,
4112 action='M'),
4113 MockAffectedFile('part.grdp',
4114 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4115 self.NEW_GRD_CONTENTS1,
4116 action='M')
4117 ])
4118 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4119 # We expect 2 ICU syntax errors.
4120 icu_errors = [
4121 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4122 ]
4123 self.assertEqual(1, len(icu_errors))
4124 self.assertEqual([
4125 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4126 'ICU syntax.',
4127 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4128 ], icu_errors[0].items)
4129
4130 # Change two strings to have ICU syntax errors. Should raise two errors.
4131 input_api = self.makeInputApi([
4132 MockAffectedFile('test.grd',
4133 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4134 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4135 action='M'),
4136 MockAffectedFile('part.grdp',
4137 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4138 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4139 action='M')
4140 ])
4141 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4142 # We expect 2 ICU syntax errors.
4143 icu_errors = [
4144 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4145 ]
4146 self.assertEqual(1, len(icu_errors))
4147 self.assertEqual([
4148 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4149 'ICU syntax.',
4150 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4151 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264152
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144153
Mustafa Emre Acer51f2f742020-03-09 19:41:124154class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534155 ERROR_MESSAGE_FORMAT = (
4156 "Failed to get a list of translatable grd files. "
4157 "This happens when:\n"
4158 " - One of the modified grd or grdp files cannot be parsed or\n"
4159 " - %s is not updated.\n"
4160 "Stack:\n")
4161 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4162 # This lists all .grd files under REPO_ROOT.
4163 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4164 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4165 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4166 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124167
Daniel Cheng566634ff2024-06-29 14:56:534168 # Tests that the presubmit doesn't return when no grd or grdp files are
4169 # modified.
4170 def testExpectationsNoModifiedGrd(self):
4171 input_api = MockInputApi()
4172 input_api.files = [
4173 MockAffectedFile('not_used.txt',
4174 'not used',
4175 'not used',
4176 action='M')
4177 ]
4178 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4179 # under tools/translation/testdata. This is OK because the presubmit won't
4180 # run in the first place since there are no modified grd/grps in input_api.
4181 grd_files = ['doesnt_exist_doesnt_matter.grd']
4182 warnings = PRESUBMIT.CheckTranslationExpectations(
4183 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4184 grd_files)
4185 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124186
Daniel Cheng566634ff2024-06-29 14:56:534187 # Tests that the list of files passed to the presubmit matches the list of
4188 # files in the expectations.
4189 def testExpectationsSuccess(self):
4190 # Mock input file list needs a grd or grdp file in order to run the
4191 # presubmit. The file itself doesn't matter.
4192 input_api = MockInputApi()
4193 input_api.files = [
4194 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4195 ]
4196 # List of all grd files in the repo.
4197 grd_files = [
4198 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4199 ]
4200 warnings = PRESUBMIT.CheckTranslationExpectations(
4201 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4202 grd_files)
4203 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124204
Ben Mason5d4c3242025-04-15 20:28:374205 # Tests that the list of files passed to the presubmit does not
4206 # contain duplicate basenames.
4207 def testExpectationsSuccess(self):
4208 # Mock input file list needs a grd or grdp file in order to run the
4209 # presubmit. The file itself doesn't matter.
4210 input_api = MockInputApi()
4211 input_api.files = [
4212 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4213 ]
4214 # List of all grd files in the repo.
4215 grd_files = [
4216 'dir1/test.grd', 'unlisted.grd', 'not_translated.grd',
4217 'internal.grd', 'dir2/test.grd'
4218 ]
4219 warnings = PRESUBMIT.CheckTranslationExpectations(
4220 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4221 grd_files)
4222 self.assertEqual(1, len(warnings))
4223 self.assertTrue(
4224 ("Multiple string files have the same basename. "
4225 "This will result in missing translations. "
4226 "Files: dir1/test.grd, dir2/test.grd") in warnings[0].message)
4227
Daniel Cheng566634ff2024-06-29 14:56:534228 # Tests that the presubmit warns when a file is listed in expectations, but
4229 # does not actually exist.
4230 def testExpectationsMissingFile(self):
4231 # Mock input file list needs a grd or grdp file in order to run the
4232 # presubmit.
4233 input_api = MockInputApi()
4234 input_api.files = [
4235 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4236 ]
4237 # unlisted.grd is listed under tools/translation/testdata but is not
4238 # included in translation expectations.
4239 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4240 warnings = PRESUBMIT.CheckTranslationExpectations(
4241 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4242 grd_files)
4243 self.assertEqual(1, len(warnings))
4244 self.assertTrue(warnings[0].message.startswith(
4245 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4246 self.assertTrue(
4247 ("test.grd is listed in the translation expectations, "
4248 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124249
Daniel Cheng566634ff2024-06-29 14:56:534250 # Tests that the presubmit warns when a file is not listed in expectations but
4251 # does actually exist.
4252 def testExpectationsUnlistedFile(self):
4253 # Mock input file list needs a grd or grdp file in order to run the
4254 # presubmit.
4255 input_api = MockInputApi()
4256 input_api.files = [
4257 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4258 ]
4259 # unlisted.grd is listed under tools/translation/testdata but is not
4260 # included in translation expectations.
4261 grd_files = [
4262 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4263 ]
4264 warnings = PRESUBMIT.CheckTranslationExpectations(
4265 input_api, MockOutputApi(), self.REPO_ROOT,
4266 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4267 self.assertEqual(1, len(warnings))
4268 self.assertTrue(warnings[0].message.startswith(
4269 self.ERROR_MESSAGE_FORMAT %
4270 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4271 self.assertTrue(("unlisted.grd appears to be translatable "
4272 "(because it contains <file> or <message> elements), "
4273 "but is not listed in the translation expectations."
4274 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124275
Daniel Cheng566634ff2024-06-29 14:56:534276 # Tests that the presubmit warns twice:
4277 # - for a non-existing file listed in expectations
4278 # - for an existing file not listed in expectations
4279 def testMultipleWarnings(self):
4280 # Mock input file list needs a grd or grdp file in order to run the
4281 # presubmit.
4282 input_api = MockInputApi()
4283 input_api.files = [
4284 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4285 ]
4286 # unlisted.grd is listed under tools/translation/testdata but is not
4287 # included in translation expectations.
4288 # test.grd is not listed under tools/translation/testdata but is included
4289 # in translation expectations.
4290 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4291 warnings = PRESUBMIT.CheckTranslationExpectations(
4292 input_api, MockOutputApi(), self.REPO_ROOT,
4293 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4294 self.assertEqual(1, len(warnings))
4295 self.assertTrue(warnings[0].message.startswith(
4296 self.ERROR_MESSAGE_FORMAT %
4297 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4298 self.assertTrue(("unlisted.grd appears to be translatable "
4299 "(because it contains <file> or <message> elements), "
4300 "but is not listed in the translation expectations."
4301 ) in warnings[0].message)
4302 self.assertTrue(
4303 ("test.grd is listed in the translation expectations, "
4304 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124305
4306
Dominic Battre033531052018-09-24 15:45:344307class DISABLETypoInTest(unittest.TestCase):
4308
Daniel Cheng566634ff2024-06-29 14:56:534309 def testPositive(self):
4310 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4311 # where the desire is to disable a test.
4312 tests = [
4313 # Disabled on one platform:
4314 '#if defined(OS_WIN)\n'
4315 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4316 '#else\n'
4317 '#define MAYBE_FoobarTest FoobarTest\n'
4318 '#endif\n',
4319 # Disabled on one platform spread cross lines:
4320 '#if defined(OS_WIN)\n'
4321 '#define MAYBE_FoobarTest \\\n'
4322 ' DISABLE_FoobarTest\n'
4323 '#else\n'
4324 '#define MAYBE_FoobarTest FoobarTest\n'
4325 '#endif\n',
4326 # Disabled on all platforms:
4327 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4328 # Disabled on all platforms but multiple lines
4329 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4330 ]
Dominic Battre033531052018-09-24 15:45:344331
Daniel Cheng566634ff2024-06-29 14:56:534332 for test in tests:
4333 mock_input_api = MockInputApi()
4334 mock_input_api.files = [
4335 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4336 ]
Dominic Battre033531052018-09-24 15:45:344337
Daniel Cheng566634ff2024-06-29 14:56:534338 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4339 mock_input_api, MockOutputApi())
4340 self.assertEqual(
4341 1,
4342 len(results),
4343 msg=('expected len(results) == 1 but got %d in test: %s' %
4344 (len(results), test)))
4345 self.assertTrue(
4346 'foo_unittest.cc' in results[0].message,
4347 msg=(
4348 'expected foo_unittest.cc in message but got %s in test %s'
4349 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344350
Daniel Cheng566634ff2024-06-29 14:56:534351 def testIgnoreNotTestFiles(self):
4352 mock_input_api = MockInputApi()
4353 mock_input_api.files = [
4354 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4355 ]
Dominic Battre033531052018-09-24 15:45:344356
Daniel Cheng566634ff2024-06-29 14:56:534357 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4358 MockOutputApi())
4359 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344360
Daniel Cheng566634ff2024-06-29 14:56:534361 def testIgnoreDeletedFiles(self):
4362 mock_input_api = MockInputApi()
4363 mock_input_api.files = [
4364 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4365 action='D'),
4366 ]
Katie Df13948e2018-09-25 07:33:444367
Daniel Cheng566634ff2024-06-29 14:56:534368 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4369 MockOutputApi())
4370 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344371
Nina Satragnof7660532021-09-20 18:03:354372class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354373
Daniel Cheng566634ff2024-06-29 14:56:534374 def testPositive(self):
4375 test = ('#if defined(HAS_ENERGY)\n'
4376 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4377 '#else\n'
4378 '#define MAYBE_CastExplosion CastExplosion\n'
4379 '#endif\n'
4380 'TEST_F(ArchWizard, CastExplosion) {\n'
4381 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4382 '#define MAYBE_ArchPriest ArchPriest\n'
4383 '#else\n'
4384 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4385 '#endif\n'
4386 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4387 '#if !defined(CRUSADER_IN_PARTY)\n'
4388 '#define MAYBE_Crusader \\\n'
4389 ' DISABLED_Crusader \n'
4390 '#else\n'
4391 '#define MAYBE_Crusader \\\n'
4392 ' Crusader\n'
4393 '#endif\n'
4394 ' TEST_F(\n'
4395 ' Crusader,\n'
4396 ' CastTaunt) { }\n'
4397 '#if defined(LEARNED_BASIC_SKILLS)\n'
4398 '#define MAYBE_CastSteal \\\n'
4399 ' DISABLED_CastSteal \n'
4400 '#else\n'
4401 '#define MAYBE_CastSteal \\\n'
4402 ' CastSteal\n'
4403 '#endif\n'
4404 ' TEST_F(\n'
4405 ' ThiefClass,\n'
4406 ' CastSteal) { }\n')
4407 mock_input_api = MockInputApi()
4408 mock_input_api.files = [
4409 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4410 ]
4411 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4412 mock_input_api, MockOutputApi())
4413 self.assertEqual(4, len(results))
4414 self.assertTrue('CastExplosion' in results[0].message)
4415 self.assertTrue(
4416 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4417 self.assertTrue('ArchPriest' in results[1].message)
4418 self.assertTrue(
4419 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4420 self.assertTrue('Crusader' in results[2].message)
4421 self.assertTrue(
4422 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4423 self.assertTrue('CastSteal' in results[3].message)
4424 self.assertTrue(
4425 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354426
Daniel Cheng566634ff2024-06-29 14:56:534427 def testNegative(self):
4428 test = ('#if defined(HAS_ENERGY)\n'
4429 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4430 '#else\n'
4431 '#define MAYBE_CastExplosion CastExplosion\n'
4432 '#endif\n'
4433 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4434 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4435 '#define MAYBE_ArchPriest ArchPriest\n'
4436 '#else\n'
4437 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4438 '#endif\n'
4439 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4440 '#if !defined(CRUSADER_IN_PARTY)\n'
4441 '#define MAYBE_Crusader \\\n'
4442 ' DISABLED_Crusader \n'
4443 '#else\n'
4444 '#define MAYBE_Crusader \\\n'
4445 ' Crusader\n'
4446 '#endif\n'
4447 ' TEST_F(\n'
4448 ' MAYBE_Crusader,\n'
4449 ' CastTaunt) { }\n'
4450 '#if defined(LEARNED_BASIC_SKILLS)\n'
4451 '#define MAYBE_CastSteal \\\n'
4452 ' DISABLED_CastSteal \n'
4453 '#else\n'
4454 '#define MAYBE_CastSteal \\\n'
4455 ' CastSteal\n'
4456 '#endif\n'
4457 ' TEST_F(\n'
4458 ' ThiefClass,\n'
4459 ' MAYBE_CastSteal) { }\n')
4460
4461 mock_input_api = MockInputApi()
4462 mock_input_api.files = [
4463 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4464 ]
4465 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4466 mock_input_api, MockOutputApi())
4467 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514468
Max Morozb47503b2019-08-08 21:03:274469class CheckFuzzTargetsTest(unittest.TestCase):
4470
Daniel Cheng566634ff2024-06-29 14:56:534471 def _check(self, files):
4472 mock_input_api = MockInputApi()
4473 mock_input_api.files = []
4474 for fname, contents in files.items():
4475 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4476 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4477 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274478
Daniel Cheng566634ff2024-06-29 14:56:534479 def testLibFuzzerSourcesIgnored(self):
4480 results = self._check({
4481 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4482 "LLVMFuzzerInitialize",
4483 })
4484 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274485
Daniel Cheng566634ff2024-06-29 14:56:534486 def testNonCodeFilesIgnored(self):
4487 results = self._check({
4488 "README.md": "LLVMFuzzerInitialize",
4489 })
4490 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274491
Daniel Cheng566634ff2024-06-29 14:56:534492 def testNoErrorHeaderPresent(self):
4493 results = self._check({
4494 "fuzzer.cc":
4495 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4496 "LLVMFuzzerInitialize")
4497 })
4498 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274499
Daniel Cheng566634ff2024-06-29 14:56:534500 def testErrorMissingHeader(self):
4501 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4502 self.assertEqual(len(results), 1)
4503 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274504
4505
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264506class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404507
Daniel Cheng566634ff2024-06-29 14:56:534508 def testSetNoParentTopLevelAllowed(self):
4509 mock_input_api = MockInputApi()
4510 mock_input_api.files = [
4511 MockAffectedFile('goat/OWNERS', [
4512 'set noparent',
4513 '[email protected]',
4514 ])
4515 ]
4516 mock_output_api = MockOutputApi()
4517 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4518 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264519
Daniel Cheng566634ff2024-06-29 14:56:534520 def testSetNoParentMissing(self):
4521 mock_input_api = MockInputApi()
4522 mock_input_api.files = [
4523 MockAffectedFile('services/goat/OWNERS', [
4524 'set noparent',
4525 '[email protected]',
4526 'per-file *.json=set noparent',
4527 'per-file *[email protected]',
4528 ])
4529 ]
4530 mock_output_api = MockOutputApi()
4531 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4532 self.assertEqual(1, len(errors))
4533 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4534 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4535
4536 def testSetNoParentWithCorrectRule(self):
4537 mock_input_api = MockInputApi()
4538 mock_input_api.files = [
4539 MockAffectedFile('services/goat/OWNERS', [
4540 'set noparent',
4541 'file://ipc/SECURITY_OWNERS',
4542 'per-file *.json=set noparent',
4543 'per-file *.json=file://ipc/SECURITY_OWNERS',
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
4550
Ken Rockotc31f4832020-05-29 18:58:514551class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514552
Daniel Cheng566634ff2024-06-29 14:56:534553 def runTestWithAffectedFiles(self, affected_files):
4554 mock_input_api = MockInputApi()
4555 mock_input_api.files = affected_files
4556 mock_output_api = MockOutputApi()
4557 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4558 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514559
Daniel Cheng566634ff2024-06-29 14:56:534560 def testSafeChangePasses(self):
4561 errors = self.runTestWithAffectedFiles([
4562 MockAffectedFile(
4563 'foo/foo.mojom',
4564 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4565 old_contents=['[Stable] struct S {};'])
4566 ])
4567 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514568
Daniel Cheng566634ff2024-06-29 14:56:534569 def testBadChangeFails(self):
4570 errors = self.runTestWithAffectedFiles([
4571 MockAffectedFile('foo/foo.mojom',
4572 ['[Stable] struct S { int32 x; };'],
4573 old_contents=['[Stable] struct S {};'])
4574 ])
4575 self.assertEqual(1, len(errors))
4576 self.assertTrue('not backward-compatible' in errors[0].message)
4577
4578 def testDeletedFile(self):
4579 """Regression test for https://crbug.com/1091407."""
4580 errors = self.runTestWithAffectedFiles([
4581 MockAffectedFile('a.mojom', [],
4582 old_contents=['struct S {};'],
4583 action='D'),
4584 MockAffectedFile(
4585 'b.mojom', ['struct S {}; struct T { S s; };'],
4586 old_contents=['import "a.mojom"; struct T { S s; };'])
4587 ])
4588 self.assertEqual([], errors)
4589
Ken Rockotad7901f942020-06-04 20:17:094590
Jose Magana2b456f22021-03-09 23:26:404591class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4592
Daniel Cheng566634ff2024-06-29 14:56:534593 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404594
Daniel Cheng566634ff2024-06-29 14:56:534595 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404596
Daniel Cheng566634ff2024-06-29 14:56:534597 def testWarningNMF(self):
4598 mock_input_api = MockInputApi()
4599 mock_input_api.files = [
4600 MockAffectedFile(
4601 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4602 ['"program"', 'B'],
4603 scm_diff='\n'.join([
4604 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4605 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4606 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4607 ]),
4608 action='M')
4609 ]
4610 mock_output_api = MockOutputApi()
4611 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4612 mock_input_api, mock_output_api)
4613 self.assertEqual(1, len(errors))
4614 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4615 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404616
Daniel Cheng566634ff2024-06-29 14:56:534617 def testWarningManifest(self):
4618 mock_input_api = MockInputApi()
4619 mock_input_api.files = [
4620 MockAffectedFile(
4621 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4622 ['"app":"', 'B'],
4623 scm_diff='\n'.join([
4624 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4625 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4626 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4627 ]),
4628 action='M')
4629 ]
4630 mock_output_api = MockOutputApi()
4631 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4632 mock_input_api, mock_output_api)
4633 self.assertEqual(1, len(errors))
4634 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4635 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404636
Daniel Cheng566634ff2024-06-29 14:56:534637 def testOKWarningManifestWithoutApp(self):
4638 mock_input_api = MockInputApi()
4639 mock_input_api.files = [
4640 MockAffectedFile(
4641 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4642 ['"name":"', 'B'],
4643 scm_diff='\n'.join([
4644 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4645 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4646 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4647 ]),
4648 action='M')
4649 ]
4650 mock_output_api = MockOutputApi()
4651 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4652 mock_input_api, mock_output_api)
4653 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404654
Daniel Cheng566634ff2024-06-29 14:56:534655 def testWarningPPAPI(self):
4656 mock_input_api = MockInputApi()
4657 mock_input_api.files = [
4658 MockAffectedFile(
4659 'foo.hpp', ['A', '#include <ppapi.h>', 'B'], ['A', 'B'],
4660 scm_diff='\n'.join([
4661 '--- foo.hpp.old 2020-12-02 20:40:54.430676385 +0100',
4662 '+++ foo.hpp.new 2020-12-02 20:41:02.086700197 +0100',
4663 '@@ -1,2 +1,3 @@', ' A', '+#include <ppapi.h>', ' B'
4664 ]),
4665 action='M')
4666 ]
4667 mock_output_api = MockOutputApi()
4668 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4669 mock_input_api, mock_output_api)
4670 self.assertEqual(1, len(errors))
4671 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4672 self.assertTrue('foo.hpp' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404673
Daniel Cheng566634ff2024-06-29 14:56:534674 def testNoWarningPPAPI(self):
4675 mock_input_api = MockInputApi()
4676 mock_input_api.files = [
4677 MockAffectedFile(
4678 'foo.txt', ['A', 'Peppapig', 'B'], ['A', 'B'],
4679 scm_diff='\n'.join([
4680 '--- foo.txt.old 2020-12-02 20:40:54.430676385 +0100',
4681 '+++ foo.txt.new 2020-12-02 20:41:02.086700197 +0100',
4682 '@@ -1,2 +1,3 @@', ' A', '+Peppapig', ' B'
4683 ]),
4684 action='M')
4685 ]
4686 mock_output_api = MockOutputApi()
4687 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4688 mock_input_api, mock_output_api)
4689 self.assertEqual(0, len(errors))
4690
Jose Magana2b456f22021-03-09 23:26:404691
Dominic Battre645d42342020-12-04 16:14:104692class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534693 # Test that a warning is generated if a preference registration is removed
4694 # from a random file.
4695 def testWarning(self):
4696 mock_input_api = MockInputApi()
4697 mock_input_api.files = [
4698 MockAffectedFile(
4699 'foo.cc', ['A', 'B'],
4700 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4701 scm_diff='\n'.join([
4702 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4703 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4704 '@@ -1,3 +1,2 @@', ' A',
4705 '-prefs->RegisterStringPref("foo", "default");', ' B'
4706 ]),
4707 action='M')
4708 ]
4709 mock_output_api = MockOutputApi()
4710 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4711 mock_input_api, mock_output_api)
4712 self.assertEqual(1, len(errors))
4713 self.assertTrue(
4714 'Discovered possible removal of preference registrations' in
4715 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104716
Daniel Cheng566634ff2024-06-29 14:56:534717 # Test that a warning is inhibited if the preference registration was moved
4718 # to the deprecation functions in browser prefs.
4719 def testNoWarningForMigration(self):
4720 mock_input_api = MockInputApi()
4721 mock_input_api.files = [
4722 # RegisterStringPref was removed from foo.cc.
4723 MockAffectedFile(
4724 'foo.cc', ['A', 'B'],
4725 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4726 scm_diff='\n'.join([
4727 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4728 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4729 '@@ -1,3 +1,2 @@', ' A',
4730 '-prefs->RegisterStringPref("foo", "default");', ' B'
4731 ]),
4732 action='M'),
4733 # But the preference was properly migrated.
4734 MockAffectedFile(
4735 'chrome/browser/prefs/browser_prefs.cc', [
4736 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4737 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4738 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4739 'prefs->RegisterStringPref("foo", "default");',
4740 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4741 ], [
4742 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4743 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4744 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4745 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4746 ],
4747 scm_diff='\n'.join([
4748 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4749 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4750 '@@ -2,3 +2,4 @@',
4751 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4752 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4753 '+prefs->RegisterStringPref("foo", "default");',
4754 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4755 ]),
4756 action='M'),
4757 ]
4758 mock_output_api = MockOutputApi()
4759 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4760 mock_input_api, mock_output_api)
4761 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104762
Daniel Cheng566634ff2024-06-29 14:56:534763 # Test that a warning is NOT inhibited if the preference registration was
4764 # moved to a place outside of the migration functions in browser_prefs.cc
4765 def testWarningForImproperMigration(self):
4766 mock_input_api = MockInputApi()
4767 mock_input_api.files = [
4768 # RegisterStringPref was removed from foo.cc.
4769 MockAffectedFile(
4770 'foo.cc', ['A', 'B'],
4771 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4772 scm_diff='\n'.join([
4773 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4774 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4775 '@@ -1,3 +1,2 @@', ' A',
4776 '-prefs->RegisterStringPref("foo", "default");', ' B'
4777 ]),
4778 action='M'),
4779 # The registration call was moved to a place in browser_prefs.cc that
4780 # is outside the migration functions.
4781 MockAffectedFile(
4782 'chrome/browser/prefs/browser_prefs.cc', [
4783 'prefs->RegisterStringPref("foo", "default");',
4784 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4785 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4786 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4787 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4788 ], [
4789 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4790 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4791 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4792 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4793 ],
4794 scm_diff='\n'.join([
4795 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4796 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4797 '@@ -1,2 +1,3 @@',
4798 '+prefs->RegisterStringPref("foo", "default");',
4799 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4800 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4801 ]),
4802 action='M'),
4803 ]
4804 mock_output_api = MockOutputApi()
4805 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4806 mock_input_api, mock_output_api)
4807 self.assertEqual(1, len(errors))
4808 self.assertTrue(
4809 'Discovered possible removal of preference registrations' in
4810 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104811
Daniel Cheng566634ff2024-06-29 14:56:534812 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4813 # deleted.
4814 def testDeletedMarkerRaisesError(self):
4815 mock_input_api = MockInputApi()
4816 mock_input_api.files = [
4817 MockAffectedFile(
4818 'chrome/browser/prefs/browser_prefs.cc',
4819 [
4820 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4821 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4822 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4823 # The following line is deleted for this test
4824 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4825 ])
4826 ]
4827 mock_output_api = MockOutputApi()
4828 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4829 mock_input_api, mock_output_api)
4830 self.assertEqual(1, len(errors))
4831 self.assertEqual(
4832 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4833 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104834
Sven Zheng76a79ea2022-12-21 21:25:244835class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4836 def testWarning(self):
4837 mock_input_api = MockInputApi()
4838 mock_output_api = MockOutputApi()
4839 mock_input_api.files = [
4840 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4841 ]
4842 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4843 self.assertEqual(1, len(result))
4844 self.assertEqual(result[0].type, 'warning')
4845
4846 def testNoWarningWithBrowserTest(self):
4847 mock_input_api = MockInputApi()
4848 mock_output_api = MockOutputApi()
4849 mock_input_api.files = [
4850 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4851 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4852 ]
4853 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4854 self.assertEqual(0, len(result))
4855
4856 def testNoWarningModifyCrosapi(self):
4857 mock_input_api = MockInputApi()
4858 mock_output_api = MockOutputApi()
4859 mock_input_api.files = [
4860 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4861 ]
4862 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4863 self.assertEqual(0, len(result))
4864
4865 def testNoWarningAddNonMojomFile(self):
4866 mock_input_api = MockInputApi()
4867 mock_output_api = MockOutputApi()
4868 mock_input_api.files = [
4869 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4870 ]
4871 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4872 self.assertEqual(0, len(result))
4873
4874 def testNoWarningNoneRelatedMojom(self):
4875 mock_input_api = MockInputApi()
4876 mock_output_api = MockOutputApi()
4877 mock_input_api.files = [
4878 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4879 ]
4880 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4881 self.assertEqual(0, len(result))
4882
4883
Henrique Ferreiro2a4b55942021-11-29 23:45:364884class AssertAshOnlyCodeTest(unittest.TestCase):
4885 def testErrorsOnlyOnAshDirectories(self):
4886 files_in_ash = [
4887 MockFile('ash/BUILD.gn', []),
4888 MockFile('chrome/browser/ash/BUILD.gn', []),
4889 ]
4890 other_files = [
4891 MockFile('chrome/browser/BUILD.gn', []),
Georg Neis94f87f02024-10-22 08:20:134892 MockFile('chrome/browser/foo/BUILD.gn', ['assert(is_chromeos_ash)']),
Henrique Ferreiro2a4b55942021-11-29 23:45:364893 ]
4894 input_api = MockInputApi()
4895 input_api.files = files_in_ash
4896 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4897 self.assertEqual(2, len(errors))
4898
4899 input_api.files = other_files
4900 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4901 self.assertEqual(0, len(errors))
4902
4903 def testDoesNotErrorOnNonGNFiles(self):
4904 input_api = MockInputApi()
4905 input_api.files = [
4906 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4907 MockFile('chrome/browser/ash/test.cc',
4908 ['assert(is_chromeos_ash)']),
4909 ]
4910 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4911 self.assertEqual(0, len(errors))
4912
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214913 def testDeletedFile(self):
4914 input_api = MockInputApi()
4915 input_api.files = [
4916 MockFile('ash/BUILD.gn', []),
4917 MockFile('ash/foo/BUILD.gn', [], action='D'),
4918 ]
4919 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4920 self.assertEqual(1, len(errors))
4921
Henrique Ferreiro2a4b55942021-11-29 23:45:364922 def testDoesNotErrorWithAssertion(self):
4923 input_api = MockInputApi()
4924 input_api.files = [
4925 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4926 MockFile('chrome/browser/ash/BUILD.gn',
4927 ['assert(is_chromeos_ash)']),
Georg Neis94f87f02024-10-22 08:20:134928 MockFile('chrome/browser/ash/1/BUILD.gn',
4929 ['assert(is_chromeos)']),
4930 MockFile('chrome/browser/ash/2/BUILD.gn',
4931 ['assert(is_chromeos_ash)']),
4932 MockFile('chrome/browser/ash/3/BUILD.gn',
4933 ['assert(is_chromeos, "test")']),
4934 MockFile('chrome/browser/ash/4/BUILD.gn',
Henrique Ferreiro2a4b55942021-11-29 23:45:364935 ['assert(is_chromeos_ash, "test")']),
4936 ]
4937 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4938 self.assertEqual(0, len(errors))
4939
4940
Lukasz Anforowicz7016d05e2021-11-30 03:56:274941class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274942
Daniel Cheng566634ff2024-06-29 14:56:534943 def testAllowedCases(self):
4944 mock_input_api = MockInputApi()
4945 mock_input_api.files = [
4946 # Browser-side files are allowed.
4947 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4948 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4949 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4950 MockAffectedFile('test13/blink/public/common/foo.cc',
4951 ['raw_ptr<int>']),
4952 MockAffectedFile('test14/blink/public/platform/foo.cc',
4953 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274954
Daniel Cheng566634ff2024-06-29 14:56:534955 # Non-C++ files are allowed.
4956 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274957
Daniel Cheng566634ff2024-06-29 14:56:534958 # Renderer code is generally allowed (except specifically
4959 # disallowed directories).
4960 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
4961 ]
4962 mock_output_api = MockOutputApi()
4963 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4964 self.assertFalse(errors)
4965
4966 def testDisallowedCases(self):
4967 mock_input_api = MockInputApi()
4968 mock_input_api.files = [
4969 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
4970 ['raw_ptr<int>']),
4971 MockAffectedFile(
4972 'test2/third_party/blink/renderer/platform/heap/foo.cc',
4973 ['raw_ptr<int>']),
4974 MockAffectedFile(
4975 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
4976 ['raw_ptr<int>']),
4977 MockAffectedFile(
4978 'test4/third_party/blink/renderer/platform/fonts/foo.h',
4979 ['raw_ptr<int>']),
4980 MockAffectedFile(
4981 'test5/third_party/blink/renderer/core/paint/foo.cc',
4982 ['raw_ptr<int>']),
4983 MockAffectedFile(
4984 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
4985 ['raw_ptr<int>']),
4986 MockAffectedFile(
4987 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
4988 ['raw_ptr<int>']),
4989 ]
4990 mock_output_api = MockOutputApi()
4991 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
4992 self.assertEqual(len(mock_input_api.files), len(errors))
4993 for error in errors:
4994 self.assertTrue(
4995 'raw_ptr<T> should not be used in this renderer code' in
4996 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:274997
mikt9337567c2023-09-08 18:38:174998class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:174999
Daniel Cheng566634ff2024-06-29 14:56:535000 def testAllowedCases(self):
5001 mock_input_api = MockInputApi()
5002 mock_input_api.files = [
5003 # Non-C++ files are allowed.
5004 MockAffectedFile('test20/renderer/foo.md',
5005 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:175006
Daniel Cheng566634ff2024-06-29 14:56:535007 # Mentions in a comment are allowed.
5008 MockAffectedFile('test30/renderer/foo.cc',
5009 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
5010 ]
5011 mock_output_api = MockOutputApi()
5012 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5013 mock_input_api, mock_output_api)
5014 self.assertFalse(errors)
5015
5016 def testDisallowedCases(self):
5017 mock_input_api = MockInputApi()
5018 mock_input_api.files = [
5019 MockAffectedFile('test1/foo.h',
5020 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5021 MockAffectedFile('test2/foo.cc',
5022 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5023 ]
5024 mock_output_api = MockOutputApi()
5025 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5026 mock_input_api, mock_output_api)
5027 self.assertEqual(1, len(errors))
5028 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
5029 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275030
Henrique Ferreirof9819f2e32021-11-30 13:31:565031class AssertPythonShebangTest(unittest.TestCase):
5032 def testError(self):
5033 input_api = MockInputApi()
5034 input_api.files = [
5035 MockFile('ash/test.py', ['#!/usr/bin/python']),
5036 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
5037 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:275038 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:565039 ]
5040 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5041 self.assertEqual(3, len(errors))
5042
5043 def testNonError(self):
5044 input_api = MockInputApi()
5045 input_api.files = [
5046 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
5047 MockFile('third_party/blink/web_tests/external/test.py',
5048 ['#!/usr/bin/python2']),
5049 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
5050 ]
5051 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5052 self.assertEqual(0, len(errors))
5053
Kalvin Lee4a3b79de2022-05-26 16:00:165054class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:165055
Daniel Cheng566634ff2024-06-29 14:56:535056 def testPermissibleUsage(self):
5057 input_api = MockInputApi()
5058 input_api.files = [
5059 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
5060 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:165061
Daniel Cheng566634ff2024-06-29 14:56:535062 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
5063 # own thing at their own risk.
5064 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
5065 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
5066 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
5067 ]
5068 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5069 MockOutputApi())
5070 self.assertEqual(0, len(errors))
5071
5072 def testMissingParentheses(self):
5073 input_api = MockInputApi()
5074 input_api.files = [
5075 MockFile('bad1.cc', ['DCHECK_IS_ON']),
5076 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
5077 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
5078 ]
5079 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5080 MockOutputApi())
5081 self.assertEqual(3, len(errors))
5082 for error in errors:
5083 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:565084
Sam Maier4cef9242022-10-03 14:21:245085
Andrew Grieve5a66ae72024-12-13 15:21:535086class CheckAndroidTestAnnotations(unittest.TestCase):
5087 """Test the CheckAndroidTestAnnotations presubmit check."""
James Shen81cc0e22022-06-15 21:10:455088
Andrew Grieve5a66ae72024-12-13 15:21:535089 def testBatchTruePositives(self):
Daniel Cheng566634ff2024-06-29 14:56:535090 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455091"""
Daniel Cheng566634ff2024-06-29 14:56:535092 mock_input = MockInputApi()
5093 mock_input.files = [
5094 MockFile('path/OneTest.java', ['public class OneTest']),
5095 MockFile('path/TwoTest.java', ['public class TwoTest']),
5096 MockFile('path/ThreeTest.java', [
5097 '@Batch(Batch.PER_CLASS)',
Andrew Grieve5a66ae72024-12-13 15:21:535098 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535099 'public class Three {'
5100 ]),
5101 MockFile('path/FourTest.java', [
5102 '@DoNotBatch(reason = "placeholder reason 1")',
Andrew Grieve5a66ae72024-12-13 15:21:535103 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535104 'public class Four {'
5105 ]),
5106 ]
Andrew Grieve5a66ae72024-12-13 15:21:535107 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535108 self.assertEqual(2, len(errors))
5109 self.assertEqual(2, len(errors[0].items))
5110 self.assertIn('OneTest.java', errors[0].items[0])
5111 self.assertIn('TwoTest.java', errors[0].items[1])
5112 self.assertEqual(2, len(errors[1].items))
5113 self.assertIn('ThreeTest.java', errors[1].items[0])
5114 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385115
Andrew Grieve5a66ae72024-12-13 15:21:535116 def testBatchAnnotationsPresent(self):
Daniel Cheng566634ff2024-06-29 14:56:535117 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5118 mock_input = MockInputApi()
5119 mock_input.files = [
5120 MockFile('path/OneTest.java',
5121 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5122 MockFile('path/TwoTest.java', [
5123 '@DoNotBatch(reason = "placeholder reasons.")',
5124 'public class Two {'
5125 ]),
5126 MockFile('path/ThreeTest.java', [
5127 '@Batch(Batch.PER_CLASS)',
5128 'public class Three extends BaseTestA {'
5129 ], [
5130 '@Batch(Batch.PER_CLASS)',
5131 'public class Three extends BaseTestB {'
5132 ]),
5133 MockFile('path/FourTest.java', [
5134 '@DoNotBatch(reason = "placeholder reason 1")',
5135 'public class Four extends BaseTestA {'
5136 ], [
5137 '@DoNotBatch(reason = "placeholder reason 2")',
5138 'public class Four extends BaseTestB {'
5139 ]),
5140 MockFile('path/FiveTest.java', [
5141 'import androidx.test.uiautomator.UiDevice;',
5142 'public class Five extends BaseTestA {'
5143 ], [
5144 'import androidx.test.uiautomator.UiDevice;',
5145 'public class Five extends BaseTestB {'
5146 ]),
5147 MockFile('path/SixTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535148 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535149 'public class Six extends BaseTestA {'
5150 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535151 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535152 'public class Six extends BaseTestB {'
5153 ]),
5154 MockFile('path/SevenTest.java', [
Andrew Grieve5a66ae72024-12-13 15:21:535155 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535156 'public class Seven extends BaseTestA {'
5157 ], [
Andrew Grieve5a66ae72024-12-13 15:21:535158 '@RunWith(BaseRobolectricTestRunner.class)',
Daniel Cheng566634ff2024-06-29 14:56:535159 'public class Seven extends BaseTestB {'
5160 ]),
5161 MockFile(
5162 'path/OtherClass.java',
5163 ['public class OtherClass {'],
5164 ),
5165 MockFile('path/PRESUBMIT.py', [
5166 '@Batch(Batch.PER_CLASS)',
5167 '@DoNotBatch(reason = "placeholder reason)'
5168 ]),
5169 MockFile(
5170 'path/AnnotationTest.java',
5171 ['public @interface SomeAnnotation {'],
5172 ),
5173 ]
Andrew Grieve5a66ae72024-12-13 15:21:535174 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
Daniel Cheng566634ff2024-06-29 14:56:535175 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455176
Andrew Grieve5a66ae72024-12-13 15:21:535177 def testWrongRobolectricTestRunner(self):
5178 mock_input = MockInputApi()
5179 mock_input.files = [
5180 MockFile('path/OneTest.java', [
5181 '@RunWith(RobolectricTestRunner.class)',
5182 'public class ThreeTest {'
5183 ]),
5184 MockFile('path/TwoTest.java', [
5185 'import org.chromium.base.test.BaseRobolectricTestRule;',
5186 '@RunWith(RobolectricTestRunner.class)',
5187 'public class TwoTest {'
5188 ]),
5189 MockFile('path/ThreeTest.java', [
5190 '@RunWith(FooRobolectricTestRunner.class)',
5191 'public class ThreeTest {'
5192 ]),
5193 MockFile('webapks/FourTest.java', [
5194 '@RunWith(RobolectricTestRunner.class)',
5195 'public class ThreeTest {'
5196 ]),
5197 ]
5198 errors = PRESUBMIT.CheckAndroidTestAnnotations(mock_input, MockOutputApi())
5199 self.assertEqual(1, len(errors))
5200 self.assertEqual(1, len(errors[0].items))
5201 self.assertIn('OneTest.java', errors[0].items[0])
5202
Sam Maier4cef9242022-10-03 14:21:245203
Henrique Nakashima224ee2482025-03-21 18:35:025204class CheckAndroidNullAwayAnnotatedClasses(unittest.TestCase):
5205 """Test the _CheckAndroidNullAwayAnnotatedClasses presubmit check."""
5206
5207 def testDetectsInClasses(self):
5208 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in classes."""
5209 mock_input = MockInputApi()
5210 mock_input.files = [
5211 MockFile('path/OneMissing.java', ['public class OneMissing']),
5212 MockFile('path/TwoMarked.java', [
5213 '@NullMarked',
5214 'public class TwoMarked {',
5215 ]),
5216 MockFile('path/ThreeMarked.java', [
5217 '@NullUnmarked',
5218 'public class ThreeMarked {',
5219 ]),
5220 MockFile('path/FourMissing.java', ['class FourMissing']),
5221 ]
5222 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5223 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425224 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025225 self.assertEqual(2, len(results[0].items))
5226 self.assertIn('OneMissing.java', results[0].items[0])
5227 self.assertIn('FourMissing.java', results[0].items[1])
5228
5229 def testDetectsInAnnotations(self):
5230 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in annotations."""
5231 mock_input = MockInputApi()
5232 mock_input.files = [
5233 MockFile('path/OneMissing.java', ['@interface OneMissing']),
5234 MockFile('path/TwoMarked.java', [
5235 '@NullMarked',
5236 '@interface TwoMarked {',
5237 ]),
5238 ]
5239 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5240 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425241 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025242 self.assertEqual(1, len(results[0].items))
5243 self.assertIn('OneMissing.java', results[0].items[0])
5244
5245 def testDetectsInInterfaces(self):
5246 """Tests that missing @NullMarked or @NullUnmarked are correctly flagged in interfaces."""
5247 mock_input = MockInputApi()
5248 mock_input.files = [
5249 MockFile('path/OneMissing.java', ['interface OneMissing']),
5250 MockFile('path/TwoMarked.java', [
5251 '@NullMarked',
5252 'interface TwoMarked {',
5253 ]),
5254 ]
5255 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5256 self.assertEqual(1, len(results))
Henrique Nakashima8bafbc52025-04-22 19:38:425257 self.assertEqual('error', results[0].type)
Henrique Nakashima224ee2482025-03-21 18:35:025258 self.assertEqual(1, len(results[0].items))
5259 self.assertIn('OneMissing.java', results[0].items[0])
5260
Henrique Nakashimac6605432025-04-24 18:11:595261 def testOnlyChecksAddedFiles(self):
5262 """Tests that missing @NullMarked or @NullUnmarked is only flagged in newly added files."""
5263 mock_input = MockInputApi()
5264 mock_input.files = [
5265 MockFile('path/OneMissing.java', ['public class OneMissing'], action='M'),
5266 ]
5267 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5268 self.assertEqual(0, len(results))
5269
Henrique Nakashima224ee2482025-03-21 18:35:025270 def testExcludesTests(self):
5271 """Tests that missing @NullMarked or @NullUnmarked are not flagged in tests."""
5272 mock_input = MockInputApi()
5273 mock_input.files = [
5274 MockFile('path/OneTest.java', ['public class OneTest']),
5275 ]
5276 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5277 self.assertEqual(0, len(results))
5278
5279 def testExcludesTestSupport(self):
5280 """Tests that missing @NullMarked or @NullUnmarked are not flagged in test support classes."""
5281 mock_input = MockInputApi()
5282 mock_input.files = [
5283 MockFile('path/test/Two.java', [
5284 'public class Two'
5285 ]),
5286 ]
5287 results = PRESUBMIT._CheckAndroidNullAwayAnnotatedClasses(mock_input, MockOutputApi())
5288 self.assertEqual(0, len(results))
5289
5290
Mike Dougherty1b8be712022-10-20 00:15:135291class AssertNoJsInIosTest(unittest.TestCase):
5292 def testErrorJs(self):
5293 input_api = MockInputApi()
5294 input_api.files = [
5295 MockFile('components/feature/ios/resources/script.js', []),
5296 MockFile('ios/chrome/feature/resources/script.js', []),
5297 ]
5298 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5299 self.assertEqual(1, len(results))
5300 self.assertEqual('error', results[0].type)
5301 self.assertEqual(2, len(results[0].items))
5302
5303 def testNonError(self):
5304 input_api = MockInputApi()
5305 input_api.files = [
5306 MockFile('chrome/resources/script.js', []),
5307 MockFile('components/feature/ios/resources/script.ts', []),
5308 MockFile('ios/chrome/feature/resources/script.ts', []),
5309 MockFile('ios/web/feature/resources/script.ts', []),
5310 MockFile('ios/third_party/script.js', []),
5311 MockFile('third_party/ios/script.js', []),
5312 ]
5313 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5314 self.assertEqual(0, len(results))
5315
5316 def testExistingFilesWarningOnly(self):
5317 input_api = MockInputApi()
5318 input_api.files = [
5319 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5320 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5321 ]
5322 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5323 self.assertEqual(1, len(results))
5324 self.assertEqual('warning', results[0].type)
5325 self.assertEqual(1, len(results[0].items))
5326
Mike Dougherty4d1050b2023-03-14 15:59:535327 def testMovedScriptWarningOnly(self):
5328 input_api = MockInputApi()
5329 input_api.files = [
5330 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5331 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5332 ]
5333 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5334 self.assertEqual(1, len(results))
5335 self.assertEqual('warning', results[0].type)
5336 self.assertEqual(1, len(results[0].items))
5337
Yuanqing Zhu9eef02832022-12-04 14:42:175338class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175339
Daniel Cheng566634ff2024-06-29 14:56:535340 def testHasAbbreviation(self):
5341 """test png file names with abbreviation that fails the check"""
5342 input_api = MockInputApi()
5343 input_api.files = [
5344 MockFile('image_a.png', [], action='A'),
5345 MockFile('image_a_.png', [], action='A'),
5346 MockFile('image_a_name.png', [], action='A'),
5347 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5348 action='A'),
5349 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5350 action='A'),
5351 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5352 action='A'),
5353 ]
5354 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5355 input_api, MockOutputApi())
5356 self.assertEqual(1, len(results))
5357 self.assertEqual('error', results[0].type)
5358 self.assertEqual(len(input_api.files), len(results[0].items))
5359
5360 def testNoAbbreviation(self):
5361 """test png file names without abbreviation that passes the check"""
5362 input_api = MockInputApi()
5363 input_api.files = [
5364 MockFile('a.png', [], action='A'),
5365 MockFile('_a.png', [], action='A'),
5366 MockFile('image.png', [], action='A'),
5367 MockFile('image_ab_.png', [], action='A'),
5368 MockFile('image_ab_name.png', [], action='A'),
5369 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5370 # They should pass now because the path components ahead of the file name are ignored in the check.
5371 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5372 action='A'),
5373 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5374 action='A'),
5375 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5376 action='A'),
5377 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5378 action='A'),
5379 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5380 [],
5381 action='A'),
5382 ]
5383 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5384 input_api, MockOutputApi())
5385 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175386
Arthur Sonzogni7109bd32023-10-03 10:34:425387class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425388
Daniel Cheng566634ff2024-06-29 14:56:535389 def testError(self):
5390 """Test patch adding dangling pointers are reported"""
5391 mock_input_api = MockInputApi()
5392 mock_output_api = MockOutputApi()
5393
5394 mock_input_api.change.DescriptionText = lambda: "description"
5395 mock_input_api.files = [
5396 MockAffectedFile(
5397 local_path="foo/foo.cc",
5398 old_contents=["raw_ptr<T>"],
5399 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5400 )
5401 ]
5402 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5403 mock_output_api)
5404 self.assertEqual(len(msgs), 1)
5405 self.assertEqual(len(msgs[0].message), 10)
5406 self.assertEqual(
5407 msgs[0].message[0],
5408 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5409 )
Arthur Sonzogni7109bd32023-10-03 10:34:425410
5411class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425412
Daniel Cheng566634ff2024-06-29 14:56:535413 def testError(self):
5414 """Test patch adding dangling pointers are reported"""
5415 mock_input_api = MockInputApi()
5416 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425417
Daniel Cheng566634ff2024-06-29 14:56:535418 mock_input_api.change.DescriptionText = lambda: "description"
5419 mock_input_api.files = [
5420 MockAffectedFile(
5421 local_path="foo/foo.cc",
5422 old_contents=["raw_ptr<T>"],
5423 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5424 )
5425 ]
5426 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5427 mock_output_api)
5428 self.assertEqual(len(msgs), 1)
5429 self.assertTrue(
5430 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5431 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425432
Daniel Cheng566634ff2024-06-29 14:56:535433 def testNonCppFile(self):
5434 """Test patch adding dangling pointers are not reported in non C++ files"""
5435 mock_input_api = MockInputApi()
5436 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425437
Daniel Cheng566634ff2024-06-29 14:56:535438 mock_input_api.change.DescriptionText = lambda: "description"
5439 mock_input_api.files = [
5440 MockAffectedFile(
5441 local_path="foo/README.md",
5442 old_contents=[""],
5443 new_contents=["The DanglingUntriaged annotation means"],
5444 )
5445 ]
5446 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5447 mock_output_api)
5448 self.assertEqual(len(msgs), 0)
5449
5450 def testDeveloperAcknowledgeInCommitDescription(self):
5451 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425452 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535453 mock_input_api = MockInputApi()
5454 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425455
Daniel Cheng566634ff2024-06-29 14:56:535456 mock_input_api.files = [
5457 MockAffectedFile(
5458 local_path="foo/foo.cc",
5459 old_contents=["raw_ptr<T>"],
5460 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5461 )
5462 ]
5463 mock_input_api.change.DescriptionText = lambda: (
5464 "DanglingUntriaged-notes: Sorry about this!")
5465 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5466 mock_output_api)
5467 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425468
Daniel Cheng566634ff2024-06-29 14:56:535469 def testDeveloperAcknowledgeInCommitFooter(self):
5470 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425471 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535472 mock_input_api = MockInputApi()
5473 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425474
Daniel Cheng566634ff2024-06-29 14:56:535475 mock_input_api.files = [
5476 MockAffectedFile(
5477 local_path="foo/foo.cc",
5478 old_contents=["raw_ptr<T>"],
5479 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5480 )
5481 ]
5482 mock_input_api.change.DescriptionText = lambda: "description"
5483 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5484 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5485 mock_output_api)
5486 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425487
Daniel Cheng566634ff2024-06-29 14:56:535488 def testCongrats(self):
5489 """Test the presubmit congrats users removing dangling pointers"""
5490 mock_input_api = MockInputApi()
5491 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425492
Daniel Cheng566634ff2024-06-29 14:56:535493 mock_input_api.files = [
5494 MockAffectedFile(
5495 local_path="foo/foo.cc",
5496 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5497 new_contents=["raw_ptr<T>"],
5498 )
5499 ]
5500 mock_input_api.change.DescriptionText = lambda: (
5501 "This patch fixes some DanglingUntriaged pointers!")
5502 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5503 mock_output_api)
5504 self.assertEqual(len(msgs), 1)
5505 self.assertTrue(
5506 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5507 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425508
Daniel Cheng566634ff2024-06-29 14:56:535509 def testRenameFile(self):
5510 """Patch that we do not warn about DanglingUntriaged when moving files"""
5511 mock_input_api = MockInputApi()
5512 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425513
Daniel Cheng566634ff2024-06-29 14:56:535514 mock_input_api.files = [
5515 MockAffectedFile(
5516 local_path="foo/foo.cc",
5517 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5518 new_contents=[""],
5519 action="D",
5520 ),
5521 MockAffectedFile(
5522 local_path="foo/foo.cc",
5523 old_contents=[""],
5524 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5525 action="A",
5526 ),
5527 ]
5528 mock_input_api.change.DescriptionText = lambda: (
5529 "This patch moves files")
5530 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5531 mock_output_api)
5532 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425533
Jan Keitel77be7522023-10-12 20:40:495534class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495535
Daniel Cheng566634ff2024-06-29 14:56:535536 def testNoInlineConstexprInHeaderFile(self):
5537 """Tests that non-inlined constexpr variables in headers fail the test."""
5538 input_api = MockInputApi()
5539 input_api.files = [
5540 MockAffectedFile('src/constants.h',
5541 ['constexpr int kVersion = 5;'])
5542 ]
5543 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5544 input_api, MockOutputApi())
5545 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495546
Daniel Cheng566634ff2024-06-29 14:56:535547 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5548 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5549 input_api = MockInputApi()
5550 input_api.files = [
5551 MockAffectedFile('src/constants.h',
5552 ['constexpr int kVersion = GetVersion();'])
5553 ]
5554 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5555 input_api, MockOutputApi())
5556 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495557
Daniel Cheng566634ff2024-06-29 14:56:535558 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5559 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5560 input_api = MockInputApi()
5561 input_api.files = [
5562 MockAffectedFile('src/constants.h',
5563 ['constexpr int kVersion = (4 + 5)*3;'])
5564 ]
5565 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5566 input_api, MockOutputApi())
5567 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495568
Daniel Cheng566634ff2024-06-29 14:56:535569 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5570 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5571 input_api = MockInputApi()
5572 input_api.files = [
5573 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5574 ]
5575 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5576 input_api, MockOutputApi())
5577 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495578
Daniel Cheng566634ff2024-06-29 14:56:535579 def testNoInlineConstexprInHeaderWithAttribute(self):
5580 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5581 input_api = MockInputApi()
5582 input_api.files = [
5583 MockAffectedFile('src/constants.h',
5584 ['constexpr [[maybe_unused]] int kVersion{5};'])
5585 ]
5586 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5587 input_api, MockOutputApi())
5588 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495589
Daniel Cheng566634ff2024-06-29 14:56:535590 def testInlineConstexprInHeaderWithAttribute(self):
5591 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5592 input_api = MockInputApi()
5593 input_api.files = [
5594 MockAffectedFile(
5595 'src/constants.h',
5596 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5597 MockAffectedFile(
5598 'src/constants.h',
5599 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5600 MockAffectedFile(
5601 'src/constants.h',
5602 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5603 ]
5604 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5605 input_api, MockOutputApi())
5606 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495607
Daniel Cheng566634ff2024-06-29 14:56:535608 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5609 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5610 input_api = MockInputApi()
5611 lines = [
5612 'constexpr char kLongName =',
5613 ' "This is a very long name of something.";'
5614 ]
5615 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5616 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5617 input_api, MockOutputApi())
5618 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495619
Daniel Cheng566634ff2024-06-29 14:56:535620 def testNoInlineConstexprInCCFile(self):
5621 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5622 input_api = MockInputApi()
5623 input_api.files = [
5624 MockAffectedFile('src/implementation.cc',
5625 ['constexpr int kVersion = 5;'])
5626 ]
5627 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5628 input_api, MockOutputApi())
5629 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495630
Daniel Cheng566634ff2024-06-29 14:56:535631 def testInlineConstexprInHeaderFile(self):
5632 """Tests that inlined constexpr variables in header files pass the test."""
5633 input_api = MockInputApi()
5634 input_api.files = [
5635 MockAffectedFile('src/constants.h',
5636 ['constexpr inline int kX = 5;']),
5637 MockAffectedFile('src/version.h',
5638 ['inline constexpr float kY = 5.0f;'])
5639 ]
5640 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5641 input_api, MockOutputApi())
5642 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495643
Daniel Cheng566634ff2024-06-29 14:56:535644 def testConstexprStandaloneFunctionInHeaderFile(self):
5645 """Tests that non-inlined constexpr functions in headers pass the test."""
5646 input_api = MockInputApi()
5647 input_api.files = [
5648 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5649 ]
5650 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5651 input_api, MockOutputApi())
5652 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495653
Daniel Cheng566634ff2024-06-29 14:56:535654 def testConstexprWithAbseilAttributeInHeader(self):
5655 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5656 input_api = MockInputApi()
5657 input_api.files = [
5658 MockAffectedFile('src/helpers.h',
5659 ['ABSL_FOOFOO constexpr int i = 5;'])
5660 ]
5661 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5662 input_api, MockOutputApi())
5663 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495664
Daniel Cheng566634ff2024-06-29 14:56:535665 def testInlineConstexprWithAbseilAttributeInHeader(self):
5666 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5667 input_api = MockInputApi()
5668 input_api.files = [
5669 MockAffectedFile('src/helpers.h',
5670 ['constexpr ABSL_FOO inline int i = 5;'])
5671 ]
5672 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5673 input_api, MockOutputApi())
5674 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495675
Daniel Cheng566634ff2024-06-29 14:56:535676 def testConstexprWithClangAttributeInHeader(self):
5677 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5678 input_api = MockInputApi()
5679 input_api.files = [
5680 MockAffectedFile('src/helpers.h',
5681 ['[[clang::someattribute]] constexpr int i = 5;'])
5682 ]
5683 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5684 input_api, MockOutputApi())
5685 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495686
Daniel Cheng566634ff2024-06-29 14:56:535687 def testInlineConstexprWithClangAttributeInHeader(self):
5688 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5689 input_api = MockInputApi()
5690 input_api.files = [
5691 MockAffectedFile(
5692 'src/helpers.h',
5693 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5694 ]
5695 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5696 input_api, MockOutputApi())
5697 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425698
Daniel Cheng566634ff2024-06-29 14:56:535699 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5700 """Tests that non-inlined constexpr class members pass the test."""
5701 input_api = MockInputApi()
5702 lines = [
5703 'class SomeClass {', ' public:',
5704 ' static constexpr kVersion = 5;', '};'
5705 ]
5706 input_api.files = [MockAffectedFile('src/class.h', lines)]
5707 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5708 input_api, MockOutputApi())
5709 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045710
Daniel Cheng566634ff2024-06-29 14:56:535711 def testTodoBugReferencesWithOldBugId(self):
5712 """Tests that an old monorail bug ID in a TODO fails."""
5713 input_api = MockInputApi()
5714 input_api.files = [
5715 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5716 ]
5717 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5718 self.assertEqual(1, len(warnings))
5719
5720 def testTodoBugReferencesWithUpdatedBugId(self):
5721 """Tests that a new issue tracker bug ID in a TODO passes."""
5722 input_api = MockInputApi()
5723 input_api.files = [
5724 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5725 ]
5726 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5727 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045728
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155729class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535730 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155731
Daniel Cheng566634ff2024-06-29 14:56:535732 def testCppMobilePlatformPath(self):
5733 input_api = MockInputApi()
5734 input_api.files = [
5735 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5736 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5737 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5738 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5739 MockFile('components/foo/delegate_android.cc',
5740 ['IsSyncFeatureActive']),
5741 MockFile('components/foo/delegate_ios.cc',
5742 ['IsSyncFeatureActive']),
5743 MockFile('components/foo/android_delegate.cc',
5744 ['IsSyncFeatureActive']),
5745 MockFile('components/foo/ios_delegate.cc',
5746 ['IsSyncFeatureActive']),
5747 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155748
Daniel Cheng566634ff2024-06-29 14:56:535749 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155750
Ben Pastenee79d66112025-04-23 19:46:155751 self.assertEqual(7, len(results))
5752 self.assertTrue(all('chrome/browser/android/file.cc' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535753 self.assertTrue('chrome/android/file.cc' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155754 self.assertTrue('ios/file.mm' in results[1].message),
5755 self.assertTrue('components/foo/ios/file.cc' in results[2].message),
Daniel Cheng566634ff2024-06-29 14:56:535756 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155757 'components/foo/delegate_android.cc' in results[3].message),
Daniel Cheng566634ff2024-06-29 14:56:535758 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155759 'components/foo/delegate_ios.cc' in results[4].message),
Daniel Cheng566634ff2024-06-29 14:56:535760 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155761 'components/foo/android_delegate.cc' in results[5].message),
Daniel Cheng566634ff2024-06-29 14:56:535762 self.assertTrue(
Ben Pastenee79d66112025-04-23 19:46:155763 'components/foo/ios_delegate.cc' in results[6].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155764
Daniel Cheng566634ff2024-06-29 14:56:535765 def testCppNonMobilePlatformPath(self):
5766 input_api = MockInputApi()
5767 input_api.files = [
5768 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5769 MockFile('bios/file.cc', ['HasSyncConsent']),
5770 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5771 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155772
Daniel Cheng566634ff2024-06-29 14:56:535773 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155774
Daniel Cheng566634ff2024-06-29 14:56:535775 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155776
Daniel Cheng566634ff2024-06-29 14:56:535777 def testJavaPath(self):
5778 input_api = MockInputApi()
5779 input_api.files = [
5780 MockFile('components/foo/file1.java', ['otherFunction']),
5781 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5782 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5783 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5784 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5785 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155786
Daniel Cheng566634ff2024-06-29 14:56:535787 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155788
Ben Pastenee79d66112025-04-23 19:46:155789 self.assertEqual(4, len(results))
5790 self.assertTrue(all('components/foo/file1.java' not in r.message for r in results))
Daniel Cheng566634ff2024-06-29 14:56:535791 self.assertTrue('components/foo/file2.java' in results[0].message),
Ben Pastenee79d66112025-04-23 19:46:155792 self.assertTrue('chrome/foo/file3.java' in results[1].message),
5793 self.assertTrue('chrome/foo/file4.java' in results[2].message),
5794 self.assertTrue('chrome/foo/file5.java' in results[3].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155795
5796
Erik Chen1396bbe2025-01-27 23:39:365797class CheckAnonymousNamespaceTest(unittest.TestCase):
5798 """Test the presubmit for anonymous namespaces."""
5799
5800 def testAnonymousNamespace(self):
5801 input_api = MockInputApi()
5802 input_api.files = [
5803 MockFile('chrome/test.h', ['namespace {']),
5804 MockFile('chrome/test.cc', ['namespace {']),
5805 MockFile('chrome/test.java', ['namespace {']),
5806 MockFile('chrome/test.cpp', ['namespace {']),
5807 MockFile('chrome/test.txt', ['namespace {']),
5808 ]
5809
5810 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
5811
5812 self.assertEqual(1, len(results))
5813 self.assertTrue(
5814 'chrome/test.h' in results[0].message),
5815 self.assertFalse(
5816 'chrome/test.cc' in results[0].message),
5817 self.assertFalse(
5818 'chrome/test.java' in results[0].message),
5819 self.assertFalse(
5820 'chrome/test.cpp' in results[0].message),
5821 self.assertFalse(
5822 'chrome/test.txt' in results[0].message),
5823
5824
[email protected]2299dcf2012-11-15 19:56:245825if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535826 unittest.main()