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

Unified Diff: tools/code_coverage/coverage_posix.py

Issue 155123: Code coverage on Windows (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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
« no previous file with comments | « chrome/chrome.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/code_coverage/coverage_posix.py
===================================================================
--- tools/code_coverage/coverage_posix.py (revision 19085)
+++ tools/code_coverage/coverage_posix.py (working copy)
@@ -3,10 +3,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Generate and process code coverage on POSIX systems.
+"""Generate and process code coverage.
-Written for and tested on Mac and Linux. To use this script to
-generate coverage numbers, please run from within a gyp-generated
+TODO(jrg): rename this from coverage_posix.py to coverage_all.py!
Randall Spangler 2009/07/07 16:14:14 Yes!
+
+Written for and tested on Mac, Linux, and Windows. To use this script
+to generate coverage numbers, please run from within a gyp-generated
project.
All platforms, to set up coverage:
@@ -53,6 +55,7 @@
def __init__(self, directory, options, args):
super(Coverage, self).__init__()
+ logging.basicConfig(level=logging.DEBUG)
self.directory = directory
self.options = options
self.args = args
@@ -60,15 +63,48 @@
self.output_directory = os.path.join(self.directory, 'coverage')
if not os.path.exists(self.output_directory):
os.mkdir(self.output_directory)
- self.lcov_directory = os.path.join(sys.path[0],
- '../../third_party/lcov/bin')
- self.lcov = os.path.join(self.lcov_directory, 'lcov')
- self.mcov = os.path.join(self.lcov_directory, 'mcov')
- self.genhtml = os.path.join(self.lcov_directory, 'genhtml')
+ # The "final" lcov-format file
self.coverage_info_file = os.path.join(self.directory, 'coverage.info')
+ # If needed, an intermediate VSTS-format file
+ self.vsts_output = os.path.join(self.directory, 'coverage.vsts')
+ # Needed for Windows.
+ self.src_root = options.src_root
+ self.FindPrograms()
self.ConfirmPlatformAndPaths()
self.tests = []
+ def FindInPath(self, program):
+ """Find program in our path. Return abs path to it, or None."""
+ if not 'PATH' in os.environ:
+ logging.fatal('No PATH environment variable?')
+ sys.exit(1)
+ paths = os.environ['PATH'].split(os.pathsep)
+ for path in paths:
+ fullpath = os.path.join(path, program)
+ if os.path.exists(fullpath):
+ return fullpath
+ return None
+
+ def FindPrograms(self):
+ """Find programs we may want to run."""
+ if self.IsPosix():
+ self.lcov_directory = os.path.join(sys.path[0],
+ '../../third_party/lcov/bin')
+ self.lcov = os.path.join(self.lcov_directory, 'lcov')
+ self.mcov = os.path.join(self.lcov_directory, 'mcov')
+ self.genhtml = os.path.join(self.lcov_directory, 'genhtml')
+ self.programs = [self.lcov, self.mcov, self.genhtml]
+ else:
+ commands = ['vsperfcmd.exe', 'vsinstr.exe', 'coverage_analyzer.exe']
+ self.perf = self.FindInPath('vsperfcmd.exe')
+ self.instrument = self.FindInPath('vsinstr.exe')
+ self.analyzer = self.FindInPath('coverage_analyzer.exe')
+ if not self.perf or not self.instrument or not self.analyzer:
+ logging.fatal('Could not find Win performance commands.')
+ logging.fatal('Commands needed in PATH: ' + str(commands))
+ sys.exit(1)
+ self.programs = [self.perf, self.instrument, self.analyzer]
+
def FindTests(self):
"""Find unit tests to run; set self.tests to this list.
@@ -86,28 +122,53 @@
self.tests += [os.path.join(self.directory, testname.split(':')[1])]
else:
self.tests += [os.path.join(self.directory, testname)]
-
- # Needs to be run in the "chrome" directory?
- # ut = os.path.join(self.directory, 'unit_tests')
- # if os.path.exists(ut):
- # self.tests.append(ut)
# Medium tests?
# Not sure all of these work yet (e.g. page_cycler_tests)
# self.tests += glob.glob(os.path.join(self.directory, '*_tests'))
+ # If needed, append .exe to tests since vsinstr.exe likes it that
+ # way.
+ if self.IsWindows():
+ for ind in range(len(self.tests)):
+ test = self.tests[ind]
+ test_exe = test + '.exe'
+ if not test.endswith('.exe') and os.path.exists(test_exe):
+ self.tests[ind] = test_exe
+
+ # Temporarily make Windows quick for bringup by filtering
+ # out all except base_unittests. Easier than a chrome.cyp change.
+ # TODO(jrg): remove this
+ if self.IsWindows():
+ t2 = []
+ for test in self.tests:
+ if 'base_unittests' in test:
+ t2.append(test)
+ self.tests = t2
+
+
+
def ConfirmPlatformAndPaths(self):
"""Confirm OS and paths (e.g. lcov)."""
- if not self.IsPosix():
- logging.fatal('Not posix.')
- sys.exit(1)
- programs = [self.lcov, self.genhtml]
- if self.IsMac():
- programs.append(self.mcov)
- for program in programs:
+ for program in self.programs:
if not os.path.exists(program):
- logging.fatal('lcov program missing: ' + program)
+ logging.fatal('Program missing: ' + program)
sys.exit(1)
+ def Run(self, cmdlist, ignore_error=False, ignore_retcode=None,
+ explanation=None):
+ """Run the command list; exit fatally on error."""
+ logging.info('Running ' + str(cmdlist))
+ retcode = subprocess.call(cmdlist)
+ if retcode:
+ if ignore_error or retcode == ignore_retcode:
+ logging.warning('COVERAGE: %s unhappy but errors ignored %s' %
+ (str(cmdlist), explanation or ''))
+ else:
+ logging.fatal('COVERAGE: %s failed; return code: %d' %
+ (str(cmdlist), retcode))
+ sys.exit(retcode)
+
+
def IsPosix(self):
"""Return True if we are POSIX."""
return self.IsMac() or self.IsLinux()
@@ -118,13 +179,36 @@
def IsLinux(self):
return sys.platform == 'linux2'
+ def IsWindows(self):
+ """Return True if we are Windows."""
+ return sys.platform in ('win32', 'cygwin')
+
def ClearData(self):
"""Clear old gcda files"""
+ if not self.IsPosix():
+ return
subprocess.call([self.lcov,
'--directory', self.directory_parent,
'--zerocounters'])
shutil.rmtree(os.path.join(self.directory, 'coverage'))
+ def BeforeRunTests(self):
+ """Do things before running tests."""
+ if not self.IsWindows():
+ return
+ # Stop old counters if needed
+ cmdlist = [self.perf, '-shutdown']
+ self.Run(cmdlist, ignore_error=True)
+ # Instrument binaries
+ for fulltest in self.tests:
+ if os.path.exists(fulltest):
+ cmdlist = [self.instrument, '/COVERAGE', fulltest]
+ self.Run(cmdlist, ignore_retcode=4,
+ explanation='OK with a multiple-instrument')
+ # Start new counters
+ cmdlist = [self.perf, '-start:coverage', '-output:' + self.vsts_output]
+ self.Run(cmdlist)
+
def RunTests(self):
"""Run all unit tests."""
for fulltest in self.tests:
@@ -138,7 +222,8 @@
# If asked, make this REAL fast for testing.
if self.options.fast_test:
- cmdlist.append('--gtest_filter=RenderWidgetHost*')
+ # cmdlist.append('--gtest_filter=RenderWidgetHost*')
+ cmdlist.append('--gtest_filter=CommandLine*')
retcode = subprocess.call(cmdlist)
if retcode:
@@ -147,7 +232,17 @@
if self.options.strict:
sys.exit(retcode)
- def GenerateLcov(self):
+ def AfterRunTests(self):
+ """Do things right after running tests."""
+ if not self.IsWindows():
+ return
+ # Stop counters
+ cmdlist = [self.perf, '-shutdown']
+ self.Run(cmdlist)
+ full_output = self.vsts_output + '.coverage'
+ shutil.move(full_output, self.vsts_output)
+
+ def GenerateLcovPosix(self):
"""Convert profile data to lcov."""
command = [self.mcov,
'--directory', self.directory_parent,
@@ -160,6 +255,34 @@
if self.options.strict:
sys.exit(retcode)
+ def GenerateLcovWindows(self):
+ """Convert VSTS format to lcov."""
+ lcov_file = self.vsts_output + '.lcov'
+ if os.path.exists(lcov_file):
+ os.remove(lcov_file)
+ # generates the file (self.vsts_output + ".lcov")
+
+ cmdlist = [self.analyzer,
+ '-sym_path=' + self.directory,
+ '-src_root=' + self.src_root,
+ self.vsts_output]
+ self.Run(cmdlist)
+ if not os.path.exists(lcov_file):
+ logging.fatal('Output file %s not created' % lcov_file)
+ sys.exit(1)
+ # So we name it appropriately
+ if os.path.exists(self.coverage_info_file):
+ os.remove(self.coverage_info_file)
+ logging.info('Renaming LCOV file to %s to be consistent' %
+ self.coverage_info_file)
+ shutil.move(self.vsts_output + '.lcov', self.coverage_info_file)
+
+ def GenerateLcov(self):
+ if self.IsPosix():
+ self.GenerateLcovPosix()
+ else:
+ self.GenerateLcovWindows()
+
def GenerateHtml(self):
"""Convert lcov to html."""
# TODO(jrg): This isn't happy when run with unit_tests since V8 has a
@@ -206,13 +329,20 @@
dest='strict',
default=False,
help='Be strict and die on test failure.')
+ parser.add_option('-S',
+ '--src_root',
+ dest='src_root',
+ default='.',
+ help='Source root (only used on Windows)')
(options, args) = parser.parse_args()
if not options.directory:
parser.error('Directory not specified')
coverage = Coverage(options.directory, options, args)
coverage.ClearData()
coverage.FindTests()
+ coverage.BeforeRunTests()
coverage.RunTests()
+ coverage.AfterRunTests()
coverage.GenerateLcov()
if options.genhtml:
coverage.GenerateHtml()
« no previous file with comments | « chrome/chrome.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698