1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#!/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.directory_parent = os.path.dirname(self.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 = os.path.join(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_parent,
'--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?
print 'Running test: ' + fulltest
# subprocess.call([fulltest, '--gtest_filter=TupleTest*']) # quick check
subprocess.call([fulltest])
def GenerateOutput(self):
"""Convert profile data to html."""
if self.IsLinux():
command = [self.lcov,
'--directory', self.directory,
'--capture',
'--output-file',
self.coverage_info_file]
else:
command = [self.mcov,
'--directory', self.directory_parent,
'--output', self.coverage_info_file]
print 'Assembly command: ' + ' '.join(command)
subprocess.call(command)
command = [self.genhtml,
self.coverage_info_file,
'--output-directory',
self.output_directory]
print 'html generation command: ' + ' '.join(command)
subprocess.call(command)
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())
|