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

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

Issue 1299693003: Handle missing EMMA files. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed jbudorick comment. 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 | « no previous file | build/android/emma_coverage_stats_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright 2015 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Generates incremental code coverage reports for Java code in Chromium. 6 """Generates incremental code coverage reports for Java code in Chromium.
7 7
8 Usage: 8 Usage:
9 9
10 build/android/coverage.py -v --out <output file path> --emma-dir 10 build/android/emma_coverage_stats.py -v --out <output file path> --emma-dir
11 <EMMA file directory> --lines-for-coverage-file 11 <EMMA file directory> --lines-for-coverage-file
12 <path to file containing lines for coverage> 12 <path to file containing lines for coverage>
13 13
14 Creates a JSON representation of the overall and file coverage stats and saves 14 Creates a JSON representation of the overall and file coverage stats and saves
15 this information to the specified output file. 15 this information to the specified output file.
16 """ 16 """
17 17
18 import argparse 18 import argparse
19 import collections 19 import collections
20 import json 20 import json
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 249
250 Returns: 250 Returns:
251 A dict containing coverage stats for the given dict of files and lines. 251 A dict containing coverage stats for the given dict of files and lines.
252 Contains absolute coverage stats for each file, coverage stats for each 252 Contains absolute coverage stats for each file, coverage stats for each
253 file's lines specified in |lines_for_coverage|, line by line coverage 253 file's lines specified in |lines_for_coverage|, line by line coverage
254 for each file, and overall coverage stats for the lines specified in 254 for each file, and overall coverage stats for the lines specified in
255 |lines_for_coverage|. 255 |lines_for_coverage|.
256 """ 256 """
257 file_coverage = {} 257 file_coverage = {}
258 for file_path, line_numbers in lines_for_coverage.iteritems(): 258 for file_path, line_numbers in lines_for_coverage.iteritems():
259 file_coverage[file_path] = self.GetCoverageDictForFile( 259 file_coverage_dict = self.GetCoverageDictForFile(file_path, line_numbers)
260 file_path, line_numbers) 260 if file_coverage_dict:
261 file_coverage[file_path] = file_coverage_dict
262 else:
263 logging.warning(
264 'No code coverage data for %s, skipping.', file_path)
261 265
262 covered_statuses = [s['incremental'] for s in file_coverage.itervalues()] 266 covered_statuses = [s['incremental'] for s in file_coverage.itervalues()]
263 num_covered_lines = sum(s['covered'] for s in covered_statuses) 267 num_covered_lines = sum(s['covered'] for s in covered_statuses)
264 num_total_lines = sum(s['total'] for s in covered_statuses) 268 num_total_lines = sum(s['total'] for s in covered_statuses)
265 return { 269 return {
266 'files': file_coverage, 270 'files': file_coverage,
267 'patch': { 271 'patch': {
268 'incremental': { 272 'incremental': {
269 'covered': num_covered_lines, 273 'covered': num_covered_lines,
270 'total': num_total_lines 274 'total': num_total_lines
271 } 275 }
272 } 276 }
273 } 277 }
274 278
275 def GetCoverageDictForFile(self, file_path, line_numbers): 279 def GetCoverageDictForFile(self, file_path, line_numbers):
276 """Returns a dict containing detailed coverage info for the given file. 280 """Returns a dict containing detailed coverage info for the given file.
277 281
278 Args: 282 Args:
279 file_path: The path to the Java source file that we want to create the 283 file_path: The path to the Java source file that we want to create the
280 coverage dict for. 284 coverage dict for.
281 line_numbers: A list of integer line numbers to retrieve additional stats 285 line_numbers: A list of integer line numbers to retrieve additional stats
282 for. 286 for.
283 287
284 Returns: 288 Returns:
285 A dict containing absolute, incremental, and line by line coverage for 289 A dict containing absolute, incremental, and line by line coverage for
286 a file. 290 a file.
287 """ 291 """
288 total_line_coverage = self._GetLineCoverageForFile(file_path) 292 if file_path not in self._source_to_emma:
293 return None
294 emma_file = self._source_to_emma[file_path]
295 total_line_coverage = self._emma_parser.GetLineCoverage(emma_file)
289 incremental_line_coverage = [line for line in total_line_coverage 296 incremental_line_coverage = [line for line in total_line_coverage
290 if line.lineno in line_numbers] 297 if line.lineno in line_numbers]
291 line_by_line_coverage = [ 298 line_by_line_coverage = [
292 { 299 {
293 'line': line.source, 300 'line': line.source,
294 'coverage': line.covered_status, 301 'coverage': line.covered_status,
295 'changed': line.lineno in line_numbers, 302 'changed': line.lineno in line_numbers,
296 } 303 }
297 for line in total_line_coverage 304 for line in total_line_coverage
298 ] 305 ]
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 if status == NOT_EXECUTABLE: 338 if status == NOT_EXECUTABLE:
332 continue 339 continue
333 covered_status_totals[status] += 1 340 covered_status_totals[status] += 1
334 if status == PARTIALLY_COVERED: 341 if status == PARTIALLY_COVERED:
335 partially_covered_sum += line.fractional_line_coverage 342 partially_covered_sum += line.fractional_line_coverage
336 343
337 total_covered = covered_status_totals[COVERED] + partially_covered_sum 344 total_covered = covered_status_totals[COVERED] + partially_covered_sum
338 total_lines = sum(covered_status_totals.values()) 345 total_lines = sum(covered_status_totals.values())
339 return total_covered, total_lines 346 return total_covered, total_lines
340 347
341 def _GetLineCoverageForFile(self, file_path):
342 """Gets a list of LineCoverage objects corresponding to the given file path.
343
344 Args:
345 file_path: String representing the path to the Java source file.
346
347 Returns:
348 A list of LineCoverage objects, or None if there is no EMMA file
349 for the given Java source file.
350 """
351 if file_path in self._source_to_emma:
352 emma_file = self._source_to_emma[file_path]
353 return self._emma_parser.GetLineCoverage(emma_file)
354 else:
355 logging.warning(
356 'No code coverage data for %s, skipping.', file_path)
357 return None
358
359 def _GetSourceFileToEmmaFileDict(self, files): 348 def _GetSourceFileToEmmaFileDict(self, files):
360 """Gets a dict used to correlate Java source files with EMMA HTML files. 349 """Gets a dict used to correlate Java source files with EMMA HTML files.
361 350
362 This method gathers the information needed to correlate EMMA HTML 351 This method gathers the information needed to correlate EMMA HTML
363 files with Java source files. EMMA XML and plain text reports do not provide 352 files with Java source files. EMMA XML and plain text reports do not provide
364 line by line coverage data, so HTML reports must be used instead. 353 line by line coverage data, so HTML reports must be used instead.
365 Unfortunately, the HTML files that are created are given garbage names 354 Unfortunately, the HTML files that are created are given garbage names
366 (i.e 1.html) so we need to manually correlate EMMA HTML files 355 (i.e 1.html) so we need to manually correlate EMMA HTML files
367 with the original Java source files. 356 with the original Java source files.
368 357
(...skipping 12 matching lines...) Expand all
381 source_to_package[file_path] = package 370 source_to_package[file_path] = package
382 else: 371 else:
383 logging.warning("Skipping %s because it doesn\'t have a package " 372 logging.warning("Skipping %s because it doesn\'t have a package "
384 "statement.", file_path) 373 "statement.", file_path)
385 374
386 # Maps package names to EMMA report HTML files. 375 # Maps package names to EMMA report HTML files.
387 # Example: org.chromium.file.java -> out/coverage/1a.html. 376 # Example: org.chromium.file.java -> out/coverage/1a.html.
388 package_to_emma = self._emma_parser.GetPackageNameToEmmaFileDict() 377 package_to_emma = self._emma_parser.GetPackageNameToEmmaFileDict()
389 # Finally, we have a dict mapping Java file paths to EMMA report files. 378 # Finally, we have a dict mapping Java file paths to EMMA report files.
390 # Example: /usr/code/file.java -> out/coverage/1a.html. 379 # Example: /usr/code/file.java -> out/coverage/1a.html.
391 source_to_emma = {source: package_to_emma.get(package) 380 source_to_emma = {source: package_to_emma[package]
392 for source, package in source_to_package.iteritems()} 381 for source, package in source_to_package.iteritems()
382 if package in package_to_emma}
393 return source_to_emma 383 return source_to_emma
394 384
395 @staticmethod 385 @staticmethod
396 def NeedsCoverage(file_path): 386 def NeedsCoverage(file_path):
397 """Checks to see if the file needs to be analyzed for code coverage. 387 """Checks to see if the file needs to be analyzed for code coverage.
398 388
399 Args: 389 Args:
400 file_path: A string representing path to the file. 390 file_path: A string representing path to the file.
401 391
402 Returns: 392 Returns:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 Args: 430 Args:
441 line_coverage_file: The path to a file which contains a dict mapping file 431 line_coverage_file: The path to a file which contains a dict mapping file
442 names to lists of line numbers. Example: {file1: [1, 2, 3], ...} means 432 names to lists of line numbers. Example: {file1: [1, 2, 3], ...} means
443 that we should compute coverage information on lines 1 - 3 for file1. 433 that we should compute coverage information on lines 1 - 3 for file1.
444 out_file_path: A string representing the location to write the JSON report. 434 out_file_path: A string representing the location to write the JSON report.
445 coverage_dir: A string representing the file path where the EMMA 435 coverage_dir: A string representing the file path where the EMMA
446 HTML coverage files are located (i.e. folder where index.html is located). 436 HTML coverage files are located (i.e. folder where index.html is located).
447 """ 437 """
448 with open(line_coverage_file) as f: 438 with open(line_coverage_file) as f:
449 potential_files_for_coverage = json.load(f) 439 potential_files_for_coverage = json.load(f)
440
450 files_for_coverage = {f: lines 441 files_for_coverage = {f: lines
451 for f, lines in potential_files_for_coverage.iteritems() 442 for f, lines in potential_files_for_coverage.iteritems()
452 if _EmmaCoverageStats.NeedsCoverage(f)} 443 if _EmmaCoverageStats.NeedsCoverage(f)}
453 444
454 coverage_results = {} 445 coverage_results = {}
455 if files_for_coverage: 446 if files_for_coverage:
456 code_coverage = _EmmaCoverageStats(coverage_dir, files_for_coverage.keys()) 447 code_coverage = _EmmaCoverageStats(coverage_dir, files_for_coverage.keys())
457 coverage_results = code_coverage.GetCoverageDict( 448 coverage_results = code_coverage.GetCoverageDict(
458 files_for_coverage) 449 files_for_coverage)
459 else: 450 else:
(...skipping 16 matching lines...) Expand all
476 'code for which coverage information is desired.') 467 'code for which coverage information is desired.')
477 argparser.add_argument('-v', '--verbose', action='count', 468 argparser.add_argument('-v', '--verbose', action='count',
478 help='Print verbose log information.') 469 help='Print verbose log information.')
479 args = argparser.parse_args() 470 args = argparser.parse_args()
480 run_tests_helper.SetLogLevel(args.verbose) 471 run_tests_helper.SetLogLevel(args.verbose)
481 GenerateCoverageReport(args.lines_for_coverage_file, args.out, args.emma_dir) 472 GenerateCoverageReport(args.lines_for_coverage_file, args.out, args.emma_dir)
482 473
483 474
484 if __name__ == '__main__': 475 if __name__ == '__main__':
485 sys.exit(main()) 476 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | build/android/emma_coverage_stats_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698