summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-03 04:35:18 +0000
committerjrg@chromium.org <jrg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-03 04:35:18 +0000
commitf5ecbba1f92417edf8759d93904e12cfe9a2d0b4 (patch)
tree88eb8f6e89012dd41189a478fa6e263569a23ffa
parenta6cf87ec511a64fc29c0bda5cf83ec282d34be59 (diff)
downloadchromium_src-f5ecbba1f92417edf8759d93904e12cfe9a2d0b4.zip
chromium_src-f5ecbba1f92417edf8759d93904e12cfe9a2d0b4.tar.gz
chromium_src-f5ecbba1f92417edf8759d93904e12cfe9a2d0b4.tar.bz2
Start of code coverage for Mac.
Only base_unittests included for now. Linux changes added as well but untested until Linux switches to gyp. Enable coverage with the following command: src/tools/gyp/gyp_dogfood -Dcoverage=1 src/build/all.gyp Review URL: http://codereview.chromium.org/56136 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13068 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--build/common.gypi35
-rw-r--r--chrome/chrome.gyp27
-rwxr-xr-xtools/code_coverage/coverage_posix.py120
3 files changed, 182 insertions, 0 deletions
diff --git a/build/common.gypi b/build/common.gypi
index 07b4f5f..2ddf44f 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -25,6 +25,12 @@
# Override branding to select the desired branding flavor.
'branding%': 'Chromium',
+
+ # Set to 1 to enable code coverage. In addition to build changes
+ # (e.g. extra CFLAGS), also creates a new target in the src/chrome
+ # project file called "coverage".
+ # Currently ignored on Windows.
+ 'coverage%': 0,
},
'target_defaults': {
'conditions': [
@@ -33,6 +39,35 @@
}, { # else: branding!="Chrome"
'defines': ['CHROMIUM_BUILD'],
}],
+ ['coverage!=0', {
+ 'conditions': [
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_INSTRUMENT_PROGRAM_FLOW_ARCS': 'YES',
+ 'GCC_GENERATE_TEST_COVERAGE_FILES': 'YES',
+ },
+ # Add -lgcov for executables, not for static_libraries.
+ # This is a delayed conditional.
+ 'target_conditions': [
+ ['_type=="executable"', {
+ 'xcode_settings': { 'OTHER_LDFLAGS': [ '-lgcov' ] },
+ }],
+ ],
+ }],
+ # TODO(jrg): complete this work once Linux transitions to gyp.
+ # This is untested (--> likely doesn't work).
+ ['OS=="linux"', {
+ 'cflags': [ '-ftest-coverage',
+ '-fprofile-arcs' ],
+ 'target_conditions': [
+ ['_type=="executable"', {
+ 'link_settings': { 'libraries': [ '-lgcov' ] },
+ }],
+ ],
+ }],
+ ]},
+ # TODO(jrg): options for code coverage on Windows
+ ],
],
'default_configuration': 'Debug',
'configurations': {
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 43b1412..615ba24 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -2805,5 +2805,32 @@
},
]}, # 'targets'
], # OS=="win"
+ # TODO(jrg): add in Windows code coverage targets.
+ # Also test on Linux.
+ ['coverage!=0 and OS=="mac"',
+ { 'targets': [
+ {
+ 'target_name': 'coverage',
+ # do NOT place this in the 'all' list; most won't want it.
+ # In gyp, booleans are 0/1 not True/False.
+ 'suppress_wildcard': 1,
+ 'type': 'none',
+ 'dependencies': [
+ '../base/base.gyp:base_unittests',
+ ],
+ 'actions': [
+ {
+ 'inputs': [],
+ 'outputs': [],
+ 'action_name': 'coverage',
+ 'action': [ 'python',
+ '../tools/code_coverage/coverage_posix.py',
+ '--directory',
+ '<(PRODUCT_DIR)' ],
+ },
+ ], # 'actions'
+ },
+ ]
+ }],
], # 'conditions'
}
diff --git a/tools/code_coverage/coverage_posix.py b/tools/code_coverage/coverage_posix.py
new file mode 100755
index 0000000..88eb23c
--- /dev/null
+++ b/tools/code_coverage/coverage_posix.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+# Copyright (c) 2009 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.
+
+"""Generate and process code coverage on POSIX systems.
+
+Written for and tested on Mac.
+Not tested on Linux yet.
+
+--directory=DIR: specify directory that contains gcda files, and where
+ a "coverage" directory will be created containing the output html.
+
+TODO(jrg): make list of unit tests an arg to this script
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+
+class Coverage(object):
+ """Doitall class for code coverage."""
+
+ # Unit test files to run.
+ UNIT_TESTS = [
+ 'base_unittests',
+ # 'unit_tests,
+ ]
+
+ def __init__(self, directory):
+ super(Coverage, self).__init__()
+ self.directory = directory
+ 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')
+ self.coverage_info_file = self.directory + 'coverage.info'
+ self.ConfirmPlatformAndPaths()
+
+ def ConfirmPlatformAndPaths(self):
+ """Confirm OS and paths (e.g. lcov)."""
+ if not self.IsPosix():
+ logging.fatal('Not posix.')
+ programs = [self.lcov, self.genhtml]
+ if self.IsMac():
+ programs.append(self.mcov)
+ for program in programs:
+ if not os.path.exists(program):
+ logging.fatal('lcov program missing: ' + program)
+
+ def IsPosix(self):
+ """Return True if we are POSIX."""
+ return self.IsMac() or self.IsLinux()
+
+ def IsMac(self):
+ return sys.platform == 'darwin'
+
+ def IsLinux(self):
+ return sys.platform == 'linux2'
+
+ def ClearData(self):
+ """Clear old gcda files"""
+ subprocess.call([self.lcov,
+ '--directory', self.directory,
+ '--zerocounters'])
+
+ def RunTests(self):
+ """Run all unit tests."""
+ for test in self.UNIT_TESTS:
+ fulltest = os.path.join(self.directory, test)
+ if not os.path.exists(fulltest):
+ logging.fatal(fulltest + ' does not exist')
+ # TODO(jrg): add timeout?
+ # TODO(jrg): check return value and choke if it failed?
+ # TODO(jrg): add --gtest_print_time like as run from XCode?
+ subprocess.call([fulltest])
+
+ def GenerateOutput(self):
+ """Convert profile data to html."""
+ if self.IsLinux():
+ subprocess.call([self.lcov,
+ '--directory', self.directory,
+ '--capture',
+ '--output-file',
+ self.coverage_info_file])
+ else:
+ subprocess.call([self.mcov,
+ '--directory', self.directory,
+ '--output', self.coverage_info_file])
+ subprocess.call([self.genhtml,
+ self.coverage_info_file,
+ '--output-directory',
+ self.output_directory])
+
+def main():
+ parser = optparse.OptionParser()
+ parser.add_option('-d',
+ '--directory',
+ dest='directory',
+ default=None,
+ help='Directory of unit test files')
+ (options, args) = parser.parse_args()
+ if not options.directory:
+ parser.error('Directory not specified')
+
+ coverage = Coverage(options.directory)
+ coverage.ClearData()
+ coverage.RunTests()
+ coverage.GenerateOutput()
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())