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

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

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

Powered by Google App Engine
This is Rietveld 408576698