Upload upstream chromium 67.0.3396
[platform/framework/web/chromium-efl.git] / PRESUBMIT_test_mocks.py
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import fnmatch
6 import json
7 import os
8 import re
9 import subprocess
10 import sys
11
12 # TODO(dcheng): It's kind of horrible that this is copy and pasted from
13 # presubmit_canned_checks.py, but it's far easier than any of the alternatives.
14 def _ReportErrorFileAndLine(filename, line_num, dummy_line):
15   """Default error formatter for _FindNewViolationsOfRule."""
16   return '%s:%s' % (filename, line_num)
17
18
19 class MockCannedChecks(object):
20   def _FindNewViolationsOfRule(self, callable_rule, input_api,
21                                source_file_filter=None,
22                                error_formatter=_ReportErrorFileAndLine):
23     """Find all newly introduced violations of a per-line rule (a callable).
24
25     Arguments:
26       callable_rule: a callable taking a file extension and line of input and
27         returning True if the rule is satisfied and False if there was a
28         problem.
29       input_api: object to enumerate the affected files.
30       source_file_filter: a filter to be passed to the input api.
31       error_formatter: a callable taking (filename, line_number, line) and
32         returning a formatted error string.
33
34     Returns:
35       A list of the newly-introduced violations reported by the rule.
36     """
37     errors = []
38     for f in input_api.AffectedFiles(include_deletes=False,
39                                      file_filter=source_file_filter):
40       # For speed, we do two passes, checking first the full file.  Shelling out
41       # to the SCM to determine the changed region can be quite expensive on
42       # Win32.  Assuming that most files will be kept problem-free, we can
43       # skip the SCM operations most of the time.
44       extension = str(f.LocalPath()).rsplit('.', 1)[-1]
45       if all(callable_rule(extension, line) for line in f.NewContents()):
46         continue  # No violation found in full text: can skip considering diff.
47
48       for line_num, line in f.ChangedContents():
49         if not callable_rule(extension, line):
50           errors.append(error_formatter(f.LocalPath(), line_num, line))
51
52     return errors
53
54
55 class MockInputApi(object):
56   """Mock class for the InputApi class.
57
58   This class can be used for unittests for presubmit by initializing the files
59   attribute as the list of changed files.
60   """
61
62   DEFAULT_BLACK_LIST = ()
63
64   def __init__(self):
65     self.canned_checks = MockCannedChecks()
66     self.fnmatch = fnmatch
67     self.json = json
68     self.re = re
69     self.os_path = os.path
70     self.platform = sys.platform
71     self.python_executable = sys.executable
72     self.platform = sys.platform
73     self.subprocess = subprocess
74     self.files = []
75     self.is_committing = False
76     self.change = MockChange([])
77     self.presubmit_local_path = os.path.dirname(__file__)
78
79   def CreateMockFileInPath(self, f_list):
80     self.os_path.exists = lambda x: x in f_list
81
82   def AffectedFiles(self, file_filter=None, include_deletes=False):
83     for file in self.files:
84       if file_filter and not file_filter(file):
85         continue
86       if not include_deletes and file.Action() == 'D':
87         continue
88       yield file
89
90   def AffectedSourceFiles(self, file_filter=None):
91     return self.AffectedFiles(file_filter=file_filter)
92
93   def FilterSourceFile(self, file, white_list=(), black_list=()):
94     local_path = file.LocalPath()
95     found_in_white_list = not white_list
96     if white_list:
97       for pattern in white_list:
98         compiled_pattern = re.compile(pattern)
99         if compiled_pattern.search(local_path):
100           found_in_white_list = True
101           break
102     if black_list:
103       for pattern in black_list:
104         compiled_pattern = re.compile(pattern)
105         if compiled_pattern.search(local_path):
106           return False
107     return found_in_white_list
108
109   def LocalPaths(self):
110     return self.files
111
112   def PresubmitLocalPath(self):
113     return self.presubmit_local_path
114
115   def ReadFile(self, filename, mode='rU'):
116     if hasattr(filename, 'AbsoluteLocalPath'):
117        filename = filename.AbsoluteLocalPath()
118     for file_ in self.files:
119       if file_.LocalPath() == filename:
120         return '\n'.join(file_.NewContents())
121     # Otherwise, file is not in our mock API.
122     raise IOError, "No such file or directory: '%s'" % filename
123
124
125 class MockOutputApi(object):
126   """Mock class for the OutputApi class.
127
128   An instance of this class can be passed to presubmit unittests for outputing
129   various types of results.
130   """
131
132   class PresubmitResult(object):
133     def __init__(self, message, items=None, long_text=''):
134       self.message = message
135       self.items = items
136       self.long_text = long_text
137
138     def __repr__(self):
139       return self.message
140
141   class PresubmitError(PresubmitResult):
142     def __init__(self, message, items=None, long_text=''):
143       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
144       self.type = 'error'
145
146   class PresubmitPromptWarning(PresubmitResult):
147     def __init__(self, message, items=None, long_text=''):
148       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
149       self.type = 'warning'
150
151   class PresubmitNotifyResult(PresubmitResult):
152     def __init__(self, message, items=None, long_text=''):
153       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
154       self.type = 'notify'
155
156   class PresubmitPromptOrNotify(PresubmitResult):
157     def __init__(self, message, items=None, long_text=''):
158       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
159       self.type = 'promptOrNotify'
160
161   def __init__(self):
162     self.more_cc = []
163
164   def AppendCC(self, more_cc):
165     self.more_cc.extend(more_cc)
166
167
168 class MockFile(object):
169   """Mock class for the File class.
170
171   This class can be used to form the mock list of changed files in
172   MockInputApi for presubmit unittests.
173   """
174
175   def __init__(self, local_path, new_contents, old_contents=None, action='A'):
176     self._local_path = local_path
177     self._new_contents = new_contents
178     self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
179     self._action = action
180     self._scm_diff = "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" % (local_path,
181       len(new_contents))
182     self._old_contents = old_contents
183     for l in new_contents:
184       self._scm_diff += "+%s\n" % l
185
186   def Action(self):
187     return self._action
188
189   def ChangedContents(self):
190     return self._changed_contents
191
192   def NewContents(self):
193     return self._new_contents
194
195   def LocalPath(self):
196     return self._local_path
197
198   def AbsoluteLocalPath(self):
199     return self._local_path
200
201   def GenerateScmDiff(self):
202     return self._scm_diff
203
204   def OldContents(self):
205     return self._old_contents
206
207   def rfind(self, p):
208     """os.path.basename is called on MockFile so we need an rfind method."""
209     return self._local_path.rfind(p)
210
211   def __getitem__(self, i):
212     """os.path.basename is called on MockFile so we need a get method."""
213     return self._local_path[i]
214
215   def __len__(self):
216     """os.path.basename is called on MockFile so we need a len method."""
217     return len(self._local_path)
218
219
220 class MockAffectedFile(MockFile):
221   def AbsoluteLocalPath(self):
222     return self._local_path
223
224
225 class MockChange(object):
226   """Mock class for Change class.
227
228   This class can be used in presubmit unittests to mock the query of the
229   current change.
230   """
231
232   def __init__(self, changed_files):
233     self._changed_files = changed_files
234
235   def LocalPaths(self):
236     return self._changed_files
237
238   def AffectedFiles(self, include_dirs=False, include_deletes=True,
239                     file_filter=None):
240     return self._changed_files