[M108 Migration] Make sure device scale factor (DSF) is not less than 1.0 on any...
[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
84   def CreateMockFileInPath(self, f_list):
85     self.os_path.exists = lambda x: x in f_list
86
87   def AffectedFiles(self, file_filter=None, include_deletes=True):
88     for file in self.files:
89       if file_filter and not file_filter(file):
90         continue
91       if not include_deletes and file.Action() == 'D':
92         continue
93       yield file
94
95   def RightHandSideLines(self, source_file_filter=None):
96     affected_files = self.AffectedSourceFiles(source_file_filter)
97     for af in affected_files:
98       lines = af.ChangedContents()
99       for line in lines:
100         yield (af, line[0], line[1])
101
102   def AffectedSourceFiles(self, file_filter=None):
103     return self.AffectedFiles(file_filter=file_filter)
104
105   def FilterSourceFile(self, file,
106                        files_to_check=(), files_to_skip=()):
107     local_path = file.LocalPath()
108     found_in_files_to_check = not files_to_check
109     if files_to_check:
110       if type(files_to_check) is str:
111         raise TypeError('files_to_check should be an iterable of strings')
112       for pattern in files_to_check:
113         compiled_pattern = re.compile(pattern)
114         if compiled_pattern.match(local_path):
115           found_in_files_to_check = True
116           break
117     if files_to_skip:
118       if type(files_to_skip) is str:
119         raise TypeError('files_to_skip should be an iterable of strings')
120       for pattern in files_to_skip:
121         compiled_pattern = re.compile(pattern)
122         if compiled_pattern.match(local_path):
123           return False
124     return found_in_files_to_check
125
126   def LocalPaths(self):
127     return [file.LocalPath() for file in self.files]
128
129   def PresubmitLocalPath(self):
130     return self.presubmit_local_path
131
132   def ReadFile(self, filename, mode='r'):
133     if hasattr(filename, 'AbsoluteLocalPath'):
134        filename = filename.AbsoluteLocalPath()
135     for file_ in self.files:
136       if file_.LocalPath() == filename:
137         return '\n'.join(file_.NewContents())
138     # Otherwise, file is not in our mock API.
139     raise IOError("No such file or directory: '%s'" % filename)
140
141
142 class MockOutputApi(object):
143   """Mock class for the OutputApi class.
144
145   An instance of this class can be passed to presubmit unittests for outputting
146   various types of results.
147   """
148
149   class PresubmitResult(object):
150     def __init__(self, message, items=None, long_text=''):
151       self.message = message
152       self.items = items
153       self.long_text = long_text
154
155     def __repr__(self):
156       return self.message
157
158   class PresubmitError(PresubmitResult):
159     def __init__(self, message, items=None, long_text=''):
160       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
161       self.type = 'error'
162
163   class PresubmitPromptWarning(PresubmitResult):
164     def __init__(self, message, items=None, long_text=''):
165       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
166       self.type = 'warning'
167
168   class PresubmitNotifyResult(PresubmitResult):
169     def __init__(self, message, items=None, long_text=''):
170       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
171       self.type = 'notify'
172
173   class PresubmitPromptOrNotify(PresubmitResult):
174     def __init__(self, message, items=None, long_text=''):
175       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
176       self.type = 'promptOrNotify'
177
178   def __init__(self):
179     self.more_cc = []
180
181   def AppendCC(self, more_cc):
182     self.more_cc.append(more_cc)
183
184
185 class MockFile(object):
186   """Mock class for the File class.
187
188   This class can be used to form the mock list of changed files in
189   MockInputApi for presubmit unittests.
190   """
191
192   def __init__(self, local_path, new_contents, old_contents=None, action='A',
193                scm_diff=None):
194     self._local_path = local_path
195     self._new_contents = new_contents
196     self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
197     self._action = action
198     if scm_diff:
199       self._scm_diff = scm_diff
200     else:
201       self._scm_diff = (
202         "--- /dev/null\n+++ %s\n@@ -0,0 +1,%d @@\n" %
203             (local_path, len(new_contents)))
204       for l in new_contents:
205         self._scm_diff += "+%s\n" % l
206     self._old_contents = old_contents
207
208   def Action(self):
209     return self._action
210
211   def ChangedContents(self):
212     return self._changed_contents
213
214   def NewContents(self):
215     return self._new_contents
216
217   def LocalPath(self):
218     return self._local_path
219
220   def AbsoluteLocalPath(self):
221     return self._local_path
222
223   def GenerateScmDiff(self):
224     return self._scm_diff
225
226   def OldContents(self):
227     return self._old_contents
228
229   def rfind(self, p):
230     """os.path.basename is called on MockFile so we need an rfind method."""
231     return self._local_path.rfind(p)
232
233   def __getitem__(self, i):
234     """os.path.basename is called on MockFile so we need a get method."""
235     return self._local_path[i]
236
237   def __len__(self):
238     """os.path.basename is called on MockFile so we need a len method."""
239     return len(self._local_path)
240
241   def replace(self, altsep, sep):
242     """os.path.basename is called on MockFile so we need a replace method."""
243     return self._local_path.replace(altsep, sep)
244
245
246 class MockAffectedFile(MockFile):
247   def AbsoluteLocalPath(self):
248     return self._local_path
249
250
251 class MockChange(object):
252   """Mock class for Change class.
253
254   This class can be used in presubmit unittests to mock the query of the
255   current change.
256   """
257
258   def __init__(self, changed_files):
259     self._changed_files = changed_files
260     self.author_email = None
261     self.footers = defaultdict(list)
262
263   def LocalPaths(self):
264     return self._changed_files
265
266   def AffectedFiles(self, include_dirs=False, include_deletes=True,
267                     file_filter=None):
268     return self._changed_files
269
270   def GitFootersFromDescription(self):
271     return self.footers