blob: 0e7ae32f392534dfdfe5a96977848385a7000f0c [file] [log] [blame]
Andrew Grieve3f9b9662022-02-02 19:07:551#!/usr/bin/env python3
Avi Drissman24976592022-09-12 15:24:312# Copyright 2012 The Chromium Authors
marja@chromium.org2299dcf2012-11-15 19:56:243# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Andrew Grieve4deedb12022-02-03 21:34:506import io
Daniel Cheng4dcdb6b2017-04-13 08:30:177import os.path
yoz@chromium.org99171a92014-06-03 08:44:478import subprocess
Min Qinbc44383c2023-02-22 17:25:269import textwrap
marja@chromium.org2299dcf2012-11-15 19:56:2410import unittest
11
12import PRESUBMIT
Saagar Sanghavifceeaae2020-08-12 16:40:3613
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3914from PRESUBMIT_test_mocks import MockFile, MockAffectedFile
gayane3dff8c22014-12-04 17:09:5115from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
marja@chromium.org2299dcf2012-11-15 19:56:2416
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3917
yoz@chromium.org99171a92014-06-03 08:44:4718_TEST_DATA_DIR = 'base/test/data/presubmit'
19
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3920
dbeam@chromium.orgb00342e7f2013-03-26 16:21:5421class VersionControlConflictsTest(unittest.TestCase):
dbeam@chromium.org70ca77752012-11-20 03:45:0322
Daniel Cheng566634ff2024-06-29 14:56:5323 def testTypicalConflict(self):
24 lines = [
25 '<<<<<<< HEAD', ' base::ScopedTempDir temp_dir_;', '=======',
26 ' ScopedTempDir temp_dir_;', '>>>>>>> master'
27 ]
28 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
29 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
30 self.assertEqual(3, len(errors))
31 self.assertTrue('1' in errors[0])
32 self.assertTrue('3' in errors[1])
33 self.assertTrue('5' in errors[2])
34
35 def testIgnoresReadmes(self):
36 lines = [
37 'A First Level Header', '====================', '',
38 'A Second Level Header', '---------------------'
39 ]
40 errors = PRESUBMIT._CheckForVersionControlConflictsInFile(
41 MockInputApi(), MockFile('some/polymer/README.md', lines))
42 self.assertEqual(0, len(errors))
dbeam95c35a2f2015-06-02 01:40:2343
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:3944
enne@chromium.orgb8079ae4a2012-12-05 19:56:4945class BadExtensionsTest(unittest.TestCase):
enne@chromium.orgb8079ae4a2012-12-05 19:56:4946
Daniel Cheng566634ff2024-06-29 14:56:5347 def testBadRejFile(self):
48 mock_input_api = MockInputApi()
49 mock_input_api.files = [
50 MockFile('some/path/foo.cc', ''),
51 MockFile('some/path/foo.cc.rej', ''),
52 MockFile('some/path2/bar.h.rej', ''),
53 ]
enne@chromium.orgb8079ae4a2012-12-05 19:56:4954
Daniel Cheng566634ff2024-06-29 14:56:5355 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
56 self.assertEqual(1, len(results))
57 self.assertEqual(2, len(results[0].items))
58 self.assertTrue('foo.cc.rej' in results[0].items[0])
59 self.assertTrue('bar.h.rej' in results[0].items[1])
enne@chromium.orgb8079ae4a2012-12-05 19:56:4960
Daniel Cheng566634ff2024-06-29 14:56:5361 def testBadOrigFile(self):
62 mock_input_api = MockInputApi()
63 mock_input_api.files = [
64 MockFile('other/path/qux.h.orig', ''),
65 MockFile('other/path/qux.h', ''),
66 MockFile('other/path/qux.cc', ''),
67 ]
enne@chromium.orgb8079ae4a2012-12-05 19:56:4968
Daniel Cheng566634ff2024-06-29 14:56:5369 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
70 self.assertEqual(1, len(results))
71 self.assertEqual(1, len(results[0].items))
72 self.assertTrue('qux.h.orig' in results[0].items[0])
73
74 def testGoodFiles(self):
75 mock_input_api = MockInputApi()
76 mock_input_api.files = [
77 MockFile('other/path/qux.h', ''),
78 MockFile('other/path/qux.cc', ''),
79 ]
80 results = PRESUBMIT.CheckPatchFiles(mock_input_api, MockOutputApi())
81 self.assertEqual(0, len(results))
enne@chromium.orgb8079ae4a2012-12-05 19:56:4982
83
Lei Zhang1c12a22f2021-05-12 11:28:4584class CheckForSuperfluousStlIncludesInHeadersTest(unittest.TestCase):
Lei Zhang1c12a22f2021-05-12 11:28:4585
Daniel Cheng566634ff2024-06-29 14:56:5386 def testGoodFiles(self):
87 mock_input_api = MockInputApi()
88 mock_input_api.files = [
89 # The check is not smart enough to figure out which definitions correspond
90 # to which header.
91 MockFile('other/path/foo.h', ['#include <string>', 'std::vector']),
92 # The check is not smart enough to do IWYU.
93 MockFile('other/path/bar.h',
94 ['#include "base/check.h"', 'std::vector']),
95 MockFile('other/path/qux.h',
96 ['#include "base/stl_util.h"', 'foobar']),
97 MockFile('other/path/baz.h',
98 ['#include "set/vector.h"', 'bazzab']),
99 # The check is only for header files.
100 MockFile('other/path/not_checked.cc',
101 ['#include <vector>', 'bazbaz']),
102 ]
103 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
104 mock_input_api, MockOutputApi())
105 self.assertEqual(0, len(results))
106
107 def testBadFiles(self):
108 mock_input_api = MockInputApi()
109 mock_input_api.files = [
110 MockFile('other/path/foo.h', ['#include <vector>', 'vector']),
111 MockFile(
112 'other/path/bar.h',
113 ['#include <limits>', '#include <set>', 'no_std_namespace']),
114 ]
115 results = PRESUBMIT.CheckForSuperfluousStlIncludesInHeaders(
116 mock_input_api, MockOutputApi())
117 self.assertEqual(1, len(results))
118 self.assertTrue('foo.h: Includes STL' in results[0].message)
119 self.assertTrue('bar.h: Includes STL' in results[0].message)
Lei Zhang1c12a22f2021-05-12 11:28:45120
121
glidere61efad2015-02-18 17:39:43122class CheckSingletonInHeadersTest(unittest.TestCase):
glidere61efad2015-02-18 17:39:43123
Daniel Cheng566634ff2024-06-29 14:56:53124 def testSingletonInArbitraryHeader(self):
125 diff_singleton_h = [
126 'base::subtle::AtomicWord '
127 'base::Singleton<Type, Traits, DifferentiatingType>::'
128 ]
129 diff_foo_h = [
130 '// base::Singleton<Foo> in comment.',
131 'friend class base::Singleton<Foo>'
132 ]
133 diff_foo2_h = [' //Foo* bar = base::Singleton<Foo>::get();']
134 diff_bad_h = ['Foo* foo = base::Singleton<Foo>::get();']
135 mock_input_api = MockInputApi()
136 mock_input_api.files = [
137 MockAffectedFile('base/memory/singleton.h', diff_singleton_h),
138 MockAffectedFile('foo.h', diff_foo_h),
139 MockAffectedFile('foo2.h', diff_foo2_h),
140 MockAffectedFile('bad.h', diff_bad_h)
141 ]
142 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
143 MockOutputApi())
144 self.assertEqual(1, len(warnings))
145 self.assertEqual(1, len(warnings[0].items))
146 self.assertEqual('error', warnings[0].type)
147 self.assertTrue('Found base::Singleton<T>' in warnings[0].message)
148
149 def testSingletonInCC(self):
150 diff_cc = ['Foo* foo = base::Singleton<Foo>::get();']
151 mock_input_api = MockInputApi()
152 mock_input_api.files = [MockAffectedFile('some/path/foo.cc', diff_cc)]
153 warnings = PRESUBMIT.CheckSingletonInHeaders(mock_input_api,
154 MockOutputApi())
155 self.assertEqual(0, len(warnings))
glidere61efad2015-02-18 17:39:43156
157
Xiaohan Wang42d96c22022-01-20 17:23:11158class DeprecatedOSMacroNamesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:53159
160 def testDeprecatedOSMacroNames(self):
161 lines = [
162 '#if defined(OS_WIN)', ' #elif defined(OS_WINDOW)',
163 ' # if defined(OS_MAC) || defined(OS_CHROME)'
164 ]
165 errors = PRESUBMIT._CheckForDeprecatedOSMacrosInFile(
166 MockInputApi(), MockFile('some/path/foo_platform.cc', lines))
167 self.assertEqual(len(lines) + 1, len(errors))
168 self.assertTrue(
169 ':1: defined(OS_WIN) -> BUILDFLAG(IS_WIN)' in errors[0])
dbeam@chromium.orgb00342e7f2013-03-26 16:21:54170
171
lliabraa35bab3932014-10-01 12:16:44172class InvalidIfDefinedMacroNamesTest(unittest.TestCase):
lliabraa35bab3932014-10-01 12:16:44173
Daniel Cheng566634ff2024-06-29 14:56:53174 def testInvalidIfDefinedMacroNames(self):
175 lines = [
176 '#if defined(TARGET_IPHONE_SIMULATOR)',
177 '#if !defined(TARGET_IPHONE_SIMULATOR)',
178 '#elif defined(TARGET_IPHONE_SIMULATOR)',
179 '#ifdef TARGET_IPHONE_SIMULATOR',
180 ' # ifdef TARGET_IPHONE_SIMULATOR',
181 '# if defined(VALID) || defined(TARGET_IPHONE_SIMULATOR)',
182 '# else // defined(TARGET_IPHONE_SIMULATOR)',
183 '#endif // defined(TARGET_IPHONE_SIMULATOR)'
184 ]
185 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
186 MockInputApi(), MockFile('some/path/source.mm', lines))
187 self.assertEqual(len(lines), len(errors))
188
189 def testValidIfDefinedMacroNames(self):
190 lines = [
191 '#if defined(FOO)', '#ifdef BAR', '#if TARGET_IPHONE_SIMULATOR'
192 ]
193 errors = PRESUBMIT._CheckForInvalidIfDefinedMacrosInFile(
194 MockInputApi(), MockFile('some/path/source.cc', lines))
195 self.assertEqual(0, len(errors))
lliabraa35bab3932014-10-01 12:16:44196
197
Andrew Williamsc9f69b482023-07-10 16:07:36198class CheckNoUNIT_TESTInSourceFilesTest(unittest.TestCase):
Andrew Williamsc9f69b482023-07-10 16:07:36199
Daniel Cheng566634ff2024-06-29 14:56:53200 def testUnitTestMacros(self):
201 lines = [
202 '#if defined(UNIT_TEST)', '#if defined UNIT_TEST',
203 '#if !defined(UNIT_TEST)', '#elif defined(UNIT_TEST)',
204 '#ifdef UNIT_TEST', ' # ifdef UNIT_TEST', '#ifndef UNIT_TEST',
205 '# if defined(VALID) || defined(UNIT_TEST)',
206 '# if defined(UNIT_TEST) && defined(VALID)',
207 '# else // defined(UNIT_TEST)', '#endif // defined(UNIT_TEST)'
208 ]
209 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
210 MockInputApi(), MockFile('some/path/source.cc', lines))
211 self.assertEqual(len(lines), len(errors))
212
213 def testNotUnitTestMacros(self):
214 lines = [
215 '// Comment about "#if defined(UNIT_TEST)"',
216 '/* Comment about #if defined(UNIT_TEST)" */',
217 '#ifndef UNIT_TEST_H', '#define UNIT_TEST_H',
218 '#ifndef TEST_UNIT_TEST', '#define TEST_UNIT_TEST',
219 '#if defined(_UNIT_TEST)', '#if defined(UNIT_TEST_)',
220 '#ifdef _UNIT_TEST', '#ifdef UNIT_TEST_', '#ifndef _UNIT_TEST',
221 '#ifndef UNIT_TEST_'
222 ]
223 errors = PRESUBMIT._CheckNoUNIT_TESTInSourceFiles(
224 MockInputApi(), MockFile('some/path/source.cc', lines))
225 self.assertEqual(0, len(errors))
Andrew Williamsc9f69b482023-07-10 16:07:36226
Rasika Navarangec2d33d22024-05-23 15:19:02227
228class CheckEachPerfettoTestDataFileHasDepsEntry(unittest.TestCase):
229
Daniel Cheng566634ff2024-06-29 14:56:53230 def testNewSha256FileNoDEPS(self):
231 input_api = MockInputApi()
232 input_api.files = [
233 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', []),
234 ]
235 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
236 input_api, MockOutputApi())
237 self.assertEqual(
238 ('You must update the DEPS file when you update a .sha256 file '
239 'in base/tracing/test/data_sha256'), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02240
Daniel Cheng566634ff2024-06-29 14:56:53241 def testNewSha256FileSuccess(self):
242 input_api = MockInputApi()
243 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02244 'src/base/tracing/test/data': {
245 'bucket': 'perfetto',
246 'objects': [
247 {
248 'object_name': 'test_data/new.pftrace-a1b2c3f4',
249 'sha256sum': 'a1b2c3f4',
250 'size_bytes': 1,
251 'generation': 1,
252 'output_file': 'new.pftrace'
253 },
254 ],
255 'dep_type': 'gcs'
256 },
257 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53258 input_api.files = [
259 MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
260 ['a1b2c3f4']),
261 MockFile('DEPS', new_deps,
262 ["deps={'src/base/tracing/test/data':{}}"]),
263 ]
264 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
265 input_api, MockOutputApi())
266 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02267
Daniel Cheng566634ff2024-06-29 14:56:53268 def testNewSha256FileWrongSha256(self):
269 input_api = MockInputApi()
270 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02271 'src/base/tracing/test/data': {
272 'bucket': 'perfetto',
273 'objects': [
274 {
275 'object_name': 'test_data/new.pftrace-a1b2c3f4',
276 'sha256sum': 'wrong_hash',
277 'size_bytes': 1,
278 'generation': 1,
279 'output_file': 'new.pftrace'
280 },
281 ],
282 'dep_type': 'gcs'
283 },
284 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53285 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256',
286 ['a1b2c3f4'])
287 input_api.files = [
288 f,
289 MockFile('DEPS', new_deps,
290 ["deps={'src/base/tracing/test/data':{}}"]),
291 ]
292 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
293 input_api, MockOutputApi())
294 self.assertEqual(
295 ('No corresponding DEPS entry found for %s. '
296 'Run `base/tracing/test/test_data.py get_deps --filepath %s` '
297 'to generate the DEPS entry.' % (f.LocalPath(), f.LocalPath())),
298 results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02299
Daniel Cheng566634ff2024-06-29 14:56:53300 def testDeleteSha256File(self):
301 input_api = MockInputApi()
302 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02303 'src/base/tracing/test/data': {
304 'bucket': 'perfetto',
305 'objects': [
306 {
307 'object_name': 'test_data/new.pftrace-a1b2c3f4',
308 'sha256sum': 'a1b2c3f4',
309 'size_bytes': 1,
310 'generation': 1,
311 'output_file': 'new.pftrace'
312 },
313 ],
314 'dep_type': 'gcs'
315 },
316 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53317 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
318 ['a1b2c3f4'],
319 action='D')
320 input_api.files = [
321 f,
322 MockFile('DEPS', old_deps, old_deps),
323 ]
324 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
325 input_api, MockOutputApi())
326 self.assertEqual((
327 'You deleted %s so you must also remove the corresponding DEPS entry.'
328 % f.LocalPath()), results[0].message)
Rasika Navarangec2d33d22024-05-23 15:19:02329
Daniel Cheng566634ff2024-06-29 14:56:53330 def testDeleteSha256Success(self):
331 input_api = MockInputApi()
332 new_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02333 'src/base/tracing/test/data': {
334 'bucket': 'perfetto',
335 'objects': [],
336 'dep_type': 'gcs'
337 },
338 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53339 old_deps = """deps = {
Rasika Navarangec2d33d22024-05-23 15:19:02340 'src/base/tracing/test/data': {
341 'bucket': 'perfetto',
342 'objects': [
343 {
344 'object_name': 'test_data/new.pftrace-a1b2c3f4',
345 'sha256sum': 'a1b2c3f4',
346 'size_bytes': 1,
347 'generation': 1,
348 'output_file': 'new.pftrace'
349 },
350 ],
351 'dep_type': 'gcs'
352 },
353 }""".splitlines()
Daniel Cheng566634ff2024-06-29 14:56:53354 f = MockFile('base/tracing/test/data_sha256/new.pftrace.sha256', [],
355 ['a1b2c3f4'],
356 action='D')
357 input_api.files = [
358 f,
359 MockFile('DEPS', new_deps, old_deps),
360 ]
361 results = PRESUBMIT.CheckEachPerfettoTestDataFileHasDepsEntry(
362 input_api, MockOutputApi())
363 self.assertEqual(0, len(results))
Rasika Navarangec2d33d22024-05-23 15:19:02364
365
Samuel Huang0db2ea22019-12-09 16:42:47366class CheckAddedDepsHaveTestApprovalsTest(unittest.TestCase):
Daniel Cheng4dcdb6b2017-04-13 08:30:17367
Daniel Cheng566634ff2024-06-29 14:56:53368 def calculate(self, old_include_rules, old_specific_include_rules,
369 new_include_rules, new_specific_include_rules):
370 return PRESUBMIT._CalculateAddedDeps(
371 os.path, 'include_rules = %r\nspecific_include_rules = %r' %
372 (old_include_rules, old_specific_include_rules),
373 'include_rules = %r\nspecific_include_rules = %r' %
374 (new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17375
Daniel Cheng566634ff2024-06-29 14:56:53376 def testCalculateAddedDeps(self):
377 old_include_rules = [
378 '+base',
379 '-chrome',
380 '+content',
381 '-grit',
382 '-grit/",',
383 '+jni/fooblat.h',
384 '!sandbox',
385 ]
386 old_specific_include_rules = {
387 'compositor\.*': {
388 '+cc',
389 },
390 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17391
Daniel Cheng566634ff2024-06-29 14:56:53392 new_include_rules = [
393 '-ash',
394 '+base',
395 '+chrome',
396 '+components',
397 '+content',
398 '+grit',
399 '+grit/generated_resources.h",',
400 '+grit/",',
401 '+jni/fooblat.h',
402 '+policy',
403 '+' + os.path.join('third_party', 'WebKit'),
404 ]
405 new_specific_include_rules = {
406 'compositor\.*': {
407 '+cc',
408 },
409 'widget\.*': {
410 '+gpu',
411 },
412 }
Daniel Cheng4dcdb6b2017-04-13 08:30:17413
Daniel Cheng566634ff2024-06-29 14:56:53414 expected = set([
415 os.path.join('chrome', 'DEPS'),
416 os.path.join('gpu', 'DEPS'),
417 os.path.join('components', 'DEPS'),
418 os.path.join('policy', 'DEPS'),
419 os.path.join('third_party', 'WebKit', 'DEPS'),
420 ])
421 self.assertEqual(
422 expected,
423 self.calculate(old_include_rules, old_specific_include_rules,
424 new_include_rules, new_specific_include_rules))
Daniel Cheng4dcdb6b2017-04-13 08:30:17425
Daniel Cheng566634ff2024-06-29 14:56:53426 def testCalculateAddedDepsIgnoresPermutations(self):
427 old_include_rules = [
428 '+base',
429 '+chrome',
430 ]
431 new_include_rules = [
432 '+chrome',
433 '+base',
434 ]
435 self.assertEqual(
436 set(), self.calculate(old_include_rules, {}, new_include_rules,
437 {}))
tony@chromium.orgf32e2d1e2013-07-26 21:39:08438
Daniel Cheng566634ff2024-06-29 14:56:53439 class FakeOwnersClient(object):
440 APPROVED = "APPROVED"
441 PENDING = "PENDING"
442 returns = {}
Scott Leebf6a0942024-06-26 22:59:39443
Daniel Cheng566634ff2024-06-29 14:56:53444 def ListOwners(self, *args, **kwargs):
445 return self.returns.get(self.ListOwners.__name__, "")
Scott Leebf6a0942024-06-26 22:59:39446
Daniel Cheng566634ff2024-06-29 14:56:53447 def mockListOwners(self, owners):
448 self.returns[self.ListOwners.__name__] = owners
Scott Leebf6a0942024-06-26 22:59:39449
Daniel Cheng566634ff2024-06-29 14:56:53450 def GetFilesApprovalStatus(self, *args, **kwargs):
451 return self.returns.get(self.GetFilesApprovalStatus.__name__, {})
Scott Leebf6a0942024-06-26 22:59:39452
Daniel Cheng566634ff2024-06-29 14:56:53453 def mockGetFilesApprovalStatus(self, status):
454 self.returns[self.GetFilesApprovalStatus.__name__] = status
Scott Leebf6a0942024-06-26 22:59:39455
Daniel Cheng566634ff2024-06-29 14:56:53456 def SuggestOwners(self, *args, **kwargs):
457 return ["eng1", "eng2", "eng3"]
Scott Leebf6a0942024-06-26 22:59:39458
Daniel Cheng566634ff2024-06-29 14:56:53459 class fakeGerrit(object):
Scott Leebf6a0942024-06-26 22:59:39460
Daniel Cheng566634ff2024-06-29 14:56:53461 def IsOwnersOverrideApproved(self, issue):
462 return False
Scott Leebf6a0942024-06-26 22:59:39463
Daniel Cheng566634ff2024-06-29 14:56:53464 def setUp(self):
465 self.input_api = input_api = MockInputApi()
466 input_api.environ = {}
467 input_api.owners_client = self.FakeOwnersClient()
468 input_api.gerrit = self.fakeGerrit()
469 input_api.change.issue = 123
470 self.mockOwnersAndReviewers("owner", set(["reviewer"]))
471 self.mockListSubmodules([])
Scott Leebf6a0942024-06-26 22:59:39472
Daniel Cheng566634ff2024-06-29 14:56:53473 def mockOwnersAndReviewers(self, owner, reviewers):
Scott Leebf6a0942024-06-26 22:59:39474
Daniel Cheng566634ff2024-06-29 14:56:53475 def mock(*args, **kwargs):
476 return [owner, reviewers]
Scott Leebf6a0942024-06-26 22:59:39477
Daniel Cheng566634ff2024-06-29 14:56:53478 self.input_api.canned_checks.GetCodereviewOwnerAndReviewers = mock
Scott Leebf6a0942024-06-26 22:59:39479
Daniel Cheng566634ff2024-06-29 14:56:53480 def mockListSubmodules(self, paths):
Scott Leebf6a0942024-06-26 22:59:39481
Daniel Cheng566634ff2024-06-29 14:56:53482 def mock(*args, **kwargs):
483 return paths
Scott Leebf6a0942024-06-26 22:59:39484
Daniel Cheng566634ff2024-06-29 14:56:53485 self.input_api.ListSubmodules = mock
486
487 def testApprovedAdditionalDep(self):
488 old_deps = """include_rules = []""".splitlines()
489 new_deps = """include_rules = ["+v8/123"]""".splitlines()
490 self.input_api.files = [
491 MockAffectedFile("pdf/DEPS", new_deps, old_deps)
492 ]
493
494 # mark the additional dep as approved.
495 os_path = self.input_api.os_path
496 self.input_api.owners_client.mockGetFilesApprovalStatus(
497 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.APPROVED})
498 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
499 self.input_api, MockOutputApi())
500 # Then, the check should pass.
501 self.assertEqual([], results)
502
503 def testUnapprovedAdditionalDep(self):
504 old_deps = """include_rules = []""".splitlines()
505 new_deps = """include_rules = ["+v8/123"]""".splitlines()
506 self.input_api.files = [
507 MockAffectedFile('pdf/DEPS', new_deps, old_deps),
508 ]
509
510 # pending.
511 os_path = self.input_api.os_path
512 self.input_api.owners_client.mockGetFilesApprovalStatus(
513 {os_path.join('v8/123', 'DEPS'): self.FakeOwnersClient.PENDING})
514 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
515 self.input_api, MockOutputApi())
516 # the check should fail
517 self.assertIn('You need LGTM', results[0].message)
518 self.assertIn('+v8/123', results[0].message)
519
520 # unless the added dep is from a submodule.
521 self.mockListSubmodules(['v8'])
522 results = PRESUBMIT.CheckAddedDepsHaveTargetApprovals(
523 self.input_api, MockOutputApi())
524 self.assertEqual([], results)
Scott Leebf6a0942024-06-26 22:59:39525
tony@chromium.orgf32e2d1e2013-07-26 21:39:08526
yoz@chromium.org99171a92014-06-03 08:44:47527class JSONParsingTest(unittest.TestCase):
yoz@chromium.org99171a92014-06-03 08:44:47528
Daniel Cheng566634ff2024-06-29 14:56:53529 def testSuccess(self):
530 input_api = MockInputApi()
531 filename = 'valid_json.json'
532 contents = [
533 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
534 ' "key2": 3 // This is an inline comment.', '}'
535 ]
536 input_api.files = [MockFile(filename, contents)]
537 self.assertEqual(None,
538 PRESUBMIT._GetJSONParseError(input_api, filename))
yoz@chromium.org99171a92014-06-03 08:44:47539
Daniel Cheng566634ff2024-06-29 14:56:53540 def testFailure(self):
541 input_api = MockInputApi()
542 test_data = [
543 ('invalid_json_1.json', ['{ x }'], 'Expecting property name'),
544 ('invalid_json_2.json', ['// Hello world!', '{ "hello": "world }'],
545 'Unterminated string starting at:'),
546 ('invalid_json_3.json', ['{ "a": "b", "c": "d", }'],
547 'Expecting property name'),
548 ('invalid_json_4.json', ['{ "a": "b" "c": "d" }'],
549 "Expecting ',' delimiter:"),
550 ]
yoz@chromium.org99171a92014-06-03 08:44:47551
Daniel Cheng566634ff2024-06-29 14:56:53552 input_api.files = [
553 MockFile(filename, contents)
554 for (filename, contents, _) in test_data
555 ]
yoz@chromium.org99171a92014-06-03 08:44:47556
Daniel Cheng566634ff2024-06-29 14:56:53557 for (filename, _, expected_error) in test_data:
558 actual_error = PRESUBMIT._GetJSONParseError(input_api, filename)
559 self.assertTrue(
560 expected_error in str(actual_error),
561 "'%s' not found in '%s'" % (expected_error, actual_error))
yoz@chromium.org99171a92014-06-03 08:44:47562
Daniel Cheng566634ff2024-06-29 14:56:53563 def testNoEatComments(self):
564 input_api = MockInputApi()
565 file_with_comments = 'file_with_comments.json'
566 contents_with_comments = [
567 '// This is a comment.', '{', ' "key1": ["value1", "value2"],',
568 ' "key2": 3 // This is an inline comment.', '}'
569 ]
570 file_without_comments = 'file_without_comments.json'
571 contents_without_comments = [
572 '{', ' "key1": ["value1", "value2"],', ' "key2": 3', '}'
573 ]
574 input_api.files = [
575 MockFile(file_with_comments, contents_with_comments),
576 MockFile(file_without_comments, contents_without_comments)
577 ]
578
579 self.assertNotEqual(
580 None,
581 str(
582 PRESUBMIT._GetJSONParseError(input_api,
583 file_with_comments,
584 eat_comments=False)))
585 self.assertEqual(
586 None,
587 PRESUBMIT._GetJSONParseError(input_api,
588 file_without_comments,
589 eat_comments=False))
yoz@chromium.org99171a92014-06-03 08:44:47590
591
592class IDLParsingTest(unittest.TestCase):
yoz@chromium.org99171a92014-06-03 08:44:47593
Daniel Cheng566634ff2024-06-29 14:56:53594 def testSuccess(self):
595 input_api = MockInputApi()
596 filename = 'valid_idl_basics.idl'
597 contents = [
598 '// Tests a valid IDL file.', 'namespace idl_basics {',
599 ' enum EnumType {', ' name1,', ' name2', ' };', '',
600 ' dictionary MyType1 {', ' DOMString a;', ' };', '',
601 ' callback Callback1 = void();',
602 ' callback Callback2 = void(long x);',
603 ' callback Callback3 = void(MyType1 arg);',
604 ' callback Callback4 = void(EnumType type);', '',
605 ' interface Functions {', ' static void function1();',
606 ' static void function2(long x);',
607 ' static void function3(MyType1 arg);',
608 ' static void function4(Callback1 cb);',
609 ' static void function5(Callback2 cb);',
610 ' static void function6(Callback3 cb);',
611 ' static void function7(Callback4 cb);', ' };', '',
612 ' interface Events {', ' static void onFoo1();',
613 ' static void onFoo2(long x);',
614 ' static void onFoo2(MyType1 arg);',
615 ' static void onFoo3(EnumType type);', ' };', '};'
616 ]
617 input_api.files = [MockFile(filename, contents)]
618 self.assertEqual(None,
619 PRESUBMIT._GetIDLParseError(input_api, filename))
yoz@chromium.org99171a92014-06-03 08:44:47620
Daniel Cheng566634ff2024-06-29 14:56:53621 def testFailure(self):
622 input_api = MockInputApi()
623 test_data = [
624 ('invalid_idl_1.idl', [
625 '//', 'namespace test {', ' dictionary {', ' DOMString s;',
626 ' };', '};'
627 ], 'Unexpected "{" after keyword "dictionary".\n'),
628 # TODO(yoz): Disabled because it causes the IDL parser to hang.
629 # See crbug.com/363830.
630 # ('invalid_idl_2.idl',
631 # (['namespace test {',
632 # ' dictionary MissingSemicolon {',
633 # ' DOMString a',
634 # ' DOMString b;',
635 # ' };',
636 # '};'],
637 # 'Unexpected symbol DOMString after symbol a.'),
638 ('invalid_idl_3.idl', [
639 '//', 'namespace test {', ' enum MissingComma {', ' name1',
640 ' name2', ' };', '};'
641 ], 'Unexpected symbol name2 after symbol name1.'),
642 ('invalid_idl_4.idl', [
643 '//', 'namespace test {', ' enum TrailingComma {',
644 ' name1,', ' name2,', ' };', '};'
645 ], 'Trailing comma in block.'),
646 ('invalid_idl_5.idl',
647 ['//', 'namespace test {', ' callback Callback1 = void(;',
648 '};'], 'Unexpected ";" after "(".'),
649 ('invalid_idl_6.idl', [
650 '//', 'namespace test {',
651 ' callback Callback1 = void(long );', '};'
652 ], 'Unexpected ")" after symbol long.'),
653 ('invalid_idl_7.idl', [
654 '//', 'namespace test {', ' interace Events {',
655 ' static void onFoo1();', ' };', '};'
656 ], 'Unexpected symbol Events after symbol interace.'),
657 ('invalid_idl_8.idl', [
658 '//', 'namespace test {', ' interface NotEvent {',
659 ' static void onFoo1();', ' };', '};'
660 ], 'Did not process Interface Interface(NotEvent)'),
661 ('invalid_idl_9.idl', [
662 '//', 'namespace test {', ' interface {',
663 ' static void function1();', ' };', '};'
664 ], 'Interface missing name.'),
665 ]
yoz@chromium.org99171a92014-06-03 08:44:47666
Daniel Cheng566634ff2024-06-29 14:56:53667 input_api.files = [
668 MockFile(filename, contents)
669 for (filename, contents, _) in test_data
670 ]
671
672 for (filename, _, expected_error) in test_data:
673 actual_error = PRESUBMIT._GetIDLParseError(input_api, filename)
674 self.assertTrue(
675 expected_error in str(actual_error),
676 "'%s' not found in '%s'" % (expected_error, actual_error))
yoz@chromium.org99171a92014-06-03 08:44:47677
678
davileene0426252015-03-02 21:10:41679class UserMetricsActionTest(unittest.TestCase):
davileene0426252015-03-02 21:10:41680
Daniel Cheng566634ff2024-06-29 14:56:53681 def testUserMetricsActionInActions(self):
682 input_api = MockInputApi()
683 file_with_user_action = 'file_with_user_action.cc'
684 contents_with_user_action = ['base::UserMetricsAction("AboutChrome")']
davileene0426252015-03-02 21:10:41685
Daniel Cheng566634ff2024-06-29 14:56:53686 input_api.files = [
687 MockFile(file_with_user_action, contents_with_user_action)
688 ]
davileene0426252015-03-02 21:10:41689
Daniel Cheng566634ff2024-06-29 14:56:53690 self.assertEqual([],
691 PRESUBMIT.CheckUserActionUpdate(
692 input_api, MockOutputApi()))
davileene0426252015-03-02 21:10:41693
Daniel Cheng566634ff2024-06-29 14:56:53694 def testUserMetricsActionNotAddedToActions(self):
695 input_api = MockInputApi()
696 file_with_user_action = 'file_with_user_action.cc'
697 contents_with_user_action = [
698 'base::UserMetricsAction("NotInActionsXml")'
699 ]
davileene0426252015-03-02 21:10:41700
Daniel Cheng566634ff2024-06-29 14:56:53701 input_api.files = [
702 MockFile(file_with_user_action, contents_with_user_action)
703 ]
davileene0426252015-03-02 21:10:41704
Daniel Cheng566634ff2024-06-29 14:56:53705 output = PRESUBMIT.CheckUserActionUpdate(input_api, MockOutputApi())
706 self.assertEqual(
707 ('File %s line %d: %s is missing in '
708 'tools/metrics/actions/actions.xml. Please run '
709 'tools/metrics/actions/extract_actions.py to update.' %
710 (file_with_user_action, 1, 'NotInActionsXml')), output[0].message)
Alexei Svitkine64505a92021-03-11 22:00:54711
Daniel Cheng566634ff2024-06-29 14:56:53712 def testUserMetricsActionInTestFile(self):
713 input_api = MockInputApi()
714 file_with_user_action = 'file_with_user_action_unittest.cc'
715 contents_with_user_action = [
716 'base::UserMetricsAction("NotInActionsXml")'
717 ]
Alexei Svitkine64505a92021-03-11 22:00:54718
Daniel Cheng566634ff2024-06-29 14:56:53719 input_api.files = [
720 MockFile(file_with_user_action, contents_with_user_action)
721 ]
722
723 self.assertEqual([],
724 PRESUBMIT.CheckUserActionUpdate(
725 input_api, MockOutputApi()))
Alexei Svitkine64505a92021-03-11 22:00:54726
davileene0426252015-03-02 21:10:41727
agrievef32bcc72016-04-04 14:57:40728class PydepsNeedsUpdatingTest(unittest.TestCase):
729
Daniel Cheng566634ff2024-06-29 14:56:53730 class MockPopen:
Andrew Grieve4deedb12022-02-03 21:34:50731
Daniel Cheng566634ff2024-06-29 14:56:53732 def __init__(self, stdout):
733 self.stdout = io.StringIO(stdout)
Andrew Grieve4deedb12022-02-03 21:34:50734
Daniel Cheng566634ff2024-06-29 14:56:53735 def wait(self):
736 return 0
Andrew Grieve4deedb12022-02-03 21:34:50737
Daniel Cheng566634ff2024-06-29 14:56:53738 class MockSubprocess:
739 CalledProcessError = subprocess.CalledProcessError
740 PIPE = 0
Andrew Grieve4deedb12022-02-03 21:34:50741
Daniel Cheng566634ff2024-06-29 14:56:53742 def __init__(self):
743 self._popen_func = None
agrievef32bcc72016-04-04 14:57:40744
Daniel Cheng566634ff2024-06-29 14:56:53745 def SetPopenCallback(self, func):
746 self._popen_func = func
Mohamed Heikal7cd4d8312020-06-16 16:49:40747
Daniel Cheng566634ff2024-06-29 14:56:53748 def Popen(self, cmd, *args, **kwargs):
749 return PydepsNeedsUpdatingTest.MockPopen(self._popen_func(cmd))
agrievef32bcc72016-04-04 14:57:40750
Daniel Cheng566634ff2024-06-29 14:56:53751 def _MockParseGclientArgs(self, is_android=True):
752 return lambda: {'checkout_android': 'true' if is_android else 'false'}
agrievef32bcc72016-04-04 14:57:40753
Daniel Cheng566634ff2024-06-29 14:56:53754 def setUp(self):
755 mock_all_pydeps = ['A.pydeps', 'B.pydeps', 'D.pydeps']
756 self.old_ALL_PYDEPS_FILES = PRESUBMIT._ALL_PYDEPS_FILES
757 PRESUBMIT._ALL_PYDEPS_FILES = mock_all_pydeps
758 mock_android_pydeps = ['D.pydeps']
759 self.old_ANDROID_SPECIFIC_PYDEPS_FILES = (
760 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES)
761 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = mock_android_pydeps
762 self.old_ParseGclientArgs = PRESUBMIT._ParseGclientArgs
763 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs()
764 self.mock_input_api = MockInputApi()
765 self.mock_output_api = MockOutputApi()
766 self.mock_input_api.subprocess = PydepsNeedsUpdatingTest.MockSubprocess(
767 )
768 self.checker = PRESUBMIT.PydepsChecker(self.mock_input_api,
769 mock_all_pydeps)
770 self.checker._file_cache = {
771 'A.pydeps':
772 '# Generated by:\n# CMD --output A.pydeps A\nA.py\nC.py\n',
773 'B.pydeps':
774 '# Generated by:\n# CMD --output B.pydeps B\nB.py\nC.py\n',
775 'D.pydeps': '# Generated by:\n# CMD --output D.pydeps D\nD.py\n',
776 }
agrievef32bcc72016-04-04 14:57:40777
Daniel Cheng566634ff2024-06-29 14:56:53778 def tearDown(self):
779 PRESUBMIT._ALL_PYDEPS_FILES = self.old_ALL_PYDEPS_FILES
780 PRESUBMIT._ANDROID_SPECIFIC_PYDEPS_FILES = (
781 self.old_ANDROID_SPECIFIC_PYDEPS_FILES)
782 PRESUBMIT._ParseGclientArgs = self.old_ParseGclientArgs
pastarmovj89f7ee12016-09-20 14:58:13783
Daniel Cheng566634ff2024-06-29 14:56:53784 def _RunCheck(self):
785 return PRESUBMIT.CheckPydepsNeedsUpdating(
786 self.mock_input_api,
787 self.mock_output_api,
788 checker_for_tests=self.checker)
agrievef32bcc72016-04-04 14:57:40789
Daniel Cheng566634ff2024-06-29 14:56:53790 def testAddedPydep(self):
791 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
792 if not self.mock_input_api.platform.startswith('linux'):
793 return []
agrievef32bcc72016-04-04 14:57:40794
Daniel Cheng566634ff2024-06-29 14:56:53795 self.mock_input_api.files = [
796 MockAffectedFile('new.pydeps', [], action='A'),
797 ]
Zhiling Huang45cabf32018-03-10 00:50:03798
Daniel Cheng566634ff2024-06-29 14:56:53799 self.mock_input_api.CreateMockFileInPath([
800 x.LocalPath()
801 for x in self.mock_input_api.AffectedFiles(include_deletes=True)
802 ])
803 results = self._RunCheck()
804 self.assertEqual(1, len(results))
805 self.assertIn('PYDEPS_FILES', str(results[0]))
pastarmovj89f7ee12016-09-20 14:58:13806
Daniel Cheng566634ff2024-06-29 14:56:53807 def testPydepNotInSrc(self):
808 self.mock_input_api.files = [
809 MockAffectedFile('new.pydeps', [], action='A'),
810 ]
811 self.mock_input_api.CreateMockFileInPath([])
812 results = self._RunCheck()
813 self.assertEqual(0, len(results))
agrievef32bcc72016-04-04 14:57:40814
Daniel Cheng566634ff2024-06-29 14:56:53815 def testRemovedPydep(self):
816 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
817 if not self.mock_input_api.platform.startswith('linux'):
818 return []
pastarmovj89f7ee12016-09-20 14:58:13819
Daniel Cheng566634ff2024-06-29 14:56:53820 self.mock_input_api.files = [
821 MockAffectedFile(PRESUBMIT._ALL_PYDEPS_FILES[0], [], action='D'),
822 ]
823 self.mock_input_api.CreateMockFileInPath([
824 x.LocalPath()
825 for x in self.mock_input_api.AffectedFiles(include_deletes=True)
826 ])
827 results = self._RunCheck()
828 self.assertEqual(1, len(results))
829 self.assertIn('PYDEPS_FILES', str(results[0]))
agrievef32bcc72016-04-04 14:57:40830
Daniel Cheng566634ff2024-06-29 14:56:53831 def testRandomPyIgnored(self):
832 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
833 if not self.mock_input_api.platform.startswith('linux'):
834 return []
agrievef32bcc72016-04-04 14:57:40835
Daniel Cheng566634ff2024-06-29 14:56:53836 self.mock_input_api.files = [
837 MockAffectedFile('random.py', []),
838 ]
pastarmovj89f7ee12016-09-20 14:58:13839
Daniel Cheng566634ff2024-06-29 14:56:53840 results = self._RunCheck()
841 self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
agrievef32bcc72016-04-04 14:57:40842
Daniel Cheng566634ff2024-06-29 14:56:53843 def testRelevantPyNoChange(self):
844 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
845 if not self.mock_input_api.platform.startswith('linux'):
846 return []
agrievef32bcc72016-04-04 14:57:40847
Daniel Cheng566634ff2024-06-29 14:56:53848 self.mock_input_api.files = [
849 MockAffectedFile('A.py', []),
850 ]
agrievef32bcc72016-04-04 14:57:40851
Daniel Cheng566634ff2024-06-29 14:56:53852 def popen_callback(cmd):
853 self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
854 return self.checker._file_cache['A.pydeps']
agrievef32bcc72016-04-04 14:57:40855
Daniel Cheng566634ff2024-06-29 14:56:53856 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
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 testRelevantPyOneChange(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 'changed data'
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(1, len(results))
878 # Check that --output "" is not included.
879 self.assertNotIn('""', str(results[0]))
880 self.assertIn('File is stale', str(results[0]))
agrievef32bcc72016-04-04 14:57:40881
Daniel Cheng566634ff2024-06-29 14:56:53882 def testRelevantPyTwoChanges(self):
883 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
884 if not self.mock_input_api.platform.startswith('linux'):
885 return []
agrievef32bcc72016-04-04 14:57:40886
Daniel Cheng566634ff2024-06-29 14:56:53887 self.mock_input_api.files = [
888 MockAffectedFile('C.py', []),
889 ]
agrievef32bcc72016-04-04 14:57:40890
Daniel Cheng566634ff2024-06-29 14:56:53891 def popen_callback(cmd):
892 return 'changed data'
agrievef32bcc72016-04-04 14:57:40893
Daniel Cheng566634ff2024-06-29 14:56:53894 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
Mohamed Heikal7cd4d8312020-06-16 16:49:40895
Daniel Cheng566634ff2024-06-29 14:56:53896 results = self._RunCheck()
897 self.assertEqual(2, len(results))
898 self.assertIn('File is stale', str(results[0]))
899 self.assertIn('File is stale', str(results[1]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40900
Daniel Cheng566634ff2024-06-29 14:56:53901 def testRelevantAndroidPyInNonAndroidCheckout(self):
902 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
903 if not self.mock_input_api.platform.startswith('linux'):
904 return []
Mohamed Heikal7cd4d8312020-06-16 16:49:40905
Daniel Cheng566634ff2024-06-29 14:56:53906 self.mock_input_api.files = [
907 MockAffectedFile('D.py', []),
908 ]
Mohamed Heikal7cd4d8312020-06-16 16:49:40909
Daniel Cheng566634ff2024-06-29 14:56:53910 def popen_callback(cmd):
911 self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
912 return 'changed data'
Andrew Grieve5bb4cf702020-10-22 20:21:39913
Daniel Cheng566634ff2024-06-29 14:56:53914 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
915 PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(
916 is_android=False)
Andrew Grieve5bb4cf702020-10-22 20:21:39917
Daniel Cheng566634ff2024-06-29 14:56:53918 results = self._RunCheck()
919 self.assertEqual(1, len(results))
920 self.assertIn('Android', str(results[0]))
921 self.assertIn('D.pydeps', str(results[0]))
Andrew Grieve5bb4cf702020-10-22 20:21:39922
Daniel Cheng566634ff2024-06-29 14:56:53923 def testGnPathsAndMissingOutputFlag(self):
924 # PRESUBMIT.CheckPydepsNeedsUpdating is only implemented for Linux.
925 if not self.mock_input_api.platform.startswith('linux'):
926 return []
Andrew Grieve5bb4cf702020-10-22 20:21:39927
Daniel Cheng566634ff2024-06-29 14:56:53928 self.checker._file_cache = {
929 'A.pydeps':
930 '# Generated by:\n# CMD --gn-paths A\n//A.py\n//C.py\n',
931 'B.pydeps':
932 '# Generated by:\n# CMD --gn-paths B\n//B.py\n//C.py\n',
933 'D.pydeps': '# Generated by:\n# CMD --gn-paths D\n//D.py\n',
934 }
Andrew Grieve5bb4cf702020-10-22 20:21:39935
Daniel Cheng566634ff2024-06-29 14:56:53936 self.mock_input_api.files = [
937 MockAffectedFile('A.py', []),
938 ]
Andrew Grieve5bb4cf702020-10-22 20:21:39939
Daniel Cheng566634ff2024-06-29 14:56:53940 def popen_callback(cmd):
941 self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""',
942 cmd)
943 return 'changed data'
944
945 self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
946
947 results = self._RunCheck()
948 self.assertEqual(1, len(results))
949 self.assertIn('File is stale', str(results[0]))
Mohamed Heikal7cd4d8312020-06-16 16:49:40950
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:39951
Daniel Bratell8ba52722018-03-02 16:06:14952class IncludeGuardTest(unittest.TestCase):
Daniel Bratell8ba52722018-03-02 16:06:14953
Daniel Cheng566634ff2024-06-29 14:56:53954 def testIncludeGuardChecks(self):
955 mock_input_api = MockInputApi()
956 mock_output_api = MockOutputApi()
957 mock_input_api.files = [
958 MockAffectedFile('content/browser/thing/foo.h', [
959 '// Comment',
960 '#ifndef CONTENT_BROWSER_THING_FOO_H_',
961 '#define CONTENT_BROWSER_THING_FOO_H_',
962 'struct McBoatFace;',
963 '#endif // CONTENT_BROWSER_THING_FOO_H_',
964 ]),
965 MockAffectedFile('content/browser/thing/bar.h', [
966 '#ifndef CONTENT_BROWSER_THING_BAR_H_',
967 '#define CONTENT_BROWSER_THING_BAR_H_',
968 'namespace content {',
969 '#endif // CONTENT_BROWSER_THING_BAR_H_',
970 '} // namespace content',
971 ]),
972 MockAffectedFile('content/browser/test1.h', [
973 'namespace content {',
974 '} // namespace content',
975 ]),
976 MockAffectedFile('content\\browser\\win.h', [
977 '#ifndef CONTENT_BROWSER_WIN_H_',
978 '#define CONTENT_BROWSER_WIN_H_',
979 'struct McBoatFace;',
980 '#endif // CONTENT_BROWSER_WIN_H_',
981 ]),
982 MockAffectedFile('content/browser/test2.h', [
983 '// Comment',
984 '#ifndef CONTENT_BROWSER_TEST2_H_',
985 'struct McBoatFace;',
986 '#endif // CONTENT_BROWSER_TEST2_H_',
987 ]),
988 MockAffectedFile('content/browser/internal.h', [
989 '// Comment',
990 '#ifndef CONTENT_BROWSER_INTERNAL_H_',
991 '#define CONTENT_BROWSER_INTERNAL_H_',
992 '// Comment',
993 '#ifndef INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
994 '#define INTERNAL_CONTENT_BROWSER_INTERNAL_H_',
995 'namespace internal {',
996 '} // namespace internal',
997 '#endif // INTERNAL_CONTENT_BROWSER_THING_BAR_H_',
998 'namespace content {',
999 '} // namespace content',
1000 '#endif // CONTENT_BROWSER_THING_BAR_H_',
1001 ]),
1002 MockAffectedFile('content/browser/thing/foo.cc', [
1003 '// This is a non-header.',
1004 ]),
1005 MockAffectedFile('content/browser/disabled.h', [
1006 '// no-include-guard-because-multiply-included',
1007 'struct McBoatFace;',
1008 ]),
1009 # New files don't allow misspelled include guards.
1010 MockAffectedFile('content/browser/spleling.h', [
1011 '#ifndef CONTENT_BROWSER_SPLLEING_H_',
1012 '#define CONTENT_BROWSER_SPLLEING_H_',
1013 'struct McBoatFace;',
1014 '#endif // CONTENT_BROWSER_SPLLEING_H_',
1015 ]),
1016 # New files don't allow + in include guards.
1017 MockAffectedFile('content/browser/foo+bar.h', [
1018 '#ifndef CONTENT_BROWSER_FOO+BAR_H_',
1019 '#define CONTENT_BROWSER_FOO+BAR_H_',
1020 'struct McBoatFace;',
1021 '#endif // CONTENT_BROWSER_FOO+BAR_H_',
1022 ]),
1023 # Old files allow misspelled include guards (for now).
1024 MockAffectedFile('chrome/old.h', [
1025 '// New contents',
1026 '#ifndef CHROME_ODL_H_',
1027 '#define CHROME_ODL_H_',
1028 '#endif // CHROME_ODL_H_',
1029 ], [
1030 '// Old contents',
1031 '#ifndef CHROME_ODL_H_',
1032 '#define CHROME_ODL_H_',
1033 '#endif // CHROME_ODL_H_',
1034 ],
1035 action='M'),
1036 # Using a Blink style include guard outside Blink is wrong.
1037 MockAffectedFile('content/NotInBlink.h', [
1038 '#ifndef NotInBlink_h',
1039 '#define NotInBlink_h',
1040 'struct McBoatFace;',
1041 '#endif // NotInBlink_h',
1042 ]),
1043 # Using a Blink style include guard in Blink is no longer ok.
1044 MockAffectedFile('third_party/blink/InBlink.h', [
1045 '#ifndef InBlink_h',
1046 '#define InBlink_h',
1047 'struct McBoatFace;',
1048 '#endif // InBlink_h',
1049 ]),
1050 # Using a bad include guard in Blink is not ok.
1051 MockAffectedFile('third_party/blink/AlsoInBlink.h', [
1052 '#ifndef WrongInBlink_h',
1053 '#define WrongInBlink_h',
1054 'struct McBoatFace;',
1055 '#endif // WrongInBlink_h',
1056 ]),
1057 # Using a bad include guard in Blink is not supposed to be accepted even
1058 # if it's an old file. However the current presubmit has accepted this
1059 # for a while.
1060 MockAffectedFile('third_party/blink/StillInBlink.h', [
1061 '// New contents',
1062 '#ifndef AcceptedInBlink_h',
1063 '#define AcceptedInBlink_h',
1064 'struct McBoatFace;',
1065 '#endif // AcceptedInBlink_h',
1066 ], [
1067 '// Old contents',
1068 '#ifndef AcceptedInBlink_h',
1069 '#define AcceptedInBlink_h',
1070 'struct McBoatFace;',
1071 '#endif // AcceptedInBlink_h',
1072 ],
1073 action='M'),
1074 # Using a non-Chromium include guard in third_party
1075 # (outside blink) is accepted.
1076 MockAffectedFile('third_party/foo/some_file.h', [
1077 '#ifndef REQUIRED_RPCNDR_H_',
1078 '#define REQUIRED_RPCNDR_H_',
1079 'struct SomeFileFoo;',
1080 '#endif // REQUIRED_RPCNDR_H_',
1081 ]),
1082 # Not having proper include guard in *_message_generator.h
1083 # for old IPC messages is allowed.
1084 MockAffectedFile('content/common/content_message_generator.h', [
1085 '#undef CONTENT_COMMON_FOO_MESSAGES_H_',
1086 '#include "content/common/foo_messages.h"',
1087 '#ifndef CONTENT_COMMON_FOO_MESSAGES_H_',
1088 '#error "Failed to include content/common/foo_messages.h"',
1089 '#endif',
1090 ]),
1091 MockAffectedFile('chrome/renderer/thing/qux.h', [
1092 '// Comment',
1093 '#ifndef CHROME_RENDERER_THING_QUX_H_',
1094 '#define CHROME_RENDERER_THING_QUX_H_',
1095 'struct Boaty;',
1096 '#endif',
1097 ]),
1098 ]
1099 msgs = PRESUBMIT.CheckForIncludeGuards(mock_input_api, mock_output_api)
1100 expected_fail_count = 10
1101 self.assertEqual(
1102 expected_fail_count, len(msgs), 'Expected %d items, found %d: %s' %
1103 (expected_fail_count, len(msgs), msgs))
1104 self.assertEqual(msgs[0].items, ['content/browser/thing/bar.h'])
1105 self.assertEqual(
1106 msgs[0].message, 'Include guard CONTENT_BROWSER_THING_BAR_H_ '
1107 'not covering the whole file')
Daniel Bratell8ba52722018-03-02 16:06:141108
Daniel Cheng566634ff2024-06-29 14:56:531109 self.assertIn('content/browser/test1.h', msgs[1].message)
1110 self.assertIn('Recommended name: CONTENT_BROWSER_TEST1_H_',
1111 msgs[1].message)
Daniel Bratell8ba52722018-03-02 16:06:141112
Daniel Cheng566634ff2024-06-29 14:56:531113 self.assertEqual(msgs[2].items, ['content/browser/test2.h:3'])
1114 self.assertEqual(
1115 msgs[2].message, 'Missing "#define CONTENT_BROWSER_TEST2_H_" for '
1116 'include guard')
Lei Zhangd84f9512024-05-28 19:43:301117
Daniel Cheng566634ff2024-06-29 14:56:531118 self.assertIn('content/browser/internal.h', msgs[3].message)
1119 self.assertIn(
1120 'Recommended #endif comment: // CONTENT_BROWSER_INTERNAL_H_',
1121 msgs[3].message)
Daniel Bratell8ba52722018-03-02 16:06:141122
Daniel Cheng566634ff2024-06-29 14:56:531123 self.assertEqual(msgs[4].items, ['content/browser/spleling.h:1'])
1124 self.assertEqual(
1125 msgs[4].message, 'Header using the wrong include guard name '
1126 'CONTENT_BROWSER_SPLLEING_H_')
Olivier Robinbba137492018-07-30 11:31:341127
Daniel Cheng566634ff2024-06-29 14:56:531128 self.assertIn('content/browser/foo+bar.h', msgs[5].message)
1129 self.assertIn('Recommended name: CONTENT_BROWSER_FOO_BAR_H_',
1130 msgs[5].message)
Daniel Bratell8ba52722018-03-02 16:06:141131
Daniel Cheng566634ff2024-06-29 14:56:531132 self.assertEqual(msgs[6].items, ['content/NotInBlink.h:1'])
1133 self.assertEqual(
1134 msgs[6].message, 'Header using the wrong include guard name '
1135 'NotInBlink_h')
Daniel Bratell39b5b062018-05-16 18:09:571136
Daniel Cheng566634ff2024-06-29 14:56:531137 self.assertEqual(msgs[7].items, ['third_party/blink/InBlink.h:1'])
1138 self.assertEqual(
1139 msgs[7].message, 'Header using the wrong include guard name '
1140 'InBlink_h')
Daniel Bratell8ba52722018-03-02 16:06:141141
Daniel Cheng566634ff2024-06-29 14:56:531142 self.assertEqual(msgs[8].items, ['third_party/blink/AlsoInBlink.h:1'])
1143 self.assertEqual(
1144 msgs[8].message, 'Header using the wrong include guard name '
1145 'WrongInBlink_h')
1146
1147 self.assertIn('chrome/renderer/thing/qux.h', msgs[9].message)
1148 self.assertIn(
1149 'Recommended #endif comment: // CHROME_RENDERER_THING_QUX_H_',
1150 msgs[9].message)
Lei Zhangd84f9512024-05-28 19:43:301151
1152
Chris Hall59f8d0c72020-05-01 07:31:191153class AccessibilityRelnotesFieldTest(unittest.TestCase):
Chris Hall59f8d0c72020-05-01 07:31:191154
Daniel Cheng566634ff2024-06-29 14:56:531155 def testRelnotesPresent(self):
1156 mock_input_api = MockInputApi()
1157 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191158
Daniel Cheng566634ff2024-06-29 14:56:531159 mock_input_api.files = [
1160 MockAffectedFile('ui/accessibility/foo.bar', [''])
1161 ]
1162 mock_input_api.change.DescriptionText = lambda: 'Commit description'
1163 mock_input_api.change.footers['AX-Relnotes'] = [
1164 'Important user facing change'
1165 ]
Chris Hall59f8d0c72020-05-01 07:31:191166
Daniel Cheng566634ff2024-06-29 14:56:531167 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1168 mock_input_api, mock_output_api)
1169 self.assertEqual(
1170 0, len(msgs),
1171 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191172
Daniel Cheng566634ff2024-06-29 14:56:531173 def testRelnotesMissingFromAccessibilityChange(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('some/file', ['']),
1179 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1180 MockAffectedFile('some/other/file', [''])
1181 ]
1182 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191183
Daniel Cheng566634ff2024-06-29 14:56:531184 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1185 mock_input_api, mock_output_api)
1186 self.assertEqual(
1187 1, len(msgs),
1188 'Expected %d messages, found %d: %s' % (1, len(msgs), msgs))
1189 self.assertTrue(
1190 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1191 'Missing AX-Relnotes field message not found in errors')
Chris Hall59f8d0c72020-05-01 07:31:191192
Daniel Cheng566634ff2024-06-29 14:56:531193 # The relnotes footer is not required for changes which do not touch any
1194 # accessibility directories.
1195 def testIgnoresNonAccessibilityCode(self):
1196 mock_input_api = MockInputApi()
1197 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191198
Daniel Cheng566634ff2024-06-29 14:56:531199 mock_input_api.files = [
1200 MockAffectedFile('some/file', ['']),
1201 MockAffectedFile('some/other/file', [''])
1202 ]
1203 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Chris Hall59f8d0c72020-05-01 07:31:191204
Daniel Cheng566634ff2024-06-29 14:56:531205 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1206 mock_input_api, mock_output_api)
1207 self.assertEqual(
1208 0, len(msgs),
1209 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Chris Hall59f8d0c72020-05-01 07:31:191210
Daniel Cheng566634ff2024-06-29 14:56:531211 # Test that our presubmit correctly raises an error for a set of known paths.
1212 def testExpectedPaths(self):
1213 filesToTest = [
1214 "chrome/browser/accessibility/foo.py",
1215 "chrome/browser/ash/arc/accessibility/foo.cc",
1216 "chrome/browser/ui/views/accessibility/foo.h",
1217 "chrome/browser/extensions/api/automation/foo.h",
1218 "chrome/browser/extensions/api/automation_internal/foo.cc",
1219 "chrome/renderer/extensions/accessibility_foo.h",
1220 "chrome/tests/data/accessibility/foo.html",
1221 "content/browser/accessibility/foo.cc",
1222 "content/renderer/accessibility/foo.h",
1223 "content/tests/data/accessibility/foo.cc",
1224 "extensions/renderer/api/automation/foo.h",
1225 "ui/accessibility/foo/bar/baz.cc",
1226 "ui/views/accessibility/foo/bar/baz.h",
1227 ]
Chris Hall59f8d0c72020-05-01 07:31:191228
Daniel Cheng566634ff2024-06-29 14:56:531229 for testFile in filesToTest:
1230 mock_input_api = MockInputApi()
1231 mock_output_api = MockOutputApi()
Chris Hall59f8d0c72020-05-01 07:31:191232
Daniel Cheng566634ff2024-06-29 14:56:531233 mock_input_api.files = [MockAffectedFile(testFile, [''])]
1234 mock_input_api.change.DescriptionText = lambda: 'Commit description'
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391235
Daniel Cheng566634ff2024-06-29 14:56:531236 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1237 mock_input_api, mock_output_api)
1238 self.assertEqual(
1239 1, len(msgs),
1240 'Expected %d messages, found %d: %s, for file %s' %
1241 (1, len(msgs), msgs, testFile))
1242 self.assertTrue(
1243 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1244 ('Missing AX-Relnotes field message not found in errors '
1245 ' for file %s' % (testFile)))
Akihiro Ota08108e542020-05-20 15:30:531246
Daniel Cheng566634ff2024-06-29 14:56:531247 # Test that AX-Relnotes field can appear in the commit description (as long
1248 # as it appears at the beginning of a line).
1249 def testRelnotesInCommitDescription(self):
1250 mock_input_api = MockInputApi()
1251 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531252
Daniel Cheng566634ff2024-06-29 14:56:531253 mock_input_api.files = [
1254 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1255 ]
1256 mock_input_api.change.DescriptionText = lambda: (
1257 'Description:\n' +
1258 'AX-Relnotes: solves all accessibility issues forever')
Akihiro Ota08108e542020-05-20 15:30:531259
Daniel Cheng566634ff2024-06-29 14:56:531260 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1261 mock_input_api, mock_output_api)
1262 self.assertEqual(
1263 0, len(msgs),
1264 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Akihiro Ota08108e542020-05-20 15:30:531265
Daniel Cheng566634ff2024-06-29 14:56:531266 # Test that we don't match AX-Relnotes if it appears in the middle of a line.
1267 def testRelnotesMustAppearAtBeginningOfLine(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 'This change has no AX-Relnotes: we should print a warning')
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.assertTrue(
1281 "Missing 'AX-Relnotes:' field" in msgs[0].message,
1282 'Missing AX-Relnotes field message not found in errors')
Akihiro Ota08108e542020-05-20 15:30:531283
Daniel Cheng566634ff2024-06-29 14:56:531284 # Tests that the AX-Relnotes field can be lowercase and use a '=' in place
1285 # of a ':'.
1286 def testRelnotesLowercaseWithEqualSign(self):
1287 mock_input_api = MockInputApi()
1288 mock_output_api = MockOutputApi()
Akihiro Ota08108e542020-05-20 15:30:531289
Daniel Cheng566634ff2024-06-29 14:56:531290 mock_input_api.files = [
1291 MockAffectedFile('ui/accessibility/foo.bar', ['']),
1292 ]
1293 mock_input_api.change.DescriptionText = lambda: (
1294 'Description:\n' +
1295 'ax-relnotes= this is a valid format for accessibility relnotes')
1296
1297 msgs = PRESUBMIT.CheckAccessibilityRelnotesField(
1298 mock_input_api, mock_output_api)
1299 self.assertEqual(
1300 0, len(msgs),
1301 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1302
Akihiro Ota08108e542020-05-20 15:30:531303
Mark Schillacie5a0be22022-01-19 00:38:391304class AccessibilityEventsTestsAreIncludedForAndroidTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:531305 # Test that no warning is raised when the Android file is also modified.
1306 def testAndroidChangeIncluded(self):
1307 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391308
Daniel Cheng566634ff2024-06-29 14:56:531309 mock_input_api.files = [
1310 MockAffectedFile(
1311 'content/test/data/accessibility/event/foo-expected-mac.txt',
1312 [''],
1313 action='A'),
1314 MockAffectedFile(
1315 'accessibility/WebContentsAccessibilityEventsTest.java', [''],
1316 action='M')
1317 ]
Mark Schillacie5a0be22022-01-19 00:38:391318
Daniel Cheng566634ff2024-06-29 14:56:531319 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1320 mock_input_api, MockOutputApi())
1321 self.assertEqual(
1322 0, len(msgs),
1323 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391324
Daniel Cheng566634ff2024-06-29 14:56:531325 # Test that Android change is not required when no html file is added/removed.
1326 def testIgnoreNonHtmlFiles(self):
1327 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391328
Daniel Cheng566634ff2024-06-29 14:56:531329 mock_input_api.files = [
1330 MockAffectedFile('content/test/data/accessibility/event/foo.txt',
1331 [''],
1332 action='A'),
1333 MockAffectedFile('content/test/data/accessibility/event/foo.cc',
1334 [''],
1335 action='A'),
1336 MockAffectedFile('content/test/data/accessibility/event/foo.h',
1337 [''],
1338 action='A'),
1339 MockAffectedFile('content/test/data/accessibility/event/foo.py',
1340 [''],
1341 action='A')
1342 ]
Mark Schillacie5a0be22022-01-19 00:38:391343
Daniel Cheng566634ff2024-06-29 14:56:531344 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1345 mock_input_api, MockOutputApi())
1346 self.assertEqual(
1347 0, len(msgs),
1348 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391349
Daniel Cheng566634ff2024-06-29 14:56:531350 # Test that Android change is not required for unrelated html files.
1351 def testIgnoreNonRelatedHtmlFiles(self):
1352 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391353
Daniel Cheng566634ff2024-06-29 14:56:531354 mock_input_api.files = [
1355 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1356 [''],
1357 action='A'),
1358 MockAffectedFile('content/test/data/accessibility/html/foo.html',
1359 [''],
1360 action='A'),
1361 MockAffectedFile('chrome/tests/data/accessibility/foo.html', [''],
1362 action='A')
1363 ]
Mark Schillacie5a0be22022-01-19 00:38:391364
Daniel Cheng566634ff2024-06-29 14:56:531365 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1366 mock_input_api, MockOutputApi())
1367 self.assertEqual(
1368 0, len(msgs),
1369 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391370
Daniel Cheng566634ff2024-06-29 14:56:531371 # Test that only modifying an html file will not trigger the warning.
1372 def testIgnoreModifiedFiles(self):
1373 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391374
Daniel Cheng566634ff2024-06-29 14:56:531375 mock_input_api.files = [
1376 MockAffectedFile(
1377 'content/test/data/accessibility/event/foo-expected-win.txt',
1378 [''],
1379 action='M')
1380 ]
Mark Schillacie5a0be22022-01-19 00:38:391381
Daniel Cheng566634ff2024-06-29 14:56:531382 msgs = PRESUBMIT.CheckAccessibilityEventsTestsAreIncludedForAndroid(
1383 mock_input_api, MockOutputApi())
1384 self.assertEqual(
1385 0, len(msgs),
1386 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1387
Mark Schillacie5a0be22022-01-19 00:38:391388
Mark Schillacie5a0be22022-01-19 00:38:391389class AccessibilityTreeTestsAreIncludedForAndroidTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:531390 # Test that no warning is raised when the Android file is also modified.
1391 def testAndroidChangeIncluded(self):
1392 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391393
Daniel Cheng566634ff2024-06-29 14:56:531394 mock_input_api.files = [
1395 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1396 [''],
1397 action='A'),
1398 MockAffectedFile(
1399 'accessibility/WebContentsAccessibilityTreeTest.java', [''],
1400 action='M')
1401 ]
Mark Schillacie5a0be22022-01-19 00:38:391402
Daniel Cheng566634ff2024-06-29 14:56:531403 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1404 mock_input_api, MockOutputApi())
1405 self.assertEqual(
1406 0, len(msgs),
1407 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391408
Daniel Cheng566634ff2024-06-29 14:56:531409 # Test that no warning is raised when the Android file is also modified.
1410 def testAndroidChangeIncludedManyFiles(self):
1411 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391412
Daniel Cheng566634ff2024-06-29 14:56:531413 mock_input_api.files = [
1414 MockAffectedFile(
1415 'content/test/data/accessibility/accname/foo.html', [''],
1416 action='A'),
1417 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1418 [''],
1419 action='A'),
1420 MockAffectedFile('content/test/data/accessibility/css/foo.html',
1421 [''],
1422 action='A'),
1423 MockAffectedFile('content/test/data/accessibility/html/foo.html',
1424 [''],
1425 action='A'),
1426 MockAffectedFile(
1427 'accessibility/WebContentsAccessibilityTreeTest.java', [''],
1428 action='M')
1429 ]
Mark Schillacie5a0be22022-01-19 00:38:391430
Daniel Cheng566634ff2024-06-29 14:56:531431 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1432 mock_input_api, MockOutputApi())
1433 self.assertEqual(
1434 0, len(msgs),
1435 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391436
Daniel Cheng566634ff2024-06-29 14:56:531437 # Test that a warning is raised when the Android file is not modified.
1438 def testAndroidChangeMissing(self):
1439 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391440
Daniel Cheng566634ff2024-06-29 14:56:531441 mock_input_api.files = [
1442 MockAffectedFile(
1443 'content/test/data/accessibility/aria/foo-expected-win.txt',
1444 [''],
1445 action='A'),
1446 ]
Mark Schillacie5a0be22022-01-19 00:38:391447
Daniel Cheng566634ff2024-06-29 14:56:531448 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1449 mock_input_api, MockOutputApi())
1450 self.assertEqual(
1451 1, len(msgs),
1452 'Expected %d messages, found %d: %s' % (1, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391453
Daniel Cheng566634ff2024-06-29 14:56:531454 # Test that Android change is not required when no platform expectations files are changed.
1455 def testAndroidChangNotMissing(self):
1456 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391457
Daniel Cheng566634ff2024-06-29 14:56:531458 mock_input_api.files = [
1459 MockAffectedFile('content/test/data/accessibility/accname/foo.txt',
1460 [''],
1461 action='A'),
1462 MockAffectedFile(
1463 'content/test/data/accessibility/html/foo-expected-blink.txt',
1464 [''],
1465 action='A'),
1466 MockAffectedFile('content/test/data/accessibility/html/foo.html',
1467 [''],
1468 action='A'),
1469 MockAffectedFile('content/test/data/accessibility/aria/foo.cc',
1470 [''],
1471 action='A'),
1472 MockAffectedFile('content/test/data/accessibility/css/foo.h', [''],
1473 action='A'),
1474 MockAffectedFile('content/test/data/accessibility/tree/foo.py',
1475 [''],
1476 action='A')
1477 ]
Mark Schillacie5a0be22022-01-19 00:38:391478
Daniel Cheng566634ff2024-06-29 14:56:531479 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1480 mock_input_api, MockOutputApi())
1481 self.assertEqual(
1482 0, len(msgs),
1483 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391484
Daniel Cheng566634ff2024-06-29 14:56:531485 # Test that Android change is not required for unrelated html files.
1486 def testIgnoreNonRelatedHtmlFiles(self):
1487 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391488
Daniel Cheng566634ff2024-06-29 14:56:531489 mock_input_api.files = [
1490 MockAffectedFile('content/test/data/accessibility/event/foo.html',
1491 [''],
1492 action='A'),
1493 ]
Mark Schillacie5a0be22022-01-19 00:38:391494
Daniel Cheng566634ff2024-06-29 14:56:531495 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1496 mock_input_api, MockOutputApi())
1497 self.assertEqual(
1498 0, len(msgs),
1499 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
Mark Schillacie5a0be22022-01-19 00:38:391500
Daniel Cheng566634ff2024-06-29 14:56:531501 # Test that only modifying an html file will not trigger the warning.
1502 def testIgnoreModifiedFiles(self):
1503 mock_input_api = MockInputApi()
Mark Schillacie5a0be22022-01-19 00:38:391504
Daniel Cheng566634ff2024-06-29 14:56:531505 mock_input_api.files = [
1506 MockAffectedFile('content/test/data/accessibility/aria/foo.html',
1507 [''],
1508 action='M')
1509 ]
Mark Schillacie5a0be22022-01-19 00:38:391510
Daniel Cheng566634ff2024-06-29 14:56:531511 msgs = PRESUBMIT.CheckAccessibilityTreeTestsAreIncludedForAndroid(
1512 mock_input_api, MockOutputApi())
1513 self.assertEqual(
1514 0, len(msgs),
1515 'Expected %d messages, found %d: %s' % (0, len(msgs), msgs))
1516
Mark Schillacie5a0be22022-01-19 00:38:391517
yolandyan45001472016-12-21 21:12:421518class AndroidDeprecatedTestAnnotationTest(unittest.TestCase):
yolandyan45001472016-12-21 21:12:421519
Daniel Cheng566634ff2024-06-29 14:56:531520 def testCheckAndroidTestAnnotationUsage(self):
1521 mock_input_api = MockInputApi()
1522 mock_output_api = MockOutputApi()
1523
1524 mock_input_api.files = [
1525 MockAffectedFile('LalaLand.java', ['random stuff']),
1526 MockAffectedFile('CorrectUsage.java', [
1527 'import androidx.test.filters.LargeTest;',
1528 'import androidx.test.filters.MediumTest;',
1529 'import androidx.test.filters.SmallTest;',
1530 ]),
1531 MockAffectedFile('UsedDeprecatedLargeTestAnnotation.java', [
1532 'import android.test.suitebuilder.annotation.LargeTest;',
1533 ]),
1534 MockAffectedFile('UsedDeprecatedMediumTestAnnotation.java', [
1535 'import android.test.suitebuilder.annotation.MediumTest;',
1536 ]),
1537 MockAffectedFile('UsedDeprecatedSmallTestAnnotation.java', [
1538 'import android.test.suitebuilder.annotation.SmallTest;',
1539 ]),
1540 MockAffectedFile('UsedDeprecatedSmokeAnnotation.java', [
1541 'import android.test.suitebuilder.annotation.Smoke;',
1542 ])
1543 ]
1544 msgs = PRESUBMIT._CheckAndroidTestAnnotationUsage(
1545 mock_input_api, mock_output_api)
1546 self.assertEqual(
1547 1, len(msgs),
1548 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1549 self.assertEqual(
1550 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1551 (4, len(msgs[0].items), msgs[0].items))
1552 self.assertTrue(
1553 'UsedDeprecatedLargeTestAnnotation.java:1' in msgs[0].items,
1554 'UsedDeprecatedLargeTestAnnotation not found in errors')
1555 self.assertTrue(
1556 'UsedDeprecatedMediumTestAnnotation.java:1' in msgs[0].items,
1557 'UsedDeprecatedMediumTestAnnotation not found in errors')
1558 self.assertTrue(
1559 'UsedDeprecatedSmallTestAnnotation.java:1' in msgs[0].items,
1560 'UsedDeprecatedSmallTestAnnotation not found in errors')
1561 self.assertTrue(
1562 'UsedDeprecatedSmokeAnnotation.java:1' in msgs[0].items,
1563 'UsedDeprecatedSmokeAnnotation not found in errors')
1564
yolandyan45001472016-12-21 21:12:421565
Min Qinbc44383c2023-02-22 17:25:261566class AndroidBannedImportTest(unittest.TestCase):
Min Qinbc44383c2023-02-22 17:25:261567
Daniel Cheng566634ff2024-06-29 14:56:531568 def testCheckAndroidNoBannedImports(self):
1569 mock_input_api = MockInputApi()
1570 mock_output_api = MockOutputApi()
1571
1572 test_files = [
1573 MockAffectedFile('RandomStufff.java', ['random stuff']),
1574 MockAffectedFile('NoBannedImports.java', [
1575 'import androidx.test.filters.LargeTest;',
1576 'import androidx.test.filters.MediumTest;',
1577 'import androidx.test.filters.SmallTest;',
1578 ]),
1579 MockAffectedFile('BannedUri.java', [
1580 'import java.net.URI;',
1581 ]),
1582 MockAffectedFile('BannedTargetApi.java', [
1583 'import android.annotation.TargetApi;',
1584 ]),
1585 MockAffectedFile('BannedUiThreadTestRule.java', [
1586 'import androidx.test.rule.UiThreadTestRule;',
1587 ]),
1588 MockAffectedFile('BannedUiThreadTest.java', [
1589 'import androidx.test.annotation.UiThreadTest;',
1590 ]),
1591 MockAffectedFile('BannedActivityTestRule.java', [
1592 'import androidx.test.rule.ActivityTestRule;',
1593 ]),
1594 MockAffectedFile('BannedVectorDrawableCompat.java', [
1595 'import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;',
1596 ])
1597 ]
1598 msgs = []
1599 for file in test_files:
1600 mock_input_api.files = [file]
1601 msgs.append(
1602 PRESUBMIT._CheckAndroidNoBannedImports(mock_input_api,
1603 mock_output_api))
1604 self.assertEqual(0, len(msgs[0]))
1605 self.assertEqual(0, len(msgs[1]))
1606 self.assertTrue(msgs[2][0].message.startswith(
1607 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261608 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531609 BannedUri.java:1:""")))
1610 self.assertTrue(msgs[3][0].message.startswith(
1611 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261612 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531613 BannedTargetApi.java:1:""")))
1614 self.assertTrue(msgs[4][0].message.startswith(
1615 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261616 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531617 BannedUiThreadTestRule.java:1:""")))
1618 self.assertTrue(msgs[5][0].message.startswith(
1619 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261620 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531621 BannedUiThreadTest.java:1:""")))
1622 self.assertTrue(msgs[6][0].message.startswith(
1623 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261624 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531625 BannedActivityTestRule.java:1:""")))
1626 self.assertTrue(msgs[7][0].message.startswith(
1627 textwrap.dedent("""\
Min Qinbc44383c2023-02-22 17:25:261628 Banned imports were used.
Daniel Cheng566634ff2024-06-29 14:56:531629 BannedVectorDrawableCompat.java:1:""")))
1630
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391631
Mohamed Heikal5e5b7922020-10-29 18:57:591632class CheckNoDownstreamDepsTest(unittest.TestCase):
Mohamed Heikal5e5b7922020-10-29 18:57:591633
Daniel Cheng566634ff2024-06-29 14:56:531634 def testInvalidDepFromUpstream(self):
1635 mock_input_api = MockInputApi()
1636 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591637
Daniel Cheng566634ff2024-06-29 14:56:531638 mock_input_api.files = [
1639 MockAffectedFile('BUILD.gn',
1640 ['deps = [', ' "//clank/target:test",', ']']),
1641 MockAffectedFile('chrome/android/BUILD.gn',
1642 ['deps = [ "//clank/target:test" ]']),
1643 MockAffectedFile(
1644 'chrome/chrome_java_deps.gni',
1645 ['java_deps = [', ' "//clank/target:test",', ']']),
1646 ]
1647 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1648 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1649 mock_output_api)
1650 self.assertEqual(
1651 1, len(msgs),
1652 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1653 self.assertEqual(
1654 3, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1655 (3, len(msgs[0].items), msgs[0].items))
1656 self.assertTrue(any('BUILD.gn:2' in item for item in msgs[0].items),
1657 'BUILD.gn not found in errors')
1658 self.assertTrue(
1659 any('chrome/android/BUILD.gn:1' in item for item in msgs[0].items),
1660 'chrome/android/BUILD.gn:1 not found in errors')
1661 self.assertTrue(
1662 any('chrome/chrome_java_deps.gni:2' in item
1663 for item in msgs[0].items),
1664 'chrome/chrome_java_deps.gni:2 not found in errors')
Mohamed Heikal5e5b7922020-10-29 18:57:591665
Daniel Cheng566634ff2024-06-29 14:56:531666 def testAllowsComments(self):
1667 mock_input_api = MockInputApi()
1668 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591669
Daniel Cheng566634ff2024-06-29 14:56:531670 mock_input_api.files = [
1671 MockAffectedFile('BUILD.gn', [
1672 '# real implementation in //clank/target:test',
1673 ]),
1674 ]
1675 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1676 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1677 mock_output_api)
1678 self.assertEqual(
1679 0, len(msgs),
1680 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591681
Daniel Cheng566634ff2024-06-29 14:56:531682 def testOnlyChecksBuildFiles(self):
1683 mock_input_api = MockInputApi()
1684 mock_output_api = MockOutputApi()
Mohamed Heikal5e5b7922020-10-29 18:57:591685
Daniel Cheng566634ff2024-06-29 14:56:531686 mock_input_api.files = [
1687 MockAffectedFile('README.md',
1688 ['DEPS = [ "//clank/target:test" ]']),
1689 MockAffectedFile('chrome/android/java/file.java',
1690 ['//clank/ only function']),
1691 ]
1692 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src'
1693 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1694 mock_output_api)
1695 self.assertEqual(
1696 0, len(msgs),
1697 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591698
Daniel Cheng566634ff2024-06-29 14:56:531699 def testValidDepFromDownstream(self):
1700 mock_input_api = MockInputApi()
1701 mock_output_api = MockOutputApi()
1702
1703 mock_input_api.files = [
1704 MockAffectedFile('BUILD.gn',
1705 ['DEPS = [', ' "//clank/target:test",', ']']),
1706 MockAffectedFile('java/BUILD.gn',
1707 ['DEPS = [ "//clank/target:test" ]']),
1708 ]
1709 mock_input_api.change.RepositoryRoot = lambda: 'chromium/src/clank'
1710 msgs = PRESUBMIT.CheckNoUpstreamDepsOnClank(mock_input_api,
1711 mock_output_api)
1712 self.assertEqual(
1713 0, len(msgs),
1714 'Expected %d items, found %d: %s' % (0, len(msgs), msgs))
Mohamed Heikal5e5b7922020-10-29 18:57:591715
yolandyan45001472016-12-21 21:12:421716
Jinsong Fan91ebbbd2019-04-16 14:57:171717class AndroidDebuggableBuildTest(unittest.TestCase):
1718
Daniel Cheng566634ff2024-06-29 14:56:531719 def testCheckAndroidDebuggableBuild(self):
1720 mock_input_api = MockInputApi()
1721 mock_output_api = MockOutputApi()
Jinsong Fan91ebbbd2019-04-16 14:57:171722
Daniel Cheng566634ff2024-06-29 14:56:531723 mock_input_api.files = [
1724 MockAffectedFile('RandomStuff.java', ['random stuff']),
1725 MockAffectedFile('CorrectUsage.java', [
1726 'import org.chromium.base.BuildInfo;',
1727 'some random stuff',
1728 'boolean isOsDebuggable = BuildInfo.isDebugAndroid();',
1729 ]),
1730 MockAffectedFile('JustCheckUserdebugBuild.java', [
1731 'import android.os.Build;',
1732 'some random stuff',
1733 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")',
1734 ]),
1735 MockAffectedFile('JustCheckEngineeringBuild.java', [
1736 'import android.os.Build;',
1737 'some random stuff',
1738 'boolean isOsDebuggable = "eng".equals(Build.TYPE)',
1739 ]),
1740 MockAffectedFile('UsedBuildType.java', [
1741 'import android.os.Build;',
1742 'some random stuff',
1743 'boolean isOsDebuggable = Build.TYPE.equals("userdebug")'
1744 '|| "eng".equals(Build.TYPE)',
1745 ]),
1746 MockAffectedFile('UsedExplicitBuildType.java', [
1747 'some random stuff',
1748 'boolean isOsDebuggable = android.os.Build.TYPE.equals("userdebug")'
1749 '|| "eng".equals(android.os.Build.TYPE)',
1750 ]),
1751 ]
Jinsong Fan91ebbbd2019-04-16 14:57:171752
Daniel Cheng566634ff2024-06-29 14:56:531753 msgs = PRESUBMIT._CheckAndroidDebuggableBuild(mock_input_api,
1754 mock_output_api)
1755 self.assertEqual(
1756 1, len(msgs),
1757 'Expected %d items, found %d: %s' % (1, len(msgs), msgs))
1758 self.assertEqual(
1759 4, len(msgs[0].items), 'Expected %d items, found %d: %s' %
1760 (4, len(msgs[0].items), msgs[0].items))
1761 self.assertTrue('JustCheckUserdebugBuild.java:3' in msgs[0].items)
1762 self.assertTrue('JustCheckEngineeringBuild.java:3' in msgs[0].items)
1763 self.assertTrue('UsedBuildType.java:3' in msgs[0].items)
1764 self.assertTrue('UsedExplicitBuildType.java:2' in msgs[0].items)
Jinsong Fan91ebbbd2019-04-16 14:57:171765
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391766
dgn4401aa52015-04-29 16:26:171767class LogUsageTest(unittest.TestCase):
1768
Daniel Cheng566634ff2024-06-29 14:56:531769 def testCheckAndroidCrLogUsage(self):
1770 mock_input_api = MockInputApi()
1771 mock_output_api = MockOutputApi()
dgnaa68d5e2015-06-10 10:08:221772
Daniel Cheng566634ff2024-06-29 14:56:531773 mock_input_api.files = [
1774 MockAffectedFile('RandomStuff.java', ['random stuff']),
1775 MockAffectedFile('HasAndroidLog.java', [
1776 'import android.util.Log;',
1777 'some random stuff',
1778 'Log.d("TAG", "foo");',
1779 ]),
1780 MockAffectedFile('HasExplicitUtilLog.java', [
1781 'some random stuff',
1782 'android.util.Log.d("TAG", "foo");',
1783 ]),
1784 MockAffectedFile('IsInBasePackage.java', [
1785 'package org.chromium.base;',
1786 'private static final String TAG = "cr_Foo";',
1787 'Log.d(TAG, "foo");',
1788 ]),
1789 MockAffectedFile('IsInBasePackageButImportsLog.java', [
1790 'package org.chromium.base;',
1791 'import android.util.Log;',
1792 'private static final String TAG = "cr_Foo";',
1793 'Log.d(TAG, "foo");',
1794 ]),
1795 MockAffectedFile('HasBothLog.java', [
1796 'import org.chromium.base.Log;',
1797 'some random stuff',
1798 'private static final String TAG = "cr_Foo";',
1799 'Log.d(TAG, "foo");',
1800 'android.util.Log.d("TAG", "foo");',
1801 ]),
1802 MockAffectedFile('HasCorrectTag.java', [
1803 'import org.chromium.base.Log;',
1804 'some random stuff',
1805 'private static final String TAG = "cr_Foo";',
1806 'Log.d(TAG, "foo");',
1807 ]),
1808 MockAffectedFile('HasOldTag.java', [
1809 'import org.chromium.base.Log;',
1810 'some random stuff',
1811 'private static final String TAG = "cr.Foo";',
1812 'Log.d(TAG, "foo");',
1813 ]),
1814 MockAffectedFile('HasDottedTag.java', [
1815 'import org.chromium.base.Log;',
1816 'some random stuff',
1817 'private static final String TAG = "cr_foo.bar";',
1818 'Log.d(TAG, "foo");',
1819 ]),
1820 MockAffectedFile('HasDottedTagPublic.java', [
1821 'import org.chromium.base.Log;',
1822 'some random stuff',
1823 'public static final String TAG = "cr_foo.bar";',
1824 'Log.d(TAG, "foo");',
1825 ]),
1826 MockAffectedFile('HasNoTagDecl.java', [
1827 'import org.chromium.base.Log;',
1828 'some random stuff',
1829 'Log.d(TAG, "foo");',
1830 ]),
1831 MockAffectedFile('HasIncorrectTagDecl.java', [
1832 'import org.chromium.base.Log;',
1833 'private static final String TAHG = "cr_Foo";',
1834 'some random stuff',
1835 'Log.d(TAG, "foo");',
1836 ]),
1837 MockAffectedFile('HasInlineTag.java', [
1838 'import org.chromium.base.Log;',
1839 'some random stuff',
1840 'private static final String TAG = "cr_Foo";',
1841 'Log.d("TAG", "foo");',
1842 ]),
1843 MockAffectedFile('HasInlineTagWithSpace.java', [
1844 'import org.chromium.base.Log;',
1845 'some random stuff',
1846 'private static final String TAG = "cr_Foo";',
1847 'Log.d("log message", "foo");',
1848 ]),
1849 MockAffectedFile('HasUnprefixedTag.java', [
1850 'import org.chromium.base.Log;',
1851 'some random stuff',
1852 'private static final String TAG = "rubbish";',
1853 'Log.d(TAG, "foo");',
1854 ]),
1855 MockAffectedFile('HasTooLongTag.java', [
1856 'import org.chromium.base.Log;',
1857 'some random stuff',
1858 'private static final String TAG = "21_characters_long___";',
1859 'Log.d(TAG, "foo");',
1860 ]),
1861 MockAffectedFile('HasTooLongTagWithNoLogCallsInDiff.java', [
1862 'import org.chromium.base.Log;',
1863 'some random stuff',
1864 'private static final String TAG = "21_characters_long___";',
1865 ]),
1866 ]
dgnaa68d5e2015-06-10 10:08:221867
Daniel Cheng566634ff2024-06-29 14:56:531868 msgs = PRESUBMIT._CheckAndroidCrLogUsage(mock_input_api,
1869 mock_output_api)
dgnaa68d5e2015-06-10 10:08:221870
Daniel Cheng566634ff2024-06-29 14:56:531871 self.assertEqual(
1872 5, len(msgs),
1873 'Expected %d items, found %d: %s' % (5, len(msgs), msgs))
dgnaa68d5e2015-06-10 10:08:221874
Daniel Cheng566634ff2024-06-29 14:56:531875 # Declaration format
1876 nb = len(msgs[0].items)
1877 self.assertEqual(
1878 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[0].items))
1879 self.assertTrue('HasNoTagDecl.java' in msgs[0].items)
1880 self.assertTrue('HasIncorrectTagDecl.java' in msgs[0].items)
dgnaa68d5e2015-06-10 10:08:221881
Daniel Cheng566634ff2024-06-29 14:56:531882 # Tag length
1883 nb = len(msgs[1].items)
1884 self.assertEqual(
1885 2, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[1].items))
1886 self.assertTrue('HasTooLongTag.java' in msgs[1].items)
1887 self.assertTrue(
1888 'HasTooLongTagWithNoLogCallsInDiff.java' in msgs[1].items)
Geoff Huang77e3d6f2023-12-25 06:27:381889
Daniel Cheng566634ff2024-06-29 14:56:531890 # Tag must be a variable named TAG
1891 nb = len(msgs[2].items)
1892 self.assertEqual(
1893 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[2].items))
1894 self.assertTrue('HasBothLog.java:5' in msgs[2].items)
1895 self.assertTrue('HasInlineTag.java:4' in msgs[2].items)
1896 self.assertTrue('HasInlineTagWithSpace.java:4' in msgs[2].items)
dgnaa68d5e2015-06-10 10:08:221897
Daniel Cheng566634ff2024-06-29 14:56:531898 # Util Log usage
1899 nb = len(msgs[3].items)
1900 self.assertEqual(
1901 3, nb, 'Expected %d items, found %d: %s' % (3, nb, msgs[3].items))
1902 self.assertTrue('HasAndroidLog.java:3' in msgs[3].items)
1903 self.assertTrue('HasExplicitUtilLog.java:2' in msgs[3].items)
1904 self.assertTrue('IsInBasePackageButImportsLog.java:4' in msgs[3].items)
Andrew Grieved3a35d82024-01-02 21:24:381905
Daniel Cheng566634ff2024-06-29 14:56:531906 # Tag must not contain
1907 nb = len(msgs[4].items)
1908 self.assertEqual(
1909 3, nb, 'Expected %d items, found %d: %s' % (2, nb, msgs[4].items))
1910 self.assertTrue('HasDottedTag.java' in msgs[4].items)
1911 self.assertTrue('HasDottedTagPublic.java' in msgs[4].items)
1912 self.assertTrue('HasOldTag.java' in msgs[4].items)
dgn38736db2015-09-18 19:20:511913
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391914
estadee17314a02017-01-12 16:22:161915class GoogleAnswerUrlFormatTest(unittest.TestCase):
1916
Daniel Cheng566634ff2024-06-29 14:56:531917 def testCatchAnswerUrlId(self):
1918 input_api = MockInputApi()
1919 input_api.files = [
1920 MockFile('somewhere/file.cc', [
1921 'char* host = '
1922 ' "https://support.google.com/chrome/answer/123456";'
1923 ]),
1924 MockFile('somewhere_else/file.cc', [
1925 'char* host = '
1926 ' "https://support.google.com/chrome/a/answer/123456";'
1927 ]),
1928 ]
estadee17314a02017-01-12 16:22:161929
Daniel Cheng566634ff2024-06-29 14:56:531930 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1931 input_api, MockOutputApi())
1932 self.assertEqual(1, len(warnings))
1933 self.assertEqual(2, len(warnings[0].items))
estadee17314a02017-01-12 16:22:161934
Daniel Cheng566634ff2024-06-29 14:56:531935 def testAllowAnswerUrlParam(self):
1936 input_api = MockInputApi()
1937 input_api.files = [
1938 MockFile('somewhere/file.cc', [
1939 'char* host = '
1940 ' "https://support.google.com/chrome/?p=cpn_crash_reports";'
1941 ]),
1942 ]
estadee17314a02017-01-12 16:22:161943
Daniel Cheng566634ff2024-06-29 14:56:531944 warnings = PRESUBMIT.CheckGoogleSupportAnswerUrlOnUpload(
1945 input_api, MockOutputApi())
1946 self.assertEqual(0, len(warnings))
estadee17314a02017-01-12 16:22:161947
Wei-Yin Chen (陳威尹)54086c212018-07-27 21:41:391948
reillyi38965732015-11-16 18:27:331949class HardcodedGoogleHostsTest(unittest.TestCase):
1950
Daniel Cheng566634ff2024-06-29 14:56:531951 def testWarnOnAssignedLiterals(self):
1952 input_api = MockInputApi()
1953 input_api.files = [
1954 MockFile('content/file.cc',
1955 ['char* host = "https://www.google.com";']),
1956 MockFile('content/file.cc',
1957 ['char* host = "https://www.googleapis.com";']),
1958 MockFile('content/file.cc',
1959 ['char* host = "https://clients1.google.com";']),
1960 ]
reillyi38965732015-11-16 18:27:331961
Daniel Cheng566634ff2024-06-29 14:56:531962 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1963 input_api, MockOutputApi())
1964 self.assertEqual(1, len(warnings))
1965 self.assertEqual(3, len(warnings[0].items))
reillyi38965732015-11-16 18:27:331966
Daniel Cheng566634ff2024-06-29 14:56:531967 def testAllowInComment(self):
1968 input_api = MockInputApi()
1969 input_api.files = [
1970 MockFile('content/file.cc',
1971 ['char* host = "https://www.aol.com"; // google.com'])
1972 ]
reillyi38965732015-11-16 18:27:331973
Daniel Cheng566634ff2024-06-29 14:56:531974 warnings = PRESUBMIT.CheckHardcodedGoogleHostsInLowerLayers(
1975 input_api, MockOutputApi())
1976 self.assertEqual(0, len(warnings))
reillyi38965732015-11-16 18:27:331977
dgn4401aa52015-04-29 16:26:171978
James Cook6b6597c2019-11-06 22:05:291979class ChromeOsSyncedPrefRegistrationTest(unittest.TestCase):
1980
Daniel Cheng566634ff2024-06-29 14:56:531981 def testWarnsOnChromeOsDirectories(self):
1982 files = [
1983 MockFile('ash/file.cc', ['PrefRegistrySyncable::SYNCABLE_PREF']),
1984 MockFile('chrome/browser/chromeos/file.cc',
1985 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1986 MockFile('chromeos/file.cc',
1987 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1988 MockFile('components/arc/file.cc',
1989 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1990 MockFile('components/exo/file.cc',
1991 ['PrefRegistrySyncable::SYNCABLE_PREF']),
1992 ]
1993 input_api = MockInputApi()
1994 for file in files:
1995 input_api.files = [file]
1996 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
1997 input_api, MockOutputApi())
1998 self.assertEqual(1, len(warnings))
James Cook6b6597c2019-11-06 22:05:291999
Daniel Cheng566634ff2024-06-29 14:56:532000 def testDoesNotWarnOnSyncOsPref(self):
2001 input_api = MockInputApi()
2002 input_api.files = [
2003 MockFile('chromeos/file.cc',
2004 ['PrefRegistrySyncable::SYNCABLE_OS_PREF']),
2005 ]
2006 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
2007 input_api, MockOutputApi())
2008 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:292009
Daniel Cheng566634ff2024-06-29 14:56:532010 def testDoesNotWarnOnOtherDirectories(self):
2011 input_api = MockInputApi()
2012 input_api.files = [
2013 MockFile('chrome/browser/ui/file.cc',
2014 ['PrefRegistrySyncable::SYNCABLE_PREF']),
2015 MockFile('components/sync/file.cc',
2016 ['PrefRegistrySyncable::SYNCABLE_PREF']),
2017 MockFile('content/browser/file.cc',
2018 ['PrefRegistrySyncable::SYNCABLE_PREF']),
2019 MockFile('a/notchromeos/file.cc',
2020 ['PrefRegistrySyncable::SYNCABLE_PREF']),
2021 ]
2022 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
2023 input_api, MockOutputApi())
2024 self.assertEqual(0, len(warnings))
James Cook6b6597c2019-11-06 22:05:292025
Daniel Cheng566634ff2024-06-29 14:56:532026 def testSeparateWarningForPriorityPrefs(self):
2027 input_api = MockInputApi()
2028 input_api.files = [
2029 MockFile('chromeos/file.cc', [
2030 'PrefRegistrySyncable::SYNCABLE_PREF',
2031 'PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF'
2032 ]),
2033 ]
2034 warnings = PRESUBMIT.CheckChromeOsSyncedPrefRegistration(
2035 input_api, MockOutputApi())
2036 self.assertEqual(2, len(warnings))
James Cook6b6597c2019-11-06 22:05:292037
2038
jbriance9e12f162016-11-25 07:57:502039class ForwardDeclarationTest(unittest.TestCase):
jbriance9e12f162016-11-25 07:57:502040
Daniel Cheng566634ff2024-06-29 14:56:532041 def testCheckHeadersOnlyOutsideThirdParty(self):
2042 mock_input_api = MockInputApi()
2043 mock_input_api.files = [
2044 MockAffectedFile('somewhere/file.cc', ['class DummyClass;']),
2045 MockAffectedFile('third_party/header.h', ['class DummyClass;'])
2046 ]
2047 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
2048 mock_input_api, MockOutputApi())
2049 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:502050
Daniel Cheng566634ff2024-06-29 14:56:532051 def testNoNestedDeclaration(self):
2052 mock_input_api = MockInputApi()
2053 mock_input_api.files = [
2054 MockAffectedFile('somewhere/header.h', [
2055 'class SomeClass {', ' protected:', ' class NotAMatch;', '};'
2056 ])
2057 ]
2058 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
2059 mock_input_api, MockOutputApi())
2060 self.assertEqual(0, len(warnings))
jbriance9e12f162016-11-25 07:57:502061
Daniel Cheng566634ff2024-06-29 14:56:532062 def testSubStrings(self):
2063 mock_input_api = MockInputApi()
2064 mock_input_api.files = [
2065 MockAffectedFile('somewhere/header.h', [
2066 'class NotUsefulClass;', 'struct SomeStruct;',
2067 'UsefulClass *p1;', 'SomeStructPtr *p2;'
2068 ])
2069 ]
2070 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
2071 mock_input_api, MockOutputApi())
2072 self.assertEqual(2, len(warnings))
jbriance9e12f162016-11-25 07:57:502073
Daniel Cheng566634ff2024-06-29 14:56:532074 def testUselessForwardDeclaration(self):
2075 mock_input_api = MockInputApi()
2076 mock_input_api.files = [
2077 MockAffectedFile('somewhere/header.h', [
2078 'class DummyClass;', 'struct DummyStruct;',
2079 'class UsefulClass;', 'std::unique_ptr<UsefulClass> p;'
2080 ])
2081 ]
2082 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
2083 mock_input_api, MockOutputApi())
2084 self.assertEqual(2, len(warnings))
2085
2086 def testBlinkHeaders(self):
2087 mock_input_api = MockInputApi()
2088 mock_input_api.files = [
2089 MockAffectedFile('third_party/blink/header.h', [
2090 'class DummyClass;',
2091 'struct DummyStruct;',
2092 ]),
2093 MockAffectedFile('third_party\\blink\\header.h', [
2094 'class DummyClass;',
2095 'struct DummyStruct;',
2096 ])
2097 ]
2098 warnings = PRESUBMIT.CheckUselessForwardDeclarations(
2099 mock_input_api, MockOutputApi())
2100 self.assertEqual(4, len(warnings))
jbriance2c51e821a2016-12-12 08:24:312101
jbriance9e12f162016-11-25 07:57:502102
rlanday6802cf632017-05-30 17:48:362103class RelativeIncludesTest(unittest.TestCase):
rlanday6802cf632017-05-30 17:48:362104
Daniel Cheng566634ff2024-06-29 14:56:532105 def testThirdPartyNotWebKitIgnored(self):
2106 mock_input_api = MockInputApi()
2107 mock_input_api.files = [
2108 MockAffectedFile('third_party/test.cpp', '#include "../header.h"'),
2109 MockAffectedFile('third_party/test/test.cpp',
2110 '#include "../header.h"'),
2111 ]
rlanday6802cf632017-05-30 17:48:362112
Daniel Cheng566634ff2024-06-29 14:56:532113 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362114
Daniel Cheng566634ff2024-06-29 14:56:532115 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2116 mock_output_api)
2117 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362118
Daniel Cheng566634ff2024-06-29 14:56:532119 def testNonCppFileIgnored(self):
2120 mock_input_api = MockInputApi()
2121 mock_input_api.files = [
2122 MockAffectedFile('test.py', '#include "../header.h"'),
2123 ]
rlanday6802cf632017-05-30 17:48:362124
Daniel Cheng566634ff2024-06-29 14:56:532125 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362126
Daniel Cheng566634ff2024-06-29 14:56:532127 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2128 mock_output_api)
2129 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362130
Daniel Cheng566634ff2024-06-29 14:56:532131 def testInnocuousChangesAllowed(self):
2132 mock_input_api = MockInputApi()
2133 mock_input_api.files = [
2134 MockAffectedFile('test.cpp', '#include "header.h"'),
2135 MockAffectedFile('test2.cpp', '../'),
2136 ]
rlanday6802cf632017-05-30 17:48:362137
Daniel Cheng566634ff2024-06-29 14:56:532138 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362139
Daniel Cheng566634ff2024-06-29 14:56:532140 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2141 mock_output_api)
2142 self.assertEqual(0, len(errors))
rlanday6802cf632017-05-30 17:48:362143
Daniel Cheng566634ff2024-06-29 14:56:532144 def testRelativeIncludeNonWebKitProducesError(self):
2145 mock_input_api = MockInputApi()
2146 mock_input_api.files = [
2147 MockAffectedFile('test.cpp', ['#include "../header.h"']),
2148 ]
rlanday6802cf632017-05-30 17:48:362149
Daniel Cheng566634ff2024-06-29 14:56:532150 mock_output_api = MockOutputApi()
rlanday6802cf632017-05-30 17:48:362151
Daniel Cheng566634ff2024-06-29 14:56:532152 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2153 mock_output_api)
2154 self.assertEqual(1, len(errors))
rlanday6802cf632017-05-30 17:48:362155
Daniel Cheng566634ff2024-06-29 14:56:532156 def testRelativeIncludeWebKitProducesError(self):
2157 mock_input_api = MockInputApi()
2158 mock_input_api.files = [
2159 MockAffectedFile('third_party/blink/test.cpp',
2160 ['#include "../header.h']),
2161 ]
rlanday6802cf632017-05-30 17:48:362162
Daniel Cheng566634ff2024-06-29 14:56:532163 mock_output_api = MockOutputApi()
2164
2165 errors = PRESUBMIT.CheckForRelativeIncludes(mock_input_api,
2166 mock_output_api)
2167 self.assertEqual(1, len(errors))
dbeam1ec68ac2016-12-15 05:22:242168
Daniel Cheng13ca61a882017-08-25 15:11:252169
Daniel Bratell65b033262019-04-23 08:17:062170class CCIncludeTest(unittest.TestCase):
Daniel Bratell65b033262019-04-23 08:17:062171
Daniel Cheng566634ff2024-06-29 14:56:532172 def testThirdPartyNotBlinkIgnored(self):
2173 mock_input_api = MockInputApi()
2174 mock_input_api.files = [
2175 MockAffectedFile('third_party/test.cpp', '#include "file.cc"'),
2176 ]
Daniel Bratell65b033262019-04-23 08:17:062177
Daniel Cheng566634ff2024-06-29 14:56:532178 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062179
Daniel Cheng566634ff2024-06-29 14:56:532180 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2181 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062182
Daniel Cheng566634ff2024-06-29 14:56:532183 def testPythonFileIgnored(self):
2184 mock_input_api = MockInputApi()
2185 mock_input_api.files = [
2186 MockAffectedFile('test.py', '#include "file.cc"'),
2187 ]
Daniel Bratell65b033262019-04-23 08:17:062188
Daniel Cheng566634ff2024-06-29 14:56:532189 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062190
Daniel Cheng566634ff2024-06-29 14:56:532191 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2192 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062193
Daniel Cheng566634ff2024-06-29 14:56:532194 def testIncFilesAccepted(self):
2195 mock_input_api = MockInputApi()
2196 mock_input_api.files = [
2197 MockAffectedFile('test.py', '#include "file.inc"'),
2198 ]
Daniel Bratell65b033262019-04-23 08:17:062199
Daniel Cheng566634ff2024-06-29 14:56:532200 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062201
Daniel Cheng566634ff2024-06-29 14:56:532202 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2203 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062204
Daniel Cheng566634ff2024-06-29 14:56:532205 def testInnocuousChangesAllowed(self):
2206 mock_input_api = MockInputApi()
2207 mock_input_api.files = [
2208 MockAffectedFile('test.cpp', '#include "header.h"'),
2209 MockAffectedFile('test2.cpp', 'Something "file.cc"'),
2210 ]
Daniel Bratell65b033262019-04-23 08:17:062211
Daniel Cheng566634ff2024-06-29 14:56:532212 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062213
Daniel Cheng566634ff2024-06-29 14:56:532214 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2215 self.assertEqual(0, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062216
Daniel Cheng566634ff2024-06-29 14:56:532217 def testCcIncludeNonBlinkProducesError(self):
2218 mock_input_api = MockInputApi()
2219 mock_input_api.files = [
2220 MockAffectedFile('test.cpp', ['#include "file.cc"']),
2221 ]
Daniel Bratell65b033262019-04-23 08:17:062222
Daniel Cheng566634ff2024-06-29 14:56:532223 mock_output_api = MockOutputApi()
Daniel Bratell65b033262019-04-23 08:17:062224
Daniel Cheng566634ff2024-06-29 14:56:532225 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2226 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062227
Daniel Cheng566634ff2024-06-29 14:56:532228 def testCppIncludeBlinkProducesError(self):
2229 mock_input_api = MockInputApi()
2230 mock_input_api.files = [
2231 MockAffectedFile('third_party/blink/test.cpp',
2232 ['#include "foo/file.cpp"']),
2233 ]
Daniel Bratell65b033262019-04-23 08:17:062234
Daniel Cheng566634ff2024-06-29 14:56:532235 mock_output_api = MockOutputApi()
2236
2237 errors = PRESUBMIT.CheckForCcIncludes(mock_input_api, mock_output_api)
2238 self.assertEqual(1, len(errors))
Daniel Bratell65b033262019-04-23 08:17:062239
2240
Andrew Grieve1b290e4a22020-11-24 20:07:012241class GnGlobForwardTest(unittest.TestCase):
Andrew Grieve1b290e4a22020-11-24 20:07:012242
Daniel Cheng566634ff2024-06-29 14:56:532243 def testAddBareGlobs(self):
2244 mock_input_api = MockInputApi()
2245 mock_input_api.files = [
2246 MockAffectedFile('base/stuff.gni',
2247 ['forward_variables_from(invoker, "*")']),
2248 MockAffectedFile('base/BUILD.gn',
2249 ['forward_variables_from(invoker, "*")']),
2250 ]
2251 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2252 MockOutputApi())
2253 self.assertEqual(1, len(warnings))
2254 msg = '\n'.join(warnings[0].items)
2255 self.assertIn('base/stuff.gni', msg)
2256 # Should not check .gn files. Local templates don't need to care about
2257 # visibility / testonly.
2258 self.assertNotIn('base/BUILD.gn', msg)
2259
2260 def testValidUses(self):
2261 mock_input_api = MockInputApi()
2262 mock_input_api.files = [
2263 MockAffectedFile('base/stuff.gni',
2264 ['forward_variables_from(invoker, "*", [])']),
2265 MockAffectedFile('base/stuff2.gni', [
2266 'forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)'
2267 ]),
2268 MockAffectedFile(
2269 'base/stuff3.gni',
2270 ['forward_variables_from(invoker, [ "testonly" ])']),
2271 ]
2272 warnings = PRESUBMIT.CheckGnGlobForward(mock_input_api,
2273 MockOutputApi())
2274 self.assertEqual([], warnings)
Andrew Grieve1b290e4a22020-11-24 20:07:012275
2276
Sean Kaucb7c9b32022-10-25 21:25:522277class GnRebasePathTest(unittest.TestCase):
Sean Kaucb7c9b32022-10-25 21:25:522278
Daniel Cheng566634ff2024-06-29 14:56:532279 def testAddAbsolutePath(self):
2280 mock_input_api = MockInputApi()
2281 mock_input_api.files = [
2282 MockAffectedFile('base/BUILD.gn',
2283 ['rebase_path("$target_gen_dir", "//")']),
2284 MockAffectedFile('base/root/BUILD.gn',
2285 ['rebase_path("$target_gen_dir", "/")']),
2286 MockAffectedFile('base/variable/BUILD.gn',
2287 ['rebase_path(target_gen_dir, "/")']),
2288 ]
2289 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2290 self.assertEqual(1, len(warnings))
2291 msg = '\n'.join(warnings[0].items)
2292 self.assertIn('base/BUILD.gn', msg)
2293 self.assertIn('base/root/BUILD.gn', msg)
2294 self.assertIn('base/variable/BUILD.gn', msg)
2295 self.assertEqual(3, len(warnings[0].items))
2296
2297 def testValidUses(self):
2298 mock_input_api = MockInputApi()
2299 mock_input_api.files = [
2300 MockAffectedFile(
2301 'base/foo/BUILD.gn',
2302 ['rebase_path("$target_gen_dir", root_build_dir)']),
2303 MockAffectedFile(
2304 'base/bar/BUILD.gn',
2305 ['rebase_path("$target_gen_dir", root_build_dir, "/")']),
2306 MockAffectedFile('base/baz/BUILD.gn',
2307 ['rebase_path(target_gen_dir, root_build_dir)']),
2308 MockAffectedFile(
2309 'base/baz/BUILD.gn',
2310 ['rebase_path(target_gen_dir, "//some/arbitrary/path")']),
2311 MockAffectedFile('base/okay_slash/BUILD.gn',
2312 ['rebase_path(".", "//")']),
2313 ]
2314 warnings = PRESUBMIT.CheckGnRebasePath(mock_input_api, MockOutputApi())
2315 self.assertEqual([], warnings)
Sean Kaucb7c9b32022-10-25 21:25:522316
2317
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192318class NewHeaderWithoutGnChangeTest(unittest.TestCase):
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192319
Daniel Cheng566634ff2024-06-29 14:56:532320 def testAddHeaderWithoutGn(self):
2321 mock_input_api = MockInputApi()
2322 mock_input_api.files = [
2323 MockAffectedFile('base/stuff.h', ''),
2324 ]
2325 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2326 mock_input_api, MockOutputApi())
2327 self.assertEqual(1, len(warnings))
2328 self.assertTrue('base/stuff.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192329
Daniel Cheng566634ff2024-06-29 14:56:532330 def testModifyHeader(self):
2331 mock_input_api = MockInputApi()
2332 mock_input_api.files = [
2333 MockAffectedFile('base/stuff.h', '', action='M'),
2334 ]
2335 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2336 mock_input_api, MockOutputApi())
2337 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192338
Daniel Cheng566634ff2024-06-29 14:56:532339 def testDeleteHeader(self):
2340 mock_input_api = MockInputApi()
2341 mock_input_api.files = [
2342 MockAffectedFile('base/stuff.h', '', action='D'),
2343 ]
2344 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2345 mock_input_api, MockOutputApi())
2346 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192347
Daniel Cheng566634ff2024-06-29 14:56:532348 def testAddHeaderWithGn(self):
2349 mock_input_api = MockInputApi()
2350 mock_input_api.files = [
2351 MockAffectedFile('base/stuff.h', ''),
2352 MockAffectedFile('base/BUILD.gn', 'stuff.h'),
2353 ]
2354 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2355 mock_input_api, MockOutputApi())
2356 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192357
Daniel Cheng566634ff2024-06-29 14:56:532358 def testAddHeaderWithGni(self):
2359 mock_input_api = MockInputApi()
2360 mock_input_api.files = [
2361 MockAffectedFile('base/stuff.h', ''),
2362 MockAffectedFile('base/files.gni', 'stuff.h'),
2363 ]
2364 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2365 mock_input_api, MockOutputApi())
2366 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192367
Daniel Cheng566634ff2024-06-29 14:56:532368 def testAddHeaderWithOther(self):
2369 mock_input_api = MockInputApi()
2370 mock_input_api.files = [
2371 MockAffectedFile('base/stuff.h', ''),
2372 MockAffectedFile('base/stuff.cc', 'stuff.h'),
2373 ]
2374 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2375 mock_input_api, MockOutputApi())
2376 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192377
Daniel Cheng566634ff2024-06-29 14:56:532378 def testAddHeaderWithWrongGn(self):
2379 mock_input_api = MockInputApi()
2380 mock_input_api.files = [
2381 MockAffectedFile('base/stuff.h', ''),
2382 MockAffectedFile('base/BUILD.gn', 'stuff_h'),
2383 ]
2384 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2385 mock_input_api, MockOutputApi())
2386 self.assertEqual(1, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192387
Daniel Cheng566634ff2024-06-29 14:56:532388 def testAddHeadersWithGn(self):
2389 mock_input_api = MockInputApi()
2390 mock_input_api.files = [
2391 MockAffectedFile('base/stuff.h', ''),
2392 MockAffectedFile('base/another.h', ''),
2393 MockAffectedFile('base/BUILD.gn', 'another.h\nstuff.h'),
2394 ]
2395 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2396 mock_input_api, MockOutputApi())
2397 self.assertEqual(0, len(warnings))
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192398
Daniel Cheng566634ff2024-06-29 14:56:532399 def testAddHeadersWithWrongGn(self):
2400 mock_input_api = MockInputApi()
2401 mock_input_api.files = [
2402 MockAffectedFile('base/stuff.h', ''),
2403 MockAffectedFile('base/another.h', ''),
2404 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff.h'),
2405 ]
2406 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2407 mock_input_api, MockOutputApi())
2408 self.assertEqual(1, len(warnings))
2409 self.assertFalse('base/stuff.h' in warnings[0].items)
2410 self.assertTrue('base/another.h' in warnings[0].items)
2411
2412 def testAddHeadersWithWrongGn2(self):
2413 mock_input_api = MockInputApi()
2414 mock_input_api.files = [
2415 MockAffectedFile('base/stuff.h', ''),
2416 MockAffectedFile('base/another.h', ''),
2417 MockAffectedFile('base/BUILD.gn', 'another_h\nstuff_h'),
2418 ]
2419 warnings = PRESUBMIT.CheckNewHeaderWithoutGnChangeOnUpload(
2420 mock_input_api, MockOutputApi())
2421 self.assertEqual(1, len(warnings))
2422 self.assertTrue('base/stuff.h' in warnings[0].items)
2423 self.assertTrue('base/another.h' in warnings[0].items)
Wei-Yin Chen (陳威尹)c0624d002018-07-30 18:22:192424
2425
Michael Giuffridad3bc8672018-10-25 22:48:022426class CorrectProductNameInMessagesTest(unittest.TestCase):
Michael Giuffridad3bc8672018-10-25 22:48:022427
Daniel Cheng566634ff2024-06-29 14:56:532428 def testProductNameInDesc(self):
2429 mock_input_api = MockInputApi()
2430 mock_input_api.files = [
2431 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2432 '<message name="Foo" desc="Welcome to Chrome">',
2433 ' Welcome to Chrome!',
2434 '</message>',
2435 ]),
2436 MockAffectedFile('chrome/app/chromium_strings.grd', [
2437 '<message name="Bar" desc="Welcome to Chrome">',
2438 ' Welcome to Chromium!',
2439 '</message>',
2440 ]),
2441 ]
2442 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2443 mock_input_api, MockOutputApi())
2444 self.assertEqual(0, len(warnings))
Michael Giuffridad3bc8672018-10-25 22:48:022445
Daniel Cheng566634ff2024-06-29 14:56:532446 def testChromeInChromium(self):
2447 mock_input_api = MockInputApi()
2448 mock_input_api.files = [
2449 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2450 '<message name="Foo" desc="Welcome to Chrome">',
2451 ' Welcome to Chrome!',
2452 '</message>',
2453 ]),
2454 MockAffectedFile('chrome/app/chromium_strings.grd', [
2455 '<message name="Bar" desc="Welcome to Chrome">',
2456 ' Welcome to Chrome!',
2457 '</message>',
2458 ]),
2459 ]
2460 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2461 mock_input_api, MockOutputApi())
2462 self.assertEqual(1, len(warnings))
2463 self.assertTrue(
2464 'chrome/app/chromium_strings.grd' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022465
Daniel Cheng566634ff2024-06-29 14:56:532466 def testChromiumInChrome(self):
2467 mock_input_api = MockInputApi()
2468 mock_input_api.files = [
2469 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2470 '<message name="Foo" desc="Welcome to Chrome">',
2471 ' Welcome to Chromium!',
2472 '</message>',
2473 ]),
2474 MockAffectedFile('chrome/app/chromium_strings.grd', [
2475 '<message name="Bar" desc="Welcome to Chrome">',
2476 ' Welcome to Chromium!',
2477 '</message>',
2478 ]),
2479 ]
2480 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2481 mock_input_api, MockOutputApi())
2482 self.assertEqual(1, len(warnings))
2483 self.assertTrue(
2484 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Thiago Perrotta099034f2023-06-05 18:10:202485
Daniel Cheng566634ff2024-06-29 14:56:532486 def testChromeForTestingInChromium(self):
2487 mock_input_api = MockInputApi()
2488 mock_input_api.files = [
2489 MockAffectedFile('chrome/app/chromium_strings.grd', [
2490 '<message name="Bar" desc="Welcome to Chrome">',
2491 ' Welcome to Chrome for Testing!',
2492 '</message>',
2493 ]),
2494 ]
2495 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2496 mock_input_api, MockOutputApi())
2497 self.assertEqual(0, len(warnings))
Thiago Perrotta099034f2023-06-05 18:10:202498
Daniel Cheng566634ff2024-06-29 14:56:532499 def testChromeForTestingInChrome(self):
2500 mock_input_api = MockInputApi()
2501 mock_input_api.files = [
2502 MockAffectedFile('chrome/app/google_chrome_strings.grd', [
2503 '<message name="Bar" desc="Welcome to Chrome">',
2504 ' Welcome to Chrome for Testing!',
2505 '</message>',
2506 ]),
2507 ]
2508 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2509 mock_input_api, MockOutputApi())
2510 self.assertEqual(1, len(warnings))
2511 self.assertTrue(
2512 'chrome/app/google_chrome_strings.grd:2' in warnings[0].items[0])
Michael Giuffridad3bc8672018-10-25 22:48:022513
Daniel Cheng566634ff2024-06-29 14:56:532514 def testMultipleInstances(self):
2515 mock_input_api = MockInputApi()
2516 mock_input_api.files = [
2517 MockAffectedFile('chrome/app/chromium_strings.grd', [
2518 '<message name="Bar" desc="Welcome to Chrome">',
2519 ' Welcome to Chrome!',
2520 '</message>',
2521 '<message name="Baz" desc="A correct message">',
2522 ' Chromium is the software you are using.',
2523 '</message>',
2524 '<message name="Bat" desc="An incorrect message">',
2525 ' Google Chrome is the software you are using.',
2526 '</message>',
2527 ]),
2528 ]
2529 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2530 mock_input_api, MockOutputApi())
2531 self.assertEqual(1, len(warnings))
2532 self.assertTrue(
2533 'chrome/app/chromium_strings.grd:2' in warnings[0].items[0])
2534 self.assertTrue(
2535 'chrome/app/chromium_strings.grd:8' in warnings[0].items[1])
2536
2537 def testMultipleWarnings(self):
2538 mock_input_api = MockInputApi()
2539 mock_input_api.files = [
2540 MockAffectedFile('chrome/app/chromium_strings.grd', [
2541 '<message name="Bar" desc="Welcome to Chrome">',
2542 ' Welcome to Chrome!',
2543 '</message>',
2544 '<message name="Baz" desc="A correct message">',
2545 ' Chromium is the software you are using.',
2546 '</message>',
2547 '<message name="Bat" desc="An incorrect message">',
2548 ' Google Chrome is the software you are using.',
2549 '</message>',
2550 ]),
2551 MockAffectedFile(
2552 'components/components_google_chrome_strings.grd', [
2553 '<message name="Bar" desc="Welcome to Chrome">',
2554 ' Welcome to Chrome!',
2555 '</message>',
2556 '<message name="Baz" desc="A correct message">',
2557 ' Chromium is the software you are using.',
2558 '</message>',
2559 '<message name="Bat" desc="An incorrect message">',
2560 ' Google Chrome is the software you are using.',
2561 '</message>',
2562 ]),
2563 ]
2564 warnings = PRESUBMIT.CheckCorrectProductNameInMessages(
2565 mock_input_api, MockOutputApi())
2566 self.assertEqual(2, len(warnings))
2567 self.assertTrue('components/components_google_chrome_strings.grd:5' in
2568 warnings[0].items[0])
2569 self.assertTrue(
2570 'chrome/app/chromium_strings.grd:2' in warnings[1].items[0])
2571 self.assertTrue(
2572 'chrome/app/chromium_strings.grd:8' in warnings[1].items[1])
Michael Giuffridad3bc8672018-10-25 22:48:022573
2574
Daniel Chenga37c03db2022-05-12 17:20:342575class _SecurityOwnersTestCase(unittest.TestCase):
Daniel Cheng171dad8d2022-05-21 00:40:252576
Daniel Cheng566634ff2024-06-29 14:56:532577 def _createMockInputApi(self):
2578 mock_input_api = MockInputApi()
Daniel Chengd88244472022-05-16 09:08:472579
Daniel Cheng566634ff2024-06-29 14:56:532580 def FakeRepositoryRoot():
2581 return mock_input_api.os_path.join('chromium', 'src')
Daniel Chengd88244472022-05-16 09:08:472582
Daniel Cheng566634ff2024-06-29 14:56:532583 mock_input_api.change.RepositoryRoot = FakeRepositoryRoot
2584 self._injectFakeOwnersClient(
2585 mock_input_api, ['apple@chromium.org', 'orange@chromium.org'])
2586 return mock_input_api
Daniel Chenga37c03db2022-05-12 17:20:342587
Daniel Cheng566634ff2024-06-29 14:56:532588 def _setupFakeChange(self, input_api):
Daniel Chenga37c03db2022-05-12 17:20:342589
Daniel Cheng566634ff2024-06-29 14:56:532590 class FakeGerrit(object):
2591
2592 def IsOwnersOverrideApproved(self, issue):
2593 return False
2594
2595 input_api.change.issue = 123
2596 input_api.gerrit = FakeGerrit()
2597
2598 def _injectFakeOwnersClient(self, input_api, owners):
2599
2600 class FakeOwnersClient(object):
2601
2602 def ListOwners(self, f):
2603 return owners
2604
2605 input_api.owners_client = FakeOwnersClient()
2606
2607 def _injectFakeChangeOwnerAndReviewers(self, input_api, owner, reviewers):
2608
2609 def MockOwnerAndReviewers(input_api,
2610 email_regexp,
2611 approval_needed=False):
2612 return [owner, reviewers]
2613
2614 input_api.canned_checks.GetCodereviewOwnerAndReviewers = \
2615 MockOwnerAndReviewers
Daniel Chenga37c03db2022-05-12 17:20:342616
2617
2618class IpcSecurityOwnerTest(_SecurityOwnersTestCase):
Daniel Cheng566634ff2024-06-29 14:56:532619 _test_cases = [
2620 ('*_messages.cc', 'scary_messages.cc'),
2621 ('*_messages*.h', 'scary_messages.h'),
2622 ('*_messages*.h', 'scary_messages_android.h'),
2623 ('*_param_traits*.*', 'scary_param_traits.h'),
2624 ('*_param_traits*.*', 'scary_param_traits_win.h'),
2625 ('*.mojom', 'scary.mojom'),
2626 ('*_mojom_traits*.*', 'scary_mojom_traits.h'),
2627 ('*_mojom_traits*.*', 'scary_mojom_traits_mac.h'),
2628 ('*_type_converter*.*', 'scary_type_converter.h'),
2629 ('*_type_converter*.*', 'scary_type_converter_nacl.h'),
2630 ('*.aidl', 'scary.aidl'),
Daniel Cheng171dad8d2022-05-21 00:40:252631 ]
Daniel Cheng171dad8d2022-05-21 00:40:252632
Daniel Cheng566634ff2024-06-29 14:56:532633 def testHasCorrectPerFileRulesAndSecurityReviewer(self):
2634 mock_input_api = self._createMockInputApi()
2635 new_owners_file_path = mock_input_api.os_path.join(
2636 'services', 'goat', 'public', 'OWNERS')
2637 new_owners_file = [
2638 'per-file *.mojom=set noparent',
2639 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2640 ]
Daniel Cheng3008dc12022-05-13 04:02:112641
Daniel Cheng566634ff2024-06-29 14:56:532642 def FakeReadFile(filename):
2643 self.assertEqual(
2644 mock_input_api.os_path.join('chromium', 'src',
2645 new_owners_file_path), filename)
2646 return '\n'.join(new_owners_file)
Daniel Cheng3008dc12022-05-13 04:02:112647
Daniel Cheng566634ff2024-06-29 14:56:532648 mock_input_api.ReadFile = FakeReadFile
2649 mock_input_api.files = [
2650 MockAffectedFile(new_owners_file_path, new_owners_file),
Daniel Cheng171dad8d2022-05-21 00:40:252651 MockAffectedFile(
Daniel Cheng566634ff2024-06-29 14:56:532652 mock_input_api.os_path.join('services', 'goat', 'public',
2653 'goat.mojom'),
2654 ['// Scary contents.'])
2655 ]
2656 self._setupFakeChange(mock_input_api)
2657 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2658 'owner@chromium.org',
2659 ['orange@chromium.org'])
2660 mock_input_api.is_committing = True
2661 mock_input_api.dry_run = False
2662 mock_output_api = MockOutputApi()
2663 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2664 mock_output_api)
2665 self.assertEqual(0, len(results))
Daniel Chenga37c03db2022-05-12 17:20:342666
Daniel Cheng566634ff2024-06-29 14:56:532667 def testMissingSecurityReviewerAtUpload(self):
2668 mock_input_api = self._createMockInputApi()
2669 new_owners_file_path = mock_input_api.os_path.join(
2670 'services', 'goat', 'public', 'OWNERS')
2671 new_owners_file = [
2672 'per-file *.mojom=set noparent',
2673 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2674 ]
Daniel Chenga37c03db2022-05-12 17:20:342675
Daniel Cheng566634ff2024-06-29 14:56:532676 def FakeReadFile(filename):
2677 self.assertEqual(
2678 mock_input_api.os_path.join('chromium', 'src',
2679 new_owners_file_path), filename)
2680 return '\n'.join(new_owners_file)
Ken Rockot9f668262018-12-21 18:56:362681
Daniel Cheng566634ff2024-06-29 14:56:532682 mock_input_api.ReadFile = FakeReadFile
2683 mock_input_api.files = [
2684 MockAffectedFile(new_owners_file_path, new_owners_file),
2685 MockAffectedFile(
2686 mock_input_api.os_path.join('services', 'goat', 'public',
2687 'goat.mojom'),
2688 ['// Scary contents.'])
2689 ]
2690 self._setupFakeChange(mock_input_api)
2691 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2692 'owner@chromium.org',
2693 ['banana@chromium.org'])
2694 mock_input_api.is_committing = False
2695 mock_input_api.dry_run = False
2696 mock_output_api = MockOutputApi()
2697 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2698 mock_output_api)
2699 self.assertEqual(1, len(results))
2700 self.assertEqual('notify', results[0].type)
2701 self.assertEqual(
2702 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2703 'following newly-added files:', results[0].message)
2704
2705 def testMissingSecurityReviewerAtDryRunCommit(self):
2706 mock_input_api = self._createMockInputApi()
2707 new_owners_file_path = mock_input_api.os_path.join(
2708 'services', 'goat', 'public', 'OWNERS')
2709 new_owners_file = [
2710 'per-file *.mojom=set noparent',
2711 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2712 ]
2713
2714 def FakeReadFile(filename):
2715 self.assertEqual(
2716 mock_input_api.os_path.join('chromium', 'src',
2717 new_owners_file_path), filename)
2718 return '\n'.join(new_owners_file)
2719
2720 mock_input_api.ReadFile = FakeReadFile
2721 mock_input_api.files = [
2722 MockAffectedFile(new_owners_file_path, new_owners_file),
2723 MockAffectedFile(
2724 mock_input_api.os_path.join('services', 'goat', 'public',
2725 'goat.mojom'),
2726 ['// Scary contents.'])
2727 ]
2728 self._setupFakeChange(mock_input_api)
2729 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2730 'owner@chromium.org',
2731 ['banana@chromium.org'])
2732 mock_input_api.is_committing = True
2733 mock_input_api.dry_run = True
2734 mock_output_api = MockOutputApi()
2735 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2736 mock_output_api)
2737 self.assertEqual(1, len(results))
2738 self.assertEqual('error', results[0].type)
2739 self.assertEqual(
2740 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2741 'following newly-added files:', results[0].message)
2742
2743 def testMissingSecurityApprovalAtRealCommit(self):
2744 mock_input_api = self._createMockInputApi()
2745 new_owners_file_path = mock_input_api.os_path.join(
2746 'services', 'goat', 'public', 'OWNERS')
2747 new_owners_file = [
2748 'per-file *.mojom=set noparent',
2749 'per-file *.mojom=file://ipc/SECURITY_OWNERS'
2750 ]
2751
2752 def FakeReadFile(filename):
2753 self.assertEqual(
2754 mock_input_api.os_path.join('chromium', 'src',
2755 new_owners_file_path), filename)
2756 return '\n'.join(new_owners_file)
2757
2758 mock_input_api.ReadFile = FakeReadFile
2759 mock_input_api.files = [
2760 MockAffectedFile(new_owners_file_path, new_owners_file),
2761 MockAffectedFile(
2762 mock_input_api.os_path.join('services', 'goat', 'public',
2763 'goat.mojom'),
2764 ['// Scary contents.'])
2765 ]
2766 self._setupFakeChange(mock_input_api)
2767 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2768 'owner@chromium.org',
2769 ['banana@chromium.org'])
2770 mock_input_api.is_committing = True
2771 mock_input_api.dry_run = False
2772 mock_output_api = MockOutputApi()
2773 results = PRESUBMIT.CheckSecurityOwners(mock_input_api,
2774 mock_output_api)
2775 self.assertEqual('error', results[0].type)
2776 self.assertEqual(
2777 'Review from an owner in ipc/SECURITY_OWNERS is required for the '
2778 'following newly-added files:', results[0].message)
2779
2780 def testIpcChangeNeedsSecurityOwner(self):
2781 for is_committing in [True, False]:
2782 for pattern, filename in self._test_cases:
2783 with self.subTest(
2784 line=
2785 f'is_committing={is_committing}, filename={filename}'):
2786 mock_input_api = self._createMockInputApi()
2787 mock_input_api.files = [
2788 MockAffectedFile(
2789 mock_input_api.os_path.join(
2790 'services', 'goat', 'public', filename),
2791 ['// Scary contents.'])
2792 ]
2793 self._setupFakeChange(mock_input_api)
2794 self._injectFakeChangeOwnerAndReviewers(
2795 mock_input_api, 'owner@chromium.org',
2796 ['banana@chromium.org'])
2797 mock_input_api.is_committing = is_committing
2798 mock_input_api.dry_run = False
2799 mock_output_api = MockOutputApi()
2800 results = PRESUBMIT.CheckSecurityOwners(
2801 mock_input_api, mock_output_api)
2802 self.assertEqual(1, len(results))
2803 self.assertEqual('error', results[0].type)
2804 self.assertTrue(results[0].message.replace(
2805 '\\', '/'
2806 ).startswith(
2807 'Found missing OWNERS lines for security-sensitive files. '
2808 'Please add the following lines to services/goat/public/OWNERS:'
2809 ))
2810 self.assertEqual(['ipc-security-reviews@chromium.org'],
2811 mock_output_api.more_cc)
2812
2813 def testServiceManifestChangeNeedsSecurityOwner(self):
2814 mock_input_api = self._createMockInputApi()
2815 mock_input_api.files = [
2816 MockAffectedFile(
2817 mock_input_api.os_path.join('services', 'goat', 'public',
2818 'cpp', 'manifest.cc'),
2819 [
2820 '#include "services/goat/public/cpp/manifest.h"',
2821 'const service_manager::Manifest& GetManifest() {}',
2822 ])
2823 ]
2824 self._setupFakeChange(mock_input_api)
2825 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2826 'owner@chromium.org',
2827 ['banana@chromium.org'])
2828 mock_output_api = MockOutputApi()
2829 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2830 self.assertEqual(1, len(errors))
2831 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2832 'Found missing OWNERS lines for security-sensitive files. '
2833 'Please add the following lines to services/goat/public/cpp/OWNERS:'
2834 ))
2835 self.assertEqual(['ipc-security-reviews@chromium.org'],
2836 mock_output_api.more_cc)
2837
2838 def testNonServiceManifestSourceChangesDoNotRequireSecurityOwner(self):
2839 mock_input_api = self._createMockInputApi()
2840 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2841 'owner@chromium.org',
2842 ['banana@chromium.org'])
2843 mock_input_api.files = [
2844 MockAffectedFile('some/non/service/thing/foo_manifest.cc', [
2845 'const char kNoEnforcement[] = "not a manifest!";',
2846 ])
2847 ]
2848 mock_output_api = MockOutputApi()
2849 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2850 self.assertEqual([], errors)
2851 self.assertEqual([], mock_output_api.more_cc)
Wez17c66962020-04-29 15:26:032852
2853
Daniel Chenga37c03db2022-05-12 17:20:342854class FuchsiaSecurityOwnerTest(_SecurityOwnersTestCase):
Wez17c66962020-04-29 15:26:032855
Daniel Cheng566634ff2024-06-29 14:56:532856 def testFidlChangeNeedsSecurityOwner(self):
2857 mock_input_api = self._createMockInputApi()
2858 mock_input_api.files = [
2859 MockAffectedFile('potentially/scary/ipc.fidl',
2860 ['library test.fidl'])
2861 ]
2862 self._setupFakeChange(mock_input_api)
2863 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2864 'owner@chromium.org',
2865 ['banana@chromium.org'])
2866 mock_output_api = MockOutputApi()
2867 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2868 self.assertEqual(1, len(errors))
2869 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2870 'Found missing OWNERS lines for security-sensitive files. '
2871 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032872
Daniel Cheng566634ff2024-06-29 14:56:532873 def testComponentManifestV1ChangeNeedsSecurityOwner(self):
2874 mock_input_api = self._createMockInputApi()
2875 mock_input_api.files = [
2876 MockAffectedFile('potentially/scary/v2_manifest.cmx',
2877 ['{ "that is no": "manifest!" }'])
2878 ]
2879 self._setupFakeChange(mock_input_api)
2880 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2881 'owner@chromium.org',
2882 ['banana@chromium.org'])
2883 mock_output_api = MockOutputApi()
2884 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2885 self.assertEqual(1, len(errors))
2886 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2887 'Found missing OWNERS lines for security-sensitive files. '
2888 'Please add the following lines to potentially/scary/OWNERS:'))
Wez17c66962020-04-29 15:26:032889
Daniel Cheng566634ff2024-06-29 14:56:532890 def testComponentManifestV2NeedsSecurityOwner(self):
2891 mock_input_api = self._createMockInputApi()
2892 mock_input_api.files = [
2893 MockAffectedFile('potentially/scary/v2_manifest.cml',
2894 ['{ "that is no": "manifest!" }'])
2895 ]
2896 self._setupFakeChange(mock_input_api)
2897 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2898 'owner@chromium.org',
2899 ['banana@chromium.org'])
2900 mock_output_api = MockOutputApi()
2901 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2902 self.assertEqual(1, len(errors))
2903 self.assertTrue(errors[0].message.replace('\\', '/').startswith(
2904 'Found missing OWNERS lines for security-sensitive files. '
2905 'Please add the following lines to potentially/scary/OWNERS:'))
Joshua Peraza1ca6d392020-12-08 00:14:092906
Daniel Cheng566634ff2024-06-29 14:56:532907 def testThirdPartyTestsDoNotRequireSecurityOwner(self):
2908 mock_input_api = MockInputApi()
2909 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2910 'owner@chromium.org',
2911 ['banana@chromium.org'])
2912 mock_input_api.files = [
2913 MockAffectedFile('third_party/crashpad/test/tests.cmx', [
2914 'const char kNoEnforcement[] = "Security?!? Pah!";',
2915 ])
2916 ]
2917 mock_output_api = MockOutputApi()
2918 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2919 self.assertEqual([], errors)
2920
2921 def testOtherFuchsiaChangesDoNotRequireSecurityOwner(self):
2922 mock_input_api = MockInputApi()
2923 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2924 'owner@chromium.org',
2925 ['banana@chromium.org'])
2926 mock_input_api.files = [
2927 MockAffectedFile(
2928 'some/non/service/thing/fuchsia_fidl_cml_cmx_magic.cc', [
2929 'const char kNoEnforcement[] = "Security?!? Pah!";',
2930 ])
2931 ]
2932 mock_output_api = MockOutputApi()
2933 errors = PRESUBMIT.CheckSecurityOwners(mock_input_api, mock_output_api)
2934 self.assertEqual([], errors)
Ken Rockot9f668262018-12-21 18:56:362935
Daniel Cheng13ca61a882017-08-25 15:11:252936
Daniel Chenga37c03db2022-05-12 17:20:342937class SecurityChangeTest(_SecurityOwnersTestCase):
Robert Sesek2c905332020-05-06 23:17:132938
Daniel Cheng566634ff2024-06-29 14:56:532939 def testDiffGetServiceSandboxType(self):
2940 mock_input_api = MockInputApi()
2941 mock_input_api.files = [
2942 MockAffectedFile('services/goat/teleporter_host.cc', [
2943 'template <>', 'inline content::SandboxType',
2944 'content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {',
2945 '#if defined(OS_WIN)', ' return SandboxType::kGoaty;',
2946 '#else', ' return SandboxType::kNoSandbox;',
2947 '#endif // !defined(OS_WIN)', '}'
2948 ]),
2949 ]
2950 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2951 mock_input_api)
2952 self.assertEqual(
2953 {
2954 'services/goat/teleporter_host.cc':
2955 set(['content::GetServiceSandboxType<>()'])
2956 }, files_to_functions)
2957
2958 def testDiffRemovingLine(self):
2959 mock_input_api = MockInputApi()
2960 mock_file = MockAffectedFile('services/goat/teleporter_host.cc', '')
2961 mock_file._scm_diff = """--- old 2020-05-04 14:08:25.000000000 -0400
Robert Sesek2c905332020-05-06 23:17:132962+++ new 2020-05-04 14:08:32.000000000 -0400
2963@@ -1,5 +1,4 @@
Alex Goughbc964dd2020-06-15 17:52:372964 template <>
2965 inline content::SandboxType
2966-content::GetServiceSandboxType<chrome::mojom::GoatTeleporter>() {
2967 #if defined(OS_WIN)
2968 return SandboxType::kGoaty;
Robert Sesek2c905332020-05-06 23:17:132969"""
Daniel Cheng566634ff2024-06-29 14:56:532970 mock_input_api.files = [mock_file]
2971 files_to_functions = PRESUBMIT._GetFilesUsingSecurityCriticalFunctions(
2972 mock_input_api)
2973 self.assertEqual(
2974 {
2975 'services/goat/teleporter_host.cc':
2976 set(['content::GetServiceSandboxType<>()'])
2977 }, files_to_functions)
Robert Sesek2c905332020-05-06 23:17:132978
Daniel Cheng566634ff2024-06-29 14:56:532979 def testChangeOwnersMissing(self):
2980 mock_input_api = self._createMockInputApi()
2981 self._setupFakeChange(mock_input_api)
2982 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
2983 'owner@chromium.org',
2984 ['banana@chromium.org'])
2985 mock_input_api.is_committing = False
2986 mock_input_api.files = [
2987 MockAffectedFile('file.cc',
2988 ['GetServiceSandboxType<Goat>(Sandbox)'])
2989 ]
2990 mock_output_api = MockOutputApi()
2991 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
2992 mock_output_api)
2993 self.assertEqual(1, len(result))
2994 self.assertEqual(result[0].type, 'notify')
2995 self.assertEqual(result[0].message,
2996 'The following files change calls to security-sensitive functions\n' \
2997 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
2998 ' file.cc\n'
2999 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:133000
Daniel Cheng566634ff2024-06-29 14:56:533001 def testChangeOwnersMissingAtCommit(self):
3002 mock_input_api = self._createMockInputApi()
3003 self._setupFakeChange(mock_input_api)
3004 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
3005 'owner@chromium.org',
3006 ['banana@chromium.org'])
3007 mock_input_api.is_committing = True
3008 mock_input_api.dry_run = False
3009 mock_input_api.files = [
3010 MockAffectedFile('file.cc',
3011 ['GetServiceSandboxType<mojom::Goat>()'])
3012 ]
3013 mock_output_api = MockOutputApi()
3014 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
3015 mock_output_api)
3016 self.assertEqual(1, len(result))
3017 self.assertEqual(result[0].type, 'error')
3018 self.assertEqual(result[0].message,
3019 'The following files change calls to security-sensitive functions\n' \
3020 'that need to be reviewed by ipc/SECURITY_OWNERS.\n'
3021 ' file.cc\n'
3022 ' content::GetServiceSandboxType<>()\n\n')
Robert Sesek2c905332020-05-06 23:17:133023
Daniel Cheng566634ff2024-06-29 14:56:533024 def testChangeOwnersPresent(self):
3025 mock_input_api = self._createMockInputApi()
3026 self._injectFakeChangeOwnerAndReviewers(
3027 mock_input_api, 'owner@chromium.org',
3028 ['apple@chromium.org', 'banana@chromium.org'])
3029 mock_input_api.files = [
3030 MockAffectedFile('file.cc', ['WithSandboxType(Sandbox)'])
3031 ]
3032 mock_output_api = MockOutputApi()
3033 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
3034 mock_output_api)
3035 self.assertEqual(0, len(result))
Robert Sesek2c905332020-05-06 23:17:133036
Daniel Cheng566634ff2024-06-29 14:56:533037 def testChangeOwnerIsSecurityOwner(self):
3038 mock_input_api = self._createMockInputApi()
3039 self._setupFakeChange(mock_input_api)
3040 self._injectFakeChangeOwnerAndReviewers(mock_input_api,
3041 'orange@chromium.org',
3042 ['pear@chromium.org'])
3043 mock_input_api.files = [
3044 MockAffectedFile('file.cc', ['GetServiceSandboxType<T>(Sandbox)'])
3045 ]
3046 mock_output_api = MockOutputApi()
3047 result = PRESUBMIT.CheckSecurityChanges(mock_input_api,
3048 mock_output_api)
3049 self.assertEqual(1, len(result))
Robert Sesek2c905332020-05-06 23:17:133050
3051
Mario Sanchez Prada2472cab2019-09-18 10:58:313052class BannedTypeCheckTest(unittest.TestCase):
Clement Yan9b330cb2022-11-17 05:25:293053
Daniel Cheng566634ff2024-06-29 14:56:533054 def testBannedJsFunctions(self):
3055 input_api = MockInputApi()
3056 input_api.files = [
3057 MockFile('ash/webui/file.js', ['chrome.send(something);']),
3058 MockFile('some/js/ok/file.js', ['chrome.send(something);']),
3059 ]
Clement Yan9b330cb2022-11-17 05:25:293060
Daniel Cheng566634ff2024-06-29 14:56:533061 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Sylvain Defresnea8b73d252018-02-28 15:45:543062
Daniel Cheng566634ff2024-06-29 14:56:533063 self.assertEqual(1, len(results))
3064 self.assertTrue('ash/webui/file.js' in results[0].message)
3065 self.assertFalse('some/js/ok/file.js' in results[0].message)
Min Qinbc44383c2023-02-22 17:25:263066
Daniel Cheng566634ff2024-06-29 14:56:533067 def testBannedJavaFunctions(self):
3068 input_api = MockInputApi()
3069 input_api.files = [
3070 MockFile('some/java/problematic/diskread.java',
3071 ['StrictMode.allowThreadDiskReads();']),
3072 MockFile('some/java/problematic/diskwrite.java',
3073 ['StrictMode.allowThreadDiskWrites();']),
3074 MockFile('some/java/ok/diskwrite.java',
3075 ['StrictModeContext.allowDiskWrites();']),
3076 MockFile('some/java/problematic/waitidleforsync.java',
3077 ['instrumentation.waitForIdleSync();']),
3078 MockFile('some/java/problematic/registerreceiver.java',
3079 ['context.registerReceiver();']),
3080 MockFile('some/java/problematic/property.java',
3081 ['new Property<abc, Integer>;']),
3082 MockFile('some/java/problematic/requestlayout.java',
3083 ['requestLayout();']),
3084 MockFile('some/java/problematic/lastprofile.java',
3085 ['ProfileManager.getLastUsedRegularProfile();']),
3086 MockFile('some/java/problematic/getdrawable1.java',
3087 ['ResourcesCompat.getDrawable();']),
3088 MockFile('some/java/problematic/getdrawable2.java',
3089 ['getResources().getDrawable();']),
3090 ]
Min Qinbc44383c2023-02-22 17:25:263091
Daniel Cheng566634ff2024-06-29 14:56:533092 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3093 self.assertEqual(2, len(errors))
3094 self.assertTrue(
3095 'some/java/problematic/diskread.java' in errors[0].message)
3096 self.assertTrue(
3097 'some/java/problematic/diskwrite.java' in errors[0].message)
3098 self.assertFalse('some/java/ok/diskwrite.java' in errors[0].message)
3099 self.assertFalse('some/java/ok/diskwrite.java' in errors[1].message)
3100 self.assertTrue(
3101 'some/java/problematic/waitidleforsync.java' in errors[0].message)
3102 self.assertTrue(
3103 'some/java/problematic/registerreceiver.java' in errors[1].message)
3104 self.assertTrue(
3105 'some/java/problematic/property.java' in errors[0].message)
3106 self.assertTrue(
3107 'some/java/problematic/requestlayout.java' in errors[0].message)
3108 self.assertTrue(
3109 'some/java/problematic/lastprofile.java' in errors[0].message)
3110 self.assertTrue(
3111 'some/java/problematic/getdrawable1.java' in errors[0].message)
3112 self.assertTrue(
3113 'some/java/problematic/getdrawable2.java' in errors[0].message)
Peter Kasting94a56c42019-10-25 21:54:043114
Daniel Cheng566634ff2024-06-29 14:56:533115 def testBannedCppFunctions(self):
3116 input_api = MockInputApi()
3117 input_api.files = [
3118 MockFile('some/cpp/problematic/file.cc', ['using namespace std;']),
3119 MockFile('third_party/blink/problematic/file.cc',
3120 ['GetInterfaceProvider()']),
3121 MockFile('some/cpp/ok/file.cc', ['using std::string;']),
3122 MockFile('some/cpp/problematic/file2.cc',
3123 ['set_owned_by_client()']),
3124 MockFile('some/cpp/nocheck/file.cc',
3125 ['using namespace std; // nocheck']),
3126 MockFile('some/cpp/comment/file.cc',
3127 [' // A comment about `using namespace std;`']),
3128 MockFile('some/cpp/problematic/file3.cc', [
3129 'params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET'
3130 ]),
3131 MockFile('some/cpp/problematic/file4.cc', [
3132 'params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET'
3133 ]),
3134 MockFile('some/cpp/problematic/file5.cc', [
3135 'Browser* browser = chrome::FindBrowserWithTab(web_contents)'
3136 ]),
Daniel Cheng89719222024-07-04 04:59:293137 MockFile('allowed_ranges_usage.cc', ['std::ranges::begin(vec)']),
3138 MockFile('banned_ranges_usage.cc',
3139 ['std::ranges::subrange(first, last)']),
3140 MockFile('views_usage.cc', ['std::views::all(vec)']),
Daniel Cheng566634ff2024-06-29 14:56:533141 ]
Oksana Zhuravlovac8222d22019-12-19 19:21:163142
Daniel Cheng566634ff2024-06-29 14:56:533143 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Peter Kasting94a56c42019-10-25 21:54:043144
Daniel Cheng566634ff2024-06-29 14:56:533145 # warnings are results[0], errors are results[1]
3146 self.assertEqual(2, len(results))
3147 self.assertTrue('some/cpp/problematic/file.cc' in results[1].message)
3148 self.assertTrue(
3149 'third_party/blink/problematic/file.cc' in results[0].message)
3150 self.assertTrue('some/cpp/ok/file.cc' not in results[1].message)
3151 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3152 self.assertTrue('some/cpp/problematic/file3.cc' in results[0].message)
3153 self.assertTrue('some/cpp/problematic/file4.cc' in results[0].message)
3154 self.assertTrue('some/cpp/problematic/file5.cc' in results[0].message)
3155 self.assertFalse('some/cpp/nocheck/file.cc' in results[0].message)
3156 self.assertFalse('some/cpp/nocheck/file.cc' in results[1].message)
3157 self.assertFalse('some/cpp/comment/file.cc' in results[0].message)
3158 self.assertFalse('some/cpp/comment/file.cc' in results[1].message)
Daniel Cheng89719222024-07-04 04:59:293159 self.assertFalse('allowed_ranges_usage.cc' in results[0].message)
3160 self.assertFalse('allowed_ranges_usage.cc' in results[1].message)
3161 self.assertTrue('banned_ranges_usage.cc' in results[1].message)
3162 self.assertTrue('views_usage.cc' in results[1].message)
Daniel Cheng192683f2022-11-01 20:52:443163
Daniel Cheng566634ff2024-06-29 14:56:533164 def testBannedCppRandomFunctions(self):
3165 banned_rngs = [
3166 'absl::BitGen',
3167 'absl::InsecureBitGen',
3168 'std::linear_congruential_engine',
3169 'std::mersenne_twister_engine',
3170 'std::subtract_with_carry_engine',
3171 'std::discard_block_engine',
3172 'std::independent_bits_engine',
3173 'std::shuffle_order_engine',
3174 'std::minstd_rand0',
3175 'std::minstd_rand',
3176 'std::mt19937',
3177 'std::mt19937_64',
3178 'std::ranlux24_base',
3179 'std::ranlux48_base',
3180 'std::ranlux24',
3181 'std::ranlux48',
3182 'std::knuth_b',
3183 'std::default_random_engine',
3184 'std::random_device',
3185 ]
3186 for banned_rng in banned_rngs:
3187 input_api = MockInputApi()
3188 input_api.files = [
3189 MockFile('some/cpp/problematic/file.cc',
3190 [f'{banned_rng} engine;']),
3191 MockFile('third_party/blink/problematic/file.cc',
3192 [f'{banned_rng} engine;']),
3193 MockFile('third_party/ok/file.cc', [f'{banned_rng} engine;']),
3194 ]
3195 results = PRESUBMIT.CheckNoBannedFunctions(input_api,
3196 MockOutputApi())
3197 self.assertEqual(1, len(results), banned_rng)
3198 self.assertTrue(
3199 'some/cpp/problematic/file.cc' in results[0].message,
3200 banned_rng)
3201 self.assertTrue(
3202 'third_party/blink/problematic/file.cc' in results[0].message,
3203 banned_rng)
3204 self.assertFalse('third_party/ok/file.cc' in results[0].message,
3205 banned_rng)
Sylvain Defresnea8b73d252018-02-28 15:45:543206
Daniel Cheng566634ff2024-06-29 14:56:533207 def testBannedIosObjcFunctions(self):
3208 input_api = MockInputApi()
3209 input_api.files = [
3210 MockFile('some/ios/file.mm',
3211 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3212 MockFile('some/mac/file.mm',
3213 ['TEST(SomeClassTest, SomeInteraction) {', '}']),
3214 MockFile('another/ios_file.mm',
3215 ['class SomeTest : public testing::Test {};']),
3216 MockFile(
3217 'some/ios/file_egtest.mm',
3218 ['- (void)testSomething { EXPECT_OCMOCK_VERIFY(aMock); }']),
3219 MockFile('some/ios/file_unittest.mm', [
3220 'TEST_F(SomeTest, TestThis) { EXPECT_OCMOCK_VERIFY(aMock); }'
3221 ]),
3222 ]
Sylvain Defresnea8b73d252018-02-28 15:45:543223
Daniel Cheng566634ff2024-06-29 14:56:533224 errors = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
3225 self.assertEqual(1, len(errors))
3226 self.assertTrue('some/ios/file.mm' in errors[0].message)
3227 self.assertTrue('another/ios_file.mm' in errors[0].message)
3228 self.assertTrue('some/mac/file.mm' not in errors[0].message)
3229 self.assertTrue('some/ios/file_egtest.mm' in errors[0].message)
3230 self.assertTrue('some/ios/file_unittest.mm' not in errors[0].message)
Carlos Knippschildab192b8c2019-04-08 20:02:383231
Daniel Cheng566634ff2024-06-29 14:56:533232 def testBannedMojoFunctions(self):
3233 input_api = MockInputApi()
3234 input_api.files = [
3235 MockFile('some/cpp/problematic/file2.cc', ['mojo::ConvertTo<>']),
3236 MockFile('third_party/blink/ok/file3.cc', ['mojo::ConvertTo<>']),
3237 MockFile('content/renderer/ok/file3.cc', ['mojo::ConvertTo<>']),
3238 ]
Oksana Zhuravlova1d3b59de2019-05-17 00:08:223239
Daniel Cheng566634ff2024-06-29 14:56:533240 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Carlos Knippschildab192b8c2019-04-08 20:02:383241
Daniel Cheng566634ff2024-06-29 14:56:533242 # warnings are results[0], errors are results[1]
3243 self.assertEqual(1, len(results))
3244 self.assertTrue('some/cpp/problematic/file2.cc' in results[0].message)
3245 self.assertTrue(
3246 'third_party/blink/ok/file3.cc' not in results[0].message)
3247 self.assertTrue(
3248 'content/renderer/ok/file3.cc' not in results[0].message)
3249
3250 def testBannedMojomPatterns(self):
3251 input_api = MockInputApi()
3252 input_api.files = [
3253 MockFile(
3254 'bad.mojom',
3255 ['struct Bad {', ' handle<shared_buffer> buffer;', '};']),
3256 MockFile('good.mojom', [
3257 'struct Good {',
Daniel Cheng92c15e32022-03-16 17:48:223258 ' mojo_base.mojom.ReadOnlySharedMemoryRegion region1;',
3259 ' mojo_base.mojom.WritableSharedMemoryRegion region2;',
Daniel Cheng566634ff2024-06-29 14:56:533260 ' mojo_base.mojom.UnsafeSharedMemoryRegion region3;', '};'
3261 ]),
3262 ]
Daniel Cheng92c15e32022-03-16 17:48:223263
Daniel Cheng566634ff2024-06-29 14:56:533264 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Daniel Cheng92c15e32022-03-16 17:48:223265
Daniel Cheng566634ff2024-06-29 14:56:533266 # warnings are results[0], errors are results[1]
3267 self.assertEqual(1, len(results))
3268 self.assertTrue('bad.mojom' in results[0].message)
3269 self.assertTrue('good.mojom' not in results[0].message)
Daniel Cheng92c15e32022-03-16 17:48:223270
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273271class NoProductionCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozekf01ed502018-03-16 19:38:243272
Daniel Cheng566634ff2024-06-29 14:56:533273 def testTruePositives(self):
3274 mock_input_api = MockInputApi()
3275 mock_input_api.files = [
3276 MockFile('some/path/foo.cc', ['foo_for_testing();']),
3277 MockFile('some/path/foo.mm', ['FooForTesting();']),
3278 MockFile('some/path/foo.cxx', ['FooForTests();']),
3279 MockFile('some/path/foo.cpp', ['foo_for_test();']),
3280 ]
Vaclav Brozekf01ed502018-03-16 19:38:243281
Daniel Cheng566634ff2024-06-29 14:56:533282 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3283 mock_input_api, MockOutputApi())
3284 self.assertEqual(1, len(results))
3285 self.assertEqual(4, len(results[0].items))
3286 self.assertTrue('foo.cc' in results[0].items[0])
3287 self.assertTrue('foo.mm' in results[0].items[1])
3288 self.assertTrue('foo.cxx' in results[0].items[2])
3289 self.assertTrue('foo.cpp' in results[0].items[3])
Vaclav Brozekf01ed502018-03-16 19:38:243290
Daniel Cheng566634ff2024-06-29 14:56:533291 def testFalsePositives(self):
3292 mock_input_api = MockInputApi()
3293 mock_input_api.files = [
3294 MockFile('some/path/foo.h', ['foo_for_testing();']),
3295 MockFile('some/path/foo.mm', ['FooForTesting() {']),
3296 MockFile('some/path/foo.cc', ['::FooForTests();']),
3297 MockFile('some/path/foo.cpp', ['// foo_for_test();']),
3298 MockFile('some/path/foo.cxx', ['foo_for_test(); // IN-TEST']),
3299 ]
Vaclav Brozekf01ed502018-03-16 19:38:243300
Daniel Cheng566634ff2024-06-29 14:56:533301 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3302 mock_input_api, MockOutputApi())
3303 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133304
Daniel Cheng566634ff2024-06-29 14:56:533305 def testAllowedFiles(self):
3306 mock_input_api = MockInputApi()
3307 mock_input_api.files = [
3308 MockFile('path/foo_unittest.cc', ['foo_for_testing();']),
3309 MockFile('path/bar_unittest_mac.cc', ['foo_for_testing();']),
3310 MockFile('path/baz_unittests.cc', ['foo_for_testing();']),
3311 ]
3312
3313 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctions(
3314 mock_input_api, MockOutputApi())
3315 self.assertEqual(0, len(results))
James Cook1b4dc132021-03-09 22:45:133316
Vaclav Brozekf01ed502018-03-16 19:38:243317
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273318class NoProductionJavaCodeUsingTestOnlyFunctionsTest(unittest.TestCase):
Vaclav Brozek7dbc28c2018-03-27 08:35:233319
Daniel Cheng566634ff2024-06-29 14:56:533320 def testTruePositives(self):
3321 mock_input_api = MockInputApi()
3322 mock_input_api.files = [
3323 MockFile('dir/java/src/foo.java', ['FooForTesting();']),
3324 MockFile('dir/java/src/bar.java', ['FooForTests(x);']),
3325 MockFile('dir/java/src/baz.java', ['FooForTest(', 'y', ');']),
3326 MockFile('dir/java/src/mult.java', [
3327 'int x = SomethingLongHere()',
3328 ' * SomethingLongHereForTesting();'
3329 ])
3330 ]
Vaclav Brozek7dbc28c2018-03-27 08:35:233331
Daniel Cheng566634ff2024-06-29 14:56:533332 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3333 mock_input_api, MockOutputApi())
3334 self.assertEqual(1, len(results))
3335 self.assertEqual(4, len(results[0].items))
3336 self.assertTrue('foo.java' in results[0].items[0])
3337 self.assertTrue('bar.java' in results[0].items[1])
3338 self.assertTrue('baz.java' in results[0].items[2])
3339 self.assertTrue('mult.java' in results[0].items[3])
Vaclav Brozek7dbc28c2018-03-27 08:35:233340
Daniel Cheng566634ff2024-06-29 14:56:533341 def testFalsePositives(self):
3342 mock_input_api = MockInputApi()
3343 mock_input_api.files = [
3344 MockFile('dir/java/src/foo.xml', ['FooForTesting();']),
3345 MockFile('dir/java/src/foo.java', ['FooForTests() {']),
3346 MockFile('dir/java/src/bar.java', ['// FooForTest();']),
3347 MockFile('dir/java/src/bar2.java', ['x = 1; // FooForTest();']),
3348 MockFile('dir/java/src/bar3.java', ['@VisibleForTesting']),
3349 MockFile('dir/java/src/bar4.java', ['@VisibleForTesting()']),
3350 MockFile('dir/java/src/bar5.java', [
3351 '@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)'
3352 ]),
3353 MockFile('dir/javatests/src/baz.java', ['FooForTest(', 'y', ');']),
3354 MockFile('dir/junit/src/baz.java', ['FooForTest(', 'y', ');']),
3355 MockFile('dir/junit/src/javadoc.java',
3356 ['/** Use FooForTest(); to obtain foo in tests.'
3357 ' */']),
3358 MockFile(
3359 'dir/junit/src/javadoc2.java',
3360 ['/** ', ' * Use FooForTest(); to obtain foo in tests.'
3361 ' */']),
3362 MockFile('dir/java/src/bar6.java',
3363 ['FooForTesting(); // IN-TEST']),
3364 ]
3365
3366 results = PRESUBMIT.CheckNoProductionCodeUsingTestOnlyFunctionsJava(
3367 mock_input_api, MockOutputApi())
3368 self.assertEqual(0, len(results))
Vaclav Brozek7dbc28c2018-03-27 08:35:233369
3370
Mohamed Heikald048240a2019-11-12 16:57:373371class NewImagesWarningTest(unittest.TestCase):
Mohamed Heikald048240a2019-11-12 16:57:373372
Daniel Cheng566634ff2024-06-29 14:56:533373 def testTruePositives(self):
3374 mock_input_api = MockInputApi()
3375 mock_input_api.files = [
3376 MockFile('dir/android/res/drawable/foo.png', []),
3377 MockFile('dir/android/res/drawable-v21/bar.svg', []),
3378 MockFile('dir/android/res/mipmap-v21-en/baz.webp', []),
3379 MockFile('dir/android/res_gshoe/drawable-mdpi/foobar.png', []),
3380 ]
Mohamed Heikald048240a2019-11-12 16:57:373381
Daniel Cheng566634ff2024-06-29 14:56:533382 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3383 MockOutputApi())
3384 self.assertEqual(1, len(results))
3385 self.assertEqual(4, len(results[0].items))
3386 self.assertTrue('foo.png' in results[0].items[0].LocalPath())
3387 self.assertTrue('bar.svg' in results[0].items[1].LocalPath())
3388 self.assertTrue('baz.webp' in results[0].items[2].LocalPath())
3389 self.assertTrue('foobar.png' in results[0].items[3].LocalPath())
Mohamed Heikald048240a2019-11-12 16:57:373390
Daniel Cheng566634ff2024-06-29 14:56:533391 def testFalsePositives(self):
3392 mock_input_api = MockInputApi()
3393 mock_input_api.files = [
3394 MockFile('dir/pngs/README.md', []),
3395 MockFile('java/test/res/drawable/foo.png', []),
3396 MockFile('third_party/blink/foo.png', []),
3397 MockFile('dir/third_party/libpng/src/foo.cc', ['foobar']),
3398 MockFile('dir/resources.webp/.gitignore', ['foo.png']),
3399 ]
3400
3401 results = PRESUBMIT._CheckNewImagesWarning(mock_input_api,
3402 MockOutputApi())
3403 self.assertEqual(0, len(results))
Mohamed Heikald048240a2019-11-12 16:57:373404
Evan Stade7cd4a2c2022-08-04 23:37:253405class ProductIconsTest(unittest.TestCase):
Evan Stade7cd4a2c2022-08-04 23:37:253406
Daniel Cheng566634ff2024-06-29 14:56:533407 def test(self):
3408 mock_input_api = MockInputApi()
3409 mock_input_api.files = [
3410 MockFile('components/vector_icons/google_jetpack.icon', []),
3411 MockFile('components/vector_icons/generic_jetpack.icon', []),
3412 ]
3413
3414 results = PRESUBMIT.CheckNoProductIconsAddedToPublicRepo(
3415 mock_input_api, MockOutputApi())
3416 self.assertEqual(1, len(results))
3417 self.assertEqual(1, len(results[0].items))
3418 self.assertTrue('google_jetpack.icon' in results[0].items[0])
Mohamed Heikald048240a2019-11-12 16:57:373419
Wei-Yin Chen (陳威尹)032f1ac2018-07-27 21:21:273420class CheckUniquePtrTest(unittest.TestCase):
Vaclav Brozek851d9602018-04-04 16:13:053421
Daniel Cheng566634ff2024-06-29 14:56:533422 def testTruePositivesNullptr(self):
3423 mock_input_api = MockInputApi()
3424 mock_input_api.files = [
3425 MockFile('dir/baz.cc', ['std::unique_ptr<T>()']),
3426 MockFile('dir/baz-p.cc', ['std::unique_ptr<T<P>>()']),
3427 ]
Vaclav Brozek851d9602018-04-04 16:13:053428
Daniel Cheng566634ff2024-06-29 14:56:533429 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3430 MockOutputApi())
3431 self.assertEqual(1, len(results))
3432 self.assertTrue('nullptr' in results[0].message)
3433 self.assertEqual(2, len(results[0].items))
3434 self.assertTrue('baz.cc' in results[0].items[0])
3435 self.assertTrue('baz-p.cc' in results[0].items[1])
Vaclav Brozek52e18bf2018-04-03 07:05:243436
Daniel Cheng566634ff2024-06-29 14:56:533437 def testTruePositivesConstructor(self):
3438 mock_input_api = MockInputApi()
3439 mock_input_api.files = [
3440 MockFile('dir/foo.cc', ['return std::unique_ptr<T>(foo);']),
3441 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T>(foo)']),
3442 MockFile('dir/mult.cc', [
3443 'return',
3444 ' std::unique_ptr<T>(barVeryVeryLongFooSoThatItWouldNotFitAbove);'
3445 ]),
3446 MockFile('dir/mult2.cc', [
3447 'barVeryVeryLongLongBaaaaaarSoThatTheLineLimitIsAlmostReached =',
3448 ' std::unique_ptr<T>(foo);'
3449 ]),
3450 MockFile('dir/mult3.cc', [
3451 'bar = std::unique_ptr<T>(',
3452 ' fooVeryVeryVeryLongStillGoingWellThisWillTakeAWhileFinallyThere);'
3453 ]),
3454 MockFile('dir/multi_arg.cc', [
3455 'auto p = std::unique_ptr<std::pair<T, D>>(new std::pair(T, D));'
3456 ]),
3457 ]
Vaclav Brozek52e18bf2018-04-03 07:05:243458
Daniel Cheng566634ff2024-06-29 14:56:533459 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3460 MockOutputApi())
3461 self.assertEqual(1, len(results))
3462 self.assertTrue('std::make_unique' in results[0].message)
3463 self.assertEqual(6, len(results[0].items))
3464 self.assertTrue('foo.cc' in results[0].items[0])
3465 self.assertTrue('bar.mm' in results[0].items[1])
3466 self.assertTrue('mult.cc' in results[0].items[2])
3467 self.assertTrue('mult2.cc' in results[0].items[3])
3468 self.assertTrue('mult3.cc' in results[0].items[4])
3469 self.assertTrue('multi_arg.cc' in results[0].items[5])
Vaclav Brozekb7fadb692018-08-30 06:39:533470
Daniel Cheng566634ff2024-06-29 14:56:533471 def testFalsePositives(self):
3472 mock_input_api = MockInputApi()
3473 mock_input_api.files = [
3474 MockFile('dir/foo.cc', ['return std::unique_ptr<T[]>(foo);']),
3475 MockFile('dir/bar.mm', ['bar = std::unique_ptr<T[]>(foo)']),
3476 MockFile('dir/file.cc', ['std::unique_ptr<T> p = Foo();']),
3477 MockFile('dir/baz.cc',
3478 ['std::unique_ptr<T> result = std::make_unique<T>();']),
3479 MockFile('dir/baz2.cc',
3480 ['std::unique_ptr<T> result = std::make_unique<T>(']),
3481 MockFile('dir/nested.cc', ['set<std::unique_ptr<T>>();']),
3482 MockFile('dir/nested2.cc', ['map<U, std::unique_ptr<T>>();']),
3483 # Changed line is inside a multiline template block.
3484 MockFile('dir/template.cc', [' std::unique_ptr<T>>(']),
3485 MockFile('dir/template2.cc', [' std::unique_ptr<T>>()']),
Vaclav Brozek52e18bf2018-04-03 07:05:243486
Daniel Cheng566634ff2024-06-29 14:56:533487 # Two-argument invocation of std::unique_ptr is exempt because there is
3488 # no equivalent using std::make_unique.
3489 MockFile('dir/multi_arg.cc',
3490 ['auto p = std::unique_ptr<T, D>(new T(), D());']),
3491 ]
3492
3493 results = PRESUBMIT.CheckUniquePtrOnUpload(mock_input_api,
3494 MockOutputApi())
3495 self.assertEqual([], results)
Vaclav Brozek52e18bf2018-04-03 07:05:243496
Danil Chapovalov3518f362018-08-11 16:13:433497class CheckNoDirectIncludesHeadersWhichRedefineStrCat(unittest.TestCase):
Danil Chapovalov3518f362018-08-11 16:13:433498
Daniel Cheng566634ff2024-06-29 14:56:533499 def testBlocksDirectIncludes(self):
3500 mock_input_api = MockInputApi()
3501 mock_input_api.files = [
3502 MockFile('dir/foo_win.cc', ['#include "shlwapi.h"']),
3503 MockFile('dir/bar.h', ['#include <propvarutil.h>']),
3504 MockFile('dir/baz.h', ['#include <atlbase.h>']),
3505 MockFile('dir/jumbo.h', ['#include "sphelper.h"']),
3506 ]
3507 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3508 MockOutputApi())
3509 self.assertEqual(1, len(results))
3510 self.assertEqual(4, len(results[0].items))
3511 self.assertTrue('StrCat' in results[0].message)
3512 self.assertTrue('foo_win.cc' in results[0].items[0])
3513 self.assertTrue('bar.h' in results[0].items[1])
3514 self.assertTrue('baz.h' in results[0].items[2])
3515 self.assertTrue('jumbo.h' in results[0].items[3])
Danil Chapovalov3518f362018-08-11 16:13:433516
Daniel Cheng566634ff2024-06-29 14:56:533517 def testAllowsToIncludeWrapper(self):
3518 mock_input_api = MockInputApi()
3519 mock_input_api.files = [
3520 MockFile('dir/baz_win.cc', ['#include "base/win/shlwapi.h"']),
3521 MockFile('dir/baz-win.h', ['#include "base/win/atl.h"']),
3522 ]
3523 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3524 MockOutputApi())
3525 self.assertEqual(0, len(results))
Aleksey Khoroshilov9b28c032022-06-03 16:35:323526
Daniel Cheng566634ff2024-06-29 14:56:533527 def testAllowsToCreateWrapper(self):
3528 mock_input_api = MockInputApi()
3529 mock_input_api.files = [
3530 MockFile('base/win/shlwapi.h', [
3531 '#include <shlwapi.h>',
3532 '#include "base/win/windows_defines.inc"'
3533 ]),
3534 ]
3535 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3536 MockOutputApi())
3537 self.assertEqual(0, len(results))
3538
3539 def testIgnoresNonImplAndHeaders(self):
3540 mock_input_api = MockInputApi()
3541 mock_input_api.files = [
3542 MockFile('dir/foo_win.txt', ['#include "shlwapi.h"']),
3543 MockFile('dir/bar.asm', ['#include <propvarutil.h>']),
3544 ]
3545 results = PRESUBMIT.CheckNoStrCatRedefines(mock_input_api,
3546 MockOutputApi())
3547 self.assertEqual(0, len(results))
Vaclav Brozek52e18bf2018-04-03 07:05:243548
Mustafa Emre Acer51f2f742020-03-09 19:41:123549
Rainhard Findlingfc31844c52020-05-15 09:58:263550class StringTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:533551 """Tests ICU syntax check and translation screenshots check."""
Rainhard Findlingfc31844c52020-05-15 09:58:263552
Daniel Cheng566634ff2024-06-29 14:56:533553 # An empty grd file.
3554 OLD_GRD_CONTENTS = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143555 <grit latest_public_release="1" current_release="1">
3556 <release seq="1">
3557 <messages></messages>
3558 </release>
3559 </grit>
3560 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533561 # A grd file with a single message.
3562 NEW_GRD_CONTENTS1 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143563 <grit latest_public_release="1" current_release="1">
3564 <release seq="1">
3565 <messages>
3566 <message name="IDS_TEST1">
3567 Test string 1
3568 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483569 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE1"
3570 translateable="false">
3571 Non translateable message 1, should be ignored
3572 </message>
Mustafa Emre Acered1a48962020-06-30 19:15:393573 <message name="IDS_TEST_STRING_ACCESSIBILITY"
Mustafa Emre Acerd3ca8be2020-07-07 22:35:343574 is_accessibility_with_no_ui="true">
Mustafa Emre Acered1a48962020-06-30 19:15:393575 Accessibility label 1, should be ignored
3576 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143577 </messages>
3578 </release>
3579 </grit>
3580 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533581 # A grd file with two messages.
3582 NEW_GRD_CONTENTS2 = """<?xml version="1.0" encoding="UTF-8"?>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143583 <grit latest_public_release="1" current_release="1">
3584 <release seq="1">
3585 <messages>
3586 <message name="IDS_TEST1">
3587 Test string 1
3588 </message>
3589 <message name="IDS_TEST2">
3590 Test string 2
3591 </message>
Mustafa Emre Acere4b349c2020-06-03 23:42:483592 <message name="IDS_TEST_STRING_NON_TRANSLATEABLE2"
3593 translateable="false">
3594 Non translateable message 2, should be ignored
3595 </message>
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143596 </messages>
3597 </release>
3598 </grit>
3599 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533600 # A grd file with one ICU syntax message without syntax errors.
3601 NEW_GRD_CONTENTS_ICU_SYNTAX_OK1 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263602 <grit latest_public_release="1" current_release="1">
3603 <release seq="1">
3604 <messages>
3605 <message name="IDS_TEST1">
3606 {NUM, plural,
3607 =1 {Test text for numeric one}
3608 other {Test text for plural with {NUM} as number}}
3609 </message>
3610 </messages>
3611 </release>
3612 </grit>
3613 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533614 # A grd file with one ICU syntax message without syntax errors.
3615 NEW_GRD_CONTENTS_ICU_SYNTAX_OK2 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263616 <grit latest_public_release="1" current_release="1">
3617 <release seq="1">
3618 <messages>
3619 <message name="IDS_TEST1">
3620 {NUM, plural,
3621 =1 {Different test text for numeric one}
3622 other {Different test text for plural with {NUM} as number}}
3623 </message>
3624 </messages>
3625 </release>
3626 </grit>
3627 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533628 # A grd file with multiple ICU syntax messages without syntax errors.
3629 NEW_GRD_CONTENTS_ICU_SYNTAX_OK3 = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findling3cde3ef02024-02-05 18:40:323630 <grit latest_public_release="1" current_release="1">
3631 <release seq="1">
3632 <messages>
3633 <message name="IDS_TEST1">
3634 {NUM, plural,
3635 =0 {New test text for numeric zero}
3636 =1 {Different test text for numeric one}
3637 =2 {New test text for numeric two}
3638 =3 {New test text for numeric three}
3639 other {Different test text for plural with {NUM} as number}}
3640 </message>
3641 </messages>
3642 </release>
3643 </grit>
3644 """.splitlines()
Daniel Cheng566634ff2024-06-29 14:56:533645 # A grd file with one ICU syntax message with syntax errors (misses a comma).
3646 NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR = """<?xml version="1.0" encoding="UTF-8"?>
Rainhard Findlingfc31844c52020-05-15 09:58:263647 <grit latest_public_release="1" current_release="1">
3648 <release seq="1">
3649 <messages>
3650 <message name="IDS_TEST1">
3651 {NUM, plural
3652 =1 {Test text for numeric one}
3653 other {Test text for plural with {NUM} as number}}
3654 </message>
3655 </messages>
3656 </release>
3657 </grit>
3658 """.splitlines()
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143659
Daniel Cheng566634ff2024-06-29 14:56:533660 OLD_GRDP_CONTENTS = ('<?xml version="1.0" encoding="utf-8"?>',
3661 '<grit-part>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583662
Daniel Cheng566634ff2024-06-29 14:56:533663 NEW_GRDP_CONTENTS1 = ('<?xml version="1.0" encoding="utf-8"?>',
3664 '<grit-part>', '<message name="IDS_PART_TEST1">',
3665 'Part string 1', '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583666
Daniel Cheng566634ff2024-06-29 14:56:533667 NEW_GRDP_CONTENTS2 = ('<?xml version="1.0" encoding="utf-8"?>',
3668 '<grit-part>', '<message name="IDS_PART_TEST1">',
3669 'Part string 1', '</message>',
3670 '<message name="IDS_PART_TEST2">', 'Part string 2',
3671 '</message>', '</grit-part>')
meacerff8a9b62019-12-10 19:43:583672
Daniel Cheng566634ff2024-06-29 14:56:533673 NEW_GRDP_CONTENTS3 = (
3674 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093675 '<message name="IDS_PART_TEST1" desc="Description with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533676 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093677
Daniel Cheng566634ff2024-06-29 14:56:533678 NEW_GRDP_CONTENTS4 = (
3679 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findlingd8d04372020-08-13 13:30:093680 '<message name="IDS_PART_TEST1" desc="Description with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533681 'Part string 1', '</message>', '</grit-part>')
Rainhard Findlingd8d04372020-08-13 13:30:093682
Daniel Cheng566634ff2024-06-29 14:56:533683 NEW_GRDP_CONTENTS5 = (
3684 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353685 '<message name="IDS_PART_TEST1" meaning="Meaning with typo.">',
Daniel Cheng566634ff2024-06-29 14:56:533686 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353687
Daniel Cheng566634ff2024-06-29 14:56:533688 NEW_GRDP_CONTENTS6 = (
3689 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
Rainhard Findling1a3e71e2020-09-21 07:33:353690 '<message name="IDS_PART_TEST1" meaning="Meaning with typo fixed.">',
Daniel Cheng566634ff2024-06-29 14:56:533691 'Part string 1', '</message>', '</grit-part>')
Rainhard Findling1a3e71e2020-09-21 07:33:353692
Daniel Cheng566634ff2024-06-29 14:56:533693 # A grdp file with one ICU syntax message without syntax errors.
3694 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1 = (
3695 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3696 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3697 '=1 {Test text for numeric one}',
3698 'other {Test text for plural with {NUM} as number}}', '</message>',
3699 '</grit-part>')
3700 # A grdp file with one ICU syntax message without syntax errors.
3701 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2 = (
3702 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3703 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3704 '=1 {Different test text for numeric one}',
3705 'other {Different test text for plural with {NUM} as number}}',
3706 '</message>', '</grit-part>')
3707 # A grdp file with multiple ICU syntax messages without syntax errors.
3708 NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3 = (
3709 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3710 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3711 '=0 {New test text for numeric zero}',
3712 '=1 {Different test text for numeric one}',
3713 '=2 {New test text for numeric two}',
3714 '=3 {New test text for numeric three}',
3715 'other {Different test text for plural with {NUM} as number}}',
3716 '</message>', '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263717
Daniel Cheng566634ff2024-06-29 14:56:533718 # A grdp file with one ICU syntax message with syntax errors (superfluous
3719 # space).
3720 NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR = (
3721 '<?xml version="1.0" encoding="utf-8"?>', '<grit-part>',
3722 '<message name="IDS_PART_TEST1">', '{NUM, plural,',
3723 '= 1 {Test text for numeric one}',
3724 'other {Test text for plural with {NUM} as number}}', '</message>',
3725 '</grit-part>')
Rainhard Findlingfc31844c52020-05-15 09:58:263726
Daniel Cheng566634ff2024-06-29 14:56:533727 VALID_SHA1 = ('0000000000000000000000000000000000000000', )
3728 DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the '
3729 'changelist. Run '
3730 'tools/translate/upload_screenshots.py to '
3731 'upload them instead:')
3732 ADD_SIGNATURES_MESSAGE = ('You are adding UI strings.\n'
3733 'To ensure the best translations, take '
3734 'screenshots of the relevant UI '
3735 '(https://g.co/chrome/translation) and add '
3736 'these files to your changelist:')
3737 REMOVE_SIGNATURES_MESSAGE = ('You removed strings associated with these '
3738 'files. Remove:')
3739 ICU_SYNTAX_ERROR_MESSAGE = (
3740 'ICU syntax errors were found in the following '
3741 'strings (problems or feedback? Contact '
3742 'rainhard@chromium.org):')
3743 SHA1_FORMAT_MESSAGE = (
3744 'The following files do not seem to contain valid sha1 '
3745 'hashes. Make sure they contain hashes created by '
3746 'tools/translate/upload_screenshots.py:')
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143747
Daniel Cheng566634ff2024-06-29 14:56:533748 def makeInputApi(self, files):
3749 input_api = MockInputApi()
3750 input_api.files = files
3751 # Override os_path.exists because the presubmit uses the actual
3752 # os.path.exists.
3753 input_api.CreateMockFileInPath([
3754 x.LocalPath()
3755 for x in input_api.AffectedFiles(include_deletes=True)
3756 ])
3757 return input_api
Mustafa Emre Acer29bf6ac92018-07-30 21:42:143758
Daniel Cheng566634ff2024-06-29 14:56:533759 """ CL modified and added messages, but didn't add any screenshots."""
meacerff8a9b62019-12-10 19:43:583760
Daniel Cheng566634ff2024-06-29 14:56:533761 def testNoScreenshots(self):
3762 # No new strings (file contents same). Should not warn.
3763 input_api = self.makeInputApi([
3764 MockAffectedFile('test.grd',
3765 self.NEW_GRD_CONTENTS1,
3766 self.NEW_GRD_CONTENTS1,
3767 action='M'),
3768 MockAffectedFile('part.grdp',
3769 self.NEW_GRDP_CONTENTS1,
3770 self.NEW_GRDP_CONTENTS1,
3771 action='M')
3772 ])
3773 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3774 self.assertEqual(0, len(warnings))
Mustafa Emre Acer36eaad52019-11-12 23:03:343775
Daniel Cheng566634ff2024-06-29 14:56:533776 # Add two new strings. Should have two warnings.
3777 input_api = self.makeInputApi([
3778 MockAffectedFile('test.grd',
3779 self.NEW_GRD_CONTENTS2,
3780 self.NEW_GRD_CONTENTS1,
3781 action='M'),
3782 MockAffectedFile('part.grdp',
3783 self.NEW_GRDP_CONTENTS2,
3784 self.NEW_GRDP_CONTENTS1,
3785 action='M')
3786 ])
3787 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3788 self.assertEqual(1, len(warnings))
3789 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3790 self.assertEqual('error', warnings[0].type)
3791 self.assertEqual([
3792 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3793 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
3794 ], warnings[0].items)
Mustafa Emre Acerad8fb082019-11-19 04:24:213795
Daniel Cheng566634ff2024-06-29 14:56:533796 # Add four new strings. Should have four warnings.
3797 input_api = self.makeInputApi([
3798 MockAffectedFile('test.grd',
3799 self.NEW_GRD_CONTENTS2,
3800 self.OLD_GRD_CONTENTS,
3801 action='M'),
3802 MockAffectedFile('part.grdp',
3803 self.NEW_GRDP_CONTENTS2,
3804 self.OLD_GRDP_CONTENTS,
3805 action='M')
3806 ])
3807 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3808 self.assertEqual(1, len(warnings))
3809 self.assertEqual('error', warnings[0].type)
3810 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[0].message)
3811 self.assertEqual([
meacerff8a9b62019-12-10 19:43:583812 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
meacerff8a9b62019-12-10 19:43:583813 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303814 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:303815 os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533816 ], warnings[0].items)
3817
3818 def testModifiedMessageDescription(self):
3819 # CL modified a message description for a message that does not yet have a
3820 # screenshot. Should not warn.
3821 input_api = self.makeInputApi([
3822 MockAffectedFile('part.grdp',
3823 self.NEW_GRDP_CONTENTS3,
3824 self.NEW_GRDP_CONTENTS4,
3825 action='M')
3826 ])
3827 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3828 self.assertEqual(0, len(warnings))
3829
3830 # CL modified a message description for a message that already has a
3831 # screenshot. Should not warn.
3832 input_api = self.makeInputApi([
3833 MockAffectedFile('part.grdp',
3834 self.NEW_GRDP_CONTENTS3,
3835 self.NEW_GRDP_CONTENTS4,
3836 action='M'),
3837 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3838 self.VALID_SHA1,
3839 action='A')
3840 ])
3841 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3842 self.assertEqual(0, len(warnings))
3843
3844 def testModifiedMessageMeaning(self):
3845 # CL modified a message meaning for a message that does not yet have a
3846 # screenshot. Should warn.
3847 input_api = self.makeInputApi([
3848 MockAffectedFile('part.grdp',
3849 self.NEW_GRDP_CONTENTS5,
3850 self.NEW_GRDP_CONTENTS6,
3851 action='M')
3852 ])
3853 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3854 self.assertEqual(1, len(warnings))
3855
3856 # CL modified a message meaning for a message that already has a
3857 # screenshot. Should not warn.
3858 input_api = self.makeInputApi([
3859 MockAffectedFile('part.grdp',
3860 self.NEW_GRDP_CONTENTS5,
3861 self.NEW_GRDP_CONTENTS6,
3862 action='M'),
3863 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3864 self.VALID_SHA1,
3865 action='A')
3866 ])
3867 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3868 self.assertEqual(0, len(warnings))
3869
3870 def testModifiedIntroducedInvalidSha1(self):
3871 # CL modified a message and the sha1 file changed to invalid
3872 input_api = self.makeInputApi([
3873 MockAffectedFile('part.grdp',
3874 self.NEW_GRDP_CONTENTS5,
3875 self.NEW_GRDP_CONTENTS6,
3876 action='M'),
3877 MockAffectedFile(os.path.join('part_grdp',
3878 'IDS_PART_TEST1.png.sha1'),
3879 ('some invalid sha1', ),
3880 self.VALID_SHA1,
3881 action='M')
3882 ])
3883 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3884 self.assertEqual(1, len(warnings))
3885
3886 def testPngAddedSha1NotAdded(self):
3887 # CL added one new message in a grd file and added the png file associated
3888 # with it, but did not add the corresponding sha1 file. This should warn
3889 # twice:
3890 # - Once for the added png file (because we don't want developers to upload
3891 # actual images)
3892 # - Once for the missing .sha1 file
3893 input_api = self.makeInputApi([
3894 MockAffectedFile('test.grd',
3895 self.NEW_GRD_CONTENTS1,
3896 self.OLD_GRD_CONTENTS,
3897 action='M'),
3898 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3899 'binary',
3900 action='A')
3901 ])
3902 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3903 self.assertEqual(2, len(warnings))
3904 self.assertEqual('error', warnings[0].type)
3905 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3906 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png')],
3907 warnings[0].items)
3908 self.assertEqual('error', warnings[1].type)
3909 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3910 self.assertEqual([os.path.join('test_grd', 'IDS_TEST1.png.sha1')],
3911 warnings[1].items)
3912
3913 # CL added two messages (one in grd, one in grdp) and added the png files
3914 # associated with the messages, but did not add the corresponding sha1
3915 # files. This should warn twice:
3916 # - Once for the added png files (because we don't want developers to upload
3917 # actual images)
3918 # - Once for the missing .sha1 files
3919 input_api = self.makeInputApi([
3920 # Modified files:
3921 MockAffectedFile('test.grd',
3922 self.NEW_GRD_CONTENTS1,
3923 self.OLD_GRD_CONTENTS,
3924 action='M'),
3925 MockAffectedFile('part.grdp',
3926 self.NEW_GRDP_CONTENTS1,
3927 self.OLD_GRDP_CONTENTS,
3928 action='M'),
3929 # Added files:
3930 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST1.png'),
3931 'binary',
3932 action='A'),
3933 MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3934 'binary',
3935 action='A')
3936 ])
3937 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3938 self.assertEqual(2, len(warnings))
3939 self.assertEqual('error', warnings[0].type)
3940 self.assertEqual(self.DO_NOT_UPLOAD_PNG_MESSAGE, warnings[0].message)
3941 self.assertEqual([
3942 os.path.join('part_grdp', 'IDS_PART_TEST1.png'),
3943 os.path.join('test_grd', 'IDS_TEST1.png')
3944 ], warnings[0].items)
3945 self.assertEqual('error', warnings[0].type)
3946 self.assertEqual(self.ADD_SIGNATURES_MESSAGE, warnings[1].message)
3947 self.assertEqual([
Jens Mueller054652c2023-05-10 15:12:303948 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:533949 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
3950 ], warnings[1].items)
3951
3952 def testScreenshotsWithSha1(self):
3953 # CL added four messages (two each in a grd and grdp) and their
3954 # corresponding .sha1 files. No warnings.
3955 input_api = self.makeInputApi([
3956 # Modified files:
3957 MockAffectedFile('test.grd',
3958 self.NEW_GRD_CONTENTS2,
3959 self.OLD_GRD_CONTENTS,
3960 action='M'),
3961 MockAffectedFile('part.grdp',
3962 self.NEW_GRDP_CONTENTS2,
3963 self.OLD_GRDP_CONTENTS,
3964 action='M'),
3965 # Added files:
3966 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3967 self.VALID_SHA1,
3968 action='A'),
3969 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3970 ('0000000000000000000000000000000000000000', ''),
3971 action='A'),
3972 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
3973 self.VALID_SHA1,
3974 action='A'),
3975 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
3976 self.VALID_SHA1,
3977 action='A'),
3978 ])
3979 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
3980 self.assertEqual([], warnings)
3981
3982 def testScreenshotsWithInvalidSha1(self):
3983 input_api = self.makeInputApi([
3984 # Modified files:
3985 MockAffectedFile('test.grd',
3986 self.NEW_GRD_CONTENTS2,
3987 self.OLD_GRD_CONTENTS,
3988 action='M'),
3989 MockAffectedFile('part.grdp',
3990 self.NEW_GRDP_CONTENTS2,
3991 self.OLD_GRDP_CONTENTS,
3992 action='M'),
3993 # Added files:
3994 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
3995 self.VALID_SHA1,
3996 action='A'),
3997 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
3998 ('‰PNG', 'test'),
3999 action='A'),
4000 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4001 self.VALID_SHA1,
4002 action='A'),
4003 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4004 self.VALID_SHA1,
4005 action='A'),
4006 ])
4007 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4008 self.assertEqual(1, len(warnings))
4009 self.assertEqual('error', warnings[0].type)
4010 self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message)
4011 self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')],
4012 warnings[0].items)
4013
4014 def testScreenshotsRemovedWithSha1(self):
4015 # Replace new contents with old contents in grd and grp files, removing
4016 # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2.
4017 # Should warn to remove the sha1 files associated with these strings.
4018 input_api = self.makeInputApi([
4019 # Modified files:
4020 MockAffectedFile(
4021 'test.grd',
4022 self.OLD_GRD_CONTENTS, # new_contents
4023 self.NEW_GRD_CONTENTS2, # old_contents
4024 action='M'),
4025 MockAffectedFile(
4026 'part.grdp',
4027 self.OLD_GRDP_CONTENTS, # new_contents
4028 self.NEW_GRDP_CONTENTS2, # old_contents
4029 action='M'),
4030 # Unmodified files:
4031 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4032 self.VALID_SHA1, ''),
4033 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4034 self.VALID_SHA1, ''),
4035 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4036 self.VALID_SHA1, ''),
4037 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4038 self.VALID_SHA1, '')
4039 ])
4040 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4041 self.assertEqual(1, len(warnings))
4042 self.assertEqual('error', warnings[0].type)
4043 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4044 self.assertEqual([
4045 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Jens Mueller054652c2023-05-10 15:12:304046 os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
Mustafa Emre Acerea3e57a2018-12-17 23:51:014047 os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534048 os.path.join('test_grd', 'IDS_TEST2.png.sha1')
4049 ], warnings[0].items)
4050
4051 # Same as above, but this time one of the .sha1 files is also removed.
4052 input_api = self.makeInputApi([
4053 # Modified files:
4054 MockAffectedFile(
4055 'test.grd',
4056 self.OLD_GRD_CONTENTS, # new_contents
4057 self.NEW_GRD_CONTENTS2, # old_contents
4058 action='M'),
4059 MockAffectedFile(
4060 'part.grdp',
4061 self.OLD_GRDP_CONTENTS, # new_contents
4062 self.NEW_GRDP_CONTENTS2, # old_contents
4063 action='M'),
4064 # Unmodified files:
4065 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4066 self.VALID_SHA1, ''),
4067 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4068 self.VALID_SHA1, ''),
4069 # Deleted files:
4070 MockAffectedFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4071 '',
4072 'old_contents',
4073 action='D'),
4074 MockAffectedFile(os.path.join('part_grdp',
4075 'IDS_PART_TEST2.png.sha1'),
4076 '',
4077 'old_contents',
4078 action='D')
4079 ])
4080 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4081 self.assertEqual(1, len(warnings))
4082 self.assertEqual('error', warnings[0].type)
4083 self.assertEqual(self.REMOVE_SIGNATURES_MESSAGE, warnings[0].message)
4084 self.assertEqual([
meacerff8a9b62019-12-10 19:43:584085 os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
Daniel Cheng566634ff2024-06-29 14:56:534086 os.path.join('test_grd', 'IDS_TEST1.png.sha1')
4087 ], warnings[0].items)
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144088
Daniel Cheng566634ff2024-06-29 14:56:534089 # Remove all sha1 files. There should be no warnings.
4090 input_api = self.makeInputApi([
4091 # Modified files:
4092 MockAffectedFile('test.grd',
4093 self.OLD_GRD_CONTENTS,
4094 self.NEW_GRD_CONTENTS2,
4095 action='M'),
4096 MockAffectedFile('part.grdp',
4097 self.OLD_GRDP_CONTENTS,
4098 self.NEW_GRDP_CONTENTS2,
4099 action='M'),
4100 # Deleted files:
4101 MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'),
4102 self.VALID_SHA1,
4103 action='D'),
4104 MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'),
4105 self.VALID_SHA1,
4106 action='D'),
4107 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'),
4108 self.VALID_SHA1,
4109 action='D'),
4110 MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'),
4111 self.VALID_SHA1,
4112 action='D')
4113 ])
4114 warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4115 self.assertEqual([], warnings)
Rainhard Findlingfc31844c52020-05-15 09:58:264116
Daniel Cheng566634ff2024-06-29 14:56:534117 def testIcuSyntax(self):
4118 # Add valid ICU syntax string. Should not raise an error.
4119 input_api = self.makeInputApi([
4120 MockAffectedFile('test.grd',
4121 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4122 self.NEW_GRD_CONTENTS1,
4123 action='M'),
4124 MockAffectedFile('part.grdp',
4125 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4126 self.NEW_GRDP_CONTENTS1,
4127 action='M')
4128 ])
4129 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4130 # We expect no ICU syntax errors.
4131 icu_errors = [
4132 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4133 ]
4134 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264135
Daniel Cheng566634ff2024-06-29 14:56:534136 # Valid changes in ICU syntax. Should not raise an error.
4137 input_api = self.makeInputApi([
4138 MockAffectedFile('test.grd',
4139 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK2,
4140 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4141 action='M'),
4142 MockAffectedFile('part.grdp',
4143 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK2,
4144 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4145 action='M')
4146 ])
4147 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4148 # We expect no ICU syntax errors.
4149 icu_errors = [
4150 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4151 ]
4152 self.assertEqual(0, len(icu_errors))
Rainhard Findling3cde3ef02024-02-05 18:40:324153
Daniel Cheng566634ff2024-06-29 14:56:534154 # Valid changes in ICU syntax. Should not raise an error.
4155 input_api = self.makeInputApi([
4156 MockAffectedFile('test.grd',
4157 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK3,
4158 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4159 action='M'),
4160 MockAffectedFile('part.grdp',
4161 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK3,
4162 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4163 action='M')
4164 ])
4165 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4166 # We expect no ICU syntax errors.
4167 icu_errors = [
4168 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4169 ]
4170 self.assertEqual(0, len(icu_errors))
Rainhard Findlingfc31844c52020-05-15 09:58:264171
Daniel Cheng566634ff2024-06-29 14:56:534172 # Add invalid ICU syntax strings. Should raise two errors.
4173 input_api = self.makeInputApi([
4174 MockAffectedFile('test.grd',
4175 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4176 self.NEW_GRD_CONTENTS1,
4177 action='M'),
4178 MockAffectedFile('part.grdp',
4179 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4180 self.NEW_GRD_CONTENTS1,
4181 action='M')
4182 ])
4183 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4184 # We expect 2 ICU syntax errors.
4185 icu_errors = [
4186 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4187 ]
4188 self.assertEqual(1, len(icu_errors))
4189 self.assertEqual([
4190 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4191 'ICU syntax.',
4192 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4193 ], icu_errors[0].items)
4194
4195 # Change two strings to have ICU syntax errors. Should raise two errors.
4196 input_api = self.makeInputApi([
4197 MockAffectedFile('test.grd',
4198 self.NEW_GRD_CONTENTS_ICU_SYNTAX_ERROR,
4199 self.NEW_GRD_CONTENTS_ICU_SYNTAX_OK1,
4200 action='M'),
4201 MockAffectedFile('part.grdp',
4202 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_ERROR,
4203 self.NEW_GRDP_CONTENTS_ICU_SYNTAX_OK1,
4204 action='M')
4205 ])
4206 results = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
4207 # We expect 2 ICU syntax errors.
4208 icu_errors = [
4209 e for e in results if e.message == self.ICU_SYNTAX_ERROR_MESSAGE
4210 ]
4211 self.assertEqual(1, len(icu_errors))
4212 self.assertEqual([
4213 'IDS_TEST1: This message looks like an ICU plural, but does not follow '
4214 'ICU syntax.',
4215 'IDS_PART_TEST1: Variant "= 1" is not valid for plural message'
4216 ], icu_errors[0].items)
Rainhard Findlingfc31844c52020-05-15 09:58:264217
Mustafa Emre Acer29bf6ac92018-07-30 21:42:144218
Mustafa Emre Acer51f2f742020-03-09 19:41:124219class TranslationExpectationsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534220 ERROR_MESSAGE_FORMAT = (
4221 "Failed to get a list of translatable grd files. "
4222 "This happens when:\n"
4223 " - One of the modified grd or grdp files cannot be parsed or\n"
4224 " - %s is not updated.\n"
4225 "Stack:\n")
4226 REPO_ROOT = os.path.join('tools', 'translation', 'testdata')
4227 # This lists all .grd files under REPO_ROOT.
4228 EXPECTATIONS = os.path.join(REPO_ROOT, "translation_expectations.pyl")
4229 # This lists all .grd files under REPO_ROOT except unlisted.grd.
4230 EXPECTATIONS_WITHOUT_UNLISTED_FILE = os.path.join(
4231 REPO_ROOT, "translation_expectations_without_unlisted_file.pyl")
Mustafa Emre Acer51f2f742020-03-09 19:41:124232
Daniel Cheng566634ff2024-06-29 14:56:534233 # Tests that the presubmit doesn't return when no grd or grdp files are
4234 # modified.
4235 def testExpectationsNoModifiedGrd(self):
4236 input_api = MockInputApi()
4237 input_api.files = [
4238 MockAffectedFile('not_used.txt',
4239 'not used',
4240 'not used',
4241 action='M')
4242 ]
4243 # Fake list of all grd files in the repo. This list is missing all grd/grdps
4244 # under tools/translation/testdata. This is OK because the presubmit won't
4245 # run in the first place since there are no modified grd/grps in input_api.
4246 grd_files = ['doesnt_exist_doesnt_matter.grd']
4247 warnings = PRESUBMIT.CheckTranslationExpectations(
4248 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4249 grd_files)
4250 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124251
Daniel Cheng566634ff2024-06-29 14:56:534252 # Tests that the list of files passed to the presubmit matches the list of
4253 # files in the expectations.
4254 def testExpectationsSuccess(self):
4255 # Mock input file list needs a grd or grdp file in order to run the
4256 # presubmit. The file itself doesn't matter.
4257 input_api = MockInputApi()
4258 input_api.files = [
4259 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4260 ]
4261 # List of all grd files in the repo.
4262 grd_files = [
4263 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4264 ]
4265 warnings = PRESUBMIT.CheckTranslationExpectations(
4266 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4267 grd_files)
4268 self.assertEqual(0, len(warnings))
Mustafa Emre Acer51f2f742020-03-09 19:41:124269
Daniel Cheng566634ff2024-06-29 14:56:534270 # Tests that the presubmit warns when a file is listed in expectations, but
4271 # does not actually exist.
4272 def testExpectationsMissingFile(self):
4273 # Mock input file list needs a grd or grdp file in order to run the
4274 # presubmit.
4275 input_api = MockInputApi()
4276 input_api.files = [
4277 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4278 ]
4279 # unlisted.grd is listed under tools/translation/testdata but is not
4280 # included in translation expectations.
4281 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4282 warnings = PRESUBMIT.CheckTranslationExpectations(
4283 input_api, MockOutputApi(), self.REPO_ROOT, self.EXPECTATIONS,
4284 grd_files)
4285 self.assertEqual(1, len(warnings))
4286 self.assertTrue(warnings[0].message.startswith(
4287 self.ERROR_MESSAGE_FORMAT % self.EXPECTATIONS))
4288 self.assertTrue(
4289 ("test.grd is listed in the translation expectations, "
4290 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124291
Daniel Cheng566634ff2024-06-29 14:56:534292 # Tests that the presubmit warns when a file is not listed in expectations but
4293 # does actually exist.
4294 def testExpectationsUnlistedFile(self):
4295 # Mock input file list needs a grd or grdp file in order to run the
4296 # presubmit.
4297 input_api = MockInputApi()
4298 input_api.files = [
4299 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4300 ]
4301 # unlisted.grd is listed under tools/translation/testdata but is not
4302 # included in translation expectations.
4303 grd_files = [
4304 'test.grd', 'unlisted.grd', 'not_translated.grd', 'internal.grd'
4305 ]
4306 warnings = PRESUBMIT.CheckTranslationExpectations(
4307 input_api, MockOutputApi(), self.REPO_ROOT,
4308 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4309 self.assertEqual(1, len(warnings))
4310 self.assertTrue(warnings[0].message.startswith(
4311 self.ERROR_MESSAGE_FORMAT %
4312 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4313 self.assertTrue(("unlisted.grd appears to be translatable "
4314 "(because it contains <file> or <message> elements), "
4315 "but is not listed in the translation expectations."
4316 ) in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124317
Daniel Cheng566634ff2024-06-29 14:56:534318 # Tests that the presubmit warns twice:
4319 # - for a non-existing file listed in expectations
4320 # - for an existing file not listed in expectations
4321 def testMultipleWarnings(self):
4322 # Mock input file list needs a grd or grdp file in order to run the
4323 # presubmit.
4324 input_api = MockInputApi()
4325 input_api.files = [
4326 MockAffectedFile('dummy.grd', 'not used', 'not used', action='M')
4327 ]
4328 # unlisted.grd is listed under tools/translation/testdata but is not
4329 # included in translation expectations.
4330 # test.grd is not listed under tools/translation/testdata but is included
4331 # in translation expectations.
4332 grd_files = ['unlisted.grd', 'not_translated.grd', 'internal.grd']
4333 warnings = PRESUBMIT.CheckTranslationExpectations(
4334 input_api, MockOutputApi(), self.REPO_ROOT,
4335 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE, grd_files)
4336 self.assertEqual(1, len(warnings))
4337 self.assertTrue(warnings[0].message.startswith(
4338 self.ERROR_MESSAGE_FORMAT %
4339 self.EXPECTATIONS_WITHOUT_UNLISTED_FILE))
4340 self.assertTrue(("unlisted.grd appears to be translatable "
4341 "(because it contains <file> or <message> elements), "
4342 "but is not listed in the translation expectations."
4343 ) in warnings[0].message)
4344 self.assertTrue(
4345 ("test.grd is listed in the translation expectations, "
4346 "but this grd file does not exist") in warnings[0].message)
Mustafa Emre Acer51f2f742020-03-09 19:41:124347
4348
Dominic Battre033531052018-09-24 15:45:344349class DISABLETypoInTest(unittest.TestCase):
4350
Daniel Cheng566634ff2024-06-29 14:56:534351 def testPositive(self):
4352 # Verify the typo "DISABLE_" instead of "DISABLED_" in various contexts
4353 # where the desire is to disable a test.
4354 tests = [
4355 # Disabled on one platform:
4356 '#if defined(OS_WIN)\n'
4357 '#define MAYBE_FoobarTest DISABLE_FoobarTest\n'
4358 '#else\n'
4359 '#define MAYBE_FoobarTest FoobarTest\n'
4360 '#endif\n',
4361 # Disabled on one platform spread cross lines:
4362 '#if defined(OS_WIN)\n'
4363 '#define MAYBE_FoobarTest \\\n'
4364 ' DISABLE_FoobarTest\n'
4365 '#else\n'
4366 '#define MAYBE_FoobarTest FoobarTest\n'
4367 '#endif\n',
4368 # Disabled on all platforms:
4369 ' TEST_F(FoobarTest, DISABLE_Foo)\n{\n}',
4370 # Disabled on all platforms but multiple lines
4371 ' TEST_F(FoobarTest,\n DISABLE_foo){\n}\n',
4372 ]
Dominic Battre033531052018-09-24 15:45:344373
Daniel Cheng566634ff2024-06-29 14:56:534374 for test in tests:
4375 mock_input_api = MockInputApi()
4376 mock_input_api.files = [
4377 MockFile('some/path/foo_unittest.cc', test.splitlines()),
4378 ]
Dominic Battre033531052018-09-24 15:45:344379
Daniel Cheng566634ff2024-06-29 14:56:534380 results = PRESUBMIT.CheckNoDISABLETypoInTests(
4381 mock_input_api, MockOutputApi())
4382 self.assertEqual(
4383 1,
4384 len(results),
4385 msg=('expected len(results) == 1 but got %d in test: %s' %
4386 (len(results), test)))
4387 self.assertTrue(
4388 'foo_unittest.cc' in results[0].message,
4389 msg=(
4390 'expected foo_unittest.cc in message but got %s in test %s'
4391 % (results[0].message, test)))
Dominic Battre033531052018-09-24 15:45:344392
Daniel Cheng566634ff2024-06-29 14:56:534393 def testIgnoreNotTestFiles(self):
4394 mock_input_api = MockInputApi()
4395 mock_input_api.files = [
4396 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, DISABLE_Foo)'),
4397 ]
Dominic Battre033531052018-09-24 15:45:344398
Daniel Cheng566634ff2024-06-29 14:56:534399 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4400 MockOutputApi())
4401 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344402
Daniel Cheng566634ff2024-06-29 14:56:534403 def testIgnoreDeletedFiles(self):
4404 mock_input_api = MockInputApi()
4405 mock_input_api.files = [
4406 MockFile('some/path/foo.cc', 'TEST_F(FoobarTest, Foo)',
4407 action='D'),
4408 ]
Katie Df13948e2018-09-25 07:33:444409
Daniel Cheng566634ff2024-06-29 14:56:534410 results = PRESUBMIT.CheckNoDISABLETypoInTests(mock_input_api,
4411 MockOutputApi())
4412 self.assertEqual(0, len(results))
Dominic Battre033531052018-09-24 15:45:344413
Nina Satragnof7660532021-09-20 18:03:354414class ForgettingMAYBEInTests(unittest.TestCase):
Nina Satragnof7660532021-09-20 18:03:354415
Daniel Cheng566634ff2024-06-29 14:56:534416 def testPositive(self):
4417 test = ('#if defined(HAS_ENERGY)\n'
4418 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4419 '#else\n'
4420 '#define MAYBE_CastExplosion CastExplosion\n'
4421 '#endif\n'
4422 'TEST_F(ArchWizard, CastExplosion) {\n'
4423 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4424 '#define MAYBE_ArchPriest ArchPriest\n'
4425 '#else\n'
4426 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4427 '#endif\n'
4428 'TEST_F(ArchPriest, CastNaturesBounty) {\n'
4429 '#if !defined(CRUSADER_IN_PARTY)\n'
4430 '#define MAYBE_Crusader \\\n'
4431 ' DISABLED_Crusader \n'
4432 '#else\n'
4433 '#define MAYBE_Crusader \\\n'
4434 ' Crusader\n'
4435 '#endif\n'
4436 ' TEST_F(\n'
4437 ' Crusader,\n'
4438 ' CastTaunt) { }\n'
4439 '#if defined(LEARNED_BASIC_SKILLS)\n'
4440 '#define MAYBE_CastSteal \\\n'
4441 ' DISABLED_CastSteal \n'
4442 '#else\n'
4443 '#define MAYBE_CastSteal \\\n'
4444 ' CastSteal\n'
4445 '#endif\n'
4446 ' TEST_F(\n'
4447 ' ThiefClass,\n'
4448 ' CastSteal) { }\n')
4449 mock_input_api = MockInputApi()
4450 mock_input_api.files = [
4451 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4452 ]
4453 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4454 mock_input_api, MockOutputApi())
4455 self.assertEqual(4, len(results))
4456 self.assertTrue('CastExplosion' in results[0].message)
4457 self.assertTrue(
4458 'fantasyworld/classes_unittest.cc:2' in results[0].message)
4459 self.assertTrue('ArchPriest' in results[1].message)
4460 self.assertTrue(
4461 'fantasyworld/classes_unittest.cc:8' in results[1].message)
4462 self.assertTrue('Crusader' in results[2].message)
4463 self.assertTrue(
4464 'fantasyworld/classes_unittest.cc:14' in results[2].message)
4465 self.assertTrue('CastSteal' in results[3].message)
4466 self.assertTrue(
4467 'fantasyworld/classes_unittest.cc:24' in results[3].message)
Nina Satragnof7660532021-09-20 18:03:354468
Daniel Cheng566634ff2024-06-29 14:56:534469 def testNegative(self):
4470 test = ('#if defined(HAS_ENERGY)\n'
4471 '#define MAYBE_CastExplosion DISABLED_CastExplosion\n'
4472 '#else\n'
4473 '#define MAYBE_CastExplosion CastExplosion\n'
4474 '#endif\n'
4475 'TEST_F(ArchWizard, MAYBE_CastExplosion) {\n'
4476 '#if defined(ARCH_PRIEST_IN_PARTY)\n'
4477 '#define MAYBE_ArchPriest ArchPriest\n'
4478 '#else\n'
4479 '#define MAYBE_ArchPriest DISABLED_ArchPriest\n'
4480 '#endif\n'
4481 'TEST_F(MAYBE_ArchPriest, CastNaturesBounty) {\n'
4482 '#if !defined(CRUSADER_IN_PARTY)\n'
4483 '#define MAYBE_Crusader \\\n'
4484 ' DISABLED_Crusader \n'
4485 '#else\n'
4486 '#define MAYBE_Crusader \\\n'
4487 ' Crusader\n'
4488 '#endif\n'
4489 ' TEST_F(\n'
4490 ' MAYBE_Crusader,\n'
4491 ' CastTaunt) { }\n'
4492 '#if defined(LEARNED_BASIC_SKILLS)\n'
4493 '#define MAYBE_CastSteal \\\n'
4494 ' DISABLED_CastSteal \n'
4495 '#else\n'
4496 '#define MAYBE_CastSteal \\\n'
4497 ' CastSteal\n'
4498 '#endif\n'
4499 ' TEST_F(\n'
4500 ' ThiefClass,\n'
4501 ' MAYBE_CastSteal) { }\n')
4502
4503 mock_input_api = MockInputApi()
4504 mock_input_api.files = [
4505 MockFile('fantasyworld/classes_unittest.cc', test.splitlines()),
4506 ]
4507 results = PRESUBMIT.CheckForgettingMAYBEInTests(
4508 mock_input_api, MockOutputApi())
4509 self.assertEqual(0, len(results))
Dirk Pranke3c18a382019-03-15 01:07:514510
Max Morozb47503b2019-08-08 21:03:274511class CheckFuzzTargetsTest(unittest.TestCase):
4512
Daniel Cheng566634ff2024-06-29 14:56:534513 def _check(self, files):
4514 mock_input_api = MockInputApi()
4515 mock_input_api.files = []
4516 for fname, contents in files.items():
4517 mock_input_api.files.append(MockFile(fname, contents.splitlines()))
4518 return PRESUBMIT.CheckFuzzTargetsOnUpload(mock_input_api,
4519 MockOutputApi())
Max Morozb47503b2019-08-08 21:03:274520
Daniel Cheng566634ff2024-06-29 14:56:534521 def testLibFuzzerSourcesIgnored(self):
4522 results = self._check({
4523 "third_party/lib/Fuzzer/FuzzerDriver.cpp":
4524 "LLVMFuzzerInitialize",
4525 })
4526 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274527
Daniel Cheng566634ff2024-06-29 14:56:534528 def testNonCodeFilesIgnored(self):
4529 results = self._check({
4530 "README.md": "LLVMFuzzerInitialize",
4531 })
4532 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274533
Daniel Cheng566634ff2024-06-29 14:56:534534 def testNoErrorHeaderPresent(self):
4535 results = self._check({
4536 "fuzzer.cc":
4537 ("#include \"testing/libfuzzer/libfuzzer_exports.h\"\n" +
4538 "LLVMFuzzerInitialize")
4539 })
4540 self.assertEqual(results, [])
Max Morozb47503b2019-08-08 21:03:274541
Daniel Cheng566634ff2024-06-29 14:56:534542 def testErrorMissingHeader(self):
4543 results = self._check({"fuzzer.cc": "LLVMFuzzerInitialize"})
4544 self.assertEqual(len(results), 1)
4545 self.assertEqual(results[0].items, ['fuzzer.cc'])
Max Morozb47503b2019-08-08 21:03:274546
4547
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264548class SetNoParentTest(unittest.TestCase):
John Abd-El-Malekdfd1edc2021-02-24 22:22:404549
Daniel Cheng566634ff2024-06-29 14:56:534550 def testSetNoParentTopLevelAllowed(self):
4551 mock_input_api = MockInputApi()
4552 mock_input_api.files = [
4553 MockAffectedFile('goat/OWNERS', [
4554 'set noparent',
4555 'jochen@chromium.org',
4556 ])
4557 ]
4558 mock_output_api = MockOutputApi()
4559 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4560 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264561
Daniel Cheng566634ff2024-06-29 14:56:534562 def testSetNoParentMissing(self):
4563 mock_input_api = MockInputApi()
4564 mock_input_api.files = [
4565 MockAffectedFile('services/goat/OWNERS', [
4566 'set noparent',
4567 'jochen@chromium.org',
4568 'per-file *.json=set noparent',
4569 'per-file *.json=jochen@chromium.org',
4570 ])
4571 ]
4572 mock_output_api = MockOutputApi()
4573 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4574 self.assertEqual(1, len(errors))
4575 self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
4576 self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
4577
4578 def testSetNoParentWithCorrectRule(self):
4579 mock_input_api = MockInputApi()
4580 mock_input_api.files = [
4581 MockAffectedFile('services/goat/OWNERS', [
4582 'set noparent',
4583 'file://ipc/SECURITY_OWNERS',
4584 'per-file *.json=set noparent',
4585 'per-file *.json=file://ipc/SECURITY_OWNERS',
4586 ])
4587 ]
4588 mock_output_api = MockOutputApi()
4589 errors = PRESUBMIT.CheckSetNoParent(mock_input_api, mock_output_api)
4590 self.assertEqual([], errors)
Jochen Eisingerf9fbe7b6c32019-11-18 09:37:264591
4592
Ken Rockotc31f4832020-05-29 18:58:514593class MojomStabilityCheckTest(unittest.TestCase):
Ken Rockotc31f4832020-05-29 18:58:514594
Daniel Cheng566634ff2024-06-29 14:56:534595 def runTestWithAffectedFiles(self, affected_files):
4596 mock_input_api = MockInputApi()
4597 mock_input_api.files = affected_files
4598 mock_output_api = MockOutputApi()
4599 return PRESUBMIT.CheckStableMojomChanges(mock_input_api,
4600 mock_output_api)
Ken Rockotc31f4832020-05-29 18:58:514601
Daniel Cheng566634ff2024-06-29 14:56:534602 def testSafeChangePasses(self):
4603 errors = self.runTestWithAffectedFiles([
4604 MockAffectedFile(
4605 'foo/foo.mojom',
4606 ['[Stable] struct S { [MinVersion=1] int32 x; };'],
4607 old_contents=['[Stable] struct S {};'])
4608 ])
4609 self.assertEqual([], errors)
Ken Rockotc31f4832020-05-29 18:58:514610
Daniel Cheng566634ff2024-06-29 14:56:534611 def testBadChangeFails(self):
4612 errors = self.runTestWithAffectedFiles([
4613 MockAffectedFile('foo/foo.mojom',
4614 ['[Stable] struct S { int32 x; };'],
4615 old_contents=['[Stable] struct S {};'])
4616 ])
4617 self.assertEqual(1, len(errors))
4618 self.assertTrue('not backward-compatible' in errors[0].message)
4619
4620 def testDeletedFile(self):
4621 """Regression test for https://crbug.com/1091407."""
4622 errors = self.runTestWithAffectedFiles([
4623 MockAffectedFile('a.mojom', [],
4624 old_contents=['struct S {};'],
4625 action='D'),
4626 MockAffectedFile(
4627 'b.mojom', ['struct S {}; struct T { S s; };'],
4628 old_contents=['import "a.mojom"; struct T { S s; };'])
4629 ])
4630 self.assertEqual([], errors)
4631
Ken Rockotad7901f942020-06-04 20:17:094632
Jose Magana2b456f22021-03-09 23:26:404633class CheckForUseOfChromeAppsDeprecationsTest(unittest.TestCase):
4634
Daniel Cheng566634ff2024-06-29 14:56:534635 ERROR_MSG_PIECE = 'technologies which will soon be deprecated'
Jose Magana2b456f22021-03-09 23:26:404636
Daniel Cheng566634ff2024-06-29 14:56:534637 # Each positive test is also a naive negative test for the other cases.
Jose Magana2b456f22021-03-09 23:26:404638
Daniel Cheng566634ff2024-06-29 14:56:534639 def testWarningNMF(self):
4640 mock_input_api = MockInputApi()
4641 mock_input_api.files = [
4642 MockAffectedFile(
4643 'foo.NMF', ['"program"', '"Z":"content"', 'B'],
4644 ['"program"', 'B'],
4645 scm_diff='\n'.join([
4646 '--- foo.NMF.old 2020-12-02 20:40:54.430676385 +0100',
4647 '+++ foo.NMF.new 2020-12-02 20:41:02.086700197 +0100',
4648 '@@ -1,2 +1,3 @@', ' "program"', '+"Z":"content"', ' B'
4649 ]),
4650 action='M')
4651 ]
4652 mock_output_api = MockOutputApi()
4653 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4654 mock_input_api, mock_output_api)
4655 self.assertEqual(1, len(errors))
4656 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4657 self.assertTrue('foo.NMF' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404658
Daniel Cheng566634ff2024-06-29 14:56:534659 def testWarningManifest(self):
4660 mock_input_api = MockInputApi()
4661 mock_input_api.files = [
4662 MockAffectedFile(
4663 'manifest.json', ['"app":', '"Z":"content"', 'B'],
4664 ['"app":"', 'B'],
4665 scm_diff='\n'.join([
4666 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4667 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4668 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4669 ]),
4670 action='M')
4671 ]
4672 mock_output_api = MockOutputApi()
4673 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4674 mock_input_api, mock_output_api)
4675 self.assertEqual(1, len(errors))
4676 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4677 self.assertTrue('manifest.json' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404678
Daniel Cheng566634ff2024-06-29 14:56:534679 def testOKWarningManifestWithoutApp(self):
4680 mock_input_api = MockInputApi()
4681 mock_input_api.files = [
4682 MockAffectedFile(
4683 'manifest.json', ['"name":', '"Z":"content"', 'B'],
4684 ['"name":"', 'B'],
4685 scm_diff='\n'.join([
4686 '--- manifest.json.old 2020-12-02 20:40:54.430676385 +0100',
4687 '+++ manifest.json.new 2020-12-02 20:41:02.086700197 +0100',
4688 '@@ -1,2 +1,3 @@', ' "app"', '+"Z":"content"', ' B'
4689 ]),
4690 action='M')
4691 ]
4692 mock_output_api = MockOutputApi()
4693 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4694 mock_input_api, mock_output_api)
4695 self.assertEqual(0, len(errors))
Jose Magana2b456f22021-03-09 23:26:404696
Daniel Cheng566634ff2024-06-29 14:56:534697 def testWarningPPAPI(self):
4698 mock_input_api = MockInputApi()
4699 mock_input_api.files = [
4700 MockAffectedFile(
4701 'foo.hpp', ['A', '#include <ppapi.h>', 'B'], ['A', 'B'],
4702 scm_diff='\n'.join([
4703 '--- foo.hpp.old 2020-12-02 20:40:54.430676385 +0100',
4704 '+++ foo.hpp.new 2020-12-02 20:41:02.086700197 +0100',
4705 '@@ -1,2 +1,3 @@', ' A', '+#include <ppapi.h>', ' B'
4706 ]),
4707 action='M')
4708 ]
4709 mock_output_api = MockOutputApi()
4710 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4711 mock_input_api, mock_output_api)
4712 self.assertEqual(1, len(errors))
4713 self.assertTrue(self.ERROR_MSG_PIECE in errors[0].message)
4714 self.assertTrue('foo.hpp' in errors[0].message)
Jose Magana2b456f22021-03-09 23:26:404715
Daniel Cheng566634ff2024-06-29 14:56:534716 def testNoWarningPPAPI(self):
4717 mock_input_api = MockInputApi()
4718 mock_input_api.files = [
4719 MockAffectedFile(
4720 'foo.txt', ['A', 'Peppapig', 'B'], ['A', 'B'],
4721 scm_diff='\n'.join([
4722 '--- foo.txt.old 2020-12-02 20:40:54.430676385 +0100',
4723 '+++ foo.txt.new 2020-12-02 20:41:02.086700197 +0100',
4724 '@@ -1,2 +1,3 @@', ' A', '+Peppapig', ' B'
4725 ]),
4726 action='M')
4727 ]
4728 mock_output_api = MockOutputApi()
4729 errors = PRESUBMIT.CheckForUseOfChromeAppsDeprecations(
4730 mock_input_api, mock_output_api)
4731 self.assertEqual(0, len(errors))
4732
Jose Magana2b456f22021-03-09 23:26:404733
Dominic Battre645d42342020-12-04 16:14:104734class CheckDeprecationOfPreferencesTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:534735 # Test that a warning is generated if a preference registration is removed
4736 # from a random file.
4737 def testWarning(self):
4738 mock_input_api = MockInputApi()
4739 mock_input_api.files = [
4740 MockAffectedFile(
4741 'foo.cc', ['A', 'B'],
4742 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4743 scm_diff='\n'.join([
4744 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4745 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4746 '@@ -1,3 +1,2 @@', ' A',
4747 '-prefs->RegisterStringPref("foo", "default");', ' B'
4748 ]),
4749 action='M')
4750 ]
4751 mock_output_api = MockOutputApi()
4752 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4753 mock_input_api, mock_output_api)
4754 self.assertEqual(1, len(errors))
4755 self.assertTrue(
4756 'Discovered possible removal of preference registrations' in
4757 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104758
Daniel Cheng566634ff2024-06-29 14:56:534759 # Test that a warning is inhibited if the preference registration was moved
4760 # to the deprecation functions in browser prefs.
4761 def testNoWarningForMigration(self):
4762 mock_input_api = MockInputApi()
4763 mock_input_api.files = [
4764 # RegisterStringPref was removed from foo.cc.
4765 MockAffectedFile(
4766 'foo.cc', ['A', 'B'],
4767 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4768 scm_diff='\n'.join([
4769 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4770 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4771 '@@ -1,3 +1,2 @@', ' A',
4772 '-prefs->RegisterStringPref("foo", "default");', ' B'
4773 ]),
4774 action='M'),
4775 # But the preference was properly migrated.
4776 MockAffectedFile(
4777 'chrome/browser/prefs/browser_prefs.cc', [
4778 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4779 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4780 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4781 'prefs->RegisterStringPref("foo", "default");',
4782 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4783 ], [
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 scm_diff='\n'.join([
4790 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4791 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4792 '@@ -2,3 +2,4 @@',
4793 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4794 ' // BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4795 '+prefs->RegisterStringPref("foo", "default");',
4796 ' // END_MIGRATE_OBSOLETE_PROFILE_PREFS'
4797 ]),
4798 action='M'),
4799 ]
4800 mock_output_api = MockOutputApi()
4801 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4802 mock_input_api, mock_output_api)
4803 self.assertEqual(0, len(errors))
Dominic Battre645d42342020-12-04 16:14:104804
Daniel Cheng566634ff2024-06-29 14:56:534805 # Test that a warning is NOT inhibited if the preference registration was
4806 # moved to a place outside of the migration functions in browser_prefs.cc
4807 def testWarningForImproperMigration(self):
4808 mock_input_api = MockInputApi()
4809 mock_input_api.files = [
4810 # RegisterStringPref was removed from foo.cc.
4811 MockAffectedFile(
4812 'foo.cc', ['A', 'B'],
4813 ['A', 'prefs->RegisterStringPref("foo", "default");', 'B'],
4814 scm_diff='\n'.join([
4815 '--- foo.cc.old 2020-12-02 20:40:54.430676385 +0100',
4816 '+++ foo.cc.new 2020-12-02 20:41:02.086700197 +0100',
4817 '@@ -1,3 +1,2 @@', ' A',
4818 '-prefs->RegisterStringPref("foo", "default");', ' B'
4819 ]),
4820 action='M'),
4821 # The registration call was moved to a place in browser_prefs.cc that
4822 # is outside the migration functions.
4823 MockAffectedFile(
4824 'chrome/browser/prefs/browser_prefs.cc', [
4825 'prefs->RegisterStringPref("foo", "default");',
4826 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4827 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4828 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4829 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4830 ], [
4831 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4832 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4833 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4834 '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4835 ],
4836 scm_diff='\n'.join([
4837 '--- browser_prefs.cc.old 2020-12-02 20:51:40.812686731 +0100',
4838 '+++ browser_prefs.cc.new 2020-12-02 20:52:02.936755539 +0100',
4839 '@@ -1,2 +1,3 @@',
4840 '+prefs->RegisterStringPref("foo", "default");',
4841 ' // BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4842 ' // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS'
4843 ]),
4844 action='M'),
4845 ]
4846 mock_output_api = MockOutputApi()
4847 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4848 mock_input_api, mock_output_api)
4849 self.assertEqual(1, len(errors))
4850 self.assertTrue(
4851 'Discovered possible removal of preference registrations' in
4852 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104853
Daniel Cheng566634ff2024-06-29 14:56:534854 # Check that the presubmit fails if a marker line in browser_prefs.cc is
4855 # deleted.
4856 def testDeletedMarkerRaisesError(self):
4857 mock_input_api = MockInputApi()
4858 mock_input_api.files = [
4859 MockAffectedFile(
4860 'chrome/browser/prefs/browser_prefs.cc',
4861 [
4862 '// BEGIN_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4863 '// END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS',
4864 '// BEGIN_MIGRATE_OBSOLETE_PROFILE_PREFS',
4865 # The following line is deleted for this test
4866 # '// END_MIGRATE_OBSOLETE_PROFILE_PREFS',
4867 ])
4868 ]
4869 mock_output_api = MockOutputApi()
4870 errors = PRESUBMIT.CheckDeprecationOfPreferences(
4871 mock_input_api, mock_output_api)
4872 self.assertEqual(1, len(errors))
4873 self.assertEqual(
4874 'Broken .*MIGRATE_OBSOLETE_.*_PREFS markers in browser_prefs.cc.',
4875 errors[0].message)
Dominic Battre645d42342020-12-04 16:14:104876
Sven Zheng76a79ea2022-12-21 21:25:244877class CheckCrosApiNeedBrowserTestTest(unittest.TestCase):
4878 def testWarning(self):
4879 mock_input_api = MockInputApi()
4880 mock_output_api = MockOutputApi()
4881 mock_input_api.files = [
4882 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4883 ]
4884 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4885 self.assertEqual(1, len(result))
4886 self.assertEqual(result[0].type, 'warning')
4887
4888 def testNoWarningWithBrowserTest(self):
4889 mock_input_api = MockInputApi()
4890 mock_output_api = MockOutputApi()
4891 mock_input_api.files = [
4892 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='A'),
4893 MockAffectedFile('chrome/example_browsertest.cc', [], action='A'),
4894 ]
4895 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4896 self.assertEqual(0, len(result))
4897
4898 def testNoWarningModifyCrosapi(self):
4899 mock_input_api = MockInputApi()
4900 mock_output_api = MockOutputApi()
4901 mock_input_api.files = [
4902 MockAffectedFile('chromeos/crosapi/mojom/example.mojom', [], action='M'),
4903 ]
4904 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4905 self.assertEqual(0, len(result))
4906
4907 def testNoWarningAddNonMojomFile(self):
4908 mock_input_api = MockInputApi()
4909 mock_output_api = MockOutputApi()
4910 mock_input_api.files = [
4911 MockAffectedFile('chromeos/crosapi/mojom/example.cc', [], action='A'),
4912 ]
4913 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4914 self.assertEqual(0, len(result))
4915
4916 def testNoWarningNoneRelatedMojom(self):
4917 mock_input_api = MockInputApi()
4918 mock_output_api = MockOutputApi()
4919 mock_input_api.files = [
4920 MockAffectedFile('random/folder/example.mojom', [], action='A'),
4921 ]
4922 result = PRESUBMIT.CheckCrosApiNeedBrowserTest(mock_input_api, mock_output_api)
4923 self.assertEqual(0, len(result))
4924
4925
Henrique Ferreiro2a4b55942021-11-29 23:45:364926class AssertAshOnlyCodeTest(unittest.TestCase):
4927 def testErrorsOnlyOnAshDirectories(self):
4928 files_in_ash = [
4929 MockFile('ash/BUILD.gn', []),
4930 MockFile('chrome/browser/ash/BUILD.gn', []),
4931 ]
4932 other_files = [
4933 MockFile('chrome/browser/BUILD.gn', []),
4934 MockFile('chrome/browser/BUILD.gn', ['assert(is_chromeos_ash)']),
4935 ]
4936 input_api = MockInputApi()
4937 input_api.files = files_in_ash
4938 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4939 self.assertEqual(2, len(errors))
4940
4941 input_api.files = other_files
4942 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4943 self.assertEqual(0, len(errors))
4944
4945 def testDoesNotErrorOnNonGNFiles(self):
4946 input_api = MockInputApi()
4947 input_api.files = [
4948 MockFile('ash/test.h', ['assert(is_chromeos_ash)']),
4949 MockFile('chrome/browser/ash/test.cc',
4950 ['assert(is_chromeos_ash)']),
4951 ]
4952 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4953 self.assertEqual(0, len(errors))
4954
Giovanni Ortuño Urquidiab84da62021-12-10 00:53:214955 def testDeletedFile(self):
4956 input_api = MockInputApi()
4957 input_api.files = [
4958 MockFile('ash/BUILD.gn', []),
4959 MockFile('ash/foo/BUILD.gn', [], action='D'),
4960 ]
4961 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4962 self.assertEqual(1, len(errors))
4963
Henrique Ferreiro2a4b55942021-11-29 23:45:364964 def testDoesNotErrorWithAssertion(self):
4965 input_api = MockInputApi()
4966 input_api.files = [
4967 MockFile('ash/BUILD.gn', ['assert(is_chromeos_ash)']),
4968 MockFile('chrome/browser/ash/BUILD.gn',
4969 ['assert(is_chromeos_ash)']),
4970 MockFile('chrome/browser/ash/BUILD.gn',
4971 ['assert(is_chromeos_ash, "test")']),
4972 ]
4973 errors = PRESUBMIT.CheckAssertAshOnlyCode(input_api, MockOutputApi())
4974 self.assertEqual(0, len(errors))
4975
4976
Lukasz Anforowicz7016d05e2021-11-30 03:56:274977class CheckRawPtrUsageTest(unittest.TestCase):
Lukasz Anforowicz7016d05e2021-11-30 03:56:274978
Daniel Cheng566634ff2024-06-29 14:56:534979 def testAllowedCases(self):
4980 mock_input_api = MockInputApi()
4981 mock_input_api.files = [
4982 # Browser-side files are allowed.
4983 MockAffectedFile('test10/browser/foo.h', ['raw_ptr<int>']),
4984 MockAffectedFile('test11/browser/foo.cc', ['raw_ptr<int>']),
4985 MockAffectedFile('test12/blink/common/foo.cc', ['raw_ptr<int>']),
4986 MockAffectedFile('test13/blink/public/common/foo.cc',
4987 ['raw_ptr<int>']),
4988 MockAffectedFile('test14/blink/public/platform/foo.cc',
4989 ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274990
Daniel Cheng566634ff2024-06-29 14:56:534991 # Non-C++ files are allowed.
4992 MockAffectedFile('test20/renderer/foo.md', ['raw_ptr<int>']),
Lukasz Anforowicz7016d05e2021-11-30 03:56:274993
Daniel Cheng566634ff2024-06-29 14:56:534994 # Renderer code is generally allowed (except specifically
4995 # disallowed directories).
4996 MockAffectedFile('test30/renderer/foo.cc', ['raw_ptr<int>']),
4997 ]
4998 mock_output_api = MockOutputApi()
4999 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
5000 self.assertFalse(errors)
5001
5002 def testDisallowedCases(self):
5003 mock_input_api = MockInputApi()
5004 mock_input_api.files = [
5005 MockAffectedFile('test1/third_party/blink/renderer/core/foo.h',
5006 ['raw_ptr<int>']),
5007 MockAffectedFile(
5008 'test2/third_party/blink/renderer/platform/heap/foo.cc',
5009 ['raw_ptr<int>']),
5010 MockAffectedFile(
5011 'test3/third_party/blink/renderer/platform/wtf/foo.cc',
5012 ['raw_ptr<int>']),
5013 MockAffectedFile(
5014 'test4/third_party/blink/renderer/platform/fonts/foo.h',
5015 ['raw_ptr<int>']),
5016 MockAffectedFile(
5017 'test5/third_party/blink/renderer/core/paint/foo.cc',
5018 ['raw_ptr<int>']),
5019 MockAffectedFile(
5020 'test6/third_party/blink/renderer/platform/graphics/compositing/foo.h',
5021 ['raw_ptr<int>']),
5022 MockAffectedFile(
5023 'test7/third_party/blink/renderer/platform/graphics/paint/foo.cc',
5024 ['raw_ptr<int>']),
5025 ]
5026 mock_output_api = MockOutputApi()
5027 errors = PRESUBMIT.CheckRawPtrUsage(mock_input_api, mock_output_api)
5028 self.assertEqual(len(mock_input_api.files), len(errors))
5029 for error in errors:
5030 self.assertTrue(
5031 'raw_ptr<T> should not be used in this renderer code' in
5032 error.message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275033
mikt9337567c2023-09-08 18:38:175034class CheckAdvancedMemorySafetyChecksUsageTest(unittest.TestCase):
mikt9337567c2023-09-08 18:38:175035
Daniel Cheng566634ff2024-06-29 14:56:535036 def testAllowedCases(self):
5037 mock_input_api = MockInputApi()
5038 mock_input_api.files = [
5039 # Non-C++ files are allowed.
5040 MockAffectedFile('test20/renderer/foo.md',
5041 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
mikt9337567c2023-09-08 18:38:175042
Daniel Cheng566634ff2024-06-29 14:56:535043 # Mentions in a comment are allowed.
5044 MockAffectedFile('test30/renderer/foo.cc',
5045 ['//ADVANCED_MEMORY_SAFETY_CHECKS()']),
5046 ]
5047 mock_output_api = MockOutputApi()
5048 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5049 mock_input_api, mock_output_api)
5050 self.assertFalse(errors)
5051
5052 def testDisallowedCases(self):
5053 mock_input_api = MockInputApi()
5054 mock_input_api.files = [
5055 MockAffectedFile('test1/foo.h',
5056 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5057 MockAffectedFile('test2/foo.cc',
5058 ['ADVANCED_MEMORY_SAFETY_CHECKS()']),
5059 ]
5060 mock_output_api = MockOutputApi()
5061 errors = PRESUBMIT.CheckAdvancedMemorySafetyChecksUsage(
5062 mock_input_api, mock_output_api)
5063 self.assertEqual(1, len(errors))
5064 self.assertTrue('ADVANCED_MEMORY_SAFETY_CHECKS() macro is managed by'
5065 in errors[0].message)
Lukasz Anforowicz7016d05e2021-11-30 03:56:275066
Henrique Ferreirof9819f2e32021-11-30 13:31:565067class AssertPythonShebangTest(unittest.TestCase):
5068 def testError(self):
5069 input_api = MockInputApi()
5070 input_api.files = [
5071 MockFile('ash/test.py', ['#!/usr/bin/python']),
5072 MockFile('chrome/test.py', ['#!/usr/bin/python2']),
5073 MockFile('third_party/blink/test.py', ['#!/usr/bin/python3']),
Takuto Ikuta36976512021-11-30 23:15:275074 MockFile('empty.py', []),
Henrique Ferreirof9819f2e32021-11-30 13:31:565075 ]
5076 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5077 self.assertEqual(3, len(errors))
5078
5079 def testNonError(self):
5080 input_api = MockInputApi()
5081 input_api.files = [
5082 MockFile('chrome/browser/BUILD.gn', ['#!/usr/bin/python']),
5083 MockFile('third_party/blink/web_tests/external/test.py',
5084 ['#!/usr/bin/python2']),
5085 MockFile('third_party/test/test.py', ['#!/usr/bin/python3']),
5086 ]
5087 errors = PRESUBMIT.CheckPythonShebang(input_api, MockOutputApi())
5088 self.assertEqual(0, len(errors))
5089
Kalvin Lee4a3b79de2022-05-26 16:00:165090class VerifyDcheckParentheses(unittest.TestCase):
Kalvin Lee4a3b79de2022-05-26 16:00:165091
Daniel Cheng566634ff2024-06-29 14:56:535092 def testPermissibleUsage(self):
5093 input_api = MockInputApi()
5094 input_api.files = [
5095 MockFile('okay1.cc', ['DCHECK_IS_ON()']),
5096 MockFile('okay2.cc', ['#if DCHECK_IS_ON()']),
Kalvin Lee4a3b79de2022-05-26 16:00:165097
Daniel Cheng566634ff2024-06-29 14:56:535098 # Other constructs that aren't exactly `DCHECK_IS_ON()` do their
5099 # own thing at their own risk.
5100 MockFile('okay3.cc', ['PA_DCHECK_IS_ON']),
5101 MockFile('okay4.cc', ['#if PA_DCHECK_IS_ON']),
5102 MockFile('okay6.cc', ['PA_BUILDFLAG(PA_DCHECK_IS_ON)']),
5103 ]
5104 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5105 MockOutputApi())
5106 self.assertEqual(0, len(errors))
5107
5108 def testMissingParentheses(self):
5109 input_api = MockInputApi()
5110 input_api.files = [
5111 MockFile('bad1.cc', ['DCHECK_IS_ON']),
5112 MockFile('bad2.cc', ['#if DCHECK_IS_ON']),
5113 MockFile('bad3.cc', ['DCHECK_IS_ON && foo']),
5114 ]
5115 errors = PRESUBMIT.CheckDCHECK_IS_ONHasBraces(input_api,
5116 MockOutputApi())
5117 self.assertEqual(3, len(errors))
5118 for error in errors:
5119 self.assertRegex(error.message, r'DCHECK_IS_ON().+parentheses')
Henrique Ferreirof9819f2e32021-11-30 13:31:565120
Sam Maier4cef9242022-10-03 14:21:245121
James Shen81cc0e22022-06-15 21:10:455122class CheckBatchAnnotation(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535123 """Test the CheckBatchAnnotation presubmit check."""
James Shen81cc0e22022-06-15 21:10:455124
Daniel Cheng566634ff2024-06-29 14:56:535125 def testTruePositives(self):
5126 """Examples of when there is no @Batch or @DoNotBatch is correctly flagged.
James Shen81cc0e22022-06-15 21:10:455127"""
Daniel Cheng566634ff2024-06-29 14:56:535128 mock_input = MockInputApi()
5129 mock_input.files = [
5130 MockFile('path/OneTest.java', ['public class OneTest']),
5131 MockFile('path/TwoTest.java', ['public class TwoTest']),
5132 MockFile('path/ThreeTest.java', [
5133 '@Batch(Batch.PER_CLASS)',
5134 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5135 'public class Three {'
5136 ]),
5137 MockFile('path/FourTest.java', [
5138 '@DoNotBatch(reason = "placeholder reason 1")',
5139 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5140 'public class Four {'
5141 ]),
5142 ]
5143 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
5144 self.assertEqual(2, len(errors))
5145 self.assertEqual(2, len(errors[0].items))
5146 self.assertIn('OneTest.java', errors[0].items[0])
5147 self.assertIn('TwoTest.java', errors[0].items[1])
5148 self.assertEqual(2, len(errors[1].items))
5149 self.assertIn('ThreeTest.java', errors[1].items[0])
5150 self.assertIn('FourTest.java', errors[1].items[1])
ckitagawae8fd23b2022-06-17 15:29:385151
Daniel Cheng566634ff2024-06-29 14:56:535152 def testAnnotationsPresent(self):
5153 """Examples of when there is @Batch or @DoNotBatch is correctly flagged."""
5154 mock_input = MockInputApi()
5155 mock_input.files = [
5156 MockFile('path/OneTest.java',
5157 ['@Batch(Batch.PER_CLASS)', 'public class One {']),
5158 MockFile('path/TwoTest.java', [
5159 '@DoNotBatch(reason = "placeholder reasons.")',
5160 'public class Two {'
5161 ]),
5162 MockFile('path/ThreeTest.java', [
5163 '@Batch(Batch.PER_CLASS)',
5164 'public class Three extends BaseTestA {'
5165 ], [
5166 '@Batch(Batch.PER_CLASS)',
5167 'public class Three extends BaseTestB {'
5168 ]),
5169 MockFile('path/FourTest.java', [
5170 '@DoNotBatch(reason = "placeholder reason 1")',
5171 'public class Four extends BaseTestA {'
5172 ], [
5173 '@DoNotBatch(reason = "placeholder reason 2")',
5174 'public class Four extends BaseTestB {'
5175 ]),
5176 MockFile('path/FiveTest.java', [
5177 'import androidx.test.uiautomator.UiDevice;',
5178 'public class Five extends BaseTestA {'
5179 ], [
5180 'import androidx.test.uiautomator.UiDevice;',
5181 'public class Five extends BaseTestB {'
5182 ]),
5183 MockFile('path/SixTest.java', [
5184 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5185 'public class Six extends BaseTestA {'
5186 ], [
5187 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5188 'public class Six extends BaseTestB {'
5189 ]),
5190 MockFile('path/SevenTest.java', [
5191 'import org.robolectric.annotation.Config;',
5192 'public class Seven extends BaseTestA {'
5193 ], [
5194 'import org.robolectric.annotation.Config;',
5195 'public class Seven extends BaseTestB {'
5196 ]),
5197 MockFile(
5198 'path/OtherClass.java',
5199 ['public class OtherClass {'],
5200 ),
5201 MockFile('path/PRESUBMIT.py', [
5202 '@Batch(Batch.PER_CLASS)',
5203 '@DoNotBatch(reason = "placeholder reason)'
5204 ]),
5205 MockFile(
5206 'path/AnnotationTest.java',
5207 ['public @interface SomeAnnotation {'],
5208 ),
5209 ]
5210 errors = PRESUBMIT.CheckBatchAnnotation(mock_input, MockOutputApi())
5211 self.assertEqual(0, len(errors))
James Shen81cc0e22022-06-15 21:10:455212
Sam Maier4cef9242022-10-03 14:21:245213
5214class CheckMockAnnotation(unittest.TestCase):
5215 """Test the CheckMockAnnotation presubmit check."""
5216
5217 def testTruePositives(self):
5218 """Examples of @Mock or @Spy being used and nothing should be flagged."""
5219 mock_input = MockInputApi()
5220 mock_input.files = [
5221 MockFile('path/OneTest.java', [
5222 'import a.b.c.Bar;',
5223 'import a.b.c.Foo;',
Sam Maierb8a66a02023-10-10 13:50:555224 '@Mock public static Foo f = new Foo();',
Sam Maier4cef9242022-10-03 14:21:245225 'Mockito.mock(new Bar(a, b, c))'
5226 ]),
5227 MockFile('path/TwoTest.java', [
5228 'package x.y.z;',
5229 'import static org.mockito.Mockito.spy;',
5230 '@Spy',
5231 'public static FooBar<Baz> f;',
5232 'a = spy(Baz.class)'
5233 ]),
5234 ]
5235 errors = PRESUBMIT.CheckMockAnnotation(mock_input, MockOutputApi())
5236 self.assertEqual(1, len(errors))
5237 self.assertEqual(2, len(errors[0].items))
5238 self.assertIn('a.b.c.Bar in path/OneTest.java', errors[0].items)
5239 self.assertIn('x.y.z.Baz in path/TwoTest.java', errors[0].items)
5240
5241 def testTrueNegatives(self):
5242 """Examples of when we should not be flagging mock() or spy() calls."""
5243 mock_input = MockInputApi()
5244 mock_input.files = [
5245 MockFile('path/OneTest.java', [
5246 'package a.b.c;',
5247 'import org.chromium.base.test.BaseRobolectricTestRunner;',
5248 'Mockito.mock(Abc.class)'
5249 ]),
5250 MockFile('path/TwoTest.java', [
5251 'package a.b.c;',
5252 'import androidx.test.uiautomator.UiDevice;',
5253 'Mockito.spy(new Def())'
5254 ]),
5255 MockFile('path/ThreeTest.java', [
5256 'package a.b.c;',
5257 'import static org.mockito.Mockito.spy;',
5258 '@Spy',
5259 'public static Foo f = new Abc();',
5260 'a = spy(Foo.class)'
5261 ]),
5262 MockFile('path/FourTest.java', [
5263 'package a.b.c;',
5264 'import static org.mockito.Mockito.mock;',
5265 '@Spy',
5266 'public static Bar b = new Abc(a, b, c, d);',
5267 ' mock(new Bar(a,b,c))'
5268 ]),
5269 MockFile('path/FiveTest.java', [
5270 'package a.b.c;',
5271 '@Mock',
5272 'public static Baz<abc> b;',
Sam Maierb8a66a02023-10-10 13:50:555273 'Mockito.mock(Baz.class)'
5274 ]),
Sam Maier4cef9242022-10-03 14:21:245275 MockFile('path/SixTest.java', [
5276 'package a.b.c;',
5277 'import android.view.View;',
5278 'import java.ArrayList;',
5279 'Mockito.spy(new View())',
5280 'Mockito.mock(ArrayList.class)'
5281 ]),
Sam Maierb8a66a02023-10-10 13:50:555282 MockFile('path/SevenTest.java', [
5283 'package a.b.c;',
5284 '@Mock private static Seven s;',
5285 'Mockito.mock(Seven.class)'
5286 ]),
5287 MockFile('path/EightTest.java', [
5288 'package a.b.c;',
5289 '@Spy Eight e = new Eight2();',
5290 'Mockito.py(new Eight())'
5291 ]),
Sam Maier4cef9242022-10-03 14:21:245292 ]
5293 errors = PRESUBMIT.CheckMockAnnotation(mock_input, MockOutputApi())
5294 self.assertEqual(0, len(errors))
5295
5296
Mike Dougherty1b8be712022-10-20 00:15:135297class AssertNoJsInIosTest(unittest.TestCase):
5298 def testErrorJs(self):
5299 input_api = MockInputApi()
5300 input_api.files = [
5301 MockFile('components/feature/ios/resources/script.js', []),
5302 MockFile('ios/chrome/feature/resources/script.js', []),
5303 ]
5304 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5305 self.assertEqual(1, len(results))
5306 self.assertEqual('error', results[0].type)
5307 self.assertEqual(2, len(results[0].items))
5308
5309 def testNonError(self):
5310 input_api = MockInputApi()
5311 input_api.files = [
5312 MockFile('chrome/resources/script.js', []),
5313 MockFile('components/feature/ios/resources/script.ts', []),
5314 MockFile('ios/chrome/feature/resources/script.ts', []),
5315 MockFile('ios/web/feature/resources/script.ts', []),
5316 MockFile('ios/third_party/script.js', []),
5317 MockFile('third_party/ios/script.js', []),
5318 ]
5319 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5320 self.assertEqual(0, len(results))
5321
5322 def testExistingFilesWarningOnly(self):
5323 input_api = MockInputApi()
5324 input_api.files = [
5325 MockFile('ios/chrome/feature/resources/script.js', [], action='M'),
5326 MockFile('ios/chrome/feature/resources/script2.js', [], action='D'),
5327 ]
5328 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5329 self.assertEqual(1, len(results))
5330 self.assertEqual('warning', results[0].type)
5331 self.assertEqual(1, len(results[0].items))
5332
Mike Dougherty4d1050b2023-03-14 15:59:535333 def testMovedScriptWarningOnly(self):
5334 input_api = MockInputApi()
5335 input_api.files = [
5336 MockFile('ios/chrome/feature/resources/script.js', [], action='D'),
5337 MockFile('ios/chrome/renamed_feature/resources/script.js', [], action='A'),
5338 ]
5339 results = PRESUBMIT.CheckNoJsInIos(input_api, MockOutputApi())
5340 self.assertEqual(1, len(results))
5341 self.assertEqual('warning', results[0].type)
5342 self.assertEqual(1, len(results[0].items))
5343
Yuanqing Zhu9eef02832022-12-04 14:42:175344class CheckNoAbbreviationInPngFileNameTest(unittest.TestCase):
Yuanqing Zhu9eef02832022-12-04 14:42:175345
Daniel Cheng566634ff2024-06-29 14:56:535346 def testHasAbbreviation(self):
5347 """test png file names with abbreviation that fails the check"""
5348 input_api = MockInputApi()
5349 input_api.files = [
5350 MockFile('image_a.png', [], action='A'),
5351 MockFile('image_a_.png', [], action='A'),
5352 MockFile('image_a_name.png', [], action='A'),
5353 MockFile('chrome/ui/feature_name/resources/image_a.png', [],
5354 action='A'),
5355 MockFile('chrome/ui/feature_name/resources/image_a_.png', [],
5356 action='A'),
5357 MockFile('chrome/ui/feature_name/resources/image_a_name.png', [],
5358 action='A'),
5359 ]
5360 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5361 input_api, MockOutputApi())
5362 self.assertEqual(1, len(results))
5363 self.assertEqual('error', results[0].type)
5364 self.assertEqual(len(input_api.files), len(results[0].items))
5365
5366 def testNoAbbreviation(self):
5367 """test png file names without abbreviation that passes the check"""
5368 input_api = MockInputApi()
5369 input_api.files = [
5370 MockFile('a.png', [], action='A'),
5371 MockFile('_a.png', [], action='A'),
5372 MockFile('image.png', [], action='A'),
5373 MockFile('image_ab_.png', [], action='A'),
5374 MockFile('image_ab_name.png', [], action='A'),
5375 # These paths used to fail because `feature_a_name` matched the regex by mistake.
5376 # They should pass now because the path components ahead of the file name are ignored in the check.
5377 MockFile('chrome/ui/feature_a_name/resources/a.png', [],
5378 action='A'),
5379 MockFile('chrome/ui/feature_a_name/resources/_a.png', [],
5380 action='A'),
5381 MockFile('chrome/ui/feature_a_name/resources/image.png', [],
5382 action='A'),
5383 MockFile('chrome/ui/feature_a_name/resources/image_ab_.png', [],
5384 action='A'),
5385 MockFile('chrome/ui/feature_a_name/resources/image_ab_name.png',
5386 [],
5387 action='A'),
5388 ]
5389 results = PRESUBMIT.CheckNoAbbreviationInPngFileName(
5390 input_api, MockOutputApi())
5391 self.assertEqual(0, len(results))
Yuanqing Zhu9eef02832022-12-04 14:42:175392
Arthur Sonzogni7109bd32023-10-03 10:34:425393class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425394
Daniel Cheng566634ff2024-06-29 14:56:535395 def testError(self):
5396 """Test patch adding dangling pointers are reported"""
5397 mock_input_api = MockInputApi()
5398 mock_output_api = MockOutputApi()
5399
5400 mock_input_api.change.DescriptionText = lambda: "description"
5401 mock_input_api.files = [
5402 MockAffectedFile(
5403 local_path="foo/foo.cc",
5404 old_contents=["raw_ptr<T>"],
5405 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5406 )
5407 ]
5408 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5409 mock_output_api)
5410 self.assertEqual(len(msgs), 1)
5411 self.assertEqual(len(msgs[0].message), 10)
5412 self.assertEqual(
5413 msgs[0].message[0],
5414 "Unexpected new occurrences of `DanglingUntriaged` detected. Please",
5415 )
Arthur Sonzogni7109bd32023-10-03 10:34:425416
5417class CheckDanglingUntriagedTest(unittest.TestCase):
Arthur Sonzogni7109bd32023-10-03 10:34:425418
Daniel Cheng566634ff2024-06-29 14:56:535419 def testError(self):
5420 """Test patch adding dangling pointers are reported"""
5421 mock_input_api = MockInputApi()
5422 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425423
Daniel Cheng566634ff2024-06-29 14:56:535424 mock_input_api.change.DescriptionText = lambda: "description"
5425 mock_input_api.files = [
5426 MockAffectedFile(
5427 local_path="foo/foo.cc",
5428 old_contents=["raw_ptr<T>"],
5429 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5430 )
5431 ]
5432 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5433 mock_output_api)
5434 self.assertEqual(len(msgs), 1)
5435 self.assertTrue(
5436 ("Unexpected new occurrences of `DanglingUntriaged` detected"
5437 in msgs[0].message))
Arthur Sonzogni7109bd32023-10-03 10:34:425438
Daniel Cheng566634ff2024-06-29 14:56:535439 def testNonCppFile(self):
5440 """Test patch adding dangling pointers are not reported in non C++ files"""
5441 mock_input_api = MockInputApi()
5442 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425443
Daniel Cheng566634ff2024-06-29 14:56:535444 mock_input_api.change.DescriptionText = lambda: "description"
5445 mock_input_api.files = [
5446 MockAffectedFile(
5447 local_path="foo/README.md",
5448 old_contents=[""],
5449 new_contents=["The DanglingUntriaged annotation means"],
5450 )
5451 ]
5452 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5453 mock_output_api)
5454 self.assertEqual(len(msgs), 0)
5455
5456 def testDeveloperAcknowledgeInCommitDescription(self):
5457 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425458 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535459 mock_input_api = MockInputApi()
5460 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425461
Daniel Cheng566634ff2024-06-29 14:56:535462 mock_input_api.files = [
5463 MockAffectedFile(
5464 local_path="foo/foo.cc",
5465 old_contents=["raw_ptr<T>"],
5466 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5467 )
5468 ]
5469 mock_input_api.change.DescriptionText = lambda: (
5470 "DanglingUntriaged-notes: Sorry about this!")
5471 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5472 mock_output_api)
5473 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425474
Daniel Cheng566634ff2024-06-29 14:56:535475 def testDeveloperAcknowledgeInCommitFooter(self):
5476 """Test patch adding dangling pointers, but acknowledged by the developers
Arthur Sonzogni7109bd32023-10-03 10:34:425477 aren't reported"""
Daniel Cheng566634ff2024-06-29 14:56:535478 mock_input_api = MockInputApi()
5479 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425480
Daniel Cheng566634ff2024-06-29 14:56:535481 mock_input_api.files = [
5482 MockAffectedFile(
5483 local_path="foo/foo.cc",
5484 old_contents=["raw_ptr<T>"],
5485 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5486 )
5487 ]
5488 mock_input_api.change.DescriptionText = lambda: "description"
5489 mock_input_api.change.footers["DanglingUntriaged-notes"] = ["Sorry!"]
5490 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5491 mock_output_api)
5492 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425493
Daniel Cheng566634ff2024-06-29 14:56:535494 def testCongrats(self):
5495 """Test the presubmit congrats users removing dangling pointers"""
5496 mock_input_api = MockInputApi()
5497 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425498
Daniel Cheng566634ff2024-06-29 14:56:535499 mock_input_api.files = [
5500 MockAffectedFile(
5501 local_path="foo/foo.cc",
5502 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5503 new_contents=["raw_ptr<T>"],
5504 )
5505 ]
5506 mock_input_api.change.DescriptionText = lambda: (
5507 "This patch fixes some DanglingUntriaged pointers!")
5508 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5509 mock_output_api)
5510 self.assertEqual(len(msgs), 1)
5511 self.assertTrue(
5512 "DanglingUntriaged pointers removed: 1" in msgs[0].message)
5513 self.assertTrue("Thank you!" in msgs[0].message)
Arthur Sonzogni7109bd32023-10-03 10:34:425514
Daniel Cheng566634ff2024-06-29 14:56:535515 def testRenameFile(self):
5516 """Patch that we do not warn about DanglingUntriaged when moving files"""
5517 mock_input_api = MockInputApi()
5518 mock_output_api = MockOutputApi()
Arthur Sonzogni7109bd32023-10-03 10:34:425519
Daniel Cheng566634ff2024-06-29 14:56:535520 mock_input_api.files = [
5521 MockAffectedFile(
5522 local_path="foo/foo.cc",
5523 old_contents=["raw_ptr<T, DanglingUntriaged>"],
5524 new_contents=[""],
5525 action="D",
5526 ),
5527 MockAffectedFile(
5528 local_path="foo/foo.cc",
5529 old_contents=[""],
5530 new_contents=["raw_ptr<T, DanglingUntriaged>"],
5531 action="A",
5532 ),
5533 ]
5534 mock_input_api.change.DescriptionText = lambda: (
5535 "This patch moves files")
5536 msgs = PRESUBMIT.CheckDanglingUntriaged(mock_input_api,
5537 mock_output_api)
5538 self.assertEqual(len(msgs), 0)
Arthur Sonzogni7109bd32023-10-03 10:34:425539
Jan Keitel77be7522023-10-12 20:40:495540class CheckInlineConstexprDefinitionsInHeadersTest(unittest.TestCase):
Jan Keitel77be7522023-10-12 20:40:495541
Daniel Cheng566634ff2024-06-29 14:56:535542 def testNoInlineConstexprInHeaderFile(self):
5543 """Tests that non-inlined constexpr variables in headers fail the test."""
5544 input_api = MockInputApi()
5545 input_api.files = [
5546 MockAffectedFile('src/constants.h',
5547 ['constexpr int kVersion = 5;'])
5548 ]
5549 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5550 input_api, MockOutputApi())
5551 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495552
Daniel Cheng566634ff2024-06-29 14:56:535553 def testNoInlineConstexprInHeaderFileInitializedFromFunction(self):
5554 """Tests that non-inlined constexpr header variables that are initialized from a function fail."""
5555 input_api = MockInputApi()
5556 input_api.files = [
5557 MockAffectedFile('src/constants.h',
5558 ['constexpr int kVersion = GetVersion();'])
5559 ]
5560 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5561 input_api, MockOutputApi())
5562 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495563
Daniel Cheng566634ff2024-06-29 14:56:535564 def testNoInlineConstexprInHeaderFileInitializedWithExpression(self):
5565 """Tests that non-inlined constexpr header variables initialized with an expression fail."""
5566 input_api = MockInputApi()
5567 input_api.files = [
5568 MockAffectedFile('src/constants.h',
5569 ['constexpr int kVersion = (4 + 5)*3;'])
5570 ]
5571 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5572 input_api, MockOutputApi())
5573 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495574
Daniel Cheng566634ff2024-06-29 14:56:535575 def testNoInlineConstexprInHeaderFileBraceInitialized(self):
5576 """Tests that non-inlined constexpr header variables that are brace-initialized fail."""
5577 input_api = MockInputApi()
5578 input_api.files = [
5579 MockAffectedFile('src/constants.h', ['constexpr int kVersion{5};'])
5580 ]
5581 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5582 input_api, MockOutputApi())
5583 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495584
Daniel Cheng566634ff2024-06-29 14:56:535585 def testNoInlineConstexprInHeaderWithAttribute(self):
5586 """Tests that non-inlined constexpr header variables that have compiler attributes fail."""
5587 input_api = MockInputApi()
5588 input_api.files = [
5589 MockAffectedFile('src/constants.h',
5590 ['constexpr [[maybe_unused]] int kVersion{5};'])
5591 ]
5592 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5593 input_api, MockOutputApi())
5594 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495595
Daniel Cheng566634ff2024-06-29 14:56:535596 def testInlineConstexprInHeaderWithAttribute(self):
5597 """Tests that inlined constexpr header variables that have compiler attributes pass."""
5598 input_api = MockInputApi()
5599 input_api.files = [
5600 MockAffectedFile(
5601 'src/constants.h',
5602 ['inline constexpr [[maybe_unused]] int kVersion{5};']),
5603 MockAffectedFile(
5604 'src/constants.h',
5605 ['constexpr inline [[maybe_unused]] int kVersion{5};']),
5606 MockAffectedFile(
5607 'src/constants.h',
5608 ['inline constexpr [[maybe_unused]] inline int kVersion{5};'])
5609 ]
5610 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5611 input_api, MockOutputApi())
5612 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495613
Daniel Cheng566634ff2024-06-29 14:56:535614 def testNoInlineConstexprInHeaderFileMultipleLines(self):
5615 """Tests that non-inlined constexpr header variable definitions spanning multiple lines fail."""
5616 input_api = MockInputApi()
5617 lines = [
5618 'constexpr char kLongName =',
5619 ' "This is a very long name of something.";'
5620 ]
5621 input_api.files = [MockAffectedFile('src/constants.h', lines)]
5622 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5623 input_api, MockOutputApi())
5624 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495625
Daniel Cheng566634ff2024-06-29 14:56:535626 def testNoInlineConstexprInCCFile(self):
5627 """Tests that non-inlined constexpr variables in .cc files pass the test."""
5628 input_api = MockInputApi()
5629 input_api.files = [
5630 MockAffectedFile('src/implementation.cc',
5631 ['constexpr int kVersion = 5;'])
5632 ]
5633 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5634 input_api, MockOutputApi())
5635 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495636
Daniel Cheng566634ff2024-06-29 14:56:535637 def testInlineConstexprInHeaderFile(self):
5638 """Tests that inlined constexpr variables in header files pass the test."""
5639 input_api = MockInputApi()
5640 input_api.files = [
5641 MockAffectedFile('src/constants.h',
5642 ['constexpr inline int kX = 5;']),
5643 MockAffectedFile('src/version.h',
5644 ['inline constexpr float kY = 5.0f;'])
5645 ]
5646 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5647 input_api, MockOutputApi())
5648 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495649
Daniel Cheng566634ff2024-06-29 14:56:535650 def testConstexprStandaloneFunctionInHeaderFile(self):
5651 """Tests that non-inlined constexpr functions in headers pass the test."""
5652 input_api = MockInputApi()
5653 input_api.files = [
5654 MockAffectedFile('src/helpers.h', ['constexpr int GetVersion();'])
5655 ]
5656 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5657 input_api, MockOutputApi())
5658 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495659
Daniel Cheng566634ff2024-06-29 14:56:535660 def testConstexprWithAbseilAttributeInHeader(self):
5661 """Tests that non-inlined constexpr variables with Abseil-type prefixes in headers fail."""
5662 input_api = MockInputApi()
5663 input_api.files = [
5664 MockAffectedFile('src/helpers.h',
5665 ['ABSL_FOOFOO constexpr int i = 5;'])
5666 ]
5667 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5668 input_api, MockOutputApi())
5669 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495670
Daniel Cheng566634ff2024-06-29 14:56:535671 def testInlineConstexprWithAbseilAttributeInHeader(self):
5672 """Tests that inlined constexpr variables with Abseil-type prefixes in headers pass."""
5673 input_api = MockInputApi()
5674 input_api.files = [
5675 MockAffectedFile('src/helpers.h',
5676 ['constexpr ABSL_FOO inline int i = 5;'])
5677 ]
5678 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5679 input_api, MockOutputApi())
5680 self.assertEqual(0, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495681
Daniel Cheng566634ff2024-06-29 14:56:535682 def testConstexprWithClangAttributeInHeader(self):
5683 """Tests that non-inlined constexpr variables with attributes with colons in headers fail."""
5684 input_api = MockInputApi()
5685 input_api.files = [
5686 MockAffectedFile('src/helpers.h',
5687 ['[[clang::someattribute]] constexpr int i = 5;'])
5688 ]
5689 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5690 input_api, MockOutputApi())
5691 self.assertEqual(1, len(warnings))
Jan Keitel77be7522023-10-12 20:40:495692
Daniel Cheng566634ff2024-06-29 14:56:535693 def testInlineConstexprWithClangAttributeInHeader(self):
5694 """Tests that inlined constexpr variables with attributes with colons in headers pass."""
5695 input_api = MockInputApi()
5696 input_api.files = [
5697 MockAffectedFile(
5698 'src/helpers.h',
5699 ['constexpr [[clang::someattribute]] inline int i = 5;'])
5700 ]
5701 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5702 input_api, MockOutputApi())
5703 self.assertEqual(0, len(warnings))
Arthur Sonzogni7109bd32023-10-03 10:34:425704
Daniel Cheng566634ff2024-06-29 14:56:535705 def testNoExplicitInlineConstexprInsideClassInHeaderFile(self):
5706 """Tests that non-inlined constexpr class members pass the test."""
5707 input_api = MockInputApi()
5708 lines = [
5709 'class SomeClass {', ' public:',
5710 ' static constexpr kVersion = 5;', '};'
5711 ]
5712 input_api.files = [MockAffectedFile('src/class.h', lines)]
5713 warnings = PRESUBMIT.CheckInlineConstexprDefinitionsInHeaders(
5714 input_api, MockOutputApi())
5715 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045716
Daniel Cheng566634ff2024-06-29 14:56:535717 def testTodoBugReferencesWithOldBugId(self):
5718 """Tests that an old monorail bug ID in a TODO fails."""
5719 input_api = MockInputApi()
5720 input_api.files = [
5721 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/12345)'])
5722 ]
5723 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5724 self.assertEqual(1, len(warnings))
5725
5726 def testTodoBugReferencesWithUpdatedBugId(self):
5727 """Tests that a new issue tracker bug ID in a TODO passes."""
5728 input_api = MockInputApi()
5729 input_api.files = [
5730 MockAffectedFile('src/helpers.h', ['// TODO(crbug.com/40781525)'])
5731 ]
5732 warnings = PRESUBMIT.CheckTodoBugReferences(input_api, MockOutputApi())
5733 self.assertEqual(0, len(warnings))
Alison Galed6b25fe2024-04-17 13:59:045734
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155735class CheckDeprecatedSyncConsentFunctionsTest(unittest.TestCase):
Daniel Cheng566634ff2024-06-29 14:56:535736 """Test the presubmit for deprecated ConsentLevel::kSync functions."""
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155737
Daniel Cheng566634ff2024-06-29 14:56:535738 def testCppMobilePlatformPath(self):
5739 input_api = MockInputApi()
5740 input_api.files = [
5741 MockFile('chrome/browser/android/file.cc', ['OtherFunction']),
5742 MockFile('chrome/android/file.cc', ['HasSyncConsent']),
5743 MockFile('ios/file.mm', ['CanSyncFeatureStart']),
5744 MockFile('components/foo/ios/file.cc', ['IsSyncFeatureEnabled']),
5745 MockFile('components/foo/delegate_android.cc',
5746 ['IsSyncFeatureActive']),
5747 MockFile('components/foo/delegate_ios.cc',
5748 ['IsSyncFeatureActive']),
5749 MockFile('components/foo/android_delegate.cc',
5750 ['IsSyncFeatureActive']),
5751 MockFile('components/foo/ios_delegate.cc',
5752 ['IsSyncFeatureActive']),
5753 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155754
Daniel Cheng566634ff2024-06-29 14:56:535755 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155756
Daniel Cheng566634ff2024-06-29 14:56:535757 self.assertEqual(1, len(results))
5758 self.assertFalse(
5759 'chrome/browser/android/file.cc' in results[0].message),
5760 self.assertTrue('chrome/android/file.cc' in results[0].message),
5761 self.assertTrue('ios/file.mm' in results[0].message),
5762 self.assertTrue('components/foo/ios/file.cc' in results[0].message),
5763 self.assertTrue(
5764 'components/foo/delegate_android.cc' in results[0].message),
5765 self.assertTrue(
5766 'components/foo/delegate_ios.cc' in results[0].message),
5767 self.assertTrue(
5768 'components/foo/android_delegate.cc' in results[0].message),
5769 self.assertTrue(
5770 'components/foo/ios_delegate.cc' in results[0].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155771
Daniel Cheng566634ff2024-06-29 14:56:535772 def testCppNonMobilePlatformPath(self):
5773 input_api = MockInputApi()
5774 input_api.files = [
5775 MockFile('chrome/browser/file.cc', ['HasSyncConsent']),
5776 MockFile('bios/file.cc', ['HasSyncConsent']),
5777 MockFile('components/kiosk/file.cc', ['HasSyncConsent']),
5778 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155779
Daniel Cheng566634ff2024-06-29 14:56:535780 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155781
Daniel Cheng566634ff2024-06-29 14:56:535782 self.assertEqual(0, len(results))
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155783
Daniel Cheng566634ff2024-06-29 14:56:535784 def testJavaPath(self):
5785 input_api = MockInputApi()
5786 input_api.files = [
5787 MockFile('components/foo/file1.java', ['otherFunction']),
5788 MockFile('components/foo/file2.java', ['hasSyncConsent']),
5789 MockFile('chrome/foo/file3.java', ['canSyncFeatureStart']),
5790 MockFile('chrome/foo/file4.java', ['isSyncFeatureEnabled']),
5791 MockFile('chrome/foo/file5.java', ['isSyncFeatureActive']),
5792 ]
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155793
Daniel Cheng566634ff2024-06-29 14:56:535794 results = PRESUBMIT.CheckNoBannedFunctions(input_api, MockOutputApi())
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155795
Daniel Cheng566634ff2024-06-29 14:56:535796 self.assertEqual(1, len(results))
5797 self.assertFalse('components/foo/file1.java' in results[0].message),
5798 self.assertTrue('components/foo/file2.java' in results[0].message),
5799 self.assertTrue('chrome/foo/file3.java' in results[0].message),
5800 self.assertTrue('chrome/foo/file4.java' in results[0].message),
5801 self.assertTrue('chrome/foo/file5.java' in results[0].message),
Victor Hugo Vianna Silvadbe81542024-05-21 11:09:155802
5803
marja@chromium.org2299dcf2012-11-15 19:56:245804if __name__ == '__main__':
Daniel Cheng566634ff2024-06-29 14:56:535805 unittest.main()