OLD | NEW |
(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): |
| 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('*'): |
| 296 if elem.text is not None: |
| 297 elem.text = elem.text.strip() |
| 298 return root |
| 299 |
| 300 |
| 301 class _EmmaCoverageStatsTest(unittest.TestCase): |
| 302 """Tests for _EmmaCoverageStats.""" |
| 303 |
| 304 def setUp(self): |
| 305 self.good_source_to_emma = { |
| 306 '/path/to/1/File1.java': '/emma/1.html', |
| 307 '/path/2/File2.java': '/emma/2.html', |
| 308 '/path/2/File3.java': '/emma/3.html' |
| 309 } |
| 310 self.line_coverage = [ |
| 311 coverage.LineCoverage(1, '', coverage.LineCoverage.COVERED, 1.0), |
| 312 coverage.LineCoverage(2, '', coverage.LineCoverage.COVERED, 1.0), |
| 313 coverage.LineCoverage(3, '', coverage.LineCoverage.NOT_EXECUTABLE, 1.0), |
| 314 coverage.LineCoverage(4, '', coverage.LineCoverage.NOT_COVERED, 1.0), |
| 315 coverage.LineCoverage(5, '', |
| 316 coverage.LineCoverage.PARTIALLY_COVERED, 0.85), |
| 317 coverage.LineCoverage(6, '', |
| 318 coverage.LineCoverage.PARTIALLY_COVERED, 0.20) |
| 319 ] |
| 320 self.lines_for_coverage = [1, 3, 5, 6] |
| 321 self.simple_coverage = coverage._EmmaCoverageStats('fake_dir', {}) |
| 322 |
| 323 def testInit(self): |
| 324 coverage_stats = self.simple_coverage |
| 325 self.assertIsInstance(coverage_stats._emma_parser, |
| 326 coverage._EmmaHtmlParser) |
| 327 self.assertIsInstance(coverage_stats._source_to_emma, dict) |
| 328 |
| 329 def testNeedsCoverage_withExistingJavaFile(self): |
| 330 test_file = '/path/to/file/File.java' |
| 331 with mock.patch('os.path.exists', return_value=True): |
| 332 self.assertTrue(coverage._EmmaCoverageStats.NeedsCoverage(test_file)) |
| 333 |
| 334 def testNeedsCoverage_withNonJavaFile(self): |
| 335 test_file = '/path/to/file/File.c' |
| 336 with mock.patch('os.path.exists', return_value=True): |
| 337 self.assertFalse(coverage._EmmaCoverageStats.NeedsCoverage(test_file)) |
| 338 |
| 339 def testNeedsCoverage_fileDoesNotExist(self): |
| 340 test_file = '/path/to/file/File.java' |
| 341 with mock.patch('os.path.exists', return_value=False): |
| 342 self.assertFalse(coverage._EmmaCoverageStats.NeedsCoverage(test_file)) |
| 343 |
| 344 def testGetPackageNameFromFile_basic(self): |
| 345 test_file_text = """// Test Copyright |
| 346 package org.chromium.chrome.browser; |
| 347 import android.graphics.RectF;""" |
| 348 result_package, _ = MockOpenForFunction( |
| 349 coverage._EmmaCoverageStats.GetPackageNameFromFile, test_file_text, |
| 350 file_path='/path/to/file/File.java') |
| 351 self.assertEqual(result_package, 'org.chromium.chrome.browser.File.java') |
| 352 |
| 353 def testGetPackageNameFromFile_noPackageStatement(self): |
| 354 result_package, _ = MockOpenForFunction( |
| 355 coverage._EmmaCoverageStats.GetPackageNameFromFile, |
| 356 'not a package statement', file_path='/path/to/file/File.java') |
| 357 self.assertEqual(result_package, None) |
| 358 |
| 359 def testGetStatsForLines_basic(self): |
| 360 covered, total = self.simple_coverage._GetStatsForLines( |
| 361 self.line_coverage, self.lines_for_coverage) |
| 362 self.assertEqual(covered, 2.05) |
| 363 self.assertEqual(total, 3) |
| 364 |
| 365 def testGetStatsForLines_noLineNumbersProvided(self): |
| 366 covered, total = self.simple_coverage._GetStatsForLines(self.line_coverage) |
| 367 self.assertEqual(covered, 3.05) |
| 368 self.assertEqual(total, 5) |
| 369 |
| 370 def testGetSourceFileToEmmaFileDict(self): |
| 371 package_names = { |
| 372 '/path/to/1/File1.java': 'org.fake.one.File1.java', |
| 373 '/path/2/File2.java': 'org.fake.File2.java', |
| 374 '/path/2/File3.java': 'org.fake.File3.java' |
| 375 } |
| 376 package_to_emma = { |
| 377 'org.fake.one.File1.java': '/emma/1.html', |
| 378 'org.fake.File2.java': '/emma/2.html', |
| 379 'org.fake.File3.java': '/emma/3.html' |
| 380 } |
| 381 with mock.patch('os.path.exists', return_value=True): |
| 382 coverage_stats = self.simple_coverage |
| 383 coverage_stats._emma_parser.GetPackageNameToEmmaFileDict = mock.MagicMock( |
| 384 return_value=package_to_emma) |
| 385 coverage_stats.GetPackageNameFromFile = lambda x: package_names[x] |
| 386 result_dict = coverage_stats._GetSourceFileToEmmaFileDict( |
| 387 package_names.keys()) |
| 388 self.assertDictEqual(result_dict, self.good_source_to_emma) |
| 389 |
| 390 def testGetCoverageStatusFromFile_basic(self): |
| 391 java_file_path = '/path/to/1/File1.java' |
| 392 line_coverage = [ |
| 393 coverage.LineCoverage(1, '', coverage.LineCoverage.COVERED, 1.0)] |
| 394 coverage_stats = self.simple_coverage |
| 395 coverage_stats._source_to_emma = self.good_source_to_emma |
| 396 coverage_stats._emma_parser.GetLineCoverage = mock.MagicMock( |
| 397 return_value=line_coverage) |
| 398 coverage_info = coverage_stats._GetCoverageStatusForFile(java_file_path) |
| 399 self.assertDictEqual(coverage_info[0].__dict__, line_coverage[0].__dict__) |
| 400 |
| 401 def testGetCoverageStatusFromFile_noInfo(self): |
| 402 coverage_info = self.simple_coverage._GetCoverageStatusForFile('fake_path') |
| 403 self.assertIsNone(coverage_info) |
| 404 |
| 405 def testGetCoverageReportForLines(self): |
| 406 line_coverage = self.line_coverage |
| 407 lines = self.lines_for_coverage |
| 408 expected_dict = { |
| 409 'absolute': { |
| 410 'covered': 3.05, |
| 411 'total': 5 |
| 412 }, |
| 413 'incremental': { |
| 414 'covered': 2.05, |
| 415 'total': 3 |
| 416 }, |
| 417 'source': [ |
| 418 { |
| 419 'line': line_coverage[0].source, |
| 420 'coverage': line_coverage[0].covered_status, |
| 421 'changed': True |
| 422 }, |
| 423 { |
| 424 'line': line_coverage[1].source, |
| 425 'coverage': line_coverage[1].covered_status, |
| 426 'changed': False |
| 427 }, |
| 428 { |
| 429 'line': line_coverage[2].source, |
| 430 'coverage': line_coverage[2].covered_status, |
| 431 'changed': True |
| 432 }, |
| 433 { |
| 434 'line': line_coverage[3].source, |
| 435 'coverage': line_coverage[3].covered_status, |
| 436 'changed': False |
| 437 }, |
| 438 { |
| 439 'line': line_coverage[4].source, |
| 440 'coverage': line_coverage[4].covered_status, |
| 441 'changed': True |
| 442 }, |
| 443 { |
| 444 'line': line_coverage[5].source, |
| 445 'coverage': line_coverage[5].covered_status, |
| 446 'changed': True |
| 447 } |
| 448 ] |
| 449 } |
| 450 result_dict = self.simple_coverage.GetCoverageReportForLines(line_coverage, |
| 451 lines) |
| 452 self.assertDictEqual(result_dict, expected_dict) |
| 453 |
| 454 def testGetCoverageReportForLines_emptyCoverage(self): |
| 455 expected_dict = { |
| 456 'absolute': {'covered': 0, 'total': 0}, |
| 457 'incremental': {'covered': 0, 'total': 0}, |
| 458 'source': [] |
| 459 } |
| 460 result_dict = self.simple_coverage.GetCoverageReportForLines({}, []) |
| 461 self.assertDictEqual(result_dict, expected_dict) |
| 462 |
| 463 def testGetCoverageDictForFiles_basic(self): |
| 464 files_for_coverage = { |
| 465 '/path/to/1/File1.java': [1, 3, 4], |
| 466 '/path/2/File2.java': [1, 2] |
| 467 } |
| 468 coverage_info = { |
| 469 '/path/to/1/File1.java': [ |
| 470 coverage.LineCoverage(1, '', coverage.LineCoverage.COVERED, 1.0), |
| 471 coverage.LineCoverage(2, '', |
| 472 coverage.LineCoverage.PARTIALLY_COVERED, 0.5), |
| 473 coverage.LineCoverage(3, '', |
| 474 coverage.LineCoverage.NOT_EXECUTABLE, 1.0), |
| 475 coverage.LineCoverage(4, '', coverage.LineCoverage.COVERED, 1.0) |
| 476 ], |
| 477 '/path/2/File2.java': [ |
| 478 coverage.LineCoverage(1, '', coverage.LineCoverage.NOT_COVERED, 1.0), |
| 479 coverage.LineCoverage(2, '', coverage.LineCoverage.COVERED, 1.0) |
| 480 ] |
| 481 } |
| 482 expected_dict = { |
| 483 'files': { |
| 484 '/path/2/File2.java': { |
| 485 'absolute': {'covered': 1, 'total': 2}, |
| 486 'incremental': {'covered': 1, 'total': 2}, |
| 487 'source': [{'changed': True, 'coverage': 0, 'line': ''}, |
| 488 {'changed': True, 'coverage': 1, 'line': ''}] |
| 489 }, |
| 490 '/path/to/1/File1.java': { |
| 491 'absolute': {'covered': 2.5, 'total': 3}, |
| 492 'incremental': {'covered': 2, 'total': 2}, |
| 493 'source': [{'changed': True, 'coverage': 1, 'line': ''}, |
| 494 {'changed': False, 'coverage': 2, 'line': ''}, |
| 495 {'changed': True, 'coverage': -1, 'line': ''}, |
| 496 {'changed': True, 'coverage': 1, 'line': ''}] |
| 497 } |
| 498 }, |
| 499 'patch': {'incremental': {'covered': 3, 'total': 4}} |
| 500 } |
| 501 self.simple_coverage._GetCoverageStatusForFile = lambda x: coverage_info[x] |
| 502 result_dict = self.simple_coverage.GetCoverageDictForFiles( |
| 503 files_for_coverage) |
| 504 self.assertDictEqual(result_dict, expected_dict) |
| 505 |
| 506 def testGetCoverageDictForFiles_noCoverage(self): |
| 507 expected_dict = { |
| 508 'files': {}, |
| 509 'patch': { |
| 510 'incremental': { |
| 511 'covered': 0, 'total': 0 |
| 512 } |
| 513 } |
| 514 } |
| 515 result_dict = self.simple_coverage.GetCoverageDictForFiles({}) |
| 516 self.assertDictEqual(result_dict, expected_dict) |
| 517 |
| 518 |
| 519 class CoverageGenerateCoverageReportTest(unittest.TestCase): |
| 520 """Tests for GenerateCoverageReport.""" |
| 521 |
| 522 def testGenerateCoverageReport_missingLineCoverageFile(self): |
| 523 with self.assertRaises(IOError): |
| 524 with mock.patch('os.path.exists', return_value=False): |
| 525 coverage.GenerateCoverageReport('', '', '') |
| 526 |
| 527 def testGenerateCoverageReport_noCoverageRequired(self): |
| 528 with self.assertRaises(SystemExit) as cm: |
| 529 with mock.patch('os.path.exists', return_value=True): |
| 530 MockOpenForFunction(coverage.GenerateCoverageReport, '{}', |
| 531 line_coverage_file='', out_file_path='', |
| 532 coverage_dir='') |
| 533 self.assertEqual(cm.exception.code, 0) |
| 534 |
| 535 |
| 536 def MockOpenForFunction(func, *args, **kwargs): |
| 537 """Allows easy mock open and read for callables that open multiple files. |
| 538 |
| 539 Args: |
| 540 func: The callable to invoke once mock files are setup. |
| 541 *args: A list of return values for each file to return once read. Length of |
| 542 list should be equal to the number calls to open in |func|. |
| 543 **kwargs: Keyword arguments to be passed to |func|. |
| 544 |
| 545 Returns: |
| 546 A tuple containing the return value of |func| and the MagicMock object used |
| 547 to mock all calls to open respectively. |
| 548 """ |
| 549 mock_open = mock.mock_open() |
| 550 mock_open.side_effect = [mock.mock_open(read_data=arg).return_value |
| 551 for arg in args] |
| 552 with mock.patch('__builtin__.open', mock_open): |
| 553 return func(**kwargs), mock_open |
| 554 |
| 555 |
| 556 if __name__ == '__main__': |
| 557 # Suppress logging messages. |
| 558 unittest.main(buffer=True) |
OLD | NEW |