5"""Generates a coverage report for given tests.
7Requires that 'use_clang_coverage = true' is set in args.gn.
8Prefers that 'is_component_build = false' is set in args.gn.
12from collections
import namedtuple
21 os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
29TestSpec = namedtuple(
'TestSpec',
'binary, use_test_runner, opt_args')
34 TestSpec(
'pdfium_unittests',
False, []),
35 'pdfium_embeddertests':
36 TestSpec(
'pdfium_embeddertests',
False, []),
38 TestSpec(
'run_corpus_tests.py',
True, []),
39 'corpus_tests_javascript_disabled':
40 TestSpec(
'run_corpus_tests.py',
True, [
'--disable-javascript']),
41 'corpus_tests_xfa_disabled':
42 TestSpec(
'run_corpus_tests.py',
True, [
'--disable-xfa']),
43 'corpus_tests_render_oneshot':
44 TestSpec(
'run_corpus_tests.py',
True, [
'--render-oneshot']),
45 'corpus_tests_reverse_byte_order':
46 TestSpec(
'run_corpus_tests.py',
True, [
'--reverse-byte-order']),
48 TestSpec(
'run_javascript_tests.py',
True, []),
49 'javascript_tests_javascript_disabled':
50 TestSpec(
'run_javascript_tests.py',
True, [
'--disable-javascript']),
51 'javascript_tests_xfa_disabled':
52 TestSpec(
'run_javascript_tests.py',
True, [
'--disable-xfa']),
54 TestSpec(
'run_pixel_tests.py',
True, []),
55 'pixel_tests_javascript_disabled':
56 TestSpec(
'run_pixel_tests.py',
True, [
'--disable-javascript']),
57 'pixel_tests_xfa_disabled':
58 TestSpec(
'run_pixel_tests.py',
True, [
'--disable-xfa']),
59 'pixel_tests_render_oneshot':
60 TestSpec(
'run_pixel_tests.py',
True, [
'--render-oneshot']),
61 'pixel_tests_reverse_byte_order':
62 TestSpec(
'run_pixel_tests.py',
True, [
'--reverse-byte-order']),
69 """Initialize executor based on the current script environment
72 parser: argparse.ArgumentParser for handling improper inputs.
73 args: Dictionary of arguments passed into the calling script.
83 'llvm-build',
'Release+Asserts',
'bin')
85 parser.error(
"Cannot find LLVM bin directory , expected it to be in '%s'"
96 'No valid tests in set to be run. This is likely due to bad command '
99 if not common.GetBooleanGnArg(
'use_clang_coverage', self.
build_directory,
102 'use_clang_coverage does not appear to be set to true for build, but '
115 parser.error(
'%s is not empty, cowardly refusing to continue' %
121 """Dry run aware wrapper of subprocess.check_output()"""
123 print(
"Would have run '%s'" %
' '.join(args))
126 output = subprocess.check_output(args, env=env)
129 print(
"check_output(%s) returned '%s'" % (args, output))
132 def call(self, args, dry_run=False, env=None):
133 """Dry run aware wrapper of subprocess.call()"""
135 print(
"Would have run '%s'" %
' '.join(args))
138 output = subprocess.call(args, env=env)
141 print(
'call(%s) returned %s' % (args, output))
145 """Dry run aware wrapper of subprocess.call() that eats output from call"""
147 print(
"Would have run '%s'" %
' '.join(args))
150 with open(os.devnull,
'w')
as f:
151 output = subprocess.call(args, env=env, stdout=f)
154 print(
'call_silent(%s) returned %s' % (args, output))
158 """Determine which tests should be run."""
161 tests = args[
'tests']
if args[
'tests']
else COVERAGE_TESTS.keys()
163 build_targets =
set()
165 test_spec = COVERAGE_TESTS[name]
166 if test_spec.use_test_runner:
167 binary_path = os.path.join(testing_tools_directory, test_spec.binary)
168 build_targets.add(
'pdfium_diff')
169 build_targets.add(
'pdfium_test')
172 build_targets.add(name)
173 coverage_tests[name] =
TestSpec(binary_path, test_spec.use_test_runner,
176 build_targets =
list(build_targets)
178 return coverage_tests, build_targets
181 """Build all the binaries that are going to be needed for coverage
183 call_args = [
'ninja']
185 call_args += [
'-j',
'250']
188 return self.
call(call_args, dry_run=self.
dry_run) == 0
191 """Generate the coverage data for a test
194 name: Name associated with the test to be run. This is used as a label
195 in the coverage data, so should be unique across all of the tests
197 spec: Tuple containing the TestSpec.
200 print(
"Generating coverage for test '%s', using data '%s'" % (name, spec))
201 if not os.path.exists(spec.binary):
202 print(
'Unable to generate coverage for %s, since it appears to not exist'
203 ' @ %s' % (name, spec.binary))
206 binary_args = [spec.binary]
208 binary_args.extend(spec.opt_args)
209 profile_pattern_string =
'%8m'
210 expected_profraw_file =
'%s.%s.profraw' % (name, profile_pattern_string)
212 expected_profraw_file)
215 'LLVM_PROFILE_FILE': expected_profraw_path,
219 if spec.use_test_runner:
225 print(
'Running %s appears to have failed, which might affect '
226 'results' % spec.binary)
231 """Merge raw coverage data sets into one one file for report generation."""
232 llvm_profdata_bin = os.path.join(self.
llvm_directory,
'llvm-profdata')
235 raw_data_pattern =
'*.profraw'
237 if fnmatch.fnmatch(file_name, raw_data_pattern):
241 [llvm_profdata_bin,
'merge',
'-o', self.
prof_data,
'-sparse=true'] +
245 """Generate HTML report by calling upstream coverage.py"""
246 coverage_bin = os.path.join(self.
source_directory,
'tools',
'code_coverage',
252 coverage_args += [
'-o', report_directory]
256 coverage_args += [
'-f',
'core']
257 coverage_args += [
'-f',
'fpdfsdk']
258 coverage_args += [
'-f',
'fxbarcode']
259 coverage_args += [
'-f',
'fxjs']
260 coverage_args += [
'-f',
'public']
261 coverage_args += [
'-f',
'samples']
262 coverage_args += [
'-f',
'xfa']
265 coverage_args += [
'-i',
'.*test.*']
268 coverage_args += [
'--no-component-view']
270 return self.
call([coverage_bin] + coverage_args) == 0
273 """Setup environment, execute the tests and generate coverage report"""
275 print(
'Unable to fetch profiling tools')
279 print(
'Failed to successfully build binaries')
284 print(
'Failed to successfully generate coverage data')
288 print(
'Failed to successfully merge raw coverage results')
292 print(
'Failed to successfully generate HTML report')
298 """Call coverage.py with no args to ensure profiling tools are present."""
305 parser = argparse.ArgumentParser()
306 parser.formatter_class = argparse.RawDescriptionHelpFormatter
307 parser.description =
'Generates a coverage report for given tests.'
311 '--source_directory',
312 help=
'Location of PDFium source directory, defaults to CWD',
314 build_default = os.path.join(
'out',
'Coverage')
319 'Location of PDFium build directory with coverage enabled, defaults to '
320 '%s under CWD' % build_default,
321 default=os.path.join(os.getcwd(), build_default))
322 output_default =
'coverage_report'
325 '--output_directory',
326 help=
'Location to write out coverage report to, defaults to %s under CWD '
328 default=os.path.join(os.getcwd(), output_default))
332 help=
'Output commands instead of executing them',
337 help=
'Output additional diagnostic information',
341 help=
'Tests to be run, defaults to all. Valid entries are %s' %
342 COVERAGE_TESTS.keys(),
345 args = vars(parser.parse_args())
355if __name__ ==
'__main__':
calculate_coverage_tests(self, args)
fetch_profiling_tools(self)
call_silent(self, args, dry_run=False, env=None)
__init__(self, parser, args)
call(self, args, dry_run=False, env=None)
check_output(self, args, dry_run=False, env=None)
generate_html_report(self)
generate_coverage(self, name, spec)
merge_raw_coverage_results(self)
QDebug print(QDebug debug, QSslError::SslError error)
QFuture< QSet< QChar > > set
[10]
file open(QIODevice::ReadOnly)