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

Unified Diff: build/android/coverage_test.py

Issue 1216033009: Updated script to capture useful coverage stats. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Small refactor. 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 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..bd505e5b1f698cb5836cc568482591f281f80bff
--- /dev/null
+++ b/build/android/coverage_test.py
@@ -0,0 +1,569 @@
+#!/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.
+
+import json
+import os
+import sys
+import unittest
+from xml.etree import ElementTree
+
+import coverage
+from pylib import constants
+
+sys.path.append(os.path.join(
+ constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+EMPTY_COVERAGE_STATS_DICT = {
+ 'files': {},
+ 'patch': {
+ 'incremental': {
+ 'covered': 0, 'total': 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 = '<TR><TD CLASS="p">Test HTML</TD></TR>'
+ 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 &lt; 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):
+ read_values = [self.simple_html]
+ found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+ file_path='fake', xpath_selector='.//TD')
+ self.assertIs(type(found), list)
+ self.assertIs(type(found[0]), ElementTree.Element)
+ self.assertEqual(found[0].text, 'Test HTML')
+
+ def testFindElements_multipleElements(self):
+ multiple_trs = self.not_executable_tr_html + self.covered_tr_html
+ read_values = ['<div>' + multiple_trs + '</div>']
+ found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+ file_path='fake', xpath_selector='.//TR')
+ self.assertEquals(2, len(found))
+
+ def testFindElements_noMatch(self):
+ read_values = [self.simple_html]
+ found, _ = MockOpenForFunction(self.parser._FindElements, read_values,
+ file_path='fake', xpath_selector='.//TR')
+ self.assertEqual(found, [])
+
+ def testFindElements_badFilePath(self):
+ with self.assertRaises(IOError):
+ with mock.patch('os.path.exists', return_value=False):
+ self.parser._FindElements('fake', xpath_selector='//tr')
+
+ 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'}
+
+ read_values = [self.index_html, self.package_1_class_list_html,
+ self.package_2_class_list_html]
+ return_dict, mock_open = MockOpenForFunction(
+ self.parser.GetPackageNameToEmmaFileDict, read_values)
+
+ 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_noPackageElements(self):
+ self.parser._FindElements = mock.Mock(return_value=[])
+ return_dict = self.parser.GetPackageNameToEmmaFileDict()
+ self.assertDictEqual({}, return_dict)
+
+ def testGetLineCoverage_status_basic(self):
+ line_coverage = self.GetLineCoverageWithFakeElements([self.covered_tr_html])
+ self.assertEqual(line_coverage[0].covered_status,
+ coverage.COVERED)
+
+ def testGetLineCoverage_status_statusMissing(self):
+ line_coverage = self.GetLineCoverageWithFakeElements(
+ [self.not_executable_tr_html])
+ self.assertEqual(line_coverage[0].covered_status,
+ coverage.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=[ElementTree.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, html_elements):
+ """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:
+ html_elements: List of strings each representing an HTML element.
+
+ Returns:
+ A list of LineCoverage objects.
+ """
+ elements = [ElementTree.fromstring(string) for string in html_elements]
+ with mock.patch('coverage._EmmaHtmlParser._FindElements',
+ return_value=elements):
+ return self.parser.GetLineCoverage('fake_path')
+
+
+class _EmmaCoverageStatsTest(unittest.TestCase):
+ """Tests for _EmmaCoverageStats."""
+
+ def setUp(self):
+ self.good_source_to_emma = {
+ '/path/to/1/File1.java': '/emma/1.html',
+ '/path/2/File2.java': '/emma/2.html',
+ '/path/2/File3.java': '/emma/3.html'
+ }
+ self.line_coverage = [
+ coverage.LineCoverage(1, '', coverage.COVERED, 1.0),
+ coverage.LineCoverage(2, '', coverage.COVERED, 1.0),
+ coverage.LineCoverage(3, '', coverage.NOT_EXECUTABLE, 1.0),
+ coverage.LineCoverage(4, '', coverage.NOT_COVERED, 1.0),
+ coverage.LineCoverage(5, '',
+ coverage.PARTIALLY_COVERED, 0.85),
+ coverage.LineCoverage(6, '',
+ coverage.PARTIALLY_COVERED, 0.20)
+ ]
+ self.lines_for_coverage = [1, 3, 5, 6]
+ with mock.patch('coverage._EmmaHtmlParser._FindElements', return_value=[]):
+ self.simple_coverage = coverage._EmmaCoverageStats('fake_dir', {})
+
+ def testInit(self):
+ coverage_stats = self.simple_coverage
+ self.assertIsInstance(coverage_stats._emma_parser,
+ coverage._EmmaHtmlParser)
+ self.assertIsInstance(coverage_stats._source_to_emma, dict)
+
+ def testNeedsCoverage_withExistingJavaFile(self):
+ test_file = '/path/to/file/File.java'
+ with mock.patch('os.path.exists', return_value=True):
+ self.assertTrue(coverage._EmmaCoverageStats.NeedsCoverage(test_file))
+
+ def testNeedsCoverage_withNonJavaFile(self):
+ test_file = '/path/to/file/File.c'
+ with mock.patch('os.path.exists', return_value=True):
+ self.assertFalse(coverage._EmmaCoverageStats.NeedsCoverage(test_file))
+
+ def testNeedsCoverage_fileDoesNotExist(self):
+ test_file = '/path/to/file/File.java'
+ with mock.patch('os.path.exists', return_value=False):
+ self.assertFalse(coverage._EmmaCoverageStats.NeedsCoverage(test_file))
+
+ def testGetPackageNameFromFile_basic(self):
+ test_file_text = """// Test Copyright
+ package org.chromium.chrome.browser;
+ import android.graphics.RectF;"""
+ result_package, _ = MockOpenForFunction(
+ coverage._EmmaCoverageStats.GetPackageNameFromFile, [test_file_text],
+ file_path='/path/to/file/File.java')
+ self.assertEqual(result_package, 'org.chromium.chrome.browser.File.java')
+
+ def testGetPackageNameFromFile_noPackageStatement(self):
+ result_package, _ = MockOpenForFunction(
+ coverage._EmmaCoverageStats.GetPackageNameFromFile,
+ ['not a package statement'], file_path='/path/to/file/File.java')
+ self.assertIsNone(result_package)
+
+ def testGetStatsForLines_basic(self):
+ covered, total = self.simple_coverage.GetStatsForLines(
+ self.line_coverage, self.lines_for_coverage)
+ self.assertEqual(covered, 2.05)
+ self.assertEqual(total, 3)
+
+ def testGetStatsForLines_noLineNumbersProvided(self):
+ covered, total = self.simple_coverage.GetStatsForLines(self.line_coverage)
+ self.assertEqual(covered, 3.05)
+ self.assertEqual(total, 5)
+
+ def testGetSourceFileToEmmaFileDict(self):
+ package_names = {
+ '/path/to/1/File1.java': 'org.fake.one.File1.java',
+ '/path/2/File2.java': 'org.fake.File2.java',
+ '/path/2/File3.java': 'org.fake.File3.java'
+ }
+ package_to_emma = {
+ 'org.fake.one.File1.java': '/emma/1.html',
+ 'org.fake.File2.java': '/emma/2.html',
+ 'org.fake.File3.java': '/emma/3.html'
+ }
+ with mock.patch('os.path.exists', return_value=True):
+ coverage_stats = self.simple_coverage
+ coverage_stats._emma_parser.GetPackageNameToEmmaFileDict = mock.MagicMock(
+ return_value=package_to_emma)
+ coverage_stats.GetPackageNameFromFile = lambda x: package_names[x]
+ result_dict = coverage_stats._GetSourceFileToEmmaFileDict(
+ package_names.keys())
+ self.assertDictEqual(result_dict, self.good_source_to_emma)
+
+ def testGetCoverageStatusForFile_basic(self):
+ java_file_path = '/path/to/1/File1.java'
+ line_coverage = [
+ coverage.LineCoverage(1, '', coverage.COVERED, 1.0)]
+ coverage_stats = self.simple_coverage
+ coverage_stats._source_to_emma = self.good_source_to_emma
+ coverage_stats._emma_parser.GetLineCoverage = mock.MagicMock(
+ return_value=line_coverage)
+ coverage_info = coverage_stats._GetCoverageStatusForFile(java_file_path)
+ self.assertListEqual(coverage_info, line_coverage)
+
+ def testGetCoverageStatusForFile_noInfo(self):
+ coverage_info = self.simple_coverage._GetCoverageStatusForFile('fake_path')
+ self.assertIsNone(coverage_info)
+
+ def testGetCoverageReportForLines(self):
+ line_coverage = self.line_coverage
+ lines = self.lines_for_coverage
+ expected_dict = {
+ 'absolute': {
+ 'covered': 3.05,
+ 'total': 5
+ },
+ 'incremental': {
+ 'covered': 2.05,
+ 'total': 3
+ },
+ 'source': [
+ {
+ 'line': line_coverage[0].source,
+ 'coverage': line_coverage[0].covered_status,
+ 'changed': True
+ },
+ {
+ 'line': line_coverage[1].source,
+ 'coverage': line_coverage[1].covered_status,
+ 'changed': False
+ },
+ {
+ 'line': line_coverage[2].source,
+ 'coverage': line_coverage[2].covered_status,
+ 'changed': True
+ },
+ {
+ 'line': line_coverage[3].source,
+ 'coverage': line_coverage[3].covered_status,
+ 'changed': False
+ },
+ {
+ 'line': line_coverage[4].source,
+ 'coverage': line_coverage[4].covered_status,
+ 'changed': True
+ },
+ {
+ 'line': line_coverage[5].source,
+ 'coverage': line_coverage[5].covered_status,
+ 'changed': True
+ }
+ ]
+ }
+ result_dict = self.simple_coverage.GetCoverageReportForLines(line_coverage,
+ lines)
+ self.assertDictEqual(result_dict, expected_dict)
+
+ def testGetCoverageReportForLines_emptyCoverage(self):
+ expected_dict = {
+ 'absolute': {'covered': 0, 'total': 0},
+ 'incremental': {'covered': 0, 'total': 0},
+ 'source': []
+ }
+ result_dict = self.simple_coverage.GetCoverageReportForLines({}, [])
+ self.assertDictEqual(result_dict, expected_dict)
+
+ def testGetCoverageDictForFiles_basic(self):
+ files_for_coverage = {
+ '/path/to/1/File1.java': [1, 3, 4],
+ '/path/2/File2.java': [1, 2]
+ }
+ coverage_info = {
+ '/path/to/1/File1.java': [
+ coverage.LineCoverage(1, '', coverage.COVERED, 1.0),
+ coverage.LineCoverage(2, '',
+ coverage.PARTIALLY_COVERED, 0.5),
+ coverage.LineCoverage(3, '',
+ coverage.NOT_EXECUTABLE, 1.0),
+ coverage.LineCoverage(4, '', coverage.COVERED, 1.0)
+ ],
+ '/path/2/File2.java': [
+ coverage.LineCoverage(1, '', coverage.NOT_COVERED, 1.0),
+ coverage.LineCoverage(2, '', coverage.COVERED, 1.0)
+ ]
+ }
+ expected_dict = {
+ 'files': {
+ '/path/2/File2.java': {
+ 'absolute': {'covered': 1, 'total': 2},
+ 'incremental': {'covered': 1, 'total': 2},
+ 'source': [{'changed': True, 'coverage': 0, 'line': ''},
+ {'changed': True, 'coverage': 1, 'line': ''}]
+ },
+ '/path/to/1/File1.java': {
+ 'absolute': {'covered': 2.5, 'total': 3},
+ 'incremental': {'covered': 2, 'total': 2},
+ 'source': [{'changed': True, 'coverage': 1, 'line': ''},
+ {'changed': False, 'coverage': 2, 'line': ''},
+ {'changed': True, 'coverage': -1, 'line': ''},
+ {'changed': True, 'coverage': 1, 'line': ''}]
+ }
+ },
+ 'patch': {'incremental': {'covered': 3, 'total': 4}}
+ }
+ # Return the relevant coverage info for each file. We aren't testing
+ # _GetCoverageStatusForFile here.
+ self.simple_coverage._GetCoverageStatusForFile = lambda x: coverage_info[x]
+ result_dict = self.simple_coverage.GetCoverageDictForFiles(
+ files_for_coverage)
+ self.assertDictEqual(result_dict, expected_dict)
+
+ def testGetCoverageDictForFiles_noCoverage(self):
+ result_dict = self.simple_coverage.GetCoverageDictForFiles({})
+ self.assertDictEqual(result_dict, EMPTY_COVERAGE_STATS_DICT)
+
+
+class CoverageGenerateCoverageReportTest(unittest.TestCase):
+ """Tests for GenerateCoverageReport."""
+
+ def testGenerateCoverageReport_noCoverageRequired(self):
+ with self.assertRaises(SystemExit) as cm:
+ with mock.patch('os.path.exists', return_value=True):
+ # Returning an empty dictionary on the first call to read() will cause
+ # the method to fail gracefully. This will happen if there are no Java
+ # files to perform coverage analysis on.
+ MockOpenForFunction(coverage.GenerateCoverageReport, ['{}'],
+ line_coverage_file='', out_file_path='',
+ coverage_dir='')
+ self.assertEqual(cm.exception.code, 0)
+
+ @mock.patch('json.dump')
+ @mock.patch('coverage._EmmaCoverageStats')
+ def testGenerateCoverageReport_basic(self, mock_stats, mock_dump):
+ file_changes = '{"file1.java":[1,2,3]}'
+ # Make GetCoverageDict return a valid dictionary as expected in
+ # GenerateCoverageReport.
+ mock_get_coverage_dict = mock_stats.return_value.GetCoverageDictForFiles
+ mock_get_coverage_dict.return_value = EMPTY_COVERAGE_STATS_DICT
+ with mock.patch('os.path.exists', return_value=True):
+ # Call GenerateCoverageReport with a valid set of file changes so that
+ # the function can run to completion.
+ MockOpenForFunction(coverage.GenerateCoverageReport, [file_changes, ''],
+ line_coverage_file='', out_file_path='',
+ coverage_dir='')
+ # Assert that the method ran to completion, and that json.dump was
+ # successfully called.
+ self.assertEqual(1, mock_dump.call_count)
+
+
+def MockOpenForFunction(func, side_effects, **kwargs):
+ """Allows easy mock open and read for callables that open multiple files.
+
+ Will mock the python open function in a way such that each time read() is
+ called on an open file, the next element in |side_effects| is returned. This
+ makes it easier to test functions that call open() multiple times.
+
+ Args:
+ func: The callable to invoke once mock files are setup.
+ side_effects: 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=side_effect).return_value
+ for side_effect in side_effects]
+ with mock.patch('__builtin__.open', mock_open):
+ return func(**kwargs), mock_open
+
+
+if __name__ == '__main__':
+ # Suppress logging messages.
+ unittest.main(buffer=True)
« 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