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"])
|
|