• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython3
2
3# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
4#
5# Use of this source code is governed by a BSD-style license
6# that can be found in the LICENSE file in the root of the source
7# tree. An additional intellectual property rights grant can be found
8# in the file PATENTS.  All contributing project authors may
9# be found in the AUTHORS file in the root of the source tree.
10
11# This file is inspired to [1].
12# [1] - https://cs.chromium.org/chromium/src/PRESUBMIT_test_mocks.py
13
14from __future__ import absolute_import
15import os.path
16import re
17
18
19class MockInputApi:
20  """Mock class for the InputApi class.
21
22  This class can be used for unittests for presubmit by initializing the files
23  attribute as the list of changed files.
24  """
25
26  def __init__(self):
27    self.change = MockChange([], [])
28    self.files = []
29    self.presubmit_local_path = os.path.dirname(__file__)
30    self.re = re  # pylint: disable=invalid-name
31
32  def AffectedSourceFiles(self, file_filter=None):
33    return self.AffectedFiles(file_filter=file_filter)
34
35  def AffectedFiles(self, file_filter=None, include_deletes=False):
36    for f in self.files:
37      if file_filter and not file_filter(f):
38        continue
39      if not include_deletes and f.Action() == 'D':
40        continue
41      yield f
42
43  @classmethod
44  def FilterSourceFile(cls, affected_file, files_to_check=(), files_to_skip=()):
45    # pylint: disable=unused-argument
46    return True
47
48  def PresubmitLocalPath(self):
49    return self.presubmit_local_path
50
51  def ReadFile(self, affected_file, mode='r'):
52    filename = affected_file.AbsoluteLocalPath()
53    for f in self.files:
54      if f.LocalPath() == filename:
55        with open(filename, mode) as f:
56          return f.read()
57    # Otherwise, file is not in our mock API.
58    raise IOError("No such file or directory: '%s'" % filename)
59
60
61class MockOutputApi:
62  """Mock class for the OutputApi class.
63
64  An instance of this class can be passed to presubmit unittests for outputing
65  various types of results.
66  """
67
68  class PresubmitResult:
69    def __init__(self, message, items=None, long_text=''):
70      self.message = message
71      self.items = items
72      self.long_text = long_text
73
74    def __repr__(self):
75      return self.message
76
77  class PresubmitError(PresubmitResult):
78    def __init__(self, message, items=None, long_text=''):
79      MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
80      self.type = 'error'
81
82
83class MockChange:
84  """Mock class for Change class.
85
86  This class can be used in presubmit unittests to mock the query of the
87  current change.
88  """
89
90  def __init__(self, changed_files, bugs_from_description, tags=None):
91    self._changed_files = changed_files
92    self._bugs_from_description = bugs_from_description
93    self.tags = dict() if not tags else tags
94
95  def BugsFromDescription(self):
96    return self._bugs_from_description
97
98  def __getattr__(self, attr):
99    """Return tags directly as attributes on the object."""
100    if not re.match(r"^[A-Z_]*$", attr):
101      raise AttributeError(self, attr)
102    return self.tags.get(attr)
103
104
105class MockFile:
106  """Mock class for the File class.
107
108  This class can be used to form the mock list of changed files in
109  MockInputApi for presubmit unittests.
110  """
111
112  def __init__(self,
113               local_path,
114               new_contents=None,
115               old_contents=None,
116               action='A'):
117    if new_contents is None:
118      new_contents = ["Data"]
119    self._local_path = local_path
120    self._new_contents = new_contents
121    self._changed_contents = [(i + 1, l) for i, l in enumerate(new_contents)]
122    self._action = action
123    self._old_contents = old_contents
124
125  def Action(self):
126    return self._action
127
128  def ChangedContents(self):
129    return self._changed_contents
130
131  def NewContents(self):
132    return self._new_contents
133
134  def LocalPath(self):
135    return self._local_path
136
137  def AbsoluteLocalPath(self):
138    return self._local_path
139
140  def OldContents(self):
141    return self._old_contents
142