blob: 387d0e4e82067cb17062192bac7fc1674e06cf36 [file] [log] [blame]
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Presubmit script for Chromium browser code."""
import re
# Checks whether an autofill-related browsertest fixture class inherits from
# either InProcessBrowserTest or AndroidBrowserTest without having a member of
# type `autofill::test::AutofillBrowserTestEnvironment`. In that case, the
# functions registers a presubmit warning.
def _CheckNoAutofillBrowserTestsWithoutAutofillBrowserTestEnvironment(
input_api, output_api):
autofill_files_pattern = re.compile(
r'(autofill|password_manager).*\.(mm|cc|h)')
concerned_files = [(f, input_api.ReadFile(f))
for f in input_api.AffectedFiles(include_deletes=False)
if autofill_files_pattern.search(f.LocalPath())]
warning_files = []
class_name = r'^( *)(class|struct)\s+\w+\s*:\s*'
target_base = r'[^\{]*\bpublic\s+(InProcess|Android)BrowserTest[^\{]*\{'
class_declaration_pattern = re.compile(
class_name + target_base, re.MULTILINE)
for autofill_file, file_content in concerned_files:
for class_match in re.finditer(class_declaration_pattern, file_content):
indentation = class_match.group(1)
class_end_pattern = re.compile(
r'^' + indentation + r'\};$', re.MULTILINE)
class_end = class_end_pattern.search(file_content[class_match.start():])
corresponding_subclass = (
'' if class_end is None else
file_content[
class_match.start():
class_match.start() + class_end.end()])
required_member_pattern = re.compile(
r'^' + indentation +
r' (::)?(autofill::)?test::AutofillBrowserTestEnvironment\s+\w+_;',
re.MULTILINE)
if not required_member_pattern.search(corresponding_subclass):
warning_files.append(autofill_file)
return [output_api.PresubmitPromptWarning(
'Consider adding a member autofill::test::AutofillBrowserTestEnvironment '
'to the test fixtures that derive from InProcessBrowserTest or '
'AndroidBrowserTest in order to disable kAutofillServerCommunication in '
'browser tests.',
warning_files)] if len(warning_files) else []
def _RunHistogramChecks(input_api, output_api, histogram_name):
try:
# Setup sys.path so that we can call histograms code.
import sys
original_sys_path = sys.path
sys.path = sys.path + [input_api.os_path.join(
input_api.change.RepositoryRoot(),
'tools', 'metrics', 'histograms')]
results = []
import presubmit_bad_message_reasons
results.extend(presubmit_bad_message_reasons.PrecheckBadMessage(input_api,
output_api, histogram_name))
return results
except:
return [output_api.PresubmitError('Could not verify histogram!')]
finally:
sys.path = original_sys_path
def _CheckUnwantedDependencies(input_api, output_api):
problems = []
for f in input_api.AffectedFiles():
if not f.LocalPath().endswith('DEPS'):
continue
for line_num, line in f.ChangedContents():
if not line.strip().startswith('#'):
m = re.search(r".*\/blink\/public\/web.*", line)
if m:
problems.append(m.group(0))
if not problems:
return []
return [output_api.PresubmitPromptWarning(
'chrome/browser cannot depend on blink/public/web interfaces. ' +
'Use blink/public/common instead.',
items=problems)]
def _CheckNoInteractiveUiTestLibInNonInteractiveUiTest(input_api, output_api):
"""Makes sure that ui_controls related API are used only in
interactive_in_tests.
"""
problems = []
# There are interactive tests whose name ends with `_browsertest.cc`
# or `_browser_test.cc`.
files_to_skip = ((r'.*interactive_.*test\.cc',) +
input_api.DEFAULT_FILES_TO_SKIP)
def FileFilter(affected_file):
"""Check non interactive_uitests only."""
return input_api.FilterSourceFile(
affected_file,
files_to_check=(
r'.*browsertest\.cc',
r'.*unittest\.cc'),
files_to_skip=files_to_skip)
ui_controls_includes =(
input_api.re.compile(
r'#include.*/(ui_controls.*h|interactive_test_utils.h)"'))
for f in input_api.AffectedFiles(include_deletes=False,
file_filter=FileFilter):
for line_num, line in f.ChangedContents():
m = re.search(ui_controls_includes, line)
if m:
problems.append(' %s:%d:%s' % (f.LocalPath(), line_num, m.group(0)))
if not problems:
return []
WARNING_MSG ="""
ui_controls API can be used only in interactive_ui_tests.
If the test is in the interactive_ui_tests, please consider renaming
to xxx_interactive_uitest.cc"""
return [output_api.PresubmitPromptWarning(WARNING_MSG, items=problems)]
def _CheckForUselessExterns(input_api, output_api):
"""Makes sure developers don't copy "extern const char kFoo[]" from
foo.h to foo.cc.
"""
problems = []
BAD_PATTERN = input_api.re.compile(r'^extern const')
def FileFilter(affected_file):
"""Check only a particular list of files"""
return input_api.FilterSourceFile(
affected_file,
files_to_check=[r'chrome[/\\]browser[/\\]flag_descriptions\.cc']);
for f in input_api.AffectedFiles(include_deletes=False,
file_filter=FileFilter):
for _, line in f.ChangedContents():
if BAD_PATTERN.search(line):
problems.append(f)
if not problems:
return []
WARNING_MSG ="""Do not write "extern const char" in these .cc files:"""
return [output_api.PresubmitPromptWarning(WARNING_MSG, items=problems)]
def _CommonChecks(input_api, output_api):
"""Checks common to both upload and commit."""
results = []
results.extend(
_CheckNoAutofillBrowserTestsWithoutAutofillBrowserTestEnvironment(
input_api, output_api))
results.extend(_CheckUnwantedDependencies(input_api, output_api))
results.extend(_RunHistogramChecks(input_api, output_api,
"BadMessageReasonChrome"))
results.extend(_CheckNoInteractiveUiTestLibInNonInteractiveUiTest(
input_api, output_api))
results.extend(_CheckForUselessExterns(input_api, output_api))
return results
def CheckChangeOnUpload(input_api, output_api):
return _CommonChecks(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api):
return _CommonChecks(input_api, output_api)