diff options
Diffstat (limited to 'tools/scan-build-py/tests/unit')
-rw-r--r-- | tools/scan-build-py/tests/unit/__init__.py | 8 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/fixtures.py | 40 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_analyze.py | 1 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_clang.py | 13 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_command.py | 193 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_compilation.py | 122 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_intercept.py | 59 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_libear.py | 30 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_report.py | 30 | ||||
-rw-r--r-- | tools/scan-build-py/tests/unit/test_runner.py | 325 |
10 files changed, 421 insertions, 400 deletions
diff --git a/tools/scan-build-py/tests/unit/__init__.py b/tools/scan-build-py/tests/unit/__init__.py index 4fa9edc0fff12..dc8bf12eb47c1 100644 --- a/tools/scan-build-py/tests/unit/__init__.py +++ b/tools/scan-build-py/tests/unit/__init__.py @@ -4,7 +4,8 @@ # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -from . import test_command +from . import test_libear +from . import test_compilation from . import test_clang from . import test_runner from . import test_report @@ -13,8 +14,9 @@ from . import test_intercept from . import test_shell -def load_tests(loader, suite, pattern): - suite.addTests(loader.loadTestsFromModule(test_command)) +def load_tests(loader, suite, _): + suite.addTests(loader.loadTestsFromModule(test_libear)) + suite.addTests(loader.loadTestsFromModule(test_compilation)) suite.addTests(loader.loadTestsFromModule(test_clang)) suite.addTests(loader.loadTestsFromModule(test_runner)) suite.addTests(loader.loadTestsFromModule(test_report)) diff --git a/tools/scan-build-py/tests/unit/fixtures.py b/tools/scan-build-py/tests/unit/fixtures.py deleted file mode 100644 index d80f5e64774cc..0000000000000 --- a/tools/scan-build-py/tests/unit/fixtures.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. - -import contextlib -import tempfile -import shutil -import unittest - - -class Spy(object): - def __init__(self): - self.arg = None - self.success = 0 - - def call(self, params): - self.arg = params - return self.success - - -@contextlib.contextmanager -def TempDir(): - name = tempfile.mkdtemp(prefix='scan-build-test-') - try: - yield name - finally: - shutil.rmtree(name) - - -class TestCase(unittest.TestCase): - def assertIn(self, element, collection): - found = False - for it in collection: - if element == it: - found = True - - self.assertTrue(found, '{0} does not have {1}'.format(collection, - element)) diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py index b77db4818024a..481cc0c0993b9 100644 --- a/tools/scan-build-py/tests/unit/test_analyze.py +++ b/tools/scan-build-py/tests/unit/test_analyze.py @@ -5,4 +5,3 @@ # License. See LICENSE.TXT for details. import libscanbuild.analyze as sut -from . import fixtures diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py index 2f1fd79d4a92d..04414a85b8281 100644 --- a/tools/scan-build-py/tests/unit/test_clang.py +++ b/tools/scan-build-py/tests/unit/test_clang.py @@ -4,14 +4,15 @@ # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +import libear import libscanbuild.clang as sut -from . import fixtures +import unittest import os.path -class GetClangArgumentsTest(fixtures.TestCase): +class GetClangArgumentsTest(unittest.TestCase): def test_get_clang_arguments(self): - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: filename = os.path.join(tmpdir, 'test.c') with open(filename, 'w') as handle: handle.write('') @@ -20,8 +21,8 @@ class GetClangArgumentsTest(fixtures.TestCase): ['clang', '-c', filename, '-DNDEBUG', '-Dvar="this is it"'], tmpdir) - self.assertIn('NDEBUG', result) - self.assertIn('var="this is it"', result) + self.assertTrue('NDEBUG' in result) + self.assertTrue('var="this is it"' in result) def test_get_clang_arguments_fails(self): self.assertRaises( @@ -29,7 +30,7 @@ class GetClangArgumentsTest(fixtures.TestCase): ['clang', '-###', '-fsyntax-only', '-x', 'c', 'notexist.c'], '.') -class GetCheckersTest(fixtures.TestCase): +class GetCheckersTest(unittest.TestCase): def test_get_checkers(self): # this test is only to see is not crashing result = sut.get_checkers('clang', []) diff --git a/tools/scan-build-py/tests/unit/test_command.py b/tools/scan-build-py/tests/unit/test_command.py deleted file mode 100644 index 9a6aae65c6058..0000000000000 --- a/tools/scan-build-py/tests/unit/test_command.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- coding: utf-8 -*- -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. - -import libscanbuild.command as sut -from . import fixtures -import unittest - - -class ParseTest(unittest.TestCase): - - def test_action(self): - def test(expected, cmd): - opts = sut.classify_parameters(cmd) - self.assertEqual(expected, opts['action']) - - Link = sut.Action.Link - test(Link, ['clang', 'source.c']) - - Compile = sut.Action.Compile - test(Compile, ['clang', '-c', 'source.c']) - test(Compile, ['clang', '-c', 'source.c', '-MF', 'source.d']) - - Preprocess = sut.Action.Ignored - test(Preprocess, ['clang', '-E', 'source.c']) - test(Preprocess, ['clang', '-c', '-E', 'source.c']) - test(Preprocess, ['clang', '-c', '-M', 'source.c']) - test(Preprocess, ['clang', '-c', '-MM', 'source.c']) - - def test_optimalizations(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('compile_options', []) - - self.assertEqual(['-O'], test(['clang', '-c', 'source.c', '-O'])) - self.assertEqual(['-O1'], test(['clang', '-c', 'source.c', '-O1'])) - self.assertEqual(['-Os'], test(['clang', '-c', 'source.c', '-Os'])) - self.assertEqual(['-O2'], test(['clang', '-c', 'source.c', '-O2'])) - self.assertEqual(['-O3'], test(['clang', '-c', 'source.c', '-O3'])) - - def test_language(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('language') - - self.assertEqual(None, test(['clang', '-c', 'source.c'])) - self.assertEqual('c', test(['clang', '-c', 'source.c', '-x', 'c'])) - self.assertEqual('cpp', test(['clang', '-c', 'source.c', '-x', 'cpp'])) - - def test_output(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('output') - - self.assertEqual(None, test(['clang', '-c', 'source.c'])) - self.assertEqual('source.o', - test(['clang', '-c', '-o', 'source.o', 'source.c'])) - - def test_arch(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('archs_seen', []) - - eq = self.assertEqual - - eq([], test(['clang', '-c', 'source.c'])) - eq(['mips'], - test(['clang', '-c', 'source.c', '-arch', 'mips'])) - eq(['mips', 'i386'], - test(['clang', '-c', 'source.c', '-arch', 'mips', '-arch', 'i386'])) - - def test_input_file(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('files', []) - - eq = self.assertEqual - - eq(['src.c'], test(['clang', 'src.c'])) - eq(['src.c'], test(['clang', '-c', 'src.c'])) - eq(['s1.c', 's2.c'], test(['clang', '-c', 's1.c', 's2.c'])) - - def test_include(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('compile_options', []) - - eq = self.assertEqual - - eq([], test(['clang', '-c', 'src.c'])) - eq(['-include', '/usr/local/include'], - test(['clang', '-c', 'src.c', '-include', '/usr/local/include'])) - eq(['-I.'], - test(['clang', '-c', 'src.c', '-I.'])) - eq(['-I', '.'], - test(['clang', '-c', 'src.c', '-I', '.'])) - eq(['-I/usr/local/include'], - test(['clang', '-c', 'src.c', '-I/usr/local/include'])) - eq(['-I', '/usr/local/include'], - test(['clang', '-c', 'src.c', '-I', '/usr/local/include'])) - eq(['-I/opt', '-I', '/opt/otp/include'], - test(['clang', '-c', 'src.c', '-I/opt', '-I', '/opt/otp/include'])) - eq(['-isystem', '/path'], - test(['clang', '-c', 'src.c', '-isystem', '/path'])) - eq(['-isystem=/path'], - test(['clang', '-c', 'src.c', '-isystem=/path'])) - - def test_define(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('compile_options', []) - - eq = self.assertEqual - - eq([], test(['clang', '-c', 'src.c'])) - eq(['-DNDEBUG'], - test(['clang', '-c', 'src.c', '-DNDEBUG'])) - eq(['-UNDEBUG'], - test(['clang', '-c', 'src.c', '-UNDEBUG'])) - eq(['-Dvar1=val1', '-Dvar2=val2'], - test(['clang', '-c', 'src.c', '-Dvar1=val1', '-Dvar2=val2'])) - eq(['-Dvar="val ues"'], - test(['clang', '-c', 'src.c', '-Dvar="val ues"'])) - - def test_ignored_flags(self): - def test(flags): - cmd = ['clang', 'src.o'] - opts = sut.classify_parameters(cmd + flags) - self.assertEqual(['src.o'], opts.get('compile_options')) - - test([]) - test(['-lrt', '-L/opt/company/lib']) - test(['-static']) - test(['-Wnoexcept', '-Wall']) - test(['-mtune=i386', '-mcpu=i386']) - - def test_compile_only_flags(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('compile_options', []) - - eq = self.assertEqual - - eq(['-std=C99'], - test(['clang', '-c', 'src.c', '-std=C99'])) - eq(['-nostdinc'], - test(['clang', '-c', 'src.c', '-nostdinc'])) - eq(['-isystem', '/image/debian'], - test(['clang', '-c', 'src.c', '-isystem', '/image/debian'])) - eq(['-iprefix', '/usr/local'], - test(['clang', '-c', 'src.c', '-iprefix', '/usr/local'])) - eq(['-iquote=me'], - test(['clang', '-c', 'src.c', '-iquote=me'])) - eq(['-iquote', 'me'], - test(['clang', '-c', 'src.c', '-iquote', 'me'])) - - def test_compile_and_link_flags(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('compile_options', []) - - eq = self.assertEqual - - eq(['-fsinged-char'], - test(['clang', '-c', 'src.c', '-fsinged-char'])) - eq(['-fPIC'], - test(['clang', '-c', 'src.c', '-fPIC'])) - eq(['-stdlib=libc++'], - test(['clang', '-c', 'src.c', '-stdlib=libc++'])) - eq(['--sysroot', '/'], - test(['clang', '-c', 'src.c', '--sysroot', '/'])) - eq(['-isysroot', '/'], - test(['clang', '-c', 'src.c', '-isysroot', '/'])) - eq([], - test(['clang', '-c', 'src.c', '-fsyntax-only'])) - eq([], - test(['clang', '-c', 'src.c', '-sectorder', 'a', 'b', 'c'])) - - def test_detect_cxx_from_compiler_name(self): - def test(cmd): - opts = sut.classify_parameters(cmd) - return opts.get('c++') - - eq = self.assertEqual - - eq(False, test(['cc', '-c', 'src.c'])) - eq(True, test(['c++', '-c', 'src.c'])) - eq(False, test(['clang', '-c', 'src.c'])) - eq(True, test(['clang++', '-c', 'src.c'])) - eq(False, test(['gcc', '-c', 'src.c'])) - eq(True, test(['g++', '-c', 'src.c'])) diff --git a/tools/scan-build-py/tests/unit/test_compilation.py b/tools/scan-build-py/tests/unit/test_compilation.py new file mode 100644 index 0000000000000..124febaf01955 --- /dev/null +++ b/tools/scan-build-py/tests/unit/test_compilation.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. + +import libscanbuild.compilation as sut +import unittest + + +class CompilerTest(unittest.TestCase): + + def test_is_compiler_call(self): + self.assertIsNotNone(sut.compiler_language(['clang'])) + self.assertIsNotNone(sut.compiler_language(['clang-3.6'])) + self.assertIsNotNone(sut.compiler_language(['clang++'])) + self.assertIsNotNone(sut.compiler_language(['clang++-3.5.1'])) + self.assertIsNotNone(sut.compiler_language(['cc'])) + self.assertIsNotNone(sut.compiler_language(['c++'])) + self.assertIsNotNone(sut.compiler_language(['gcc'])) + self.assertIsNotNone(sut.compiler_language(['g++'])) + self.assertIsNotNone(sut.compiler_language(['/usr/local/bin/gcc'])) + self.assertIsNotNone(sut.compiler_language(['/usr/local/bin/g++'])) + self.assertIsNotNone(sut.compiler_language(['/usr/local/bin/clang'])) + self.assertIsNotNone( + sut.compiler_language(['armv7_neno-linux-gnueabi-g++'])) + + self.assertIsNone(sut.compiler_language([])) + self.assertIsNone(sut.compiler_language([''])) + self.assertIsNone(sut.compiler_language(['ld'])) + self.assertIsNone(sut.compiler_language(['as'])) + self.assertIsNone(sut.compiler_language(['/usr/local/bin/compiler'])) + + +class SplitTest(unittest.TestCase): + + def test_detect_cxx_from_compiler_name(self): + def test(cmd): + result = sut.split_command([cmd, '-c', 'src.c']) + self.assertIsNotNone(result, "wrong input for test") + return result.compiler == 'c++' + + self.assertFalse(test('cc')) + self.assertFalse(test('gcc')) + self.assertFalse(test('clang')) + + self.assertTrue(test('c++')) + self.assertTrue(test('g++')) + self.assertTrue(test('g++-5.3.1')) + self.assertTrue(test('clang++')) + self.assertTrue(test('clang++-3.7.1')) + self.assertTrue(test('armv7_neno-linux-gnueabi-g++')) + + def test_action(self): + self.assertIsNotNone(sut.split_command(['clang', 'source.c'])) + self.assertIsNotNone(sut.split_command(['clang', '-c', 'source.c'])) + self.assertIsNotNone(sut.split_command(['clang', '-c', 'source.c', + '-MF', 'a.d'])) + + self.assertIsNone(sut.split_command(['clang', '-E', 'source.c'])) + self.assertIsNone(sut.split_command(['clang', '-c', '-E', 'source.c'])) + self.assertIsNone(sut.split_command(['clang', '-c', '-M', 'source.c'])) + self.assertIsNone( + sut.split_command(['clang', '-c', '-MM', 'source.c'])) + + def test_source_file(self): + def test(expected, cmd): + self.assertEqual(expected, sut.split_command(cmd).files) + + test(['src.c'], ['clang', 'src.c']) + test(['src.c'], ['clang', '-c', 'src.c']) + test(['src.C'], ['clang', '-x', 'c', 'src.C']) + test(['src.cpp'], ['clang++', '-c', 'src.cpp']) + test(['s1.c', 's2.c'], ['clang', '-c', 's1.c', 's2.c']) + test(['s1.c', 's2.c'], ['cc', 's1.c', 's2.c', '-ldep', '-o', 'a.out']) + test(['src.c'], ['clang', '-c', '-I', './include', 'src.c']) + test(['src.c'], ['clang', '-c', '-I', '/opt/me/include', 'src.c']) + test(['src.c'], ['clang', '-c', '-D', 'config=file.c', 'src.c']) + + self.assertIsNone( + sut.split_command(['cc', 'this.o', 'that.o', '-o', 'a.out'])) + self.assertIsNone( + sut.split_command(['cc', 'this.o', '-lthat', '-o', 'a.out'])) + + def test_filter_flags(self): + def test(expected, flags): + command = ['clang', '-c', 'src.c'] + flags + self.assertEqual(expected, sut.split_command(command).flags) + + def same(expected): + test(expected, expected) + + def filtered(flags): + test([], flags) + + same([]) + same(['-I', '/opt/me/include', '-DNDEBUG', '-ULIMITS']) + same(['-O', '-O2']) + same(['-m32', '-mmms']) + same(['-Wall', '-Wno-unused', '-g', '-funroll-loops']) + + filtered([]) + filtered(['-lclien', '-L/opt/me/lib', '-L', '/opt/you/lib']) + filtered(['-static']) + filtered(['-MD', '-MT', 'something']) + filtered(['-MMD', '-MF', 'something']) + + +class SourceClassifierTest(unittest.TestCase): + + def test_sources(self): + self.assertIsNone(sut.classify_source('file.o')) + self.assertIsNone(sut.classify_source('file.exe')) + self.assertIsNone(sut.classify_source('/path/file.o')) + self.assertIsNone(sut.classify_source('clang')) + + self.assertEqual('c', sut.classify_source('file.c')) + self.assertEqual('c', sut.classify_source('./file.c')) + self.assertEqual('c', sut.classify_source('/path/file.c')) + self.assertEqual('c++', sut.classify_source('file.c', False)) + self.assertEqual('c++', sut.classify_source('./file.c', False)) + self.assertEqual('c++', sut.classify_source('/path/file.c', False)) diff --git a/tools/scan-build-py/tests/unit/test_intercept.py b/tools/scan-build-py/tests/unit/test_intercept.py index b6f01f36eeb3f..5b6ed2cee1f65 100644 --- a/tools/scan-build-py/tests/unit/test_intercept.py +++ b/tools/scan-build-py/tests/unit/test_intercept.py @@ -4,62 +4,37 @@ # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +import libear import libscanbuild.intercept as sut -from . import fixtures +import unittest import os.path -class InterceptUtilTest(fixtures.TestCase): - - def test_is_compiler_call_filter(self): - def test(command): - return sut.is_compiler_call({'command': [command]}) - - self.assertTrue(test('clang')) - self.assertTrue(test('clang-3.6')) - self.assertTrue(test('clang++')) - self.assertTrue(test('clang++-3.5.1')) - self.assertTrue(test('cc')) - self.assertTrue(test('c++')) - self.assertTrue(test('gcc')) - self.assertTrue(test('g++')) - self.assertTrue(test('/usr/local/bin/gcc')) - self.assertTrue(test('/usr/local/bin/g++')) - self.assertTrue(test('/usr/local/bin/clang')) - self.assertTrue(test('armv7_neno-linux-gnueabi-g++')) - - self.assertFalse(test('')) - self.assertFalse(test('ld')) - self.assertFalse(test('as')) - self.assertFalse(test('/usr/local/bin/compiler')) +class InterceptUtilTest(unittest.TestCase): def test_format_entry_filters_action(self): def test(command): - return list(sut.format_entry( - {'command': command, 'directory': '/opt/src/project'})) + trace = {'command': command, 'directory': '/opt/src/project'} + return list(sut.format_entry(trace)) self.assertTrue(test(['cc', '-c', 'file.c', '-o', 'file.o'])) self.assertFalse(test(['cc', '-E', 'file.c'])) self.assertFalse(test(['cc', '-MM', 'file.c'])) self.assertFalse(test(['cc', 'this.o', 'that.o', '-o', 'a.out'])) - self.assertFalse(test(['cc', '-print-prog-name'])) def test_format_entry_normalize_filename(self): - directory = os.path.join(os.sep, 'home', 'me', 'project') + parent = os.path.join(os.sep, 'home', 'me') + current = os.path.join(parent, 'project') - def test(command): - result = list(sut.format_entry( - {'command': command, 'directory': directory})) - return result[0]['file'] - - self.assertEqual(test(['cc', '-c', 'file.c']), - os.path.join(directory, 'file.c')) - self.assertEqual(test(['cc', '-c', './file.c']), - os.path.join(directory, 'file.c')) - self.assertEqual(test(['cc', '-c', '../file.c']), - os.path.join(os.path.dirname(directory), 'file.c')) - self.assertEqual(test(['cc', '-c', '/opt/file.c']), - '/opt/file.c') + def test(filename): + trace = {'directory': current, 'command': ['cc', '-c', filename]} + return list(sut.format_entry(trace))[0]['file'] + + self.assertEqual(os.path.join(current, 'file.c'), test('file.c')) + self.assertEqual(os.path.join(current, 'file.c'), test('./file.c')) + self.assertEqual(os.path.join(parent, 'file.c'), test('../file.c')) + self.assertEqual(os.path.join(current, 'file.c'), + test(os.path.join(current, 'file.c'))) def test_sip(self): def create_status_report(filename, message): @@ -92,7 +67,7 @@ class InterceptUtilTest(fixtures.TestCase): OSX = 'darwin' LINUX = 'linux' - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: try: saved = os.environ['PATH'] os.environ['PATH'] = tmpdir + ':' + saved diff --git a/tools/scan-build-py/tests/unit/test_libear.py b/tools/scan-build-py/tests/unit/test_libear.py new file mode 100644 index 0000000000000..f5b928028965c --- /dev/null +++ b/tools/scan-build-py/tests/unit/test_libear.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. + +import libear as sut +import unittest +import os.path + + +class TemporaryDirectoryTest(unittest.TestCase): + def test_creates_directory(self): + dirname = None + with sut.TemporaryDirectory() as tmpdir: + self.assertTrue(os.path.isdir(tmpdir)) + dirname = tmpdir + self.assertIsNotNone(dirname) + self.assertFalse(os.path.exists(dirname)) + + def test_removes_directory_when_exception(self): + dirname = None + try: + with sut.TemporaryDirectory() as tmpdir: + self.assertTrue(os.path.isdir(tmpdir)) + dirname = tmpdir + raise RuntimeError('message') + except: + self.assertIsNotNone(dirname) + self.assertFalse(os.path.exists(dirname)) diff --git a/tools/scan-build-py/tests/unit/test_report.py b/tools/scan-build-py/tests/unit/test_report.py index d505afc20a891..3f249ce2aa0c8 100644 --- a/tools/scan-build-py/tests/unit/test_report.py +++ b/tools/scan-build-py/tests/unit/test_report.py @@ -4,15 +4,15 @@ # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +import libear import libscanbuild.report as sut -from . import fixtures import unittest import os import os.path def run_bug_parse(content): - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: file_name = os.path.join(tmpdir, 'test.html') with open(file_name, 'w') as handle: handle.writelines(content) @@ -21,7 +21,7 @@ def run_bug_parse(content): def run_crash_parse(content, preproc): - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: file_name = os.path.join(tmpdir, preproc + '.info.txt') with open(file_name, 'w') as handle: handle.writelines(content) @@ -77,20 +77,22 @@ class ParseFileTest(unittest.TestCase): def test_parse_real_crash(self): import libscanbuild.runner as sut2 import re - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: filename = os.path.join(tmpdir, 'test.c') with open(filename, 'w') as handle: handle.write('int main() { return 0') # produce failure report - opts = {'directory': os.getcwd(), - 'clang': 'clang', - 'file': filename, - 'report': ['-fsyntax-only', '-E', filename], - 'language': 'c', - 'output_dir': tmpdir, - 'error_type': 'other_error', - 'error_output': 'some output', - 'exit_code': 13} + opts = { + 'clang': 'clang', + 'directory': os.getcwd(), + 'flags': [], + 'file': filename, + 'output_dir': tmpdir, + 'language': 'c', + 'error_type': 'other_error', + 'error_output': 'some output', + 'exit_code': 13 + } sut2.report_failure(opts) # find the info file pp_file = None @@ -123,7 +125,7 @@ class ReportMethodTest(unittest.TestCase): '/prefix/src/file')) -class GetPrefixFromCompilationDatabaseTest(fixtures.TestCase): +class GetPrefixFromCompilationDatabaseTest(unittest.TestCase): def test_with_different_filenames(self): self.assertEqual( diff --git a/tools/scan-build-py/tests/unit/test_runner.py b/tools/scan-build-py/tests/unit/test_runner.py index ea10051d8506f..b4730a1c5191c 100644 --- a/tools/scan-build-py/tests/unit/test_runner.py +++ b/tools/scan-build-py/tests/unit/test_runner.py @@ -4,96 +4,164 @@ # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +import libear import libscanbuild.runner as sut -from . import fixtures import unittest import re import os import os.path -def run_analyzer(content, opts): - with fixtures.TempDir() as tmpdir: - filename = os.path.join(tmpdir, 'test.cpp') - with open(filename, 'w') as handle: - handle.write(content) - - opts.update({ - 'directory': os.getcwd(), - 'clang': 'clang', - 'file': filename, - 'language': 'c++', - 'analyze': ['--analyze', '-x', 'c++', filename], - 'output': ['-o', tmpdir]}) - spy = fixtures.Spy() - result = sut.run_analyzer(opts, spy.call) - return (result, spy.arg) +class FilteringFlagsTest(unittest.TestCase): + + def test_language_captured(self): + def test(flags): + cmd = ['clang', '-c', 'source.c'] + flags + opts = sut.classify_parameters(cmd) + return opts['language'] + + self.assertEqual(None, test([])) + self.assertEqual('c', test(['-x', 'c'])) + self.assertEqual('cpp', test(['-x', 'cpp'])) + + def test_arch(self): + def test(flags): + cmd = ['clang', '-c', 'source.c'] + flags + opts = sut.classify_parameters(cmd) + return opts['arch_list'] + + self.assertEqual([], test([])) + self.assertEqual(['mips'], test(['-arch', 'mips'])) + self.assertEqual(['mips', 'i386'], + test(['-arch', 'mips', '-arch', 'i386'])) + + def assertFlagsChanged(self, expected, flags): + cmd = ['clang', '-c', 'source.c'] + flags + opts = sut.classify_parameters(cmd) + self.assertEqual(expected, opts['flags']) + + def assertFlagsUnchanged(self, flags): + self.assertFlagsChanged(flags, flags) + + def assertFlagsFiltered(self, flags): + self.assertFlagsChanged([], flags) + + def test_optimalizations_pass(self): + self.assertFlagsUnchanged(['-O']) + self.assertFlagsUnchanged(['-O1']) + self.assertFlagsUnchanged(['-Os']) + self.assertFlagsUnchanged(['-O2']) + self.assertFlagsUnchanged(['-O3']) + + def test_include_pass(self): + self.assertFlagsUnchanged([]) + self.assertFlagsUnchanged(['-include', '/usr/local/include']) + self.assertFlagsUnchanged(['-I.']) + self.assertFlagsUnchanged(['-I', '.']) + self.assertFlagsUnchanged(['-I/usr/local/include']) + self.assertFlagsUnchanged(['-I', '/usr/local/include']) + self.assertFlagsUnchanged(['-I/opt', '-I', '/opt/otp/include']) + self.assertFlagsUnchanged(['-isystem', '/path']) + self.assertFlagsUnchanged(['-isystem=/path']) + + def test_define_pass(self): + self.assertFlagsUnchanged(['-DNDEBUG']) + self.assertFlagsUnchanged(['-UNDEBUG']) + self.assertFlagsUnchanged(['-Dvar1=val1', '-Dvar2=val2']) + self.assertFlagsUnchanged(['-Dvar="val ues"']) + + def test_output_filtered(self): + self.assertFlagsFiltered(['-o', 'source.o']) + + def test_some_warning_filtered(self): + self.assertFlagsFiltered(['-Wall']) + self.assertFlagsFiltered(['-Wnoexcept']) + self.assertFlagsFiltered(['-Wreorder', '-Wunused', '-Wundef']) + self.assertFlagsUnchanged(['-Wno-reorder', '-Wno-unused']) + + def test_compile_only_flags_pass(self): + self.assertFlagsUnchanged(['-std=C99']) + self.assertFlagsUnchanged(['-nostdinc']) + self.assertFlagsUnchanged(['-isystem', '/image/debian']) + self.assertFlagsUnchanged(['-iprefix', '/usr/local']) + self.assertFlagsUnchanged(['-iquote=me']) + self.assertFlagsUnchanged(['-iquote', 'me']) + + def test_compile_and_link_flags_pass(self): + self.assertFlagsUnchanged(['-fsinged-char']) + self.assertFlagsUnchanged(['-fPIC']) + self.assertFlagsUnchanged(['-stdlib=libc++']) + self.assertFlagsUnchanged(['--sysroot', '/']) + self.assertFlagsUnchanged(['-isysroot', '/']) + + def test_some_flags_filtered(self): + self.assertFlagsFiltered(['-g']) + self.assertFlagsFiltered(['-fsyntax-only']) + self.assertFlagsFiltered(['-save-temps']) + self.assertFlagsFiltered(['-init', 'my_init']) + self.assertFlagsFiltered(['-sectorder', 'a', 'b', 'c']) + + +class Spy(object): + def __init__(self): + self.arg = None + self.success = 0 + + def call(self, params): + self.arg = params + return self.success class RunAnalyzerTest(unittest.TestCase): + @staticmethod + def run_analyzer(content, failures_report): + with libear.TemporaryDirectory() as tmpdir: + filename = os.path.join(tmpdir, 'test.cpp') + with open(filename, 'w') as handle: + handle.write(content) + + opts = { + 'clang': 'clang', + 'directory': os.getcwd(), + 'flags': [], + 'direct_args': [], + 'file': filename, + 'output_dir': tmpdir, + 'output_format': 'plist', + 'output_failures': failures_report + } + spy = Spy() + result = sut.run_analyzer(opts, spy.call) + return (result, spy.arg) + def test_run_analyzer(self): content = "int div(int n, int d) { return n / d; }" - (result, fwds) = run_analyzer(content, dict()) + (result, fwds) = RunAnalyzerTest.run_analyzer(content, False) self.assertEqual(None, fwds) self.assertEqual(0, result['exit_code']) def test_run_analyzer_crash(self): content = "int div(int n, int d) { return n / d }" - (result, fwds) = run_analyzer(content, dict()) + (result, fwds) = RunAnalyzerTest.run_analyzer(content, False) self.assertEqual(None, fwds) self.assertEqual(1, result['exit_code']) def test_run_analyzer_crash_and_forwarded(self): content = "int div(int n, int d) { return n / d }" - (_, fwds) = run_analyzer(content, {'output_failures': True}) + (_, fwds) = RunAnalyzerTest.run_analyzer(content, True) self.assertEqual('crash', fwds['error_type']) self.assertEqual(1, fwds['exit_code']) self.assertTrue(len(fwds['error_output']) > 0) -class SetAnalyzerOutputTest(fixtures.TestCase): - - def test_not_defined(self): - with fixtures.TempDir() as tmpdir: - opts = {'output_dir': tmpdir} - spy = fixtures.Spy() - sut.set_analyzer_output(opts, spy.call) - self.assertTrue(os.path.exists(spy.arg['output'][1])) - self.assertTrue(os.path.isdir(spy.arg['output'][1])) - - def test_html(self): - with fixtures.TempDir() as tmpdir: - opts = {'output_dir': tmpdir, 'output_format': 'html'} - spy = fixtures.Spy() - sut.set_analyzer_output(opts, spy.call) - self.assertTrue(os.path.exists(spy.arg['output'][1])) - self.assertTrue(os.path.isdir(spy.arg['output'][1])) - - def test_plist_html(self): - with fixtures.TempDir() as tmpdir: - opts = {'output_dir': tmpdir, 'output_format': 'plist-html'} - spy = fixtures.Spy() - sut.set_analyzer_output(opts, spy.call) - self.assertTrue(os.path.exists(spy.arg['output'][1])) - self.assertTrue(os.path.isfile(spy.arg['output'][1])) - - def test_plist(self): - with fixtures.TempDir() as tmpdir: - opts = {'output_dir': tmpdir, 'output_format': 'plist'} - spy = fixtures.Spy() - sut.set_analyzer_output(opts, spy.call) - self.assertTrue(os.path.exists(spy.arg['output'][1])) - self.assertTrue(os.path.isfile(spy.arg['output'][1])) - - -class ReportFailureTest(fixtures.TestCase): +class ReportFailureTest(unittest.TestCase): def assertUnderFailures(self, path): self.assertEqual('failures', os.path.basename(os.path.dirname(path))) def test_report_failure_create_files(self): - with fixtures.TempDir() as tmpdir: + with libear.TemporaryDirectory() as tmpdir: # create input file filename = os.path.join(tmpdir, 'test.c') with open(filename, 'w') as handle: @@ -101,15 +169,17 @@ class ReportFailureTest(fixtures.TestCase): uname_msg = ' '.join(os.uname()) + os.linesep error_msg = 'this is my error output' # execute test - opts = {'directory': os.getcwd(), - 'clang': 'clang', - 'file': filename, - 'report': ['-fsyntax-only', '-E', filename], - 'language': 'c', - 'output_dir': tmpdir, - 'error_type': 'other_error', - 'error_output': error_msg, - 'exit_code': 13} + opts = { + 'clang': 'clang', + 'directory': os.getcwd(), + 'flags': [], + 'file': filename, + 'output_dir': tmpdir, + 'language': 'c', + 'error_type': 'other_error', + 'error_output': error_msg, + 'exit_code': 13 + } sut.report_failure(opts) # verify the result result = dict() @@ -126,57 +196,110 @@ class ReportFailureTest(fixtures.TestCase): self.assertUnderFailures(pp_file) # info file generated and content dumped info_file = pp_file + '.info.txt' - self.assertIn(info_file, result) + self.assertTrue(info_file in result) self.assertEqual('Other Error\n', result[info_file][1]) self.assertEqual(uname_msg, result[info_file][3]) # error file generated and content dumped error_file = pp_file + '.stderr.txt' - self.assertIn(error_file, result) + self.assertTrue(error_file in result) self.assertEqual([error_msg], result[error_file]) class AnalyzerTest(unittest.TestCase): - def test_set_language(self): + def test_nodebug_macros_appended(self): + def test(flags): + spy = Spy() + opts = {'flags': flags, 'force_debug': True} + self.assertEqual(spy.success, + sut.filter_debug_flags(opts, spy.call)) + return spy.arg['flags'] + + self.assertEqual(['-UNDEBUG'], test([])) + self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG'])) + self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething'])) + + def test_set_file_relative_path(self): def test(expected, input): - spy = fixtures.Spy() + spy = Spy() + self.assertEqual(spy.success, + sut.set_file_path_relative(input, spy.call)) + self.assertEqual(expected, spy.arg['file']) + + test('source.c', + {'file': '/home/me/source.c', 'directory': '/home/me'}) + test('me/source.c', + {'file': '/home/me/source.c', 'directory': '/home'}) + test('../home/me/source.c', + {'file': '/home/me/source.c', 'directory': '/tmp'}) + + def test_set_language_fall_through(self): + def language(expected, input): + spy = Spy() + input.update({'compiler': 'c', 'file': 'test.c'}) self.assertEqual(spy.success, sut.language_check(input, spy.call)) self.assertEqual(expected, spy.arg['language']) - l = 'language' - f = 'file' - i = 'c++' - test('c', {f: 'file.c', l: 'c', i: False}) - test('c++', {f: 'file.c', l: 'c++', i: False}) - test('c++', {f: 'file.c', i: True}) - test('c', {f: 'file.c', i: False}) - test('c++', {f: 'file.cxx', i: False}) - test('c-cpp-output', {f: 'file.i', i: False}) - test('c++-cpp-output', {f: 'file.i', i: True}) - test('c-cpp-output', {f: 'f.i', l: 'c-cpp-output', i: True}) - - def test_arch_loop(self): - def test(input): - spy = fixtures.Spy() - sut.arch_check(input, spy.call) - return spy.arg - - input = {'key': 'value'} - self.assertEqual(input, test(input)) - - input = {'archs_seen': ['i386']} - self.assertEqual({'arch': 'i386'}, test(input)) + language('c', {'language': 'c', 'flags': []}) + language('c++', {'language': 'c++', 'flags': []}) + + def test_set_language_stops_on_not_supported(self): + spy = Spy() + input = { + 'compiler': 'c', + 'flags': [], + 'file': 'test.java', + 'language': 'java' + } + self.assertIsNone(sut.language_check(input, spy.call)) + self.assertIsNone(spy.arg) + + def test_set_language_sets_flags(self): + def flags(expected, input): + spy = Spy() + input.update({'compiler': 'c', 'file': 'test.c'}) + self.assertEqual(spy.success, sut.language_check(input, spy.call)) + self.assertEqual(expected, spy.arg['flags']) - input = {'archs_seen': ['ppc']} - self.assertEqual(None, test(input)) + flags(['-x', 'c'], {'language': 'c', 'flags': []}) + flags(['-x', 'c++'], {'language': 'c++', 'flags': []}) - input = {'archs_seen': ['i386', 'ppc']} - self.assertEqual({'arch': 'i386'}, test(input)) + def test_set_language_from_filename(self): + def language(expected, input): + spy = Spy() + input.update({'language': None, 'flags': []}) + self.assertEqual(spy.success, sut.language_check(input, spy.call)) + self.assertEqual(expected, spy.arg['language']) - input = {'archs_seen': ['i386', 'sparc']} - result = test(input) - self.assertTrue(result == {'arch': 'i386'} or - result == {'arch': 'sparc'}) + language('c', {'file': 'file.c', 'compiler': 'c'}) + language('c++', {'file': 'file.c', 'compiler': 'c++'}) + language('c++', {'file': 'file.cxx', 'compiler': 'c'}) + language('c++', {'file': 'file.cxx', 'compiler': 'c++'}) + language('c++', {'file': 'file.cpp', 'compiler': 'c++'}) + language('c-cpp-output', {'file': 'file.i', 'compiler': 'c'}) + language('c++-cpp-output', {'file': 'file.i', 'compiler': 'c++'}) + + def test_arch_loop_sets_flags(self): + def flags(archs): + spy = Spy() + input = {'flags': [], 'arch_list': archs} + sut.arch_check(input, spy.call) + return spy.arg['flags'] + + self.assertEqual([], flags([])) + self.assertEqual(['-arch', 'i386'], flags(['i386'])) + self.assertEqual(['-arch', 'i386'], flags(['i386', 'ppc'])) + self.assertEqual(['-arch', 'sparc'], flags(['i386', 'sparc'])) + + def test_arch_loop_stops_on_not_supported(self): + def stop(archs): + spy = Spy() + input = {'flags': [], 'arch_list': archs} + self.assertIsNone(sut.arch_check(input, spy.call)) + self.assertIsNone(spy.arg) + + stop(['ppc']) + stop(['ppc64']) @sut.require([]) |