gn format //base
[chromium-blink-merge.git] / tools / strict_enum_value_checker / strict_enum_value_checker_test.py
blob4f95efe0cfd66439dfad50775be5c9225ff4afdf
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 import difflib
7 import os
8 import re
9 import unittest
11 from strict_enum_value_checker import StrictEnumValueChecker
13 class MockLogging(object):
14 def __init__(self):
15 self.lines = []
17 def info(self, message):
18 self.lines.append(message)
20 def debug(self, message):
21 self.lines.append(message)
23 class MockInputApi(object):
24 def __init__(self):
25 self.re = re
26 self.os_path = os.path
27 self.files = []
28 self.is_committing = False
29 self.logging = MockLogging()
31 def AffectedFiles(self, include_deletes=None):
32 return self.files
35 class MockOutputApi(object):
36 class PresubmitResult(object):
37 def __init__(self, message, items=None, long_text=""):
38 self.message = message
39 self.items = items
40 self.long_text = long_text
42 class PresubmitError(PresubmitResult):
43 def __init__(self, message, items, long_text=""):
44 MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
45 self.type = "error"
47 class PresubmitPromptWarning(PresubmitResult):
48 def __init__(self, message, items, long_text=""):
49 MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
50 self.type = "warning"
52 class PresubmitNotifyResult(PresubmitResult):
53 def __init__(self, message, items, long_text=""):
54 MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
55 self.type = "notify"
58 class MockFile(object):
59 def __init__(self, local_path, old_contents, new_contents):
60 self._local_path = local_path
61 self._new_contents = new_contents
62 self._old_contents = old_contents
63 self._cached_changed_contents = None
65 def ChangedContents(self):
66 return self._changed_contents
68 def NewContents(self):
69 return self._new_contents
71 def LocalPath(self):
72 return self._local_path
74 def IsDirectory(self):
75 return False
77 def GenerateScmDiff(self):
78 result = ""
79 for line in difflib.unified_diff(self._old_contents, self._new_contents,
80 self._local_path, self._local_path):
81 result += line
82 return result
84 # NOTE: This method is a copy of ChangeContents method of AffectedFile in
85 # presubmit_support.py
86 def ChangedContents(self):
87 """Returns a list of tuples (line number, line text) of all new lines.
89 This relies on the scm diff output describing each changed code section
90 with a line of the form
92 ^@@ <old line num>,<old size> <new line num>,<new size> @@$
93 """
94 if self._cached_changed_contents is not None:
95 return self._cached_changed_contents[:]
96 self._cached_changed_contents = []
97 line_num = 0
99 if self.IsDirectory():
100 return []
102 for line in self.GenerateScmDiff().splitlines():
103 m = re.match(r"^@@ [0-9\,\+\-]+ \+([0-9]+)\,[0-9]+ @@", line)
104 if m:
105 line_num = int(m.groups(1)[0])
106 continue
107 if line.startswith("+") and not line.startswith("++"):
108 self._cached_changed_contents.append((line_num, line[1:]))
109 if not line.startswith("-"):
110 line_num += 1
111 return self._cached_changed_contents[:]
114 class MockChange(object):
115 def __init__(self, changed_files):
116 self._changed_files = changed_files
118 def LocalPaths(self):
119 return self._changed_files
122 class StrictEnumValueCheckerTest(unittest.TestCase):
123 TEST_FILE_PATTERN = "changed_file_%s.h"
124 MOCK_FILE_LOCAL_PATH = "mock_enum.h"
125 START_MARKER = "enum MockEnum {"
126 END_MARKER = " mBoundary"
128 def _ReadTextFileContents(self, path):
129 """Given a path, returns a list of strings corresponding to the text lines
130 in the file. Reads files in text format.
133 fo = open(path, "r")
134 try:
135 contents = fo.readlines()
136 finally:
137 fo.close()
138 return contents
140 def _ReadInputFile(self):
141 return self._ReadTextFileContents("mock_enum.h")
143 def _PrepareTest(self, new_file_path):
144 old_contents = self._ReadInputFile()
145 if not new_file_path:
146 new_contents = []
147 else:
148 new_contents = self._ReadTextFileContents(new_file_path)
149 input_api = MockInputApi()
150 mock_file = MockFile(self.MOCK_FILE_LOCAL_PATH,
151 old_contents,
152 new_contents)
153 input_api.files.append(mock_file)
154 output_api = MockOutputApi()
155 return input_api, output_api
157 def _RunTest(self, new_file_path):
158 input_api, output_api = self._PrepareTest(new_file_path)
159 checker = StrictEnumValueChecker(input_api, output_api, self.START_MARKER,
160 self.END_MARKER, self.MOCK_FILE_LOCAL_PATH)
161 results = checker.Run()
162 return results
164 def testDeleteFile(self):
165 results = self._RunTest(new_file_path=None)
166 # TODO(rpaquay) How to check it's the expected warning?'
167 self.assertEquals(1, len(results),
168 "We should get a single warning about file deletion.")
170 def testSimpleValidEdit(self):
171 results = self._RunTest(self.TEST_FILE_PATTERN % "1")
172 # TODO(rpaquay) How to check it's the expected warning?'
173 self.assertEquals(0, len(results),
174 "We should get no warning for simple edits.")
176 def testSingleDeletionOfEntry(self):
177 results = self._RunTest(self.TEST_FILE_PATTERN % "2")
178 # TODO(rpaquay) How to check it's the expected warning?'
179 self.assertEquals(1, len(results),
180 "We should get a warning for an entry deletion.")
182 def testSingleRenameOfEntry(self):
183 results = self._RunTest(self.TEST_FILE_PATTERN % "3")
184 # TODO(rpaquay) How to check it's the expected warning?'
185 self.assertEquals(1, len(results),
186 "We should get a warning for an entry rename, even "
187 "though it is not optimal.")
189 def testMissingEnumStartOfEntry(self):
190 results = self._RunTest(self.TEST_FILE_PATTERN % "4")
191 # TODO(rpaquay) How to check it's the expected warning?'
192 self.assertEquals(1, len(results),
193 "We should get a warning for a missing enum marker.")
195 def testMissingEnumEndOfEntry(self):
196 results = self._RunTest(self.TEST_FILE_PATTERN % "5")
197 # TODO(rpaquay) How to check it's the expected warning?'
198 self.assertEquals(1, len(results),
199 "We should get a warning for a missing enum marker.")
201 def testInvertedEnumMarkersOfEntry(self):
202 results = self._RunTest(self.TEST_FILE_PATTERN % "6")
203 # TODO(rpaquay) How to check it's the expected warning?'
204 self.assertEquals(1, len(results),
205 "We should get a warning for inverted enum markers.")
207 def testMultipleInvalidEdits(self):
208 results = self._RunTest(self.TEST_FILE_PATTERN % "7")
209 # TODO(rpaquay) How to check it's the expected warning?'
210 self.assertEquals(3, len(results),
211 "We should get 3 warnings (one per edit).")
213 def testSingleInvalidInserts(self):
214 results = self._RunTest(self.TEST_FILE_PATTERN % "8")
215 # TODO(rpaquay) How to check it's the expected warning?'
216 self.assertEquals(1, len(results),
217 "We should get a warning for a single invalid "
218 "insertion inside the enum.")
220 def testMulitpleValidInserts(self):
221 results = self._RunTest(self.TEST_FILE_PATTERN % "9")
222 # TODO(rpaquay) How to check it's the expected warning?'
223 self.assertEquals(0, len(results),
224 "We should not get a warning mulitple valid edits")
226 def testSingleValidDeleteOutsideOfEnum(self):
227 results = self._RunTest(self.TEST_FILE_PATTERN % "10")
228 # TODO(rpaquay) How to check it's the expected warning?'
229 self.assertEquals(0, len(results),
230 "We should not get a warning for a deletion outside of "
231 "the enum")
234 if __name__ == '__main__':
235 unittest.main()