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

Side by Side Diff: build/compiler_version_unittest.py

Issue 199793014: Extend compiler_version.py to work with clang output. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 9 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 unified diff | Download patch
« no previous file with comments | « build/compiler_version.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5 # vim: set ts=2 sw=2 et sts=2 ai:
6 #
7
8 """Compiler version checking tool unit tests.
9
10 Checks the tool correctly imports environment variables from the environment.
11 """
12
13 import doctest
14 import re
15 import subprocess
16 import sys
17 import time
18 import unittest
19
20 import compiler_version
21
22
23 class CallFake(dict):
24 """Fake for the call function in compiler_version.
25
26 You set the stdout and stderr to return on a given command line as follows;
27 >>> fake_call = CallFake()
28 >>> fake_call['.*regex.*'] = (0, 'stdout', 'stderr')
29 >>> fake_call('cmdline matching regex')
30 (0, 'stdout', 'stderr')
31
32 The empty string will match any commadline;
33 >>> fake_call = CallFake()
34 >>> fake_call[''] = (0, 'stdout', 'stderr')
35 >>> fake_call('cmdline matching regex')
36 (0, 'stdout', 'stderr')
37
38 You can have multiple options and the fake can be called multiple times;
39 >>> fake_call = CallFake()
40 >>> fake_call['.*regex one.*'] = (0, 'stdout 1', 'stderr 1')
41 >>> fake_call['.*regex two.*'] = (1, 'stdout 2', 'stderr 2')
42 >>> fake_call('cmdline matching regex one')
43 (0, 'stdout 1', 'stderr 1')
44 >>> fake_call('cmdline matching regex one')
45 (0, 'stdout 1', 'stderr 1')
46 >>> fake_call('cmdline matching regex two')
47 (1, 'stdout 2', 'stderr 2')
48
49 At least one regex must match the calling command line otherwise an
50 AssertionError is thrown;
51 >>> fake_call = CallFake()
52 >>> fake_call['.*regex one.*'] = (0, 'stdout 1', 'stderr 1')
53 >>> fake_call('non-matching cmdline')
54 Traceback (most recent call last):
55 ...
56 AssertionError: No fakes matched command line 'non-matching cmdline'
57 Possible matches where:
58 '.*regex one.*'
59
60 You should make sure only one option matches however!
61 >>> fake_call = CallFake()
62 >>> fake_call['.*match one.*'] = (0, 'stdout 1', 'stderr 1')
63 >>> fake_call['.*match two.*'] = (0, 'stdout 2', 'stderr 2')
64 >>> fake_call('match one and match two')
65 Traceback (most recent call last):
66 ...
67 AssertionError: Multiple fakes matched command line 'match one and match two'
68 '.*match two.*'
69 '.*match one.*'
70 """
71
72 def __setitem__(self, key, value):
73 key_re = re.compile(key)
74 assert isinstance(value, tuple) and len(value) == 3, "[%r] = %r" % (
75 key, value)
76 dict.__setitem__(self, key_re, (value[0], value[1], value[2]))
77
78 def __call__(self, cmdline):
79 matches = []
80 for key in self:
81 if key.search(cmdline):
82 matches.append((key, self[key]))
83
84 if len(matches) > 1:
85 raise AssertionError("Multiple fakes matched command line %r\n%s" % (
86 cmdline, "\n".join("%r" % re.pattern for re, r in matches)))
87 elif not matches:
88 raise AssertionError(
89 "No fakes matched command line %r\nPossible matches where:\n%s" % (
90 cmdline, "\n".join("%r" % re.pattern for re in self)))
91
92 return matches[0][-1]
93
94
95 class CallTest(unittest.TestCase):
96 def test_timeout(self):
97 starttime = time.time()
98 compiler_version.call("sleep 5")
99 endtime = time.time()
100 self.assertLess(endtime - starttime, 1)
101
102 def test_unknown(self):
103 retcode, test_output, test_error = compiler_version.call(
104 "command_that_doesnt_exist")
105 self.assertEqual(retcode, 127)
106
107 def test_true(self):
108 retcode, test_output, test_error = compiler_version.call("true")
109 self.assertEqual(retcode, 0)
110
111 def test_false(self):
112 retcode, test_output, test_error = compiler_version.call("false")
113 self.assertEqual(retcode, 1)
114
115
116 class VersionTestBase(unittest.TestCase):
117 def check_version_strings(self, tool_string, call_match, version_strings):
118 assert len(tool_string)
119 assert len(call_match)
120 assert len(version_strings)
121
122 for version_string, expected_version in version_strings:
123 call_fake = CallFake()
124 call_fake[call_match] = (0, version_string, "")
125 call_fake["^((?!%s).)*$" % call_match] = (-1, "STDOUT", "STDERR")
126
127 actual_version = compiler_version.GetVersion(
128 "COMPILER", tool_string, call=call_fake)
129 self.assertEqual(actual_version, expected_version)
130
131
132 class AssemblerTest(VersionTestBase):
133 def test_clang_no_integrated_assembler(self):
134 """Clang needs the no-integrated-assembler option to get system assembler.
135 """
136 error = subprocess.CalledProcessError(1, "", "")
137
138 # Older clang's use the "-no-integrated-as" option and fail otherwise.
139 call_fake = CallFake()
140 call_fake[".* -no-integrated-as .*"] = (
141 0, "GNU assembler (GNU Binutils) 2.24", "")
142 call_fake["^((?!-no-integrated-as).)*$"] = (
143 -1, "STDOUT", "STDERR")
144 self.assertEqual(
145 "224", compiler_version.GetVersion(
146 "COMPILER", "assembler", call=call_fake))
147
148 # Newer clang's use the "-fno-integrated-as" option and fail otherwise.
149 call_fake = CallFake()
150 call_fake[".* -fno-integrated-as .*"] = (
151 0, "GNU assembler (GNU Binutils for Ubuntu) 2.22", "")
152 call_fake["^((?!-fno-integrated-as).)*$"] = (
153 -1, "STDOUT", "STDERR")
154 self.assertEqual(
155 "222", compiler_version.GetVersion(
156 "COMPILER", "assembler", call=call_fake))
157
158 def test_version_strings_linux(self):
159 """The assembler version string is customized by a number of distributions.
160 """
161 self.check_version_strings("assembler", "-Xassembler -version", [
162 # Unmodified
163 ("GNU assembler (GNU Binutils) 2.24", "224"),
164 # Ubuntu short version
165 ("GNU assembler (GNU Binutils for Ubuntu) 2.22", "222"),
166 # Ubuntu long version
167 ("GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU B inutils for Ubuntu) 2.22", "222"), # noqa
168 # Fedora short version
169 ("GNU assembler version 2.23.2", "223")
170 ])
171
172 def test_version_strings_mac(self):
173 call_fake = CallFake()
174 call_fake["-Xassembler -v"] = (
175 0, "Apple Inc version cctools-836, GNU assembler version 1.38", "")
176 call_fake["^((?!-Xassembler -v).)*$"] = (-1, "STDOUT", "STDERR")
177 actual_version = compiler_version.GetVersion(
178 "COMPILER", "assembler", call=call_fake)
179 self.assertEqual(actual_version, "138")
180
181
182 class LinkerTest(VersionTestBase):
183
184 def test_version_strings_linux_bfd(self):
185 self.check_version_strings("linker", "-Xlinker -v", [
186 ("GNU ld (GNU Binutils) 2.24", "224"), # Unmodified
187 ("GNU ld (GNU Binutils for Ubuntu) 2.22", "222"), # Ubuntu
188 ("GNU ld version 2.23.2", "223"), # Fedora
189 ])
190
191 def test_version_strings_linux_gold(self):
192 self.check_version_strings("linker", "-Xlinker -v", [
193 ("GNU gold (GNU Binutils 2.24) 1.11", "111"), # Unmodified
194 ("GNU gold (GNU Binutils for Ubuntu 2.22) 1.9", "109"), # Ubuntu
195 ("GNU gold (version 2.23.2) 1.10", "110"), # Fedora
196 ])
197
198 @unittest.skip('mac not yet supported')
199 def test_version_strings_mac(self):
200 self.check_version_strings("linker", "-Xlinker -v", [
201 ("""\
202 @(#)PROGRAM:ld PROJECT:ld64-134.9
203 configured to support archs: armv6 armv7 armv7s i386 x86_64
204 LTO support using: LLVM version 3.1svn, from Apple Clang 4.1 (build 421.11.66)
205 """, "")
206 ])
207
208
209 class CompilerTest(VersionTestBase):
210 def test_failure(self):
211 call_fake = CallFake()
212 call_fake[".*"] = (-1, "STDOUT", "STDERR")
213
214 self.assertRaises(
215 compiler_version.GetVersionError,
216 compiler_version.GetVersion, "COMPILER", "compiler", call=call_fake)
217
218 def test_version_strings_gcc(self):
219 self.check_version_strings("compiler", ".*", [
220 ("""\
221 gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
222 Copyright (C) 2011 Free Software Foundation, Inc.
223 This is free software; see the source for copying conditions. There is NO
224 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
225 """, "46"),
226 ("""\
227 gcc (Ubuntu/Linaro 4.8.2-2ubuntu1) 4.8.2
228 Copyright (C) 2011 Free Software Foundation, Inc.
229 This is free software; see the source for copying conditions. There is NO
230 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
231 """, "48"),
232 ])
233
234 def test_version_strings_clang(self):
235 self.check_version_strings("compiler", ".*", [
236 # clang from third_party/llvm-build/Release+Asserts/bin/clang++
237 ("""\
238 clang version 3.5 (trunk 198389)
239 Target: x86_64-unknown-linux-gnu
240 Thread model: posix
241 """, "35"),
242 # clang on Mac OS X
243 ("""\
244 Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
245 Target: x86_64-apple-darwin13.1.0
246 Thread model: posix
247 """, "41"),
248 ])
249
250
251 # assertRegexpMatches is only available on Python 2.7 or newer
252 @unittest.skipIf(sys.version_info < (2, 7, 0), 'Python 2.7 or newer required.')
253 class RealTest(unittest.TestCase):
254 """Test on the local system.
255
256 Can't check the exact version, as we don't know what the system has. We do
257 check that the version makes sense though.
258 """
259 def test_compiler(self):
260 version = compiler_version.GetVersion("c++", "compiler")
261 self.assertRegexpMatches(version, "\d+")
262
263 def test_linker(self):
264 version = compiler_version.GetVersion("c++", "linker")
265 self.assertRegexpMatches(version, "\d+")
266
267 def test_assembler(self):
268 version = compiler_version.GetVersion("c++", "assembler")
269 self.assertRegexpMatches(version, "\d+")
270
271 def test_thirdparty_clang(self):
272 version = compiler_version.GetVersion(
273 "third_party/llvm-build/Release+Asserts/bin/clang++",
274 "compiler")
275 self.assertRegexpMatches(version, "\d+")
276
277
278 class EnvironmentTest(unittest.TestCase):
279 def test_cxx(self):
280 env = {}
281 self.assertEqual(compiler_version.FindCompiler(env), "c++")
282
283 env = {"CXX": "COMPILER"}
284 self.assertEqual(compiler_version.FindCompiler(env), "COMPILER")
285
286 def test_cxxflags(self):
287 env = {"CXXFLAGS": "CXXFLAGS"}
288 self.assertEqual(compiler_version.FindCompiler(env), "c++ CXXFLAGS")
289
290 env = {
291 "CXX": "COMPILER",
292 "CXXFLAGS": "CXXFLAGS",
293 }
294 self.assertEqual(compiler_version.FindCompiler(env), "COMPILER CXXFLAGS")
295
296
297 if __name__ == '__main__':
298 import doctest
299 doctest.testmod()
300
301 # exit is only available on Python 2.7 or newer
302 try:
303 unittest.main(exit=False)
304 except TypeError:
305 unittest.main()
306
307 print
308 print "Your compiler is version:",
309 compiler_version.main([])
310 print "Your linker is version:",
311 compiler_version.main(["linker"])
312 print "Your assembler is version:",
313 compiler_version.main(["assembler"])
OLDNEW
« no previous file with comments | « build/compiler_version.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698