-# Copyright 2014 The Chromium Authors. All rights reserved.
+# 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.
+from collections import defaultdict
import fnmatch
import json
import os
attribute as the list of changed files.
"""
- DEFAULT_BLACK_LIST = ()
+ DEFAULT_FILES_TO_SKIP = ()
def __init__(self):
self.canned_checks = MockCannedChecks()
self.os_path = os.path
self.platform = sys.platform
self.python_executable = sys.executable
+ self.python3_executable = sys.executable
self.platform = sys.platform
self.subprocess = subprocess
+ self.sys = sys
self.files = []
self.is_committing = False
self.change = MockChange([])
self.presubmit_local_path = os.path.dirname(__file__)
+ self.is_windows = sys.platform == 'win32'
+ self.no_diffs = False
+ # Although this makes assumptions about command line arguments used by test
+ # scripts that create mocks, it is a convenient way to set up the verbosity
+ # via the input api.
+ self.verbose = '--verbose' in sys.argv
def CreateMockFileInPath(self, f_list):
self.os_path.exists = lambda x: x in f_list
- def AffectedFiles(self, file_filter=None, include_deletes=False):
+ def AffectedFiles(self, file_filter=None, include_deletes=True):
for file in self.files:
if file_filter and not file_filter(file):
continue
continue
yield file
+ def RightHandSideLines(self, source_file_filter=None):
+ affected_files = self.AffectedSourceFiles(source_file_filter)
+ for af in affected_files:
+ lines = af.ChangedContents()
+ for line in lines:
+ yield (af, line[0], line[1])
+
def AffectedSourceFiles(self, file_filter=None):
return self.AffectedFiles(file_filter=file_filter)
- def FilterSourceFile(self, file, white_list=(), black_list=()):
+ def FilterSourceFile(self, file,
+ files_to_check=(), files_to_skip=()):
local_path = file.LocalPath()
- found_in_white_list = not white_list
- if white_list:
- for pattern in white_list:
+ found_in_files_to_check = not files_to_check
+ if files_to_check:
+ if type(files_to_check) is str:
+ raise TypeError('files_to_check should be an iterable of strings')
+ for pattern in files_to_check:
compiled_pattern = re.compile(pattern)
- if compiled_pattern.search(local_path):
- found_in_white_list = True
+ if compiled_pattern.match(local_path):
+ found_in_files_to_check = True
break
- if black_list:
- for pattern in black_list:
+ if files_to_skip:
+ if type(files_to_skip) is str:
+ raise TypeError('files_to_skip should be an iterable of strings')
+ for pattern in files_to_skip:
compiled_pattern = re.compile(pattern)
- if compiled_pattern.search(local_path):
+ if compiled_pattern.match(local_path):
return False
- return found_in_white_list
+ return found_in_files_to_check
def LocalPaths(self):
- return self.files
+ return [file.LocalPath() for file in self.files]
def PresubmitLocalPath(self):
return self.presubmit_local_path
- def ReadFile(self, filename, mode='rU'):
+ def ReadFile(self, filename, mode='r'):
if hasattr(filename, 'AbsoluteLocalPath'):
filename = filename.AbsoluteLocalPath()
for file_ in self.files:
if file_.LocalPath() == filename:
return '\n'.join(file_.NewContents())
# Otherwise, file is not in our mock API.
- raise IOError, "No such file or directory: '%s'" % filename
+ raise IOError("No such file or directory: '%s'" % filename)
class MockOutputApi(object):
"""Mock class for the OutputApi class.
- An instance of this class can be passed to presubmit unittests for outputing
+ An instance of this class can be passed to presubmit unittests for outputting
various types of results.
"""
self.more_cc = []
def AppendCC(self, more_cc):
- self.more_cc.extend(more_cc)
+ self.more_cc.append(more_cc)
class MockFile(object):
MockInputApi for presubmit unittests.
"""
- def __init__(self, local_path, new_contents, old_contents=None, action='A'):
+ def __init__(self, local_path, new_contents, old_contents=None, action='A',
+ scm_diff=None):
self._local_path = local_path
self._new_contents = new_contents
self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
self._action = action
- self._scm_diff = "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" % (local_path,
- len(new_contents))
+ if scm_diff:
+ self._scm_diff = scm_diff
+ else:
+ self._scm_diff = (
+ "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" %
+ (local_path, len(new_contents)))
+ for l in new_contents:
+ self._scm_diff += "+%s\n" % l
self._old_contents = old_contents
- for l in new_contents:
- self._scm_diff += "+%s\n" % l
+
+ def __str__(self):
+ return self._local_path
def Action(self):
return self._action
"""os.path.basename is called on MockFile so we need a len method."""
return len(self._local_path)
+ def replace(self, altsep, sep):
+ """os.path.basename is called on MockFile so we need a replace method."""
+ return self._local_path.replace(altsep, sep)
+
class MockAffectedFile(MockFile):
def AbsoluteLocalPath(self):
def __init__(self, changed_files):
self._changed_files = changed_files
+ self.author_email = None
+ self.footers = defaultdict(list)
def LocalPaths(self):
return self._changed_files
def AffectedFiles(self, include_dirs=False, include_deletes=True,
file_filter=None):
return self._changed_files
+
+ def GitFootersFromDescription(self):
+ return self.footers