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

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: 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 if file_path in self._source_to_emma:
260 file_path, line_numbers) 260 file_coverage[file_path] = self.GetCoverageDictForFile(
261 file_path, line_numbers)
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 emma_file = self._source_to_emma[file_path]
mikecase (-- gone --) 2015/08/17 18:53:57 nit: This will get a key error if file_path is not
estevenson1 2015/08/17 19:06:17 Done. Added a test for it as well.
293 total_line_coverage = self._emma_parser.GetLineCoverage(emma_file)
289 incremental_line_coverage = [line for line in total_line_coverage 294 incremental_line_coverage = [line for line in total_line_coverage
290 if line.lineno in line_numbers] 295 if line.lineno in line_numbers]
291 line_by_line_coverage = [ 296 line_by_line_coverage = [
292 { 297 {
293 'line': line.source, 298 'line': line.source,
294 'coverage': line.covered_status, 299 'coverage': line.covered_status,
295 'changed': line.lineno in line_numbers, 300 'changed': line.lineno in line_numbers,
296 } 301 }
297 for line in total_line_coverage 302 for line in total_line_coverage
298 ] 303 ]
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 if status == NOT_EXECUTABLE: 336 if status == NOT_EXECUTABLE:
332 continue 337 continue
333 covered_status_totals[status] += 1 338 covered_status_totals[status] += 1
334 if status == PARTIALLY_COVERED: 339 if status == PARTIALLY_COVERED:
335 partially_covered_sum += line.fractional_line_coverage 340 partially_covered_sum += line.fractional_line_coverage
336 341
337 total_covered = covered_status_totals[COVERED] + partially_covered_sum 342 total_covered = covered_status_totals[COVERED] + partially_covered_sum
338 total_lines = sum(covered_status_totals.values()) 343 total_lines = sum(covered_status_totals.values())
339 return total_covered, total_lines 344 return total_covered, total_lines
340 345
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): 346 def _GetSourceFileToEmmaFileDict(self, files):
360 """Gets a dict used to correlate Java source files with EMMA HTML files. 347 """Gets a dict used to correlate Java source files with EMMA HTML files.
361 348
362 This method gathers the information needed to correlate EMMA HTML 349 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 350 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. 351 line by line coverage data, so HTML reports must be used instead.
365 Unfortunately, the HTML files that are created are given garbage names 352 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 353 (i.e 1.html) so we need to manually correlate EMMA HTML files
367 with the original Java source files. 354 with the original Java source files.
368 355
(...skipping 12 matching lines...) Expand all
381 source_to_package[file_path] = package 368 source_to_package[file_path] = package
382 else: 369 else:
383 logging.warning("Skipping %s because it doesn\'t have a package " 370 logging.warning("Skipping %s because it doesn\'t have a package "
384 "statement.", file_path) 371 "statement.", file_path)
385 372
386 # Maps package names to EMMA report HTML files. 373 # Maps package names to EMMA report HTML files.
387 # Example: org.chromium.file.java -> out/coverage/1a.html. 374 # Example: org.chromium.file.java -> out/coverage/1a.html.
388 package_to_emma = self._emma_parser.GetPackageNameToEmmaFileDict() 375 package_to_emma = self._emma_parser.GetPackageNameToEmmaFileDict()
389 # Finally, we have a dict mapping Java file paths to EMMA report files. 376 # Finally, we have a dict mapping Java file paths to EMMA report files.
390 # Example: /usr/code/file.java -> out/coverage/1a.html. 377 # Example: /usr/code/file.java -> out/coverage/1a.html.
391 source_to_emma = {source: package_to_emma.get(package) 378 source_to_emma = {source: package_to_emma[package]
392 for source, package in source_to_package.iteritems()} 379 for source, package in source_to_package.iteritems()
380 if package in package_to_emma}
393 return source_to_emma 381 return source_to_emma
394 382
395 @staticmethod 383 @staticmethod
396 def NeedsCoverage(file_path): 384 def NeedsCoverage(file_path):
397 """Checks to see if the file needs to be analyzed for code coverage. 385 """Checks to see if the file needs to be analyzed for code coverage.
398 386
399 Args: 387 Args:
400 file_path: A string representing path to the file. 388 file_path: A string representing path to the file.
401 389
402 Returns: 390 Returns:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 Args: 428 Args:
441 line_coverage_file: The path to a file which contains a dict mapping file 429 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 430 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. 431 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. 432 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 433 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). 434 HTML coverage files are located (i.e. folder where index.html is located).
447 """ 435 """
448 with open(line_coverage_file) as f: 436 with open(line_coverage_file) as f:
449 potential_files_for_coverage = json.load(f) 437 potential_files_for_coverage = json.load(f)
438
450 files_for_coverage = {f: lines 439 files_for_coverage = {f: lines
451 for f, lines in potential_files_for_coverage.iteritems() 440 for f, lines in potential_files_for_coverage.iteritems()
452 if _EmmaCoverageStats.NeedsCoverage(f)} 441 if _EmmaCoverageStats.NeedsCoverage(f)}
453 442
454 coverage_results = {} 443 coverage_results = {}
455 if files_for_coverage: 444 if files_for_coverage:
456 code_coverage = _EmmaCoverageStats(coverage_dir, files_for_coverage.keys()) 445 code_coverage = _EmmaCoverageStats(coverage_dir, files_for_coverage.keys())
457 coverage_results = code_coverage.GetCoverageDict( 446 coverage_results = code_coverage.GetCoverageDict(
458 files_for_coverage) 447 files_for_coverage)
459 else: 448 else:
(...skipping 16 matching lines...) Expand all
476 'code for which coverage information is desired.') 465 'code for which coverage information is desired.')
477 argparser.add_argument('-v', '--verbose', action='count', 466 argparser.add_argument('-v', '--verbose', action='count',
478 help='Print verbose log information.') 467 help='Print verbose log information.')
479 args = argparser.parse_args() 468 args = argparser.parse_args()
480 run_tests_helper.SetLogLevel(args.verbose) 469 run_tests_helper.SetLogLevel(args.verbose)
481 GenerateCoverageReport(args.lines_for_coverage_file, args.out, args.emma_dir) 470 GenerateCoverageReport(args.lines_for_coverage_file, args.out, args.emma_dir)
482 471
483 472
484 if __name__ == '__main__': 473 if __name__ == '__main__':
485 sys.exit(main()) 474 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