blob: cd4eb5ef206ffff04d0d746dc9b0a7c7a9975581 [file] [log] [blame]
Artem Titarenko84d28272018-10-16 11:40:04 +02001#!/usr/bin/env python
2# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
10"""Generates command-line instructions to produce one-time iOS coverage using
11coverage.py.
12
13This script is usable for both real devices and simulator.
14But for real devices actual execution should be done manually from Xcode
15and coverage.profraw files should be also copied manually from the device.
16
17Additional prerequisites:
18
191. Xcode 10+ with iPhone Simulator SDK. Can be installed by command:
20 $ mac_toolchain install -kind ios -xcode-version 10l232m \
21 -output-dir build/mac_files/Xcode.app
22
232. For computing coverage on real device you probably also need to apply
24following patch to code_coverage/coverage.py script:
25
26========== BEGINNING OF PATCH ==========
27--- a/code_coverage/coverage.py
28+++ b/code_coverage/coverage.py
29@@ -693,8 +693,7 @@ def _AddArchArgumentForIOSIfNeeded(cmd_list, num_archs):
30 to use, and one architecture needs to be specified for each binary.
31 "" "
32if _IsIOS():
33- cmd_list.extend(['-arch=x86_64'] * num_archs)
34+ cmd_list.extend(['-arch=arm64'] * num_archs)
35
36
37def _GetBinaryPath(command):
38@@ -836,8 +835,8 @@ def _GetBinaryPathsFromTargets(targets, build_dir):
39 binary_path = os.path.join(build_dir, target)
40 if coverage_utils.GetHostPlatform() == 'win':
41 binary_path += '.exe'
42+ elif coverage_utils.GetHostPlatform() == 'mac':
43+ binary_path += '.app/%s' % target
44
45if os.path.exists(binary_path):
46 binary_paths.append(binary_path)
47========== ENDING OF PATCH ==========
48
49"""
50
51import sys
52
53DIRECTORY = 'out/coverage'
54
55TESTS = [
56 'audio_decoder_unittests',
57 'common_audio_unittests',
58 'common_video_unittests',
59 'modules_tests',
60 'modules_unittests',
61 'rtc_media_unittests',
62 'rtc_pc_unittests',
63 'rtc_stats_unittests',
64 'rtc_unittests',
65 'system_wrappers_unittests',
66 'test_support_unittests',
67 'tools_unittests',
68 'video_capture_tests',
69 'video_engine_tests',
70 'webrtc_nonparallel_tests',
71]
72
73XC_TESTS = [
74 'apprtcmobile_tests',
75 'sdk_framework_unittests',
76 'sdk_unittests',
77]
78
79
80def FormatIossimTest(test_name, is_xctest=False):
81 args = ['%s/%s.app' % (DIRECTORY, test_name)]
82 if is_xctest:
83 args += ['%s/%s_module.xctest' % (DIRECTORY, test_name)]
84
85 return '-c \'%s/iossim %s\'' % (DIRECTORY, ' '.join(args))
86
87
88def GetGNArgs(is_simulator):
89 target_cpu = 'x64' if is_simulator else 'arm64'
90 return ([] +
91 ['target_os="ios"'] +
92 ['target_cpu="%s"' % target_cpu] +
93 ['use_clang_coverage=true'] +
94 ['is_component_build=false'] +
95 ['dcheck_always_on=true'])
96
97
98def GenerateIOSSimulatorCommand():
99 gn_args_string = ' '.join(GetGNArgs(is_simulator=True))
100 gn_cmd = ['gn', 'gen', DIRECTORY, '--args=\'%s\'' % gn_args_string]
101
102 coverage_cmd = (
103 [sys.executable, 'tools/code_coverage/coverage.py'] +
104 ["%s.app" % t for t in XC_TESTS + TESTS] +
105 ['-b %s' % DIRECTORY, '-o out/report'] +
106 ['-i=\'.*/out/.*|.*/third_party/.*|.*test.*\''] +
107 [FormatIossimTest(t, is_xctest=True) for t in XC_TESTS] +
108 [FormatIossimTest(t, is_xctest=False) for t in TESTS]
109 )
110
111 print 'To get code coverage using iOS simulator just run following commands:'
112 print ''
113 print ' '.join(gn_cmd)
114 print ''
115 print ' '.join(coverage_cmd)
116 return 0
117
118
119def GenerateIOSDeviceCommand():
120 gn_args_string = ' '.join(GetGNArgs(is_simulator=False))
121
122 coverage_report_cmd = (
123 [sys.executable, 'tools/code_coverage/coverage.py'] +
124 ['%s.app' % t for t in TESTS] +
125 ['-b %s' % DIRECTORY] +
126 ['-o out/report'] +
127 ['-p %s/merged.profdata' % DIRECTORY] +
128 ['-i=\'.*/out/.*|.*/third_party/.*|.*test.*\'']
129 )
130
131 print 'Computing code coverage for real iOS device is a little bit tedious.'
132 print ''
133 print 'You will need:'
134 print ''
135 print '1. Generate xcode project and open it with Xcode 10+:'
136 print ' gn gen %s --ide=xcode --args=\'%s\'' % (DIRECTORY, gn_args_string)
137 print ' open %s/all.xcworkspace' % DIRECTORY
138 print ''
139 print '2. Execute these Run targets manually with Xcode Run button and '
140 print 'manually save generated coverage.profraw file to %s:' % DIRECTORY
141 print '\n'.join('- %s' % t for t in TESTS)
142 print ''
143 print '3. Execute these Test targets manually with Xcode Test button and '
144 print 'manually save generated coverage.profraw file to %s:' % DIRECTORY
145 print '\n'.join('- %s' % t for t in XC_TESTS)
146 print ''
147 print '4. Merge *.profraw files to *.profdata using llvm-profdata tool:'
148 print (' build/mac_files/Xcode.app/Contents/Developer/Toolchains/' +
149 'XcodeDefault.xctoolchain/usr/bin/llvm-profdata merge ' +
150 '-o %s/merged.profdata ' % DIRECTORY +
151 '-sparse=true %s/*.profraw' % DIRECTORY)
152 print ''
153 print '5. Generate coverage report:'
154 print ' ' + ' '.join(coverage_report_cmd)
155 return 0
156
157
158def Main():
159 if len(sys.argv) < 2:
160 print 'Please specify type of coverage:'
161 print ' %s simulator' % sys.argv[0]
162 print ' %s device' % sys.argv[0]
163 elif sys.argv[1] == 'simulator':
164 GenerateIOSSimulatorCommand()
165 elif sys.argv[1] == 'device':
166 GenerateIOSDeviceCommand()
167 else:
168 print 'Unsupported type of coverage'
169
170 return 0
171
172if __name__ == '__main__':
173 sys.exit(Main())