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