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