Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: build/android/coverage_test.py

Issue 1211243016: Added coverage script and tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« build/android/coverage.py ('K') | « build/android/coverage.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright 2015 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.
5
6 from lxml import etree
7 from lxml import html
8 import os
9 import sys
10 import unittest
11
12 import coverage
13 from pylib import constants
14
15 sys.path.append(os.path.join(
16 constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
17 import mock # pylint: disable=F0401
18
19
20 class LineCoverageTest(unittest.TestCase):
21 """Tests for LineCoverage."""
22
23 def testInit(self):
24 line_coverage = coverage.LineCoverage(10, 'i++;',
25 coverage.LineCoverage.COVERED, 1.0)
26 self.assertEqual(line_coverage.lineno, 10)
27 self.assertEqual(line_coverage.source, 'i++;')
28 self.assertEqual(line_coverage.covered_status,
29 coverage.LineCoverage.COVERED)
30 self.assertEqual(line_coverage.fractional_line_coverage, 1.0)
31
32
33 class _EmmaHtmlParserTest(unittest.TestCase):
34 """Tests for _EmmaHtmlParser.
35
36 Uses modified EMMA report HTML that contains only the subset of tags needed
37 for test verification.
38 """
39
40 def setUp(self):
41 self.emma_dir = 'fake/dir/'
42 self.parser = coverage._EmmaHtmlParser(self.emma_dir)
43 self.simple_html = '<td class="p">Test HTML</td>'
44 self.index_html = """
45 <HTML>
46 <BODY>
47 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
48 </TABLE>
49 <TABLE CELLSPACING="0" WIDTH="100%">
50 </TABLE>
51 <TABLE CLASS="it" CELLSPACING="0">
52 </TABLE>
53 <TABLE CELLSPACING="0" WIDTH="100%">
54 <TR>
55 <TH CLASS="f">name</TH>
56 <TH>class, %</TH>
57 <TH>method, %</TH>
58 <TH>block, %</TH>
59 <TH>line, %</TH>
60 </TR>
61 <TR CLASS="o">
62 <TD><A HREF="_files/0.html"
63 >org.chromium.chrome.browser</A></TD>
64 <TD CLASS="h">0% (0/3)</TD>
65 </TR>
66 <TR>
67 <TD><A HREF="_files/1.html"
68 >org.chromium.chrome.browser.tabmodel</A></TD>
69 <TD CLASS="h">0% (0/8)</TD>
70 </TR>
71 </TABLE>
72 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
73 </TABLE>
74 </BODY>
75 </HTML>"""
76 self.package_1_class_list_html = """
77 <HTML>
78 <BODY>
79 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
80 </TABLE>
81 <TABLE CELLSPACING="0" WIDTH="100%">
82 </TABLE>
83 <TABLE CELLSPACING="0" WIDTH="100%">
84 <TR>
85 <TH CLASS="f">name</TH>
86 <TH>class, %</TH>
87 <TH>method, %</TH>
88 <TH>block, %</TH>
89 <TH>line, %</TH>
90 </TR>
91 <TR CLASS="o">
92 <TD><A HREF="1e.html">IntentHelper.java</A></TD>
93 <TD CLASS="h">0% (0/3)</TD>
94 <TD CLASS="h">0% (0/9)</TD>
95 <TD CLASS="h">0% (0/97)</TD>
96 <TD CLASS="h">0% (0/26)</TD>
97 </TR>
98 </TABLE>
99 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
100 </TABLE>
101 </BODY>
102 </HTML>"""
103 self.package_2_class_list_html = """
104 <HTML>
105 <BODY>
106 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
107 </TABLE>
108 <TABLE CELLSPACING="0" WIDTH="100%">
109 </TABLE>
110 <TABLE CELLSPACING="0" WIDTH="100%">
111 <TR>
112 <TH CLASS="f">name</TH>
113 <TH>class, %</TH>
114 <TH>method, %</TH>
115 <TH>block, %</TH>
116 <TH>line, %</TH>
117 </TR>
118 <TR CLASS="o">
119 <TD><A HREF="1f.html">ContentSetting.java</A></TD>
120 <TD CLASS="h">0% (0/1)</TD>
121 </TR>
122 <TR>
123 <TD><A HREF="20.html">DevToolsServer.java</A></TD>
124 </TR>
125 <TR CLASS="o">
126 <TD><A HREF="21.html">FileProviderHelper.java</A></TD>
127 </TR>
128 <TR>
129 <TD><A HREF="22.html">ContextualMenuBar.java</A></TD>
130 </TR>
131 <TR CLASS="o">
132 <TD><A HREF="23.html">AccessibilityUtil.java</A></TD>
133 </TR>
134 <TR>
135 <TD><A HREF="24.html">NavigationPopup.java</A></TD>
136 </TR>
137 </TABLE>
138 <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
139 </TABLE>
140 </BODY>
141 </HTML>"""
142 self.partially_covered_tr_html = """
143 <tr class="p">
144 <td class="l" title="78% line coverage (7 out of 9)">108</td>
145 <td title="78% line coverage (7 out of 9 instructions)">
146 if (index < 0 || index = mSelectors.size()) index = 0;</td>
147 </tr>"""
148 self.covered_tr_html = """
149 <tr class="c">
150 <td class="l">110</td>
151 <td> if (mSelectors.get(index) != null) {</td>
152 </tr>"""
153 self.not_executable_tr_html = """
154 <tr>
155 <td class="l">109</td>
156 <td> </td>
157 </tr>"""
158 self.tr_with_extra_a_tag = """
159 <tr class="z">
160 <td class="l">
161 <a name="1f">54</a>
162 </td>
163 <td> }</td>
164 </tr>"""
165
166 def testInit(self):
167 emma_dir = self.emma_dir
168 parser = coverage._EmmaHtmlParser(emma_dir)
169 self.assertEqual(parser._base_dir, emma_dir)
170 self.assertEqual(parser._emma_files_path, 'fake/dir/_files')
171 self.assertEqual(parser._index_path, 'fake/dir/index.html')
172
173 def testFindElements_basic(self):
174 found, _ = MockOpenForFunction(self.parser._FindElements, self.simple_html,
175 file_path='fake', _path='//td')
176 self.assertIs(type(found), list)
177 self.assertIs(type(found[0]), html.HtmlElement)
178 self.assertEqual(found[0].text, 'Test HTML')
179
180 def testFindElements_noMatch(self):
181 found, _ = MockOpenForFunction(self.parser._FindElements, self.simple_html,
182 file_path='fake', _path='//tr')
183 self.assertEqual(found, [])
184
185 def testFindElements_badFilePath(self):
186 # Ensure that os.path.exists will fail.
187 with mock.patch('os.path.exists', return_value=False):
188 found = self.parser._FindElements('fake', _path='//tr')
189 self.assertEqual(found, [])
190
191 def testGetPackageNameToEmmaFileDict_basic(self):
192 expected_dict = {
193 'org.chromium.chrome.browser.AccessibilityUtil.java':
194 'fake/dir/_files/23.html',
195 'org.chromium.chrome.browser.ContextualMenuBar.java':
196 'fake/dir/_files/22.html',
197 'org.chromium.chrome.browser.tabmodel.IntentHelper.java':
198 'fake/dir/_files/1e.html',
199 'org.chromium.chrome.browser.ContentSetting.java':
200 'fake/dir/_files/1f.html',
201 'org.chromium.chrome.browser.DevToolsServer.java':
202 'fake/dir/_files/20.html',
203 'org.chromium.chrome.browser.NavigationPopup.java':
204 'fake/dir/_files/24.html',
205 'org.chromium.chrome.browser.FileProviderHelper.java':
206 'fake/dir/_files/21.html'}
207
208 return_dict, mock_open = MockOpenForFunction(
209 self.parser.GetPackageNameToEmmaFileDict,
210 self.index_html, self.package_1_class_list_html,
211 self.package_2_class_list_html)
212
213 self.assertDictEqual(return_dict, expected_dict)
214 self.assertEqual(mock_open.call_count, 3)
215 calls = [mock.call('fake/dir/index.html'),
216 mock.call('fake/dir/_files/1.html'),
217 mock.call('fake/dir/_files/0.html')]
218 mock_open.assert_has_calls(calls)
219
220 def testGetPackageNameToEmmaFileDict_badFilePath(self):
221 file_path = self.parser.GetPackageNameToEmmaFileDict()
222 self.assertEqual(file_path, {})
223
224 def testGetLineCoverage_status_basic(self):
225 line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
226 self.assertEqual(line_coverage[0].covered_status,
227 coverage.LineCoverage.COVERED)
228
229 def testGetLineCoverage_status_statusMissing(self):
230 line_coverage = self.GetLineCoverageWithFakeElements(
231 self.not_executable_tr_html)
232 self.assertEqual(line_coverage[0].covered_status,
233 coverage.LineCoverage.NOT_EXECUTABLE)
234
235 def testGetLineCoverage_fractionalCoverage_basic(self):
236 line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
237 self.assertEqual(line_coverage[0].fractional_line_coverage, 1.0)
238
239 def testGetLineCoverage_fractionalCoverage_partial(self):
240 line_coverage = self.GetLineCoverageWithFakeElements(
241 self.partially_covered_tr_html)
242 self.assertEqual(line_coverage[0].fractional_line_coverage, 0.78)
243
244 def testGetLineCoverage_lineno_basic(self):
245 line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
246 self.assertEqual(line_coverage[0].lineno, 110)
247
248 def testGetLineCoverage_lineno_withAlternativeHtml(self):
249 line_coverage = self.GetLineCoverageWithFakeElements(
250 self.tr_with_extra_a_tag)
251 self.assertEqual(line_coverage[0].lineno, 54)
252
253 def testGetLineCoverage_source(self):
254 self.parser._FindElements = mock.Mock(
255 return_value=[html.fromstring(self.covered_tr_html)])
256 line_coverage = self.parser.GetLineCoverage('fake_path')
257 self.assertEqual(line_coverage[0].source,
258 ' if (mSelectors.get(index) != null) {')
259
260 def testGetLineCoverage_multipleElements(self):
261 line_coverage = self.GetLineCoverageWithFakeElements(
262 self.covered_tr_html, self.partially_covered_tr_html,
263 self.tr_with_extra_a_tag)
264 self.assertEqual(len(line_coverage), 3)
265
266 def GetLineCoverageWithFakeElements(self, *args):
mikecase (-- gone --) 2015/07/07 17:12:33 Can you just change this to... GetLineCoverageWith
estevenson1 2015/07/07 23:54:56 Done.
267 """Wraps GetLineCoverage to work with extra whitespace characters.
268
269 The test HTML strings include extra whitespace characters to make the HTML
270 human readable. This isn't the case with EMMA HTML files, so we need to
271 remove all the unnecessary whitespace.
272
273 Args:
274 *args: Each is a string representing an HTML element.
275
276 Returns:
277 A list of LineCoverage objects.
278 """
279 html_elements = [self.MakeElementsWithoutWhitespace(arg) for arg in args]
280 with mock.patch('coverage._EmmaHtmlParser._FindElements',
281 return_value=html_elements):
282 return self.parser.GetLineCoverage('fake_path')
283
284 def MakeElementsWithoutWhitespace(self, html_string):
285 """Helper to make HtmlElements with excess whitespace removed.
286
287 Args:
288 html_string: String representing HTML to be used to create elements.
289
290 Returns:
291 The root element of |html_string| with all extra whitespace removed.
292 """
293 parser = etree.HTMLParser(remove_blank_text=True)
294 root = html.fromstring(html_string, parser=parser)
295 for elem in root.iter('*'):
mikecase (-- gone --) 2015/07/07 17:12:33 nit: s/elem/element
estevenson1 2015/07/07 23:54:56 Done.
296 if elem.text is not None:
297 elem.text = elem.text.strip()
298 return root
299
300
301 def MockOpenForFunction(func, *args, **kwargs):
mikecase (-- gone --) 2015/07/07 17:12:33 Can you change this to... MockOpenForFunction(func
estevenson1 2015/07/07 23:54:56 Done.
302 """Allows easy mock open and read for callables that open multiple files.
303
304 Args:
305 func: The callable to invoke once mock files are setup.
306 *args: A list of return values for each file to return once read. Length of
307 list should be equal to the number calls to open in |func|.
308 **kwargs: Keyword arguments to be passed to |func|.
309
310 Returns:
311 A tuple containing the return value of |func| and the MagicMock object used
312 to mock all calls to open respectively.
313 """
314 mock_open = mock.mock_open()
315 mock_open.side_effect = [mock.mock_open(read_data=arg).return_value
316 for arg in args]
317 with mock.patch('__builtin__.open', mock_open):
318 return func(**kwargs), mock_open
319
320
321 if __name__ == '__main__':
322 unittest.main()
OLDNEW
« build/android/coverage.py ('K') | « build/android/coverage.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698