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

Unified 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, 6 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 side-by-side diff with in-line comments
Download patch
« build/android/coverage.py ('K') | « build/android/coverage.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/coverage_test.py
diff --git a/build/android/coverage_test.py b/build/android/coverage_test.py
new file mode 100755
index 0000000000000000000000000000000000000000..14933835ee6187f18d080405a76bacd851edfc29
--- /dev/null
+++ b/build/android/coverage_test.py
@@ -0,0 +1,322 @@
+#!/usr/bin/python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from lxml import etree
+from lxml import html
+import os
+import sys
+import unittest
+
+import coverage
+from pylib import constants
+
+sys.path.append(os.path.join(
+ constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class LineCoverageTest(unittest.TestCase):
+ """Tests for LineCoverage."""
+
+ def testInit(self):
+ line_coverage = coverage.LineCoverage(10, 'i++;',
+ coverage.LineCoverage.COVERED, 1.0)
+ self.assertEqual(line_coverage.lineno, 10)
+ self.assertEqual(line_coverage.source, 'i++;')
+ self.assertEqual(line_coverage.covered_status,
+ coverage.LineCoverage.COVERED)
+ self.assertEqual(line_coverage.fractional_line_coverage, 1.0)
+
+
+class _EmmaHtmlParserTest(unittest.TestCase):
+ """Tests for _EmmaHtmlParser.
+
+ Uses modified EMMA report HTML that contains only the subset of tags needed
+ for test verification.
+ """
+
+ def setUp(self):
+ self.emma_dir = 'fake/dir/'
+ self.parser = coverage._EmmaHtmlParser(self.emma_dir)
+ self.simple_html = '<td class="p">Test HTML</td>'
+ self.index_html = """
+ <HTML>
+ <BODY>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CLASS="it" CELLSPACING="0">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ <TR>
+ <TH CLASS="f">name</TH>
+ <TH>class, %</TH>
+ <TH>method, %</TH>
+ <TH>block, %</TH>
+ <TH>line, %</TH>
+ </TR>
+ <TR CLASS="o">
+ <TD><A HREF="_files/0.html"
+ >org.chromium.chrome.browser</A></TD>
+ <TD CLASS="h">0% (0/3)</TD>
+ </TR>
+ <TR>
+ <TD><A HREF="_files/1.html"
+ >org.chromium.chrome.browser.tabmodel</A></TD>
+ <TD CLASS="h">0% (0/8)</TD>
+ </TR>
+ </TABLE>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ </BODY>
+ </HTML>"""
+ self.package_1_class_list_html = """
+ <HTML>
+ <BODY>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ <TR>
+ <TH CLASS="f">name</TH>
+ <TH>class, %</TH>
+ <TH>method, %</TH>
+ <TH>block, %</TH>
+ <TH>line, %</TH>
+ </TR>
+ <TR CLASS="o">
+ <TD><A HREF="1e.html">IntentHelper.java</A></TD>
+ <TD CLASS="h">0% (0/3)</TD>
+ <TD CLASS="h">0% (0/9)</TD>
+ <TD CLASS="h">0% (0/97)</TD>
+ <TD CLASS="h">0% (0/26)</TD>
+ </TR>
+ </TABLE>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ </BODY>
+ </HTML>"""
+ self.package_2_class_list_html = """
+ <HTML>
+ <BODY>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ <TABLE CELLSPACING="0" WIDTH="100%">
+ <TR>
+ <TH CLASS="f">name</TH>
+ <TH>class, %</TH>
+ <TH>method, %</TH>
+ <TH>block, %</TH>
+ <TH>line, %</TH>
+ </TR>
+ <TR CLASS="o">
+ <TD><A HREF="1f.html">ContentSetting.java</A></TD>
+ <TD CLASS="h">0% (0/1)</TD>
+ </TR>
+ <TR>
+ <TD><A HREF="20.html">DevToolsServer.java</A></TD>
+ </TR>
+ <TR CLASS="o">
+ <TD><A HREF="21.html">FileProviderHelper.java</A></TD>
+ </TR>
+ <TR>
+ <TD><A HREF="22.html">ContextualMenuBar.java</A></TD>
+ </TR>
+ <TR CLASS="o">
+ <TD><A HREF="23.html">AccessibilityUtil.java</A></TD>
+ </TR>
+ <TR>
+ <TD><A HREF="24.html">NavigationPopup.java</A></TD>
+ </TR>
+ </TABLE>
+ <TABLE CLASS="hdft" CELLSPACING="0" WIDTH="100%">
+ </TABLE>
+ </BODY>
+ </HTML>"""
+ self.partially_covered_tr_html = """
+ <tr class="p">
+ <td class="l" title="78% line coverage (7 out of 9)">108</td>
+ <td title="78% line coverage (7 out of 9 instructions)">
+ if (index < 0 || index = mSelectors.size()) index = 0;</td>
+ </tr>"""
+ self.covered_tr_html = """
+ <tr class="c">
+ <td class="l">110</td>
+ <td> if (mSelectors.get(index) != null) {</td>
+ </tr>"""
+ self.not_executable_tr_html = """
+ <tr>
+ <td class="l">109</td>
+ <td> </td>
+ </tr>"""
+ self.tr_with_extra_a_tag = """
+ <tr class="z">
+ <td class="l">
+ <a name="1f">54</a>
+ </td>
+ <td> }</td>
+ </tr>"""
+
+ def testInit(self):
+ emma_dir = self.emma_dir
+ parser = coverage._EmmaHtmlParser(emma_dir)
+ self.assertEqual(parser._base_dir, emma_dir)
+ self.assertEqual(parser._emma_files_path, 'fake/dir/_files')
+ self.assertEqual(parser._index_path, 'fake/dir/index.html')
+
+ def testFindElements_basic(self):
+ found, _ = MockOpenForFunction(self.parser._FindElements, self.simple_html,
+ file_path='fake', _path='//td')
+ self.assertIs(type(found), list)
+ self.assertIs(type(found[0]), html.HtmlElement)
+ self.assertEqual(found[0].text, 'Test HTML')
+
+ def testFindElements_noMatch(self):
+ found, _ = MockOpenForFunction(self.parser._FindElements, self.simple_html,
+ file_path='fake', _path='//tr')
+ self.assertEqual(found, [])
+
+ def testFindElements_badFilePath(self):
+ # Ensure that os.path.exists will fail.
+ with mock.patch('os.path.exists', return_value=False):
+ found = self.parser._FindElements('fake', _path='//tr')
+ self.assertEqual(found, [])
+
+ def testGetPackageNameToEmmaFileDict_basic(self):
+ expected_dict = {
+ 'org.chromium.chrome.browser.AccessibilityUtil.java':
+ 'fake/dir/_files/23.html',
+ 'org.chromium.chrome.browser.ContextualMenuBar.java':
+ 'fake/dir/_files/22.html',
+ 'org.chromium.chrome.browser.tabmodel.IntentHelper.java':
+ 'fake/dir/_files/1e.html',
+ 'org.chromium.chrome.browser.ContentSetting.java':
+ 'fake/dir/_files/1f.html',
+ 'org.chromium.chrome.browser.DevToolsServer.java':
+ 'fake/dir/_files/20.html',
+ 'org.chromium.chrome.browser.NavigationPopup.java':
+ 'fake/dir/_files/24.html',
+ 'org.chromium.chrome.browser.FileProviderHelper.java':
+ 'fake/dir/_files/21.html'}
+
+ return_dict, mock_open = MockOpenForFunction(
+ self.parser.GetPackageNameToEmmaFileDict,
+ self.index_html, self.package_1_class_list_html,
+ self.package_2_class_list_html)
+
+ self.assertDictEqual(return_dict, expected_dict)
+ self.assertEqual(mock_open.call_count, 3)
+ calls = [mock.call('fake/dir/index.html'),
+ mock.call('fake/dir/_files/1.html'),
+ mock.call('fake/dir/_files/0.html')]
+ mock_open.assert_has_calls(calls)
+
+ def testGetPackageNameToEmmaFileDict_badFilePath(self):
+ file_path = self.parser.GetPackageNameToEmmaFileDict()
+ self.assertEqual(file_path, {})
+
+ def testGetLineCoverage_status_basic(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
+ self.assertEqual(line_coverage[0].covered_status,
+ coverage.LineCoverage.COVERED)
+
+ def testGetLineCoverage_status_statusMissing(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(
+ self.not_executable_tr_html)
+ self.assertEqual(line_coverage[0].covered_status,
+ coverage.LineCoverage.NOT_EXECUTABLE)
+
+ def testGetLineCoverage_fractionalCoverage_basic(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
+ self.assertEqual(line_coverage[0].fractional_line_coverage, 1.0)
+
+ def testGetLineCoverage_fractionalCoverage_partial(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(
+ self.partially_covered_tr_html)
+ self.assertEqual(line_coverage[0].fractional_line_coverage, 0.78)
+
+ def testGetLineCoverage_lineno_basic(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(self.covered_tr_html)
+ self.assertEqual(line_coverage[0].lineno, 110)
+
+ def testGetLineCoverage_lineno_withAlternativeHtml(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(
+ self.tr_with_extra_a_tag)
+ self.assertEqual(line_coverage[0].lineno, 54)
+
+ def testGetLineCoverage_source(self):
+ self.parser._FindElements = mock.Mock(
+ return_value=[html.fromstring(self.covered_tr_html)])
+ line_coverage = self.parser.GetLineCoverage('fake_path')
+ self.assertEqual(line_coverage[0].source,
+ ' if (mSelectors.get(index) != null) {')
+
+ def testGetLineCoverage_multipleElements(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(
+ self.covered_tr_html, self.partially_covered_tr_html,
+ self.tr_with_extra_a_tag)
+ self.assertEqual(len(line_coverage), 3)
+
+ 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.
+ """Wraps GetLineCoverage to work with extra whitespace characters.
+
+ The test HTML strings include extra whitespace characters to make the HTML
+ human readable. This isn't the case with EMMA HTML files, so we need to
+ remove all the unnecessary whitespace.
+
+ Args:
+ *args: Each is a string representing an HTML element.
+
+ Returns:
+ A list of LineCoverage objects.
+ """
+ html_elements = [self.MakeElementsWithoutWhitespace(arg) for arg in args]
+ with mock.patch('coverage._EmmaHtmlParser._FindElements',
+ return_value=html_elements):
+ return self.parser.GetLineCoverage('fake_path')
+
+ def MakeElementsWithoutWhitespace(self, html_string):
+ """Helper to make HtmlElements with excess whitespace removed.
+
+ Args:
+ html_string: String representing HTML to be used to create elements.
+
+ Returns:
+ The root element of |html_string| with all extra whitespace removed.
+ """
+ parser = etree.HTMLParser(remove_blank_text=True)
+ root = html.fromstring(html_string, parser=parser)
+ 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.
+ if elem.text is not None:
+ elem.text = elem.text.strip()
+ return root
+
+
+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.
+ """Allows easy mock open and read for callables that open multiple files.
+
+ Args:
+ func: The callable to invoke once mock files are setup.
+ *args: A list of return values for each file to return once read. Length of
+ list should be equal to the number calls to open in |func|.
+ **kwargs: Keyword arguments to be passed to |func|.
+
+ Returns:
+ A tuple containing the return value of |func| and the MagicMock object used
+ to mock all calls to open respectively.
+ """
+ mock_open = mock.mock_open()
+ mock_open.side_effect = [mock.mock_open(read_data=arg).return_value
+ for arg in args]
+ with mock.patch('__builtin__.open', mock_open):
+ return func(**kwargs), mock_open
+
+
+if __name__ == '__main__':
+ unittest.main()
« 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