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