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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « build/compiler_version.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/compiler_version_unittest.py
diff --git a/build/compiler_version_unittest.py b/build/compiler_version_unittest.py
new file mode 100755
index 0000000000000000000000000000000000000000..1f191546204631db8099cb9890eb069e98b5b6d0
--- /dev/null
+++ b/build/compiler_version_unittest.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+# vim: set ts=2 sw=2 et sts=2 ai:
+#
+
+"""Compiler version checking tool unit tests.
+
+Checks the tool correctly imports environment variables from the environment.
+"""
+
+import doctest
+import re
+import subprocess
+import sys
+import time
+import unittest
+
+import compiler_version
+
+
+class CallFake(dict):
+ """Fake for the call function in compiler_version.
+
+ You set the stdout and stderr to return on a given command line as follows;
+ >>> fake_call = CallFake()
+ >>> fake_call['.*regex.*'] = (0, 'stdout', 'stderr')
+ >>> fake_call('cmdline matching regex')
+ (0, 'stdout', 'stderr')
+
+ The empty string will match any commadline;
+ >>> fake_call = CallFake()
+ >>> fake_call[''] = (0, 'stdout', 'stderr')
+ >>> fake_call('cmdline matching regex')
+ (0, 'stdout', 'stderr')
+
+ You can have multiple options and the fake can be called multiple times;
+ >>> fake_call = CallFake()
+ >>> fake_call['.*regex one.*'] = (0, 'stdout 1', 'stderr 1')
+ >>> fake_call['.*regex two.*'] = (1, 'stdout 2', 'stderr 2')
+ >>> fake_call('cmdline matching regex one')
+ (0, 'stdout 1', 'stderr 1')
+ >>> fake_call('cmdline matching regex one')
+ (0, 'stdout 1', 'stderr 1')
+ >>> fake_call('cmdline matching regex two')
+ (1, 'stdout 2', 'stderr 2')
+
+ At least one regex must match the calling command line otherwise an
+ AssertionError is thrown;
+ >>> fake_call = CallFake()
+ >>> fake_call['.*regex one.*'] = (0, 'stdout 1', 'stderr 1')
+ >>> fake_call('non-matching cmdline')
+ Traceback (most recent call last):
+ ...
+ AssertionError: No fakes matched command line 'non-matching cmdline'
+ Possible matches where:
+ '.*regex one.*'
+
+ You should make sure only one option matches however!
+ >>> fake_call = CallFake()
+ >>> fake_call['.*match one.*'] = (0, 'stdout 1', 'stderr 1')
+ >>> fake_call['.*match two.*'] = (0, 'stdout 2', 'stderr 2')
+ >>> fake_call('match one and match two')
+ Traceback (most recent call last):
+ ...
+ AssertionError: Multiple fakes matched command line 'match one and match two'
+ '.*match two.*'
+ '.*match one.*'
+ """
+
+ def __setitem__(self, key, value):
+ key_re = re.compile(key)
+ assert isinstance(value, tuple) and len(value) == 3, "[%r] = %r" % (
+ key, value)
+ dict.__setitem__(self, key_re, (value[0], value[1], value[2]))
+
+ def __call__(self, cmdline):
+ matches = []
+ for key in self:
+ if key.search(cmdline):
+ matches.append((key, self[key]))
+
+ if len(matches) > 1:
+ raise AssertionError("Multiple fakes matched command line %r\n%s" % (
+ cmdline, "\n".join("%r" % re.pattern for re, r in matches)))
+ elif not matches:
+ raise AssertionError(
+ "No fakes matched command line %r\nPossible matches where:\n%s" % (
+ cmdline, "\n".join("%r" % re.pattern for re in self)))
+
+ return matches[0][-1]
+
+
+class CallTest(unittest.TestCase):
+ def test_timeout(self):
+ starttime = time.time()
+ compiler_version.call("sleep 5")
+ endtime = time.time()
+ self.assertLess(endtime - starttime, 1)
+
+ def test_unknown(self):
+ retcode, test_output, test_error = compiler_version.call(
+ "command_that_doesnt_exist")
+ self.assertEqual(retcode, 127)
+
+ def test_true(self):
+ retcode, test_output, test_error = compiler_version.call("true")
+ self.assertEqual(retcode, 0)
+
+ def test_false(self):
+ retcode, test_output, test_error = compiler_version.call("false")
+ self.assertEqual(retcode, 1)
+
+
+class VersionTestBase(unittest.TestCase):
+ def check_version_strings(self, tool_string, call_match, version_strings):
+ assert len(tool_string)
+ assert len(call_match)
+ assert len(version_strings)
+
+ for version_string, expected_version in version_strings:
+ call_fake = CallFake()
+ call_fake[call_match] = (0, version_string, "")
+ call_fake["^((?!%s).)*$" % call_match] = (-1, "STDOUT", "STDERR")
+
+ actual_version = compiler_version.GetVersion(
+ "COMPILER", tool_string, call=call_fake)
+ self.assertEqual(actual_version, expected_version)
+
+
+class AssemblerTest(VersionTestBase):
+ def test_clang_no_integrated_assembler(self):
+ """Clang needs the no-integrated-assembler option to get system assembler.
+ """
+ error = subprocess.CalledProcessError(1, "", "")
+
+ # Older clang's use the "-no-integrated-as" option and fail otherwise.
+ call_fake = CallFake()
+ call_fake[".* -no-integrated-as .*"] = (
+ 0, "GNU assembler (GNU Binutils) 2.24", "")
+ call_fake["^((?!-no-integrated-as).)*$"] = (
+ -1, "STDOUT", "STDERR")
+ self.assertEqual(
+ "224", compiler_version.GetVersion(
+ "COMPILER", "assembler", call=call_fake))
+
+ # Newer clang's use the "-fno-integrated-as" option and fail otherwise.
+ call_fake = CallFake()
+ call_fake[".* -fno-integrated-as .*"] = (
+ 0, "GNU assembler (GNU Binutils for Ubuntu) 2.22", "")
+ call_fake["^((?!-fno-integrated-as).)*$"] = (
+ -1, "STDOUT", "STDERR")
+ self.assertEqual(
+ "222", compiler_version.GetVersion(
+ "COMPILER", "assembler", call=call_fake))
+
+ def test_version_strings_linux(self):
+ """The assembler version string is customized by a number of distributions.
+ """
+ self.check_version_strings("assembler", "-Xassembler -version", [
+ # Unmodified
+ ("GNU assembler (GNU Binutils) 2.24", "224"),
+ # Ubuntu short version
+ ("GNU assembler (GNU Binutils for Ubuntu) 2.22", "222"),
+ # Ubuntu long version
+ ("GNU assembler version 2.22 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.22", "222"), # noqa
+ # Fedora short version
+ ("GNU assembler version 2.23.2", "223")
+ ])
+
+ def test_version_strings_mac(self):
+ call_fake = CallFake()
+ call_fake["-Xassembler -v"] = (
+ 0, "Apple Inc version cctools-836, GNU assembler version 1.38", "")
+ call_fake["^((?!-Xassembler -v).)*$"] = (-1, "STDOUT", "STDERR")
+ actual_version = compiler_version.GetVersion(
+ "COMPILER", "assembler", call=call_fake)
+ self.assertEqual(actual_version, "138")
+
+
+class LinkerTest(VersionTestBase):
+
+ def test_version_strings_linux_bfd(self):
+ self.check_version_strings("linker", "-Xlinker -v", [
+ ("GNU ld (GNU Binutils) 2.24", "224"), # Unmodified
+ ("GNU ld (GNU Binutils for Ubuntu) 2.22", "222"), # Ubuntu
+ ("GNU ld version 2.23.2", "223"), # Fedora
+ ])
+
+ def test_version_strings_linux_gold(self):
+ self.check_version_strings("linker", "-Xlinker -v", [
+ ("GNU gold (GNU Binutils 2.24) 1.11", "111"), # Unmodified
+ ("GNU gold (GNU Binutils for Ubuntu 2.22) 1.9", "109"), # Ubuntu
+ ("GNU gold (version 2.23.2) 1.10", "110"), # Fedora
+ ])
+
+ @unittest.skip('mac not yet supported')
+ def test_version_strings_mac(self):
+ self.check_version_strings("linker", "-Xlinker -v", [
+ ("""\
+@(#)PROGRAM:ld PROJECT:ld64-134.9
+configured to support archs: armv6 armv7 armv7s i386 x86_64
+LTO support using: LLVM version 3.1svn, from Apple Clang 4.1 (build 421.11.66)
+""", "")
+ ])
+
+
+class CompilerTest(VersionTestBase):
+ def test_failure(self):
+ call_fake = CallFake()
+ call_fake[".*"] = (-1, "STDOUT", "STDERR")
+
+ self.assertRaises(
+ compiler_version.GetVersionError,
+ compiler_version.GetVersion, "COMPILER", "compiler", call=call_fake)
+
+ def test_version_strings_gcc(self):
+ self.check_version_strings("compiler", ".*", [
+ ("""\
+gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
+Copyright (C) 2011 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+""", "46"),
+ ("""\
+gcc (Ubuntu/Linaro 4.8.2-2ubuntu1) 4.8.2
+Copyright (C) 2011 Free Software Foundation, Inc.
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+""", "48"),
+ ])
+
+ def test_version_strings_clang(self):
+ self.check_version_strings("compiler", ".*", [
+ # clang from third_party/llvm-build/Release+Asserts/bin/clang++
+ ("""\
+clang version 3.5 (trunk 198389)
+Target: x86_64-unknown-linux-gnu
+Thread model: posix
+""", "35"),
+ # clang on Mac OS X
+ ("""\
+Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
+Target: x86_64-apple-darwin13.1.0
+Thread model: posix
+""", "41"),
+ ])
+
+
+# assertRegexpMatches is only available on Python 2.7 or newer
+@unittest.skipIf(sys.version_info < (2, 7, 0), 'Python 2.7 or newer required.')
+class RealTest(unittest.TestCase):
+ """Test on the local system.
+
+ Can't check the exact version, as we don't know what the system has. We do
+ check that the version makes sense though.
+ """
+ def test_compiler(self):
+ version = compiler_version.GetVersion("c++", "compiler")
+ self.assertRegexpMatches(version, "\d+")
+
+ def test_linker(self):
+ version = compiler_version.GetVersion("c++", "linker")
+ self.assertRegexpMatches(version, "\d+")
+
+ def test_assembler(self):
+ version = compiler_version.GetVersion("c++", "assembler")
+ self.assertRegexpMatches(version, "\d+")
+
+ def test_thirdparty_clang(self):
+ version = compiler_version.GetVersion(
+ "third_party/llvm-build/Release+Asserts/bin/clang++",
+ "compiler")
+ self.assertRegexpMatches(version, "\d+")
+
+
+class EnvironmentTest(unittest.TestCase):
+ def test_cxx(self):
+ env = {}
+ self.assertEqual(compiler_version.FindCompiler(env), "c++")
+
+ env = {"CXX": "COMPILER"}
+ self.assertEqual(compiler_version.FindCompiler(env), "COMPILER")
+
+ def test_cxxflags(self):
+ env = {"CXXFLAGS": "CXXFLAGS"}
+ self.assertEqual(compiler_version.FindCompiler(env), "c++ CXXFLAGS")
+
+ env = {
+ "CXX": "COMPILER",
+ "CXXFLAGS": "CXXFLAGS",
+ }
+ self.assertEqual(compiler_version.FindCompiler(env), "COMPILER CXXFLAGS")
+
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+
+ # exit is only available on Python 2.7 or newer
+ try:
+ unittest.main(exit=False)
+ except TypeError:
+ unittest.main()
+
+ print
+ print "Your compiler is version:",
+ compiler_version.main([])
+ print "Your linker is version:",
+ compiler_version.main(["linker"])
+ print "Your assembler is version:",
+ compiler_version.main(["assembler"])
« 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