summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/tools/scan-build-py/tests
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/clang/tools/scan-build-py/tests')
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/__init__.py17
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/__init__.py0
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/__init__.py70
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_create_cdb.py190
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py49
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py181
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py117
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt32
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/config.h.in19
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/main.c306
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-one.c6
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-two.c1
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/build/Makefile42
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-one.c13
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-two.c11
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in43
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in19
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in31
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-one.c23
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-two.c13
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/include/clean-one.h6
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/functional/src/main.c4
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/__init__.py23
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_analyze.py414
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_clang.py105
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_compilation.py121
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_intercept.py89
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_libear.py29
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_report.py147
-rw-r--r--gnu/llvm/clang/tools/scan-build-py/tests/unit/test_shell.py41
30 files changed, 2162 insertions, 0 deletions
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/__init__.py b/gnu/llvm/clang/tools/scan-build-py/tests/__init__.py
new file mode 100644
index 00000000000..9efd1602265
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/__init__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import unittest
+
+import tests.unit
+import tests.functional.cases
+
+
+def suite():
+ loader = unittest.TestLoader()
+ suite = unittest.TestSuite()
+ suite.addTests(loader.loadTestsFromModule(tests.unit))
+ suite.addTests(loader.loadTestsFromModule(tests.functional.cases))
+ return suite
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/__init__.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/__init__.py
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/__init__.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/__init__.py
new file mode 100644
index 00000000000..7ac3456f98a
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/__init__.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import re
+import os.path
+import subprocess
+
+
+def load_tests(loader, suite, pattern):
+ from . import test_from_cdb
+ suite.addTests(loader.loadTestsFromModule(test_from_cdb))
+ from . import test_from_cmd
+ suite.addTests(loader.loadTestsFromModule(test_from_cmd))
+ from . import test_create_cdb
+ suite.addTests(loader.loadTestsFromModule(test_create_cdb))
+ from . import test_exec_anatomy
+ suite.addTests(loader.loadTestsFromModule(test_exec_anatomy))
+ return suite
+
+
+def make_args(target):
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
+ os.path.join(path, 'build', 'Makefile')]
+
+
+def silent_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.call(cmd, *args, **kwargs)
+
+
+def silent_check_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.check_call(cmd, *args, **kwargs)
+
+
+def call_and_report(analyzer_cmd, build_cmd):
+ child = subprocess.Popen(analyzer_cmd + ['-v'] + build_cmd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ pattern = re.compile('Report directory created: (.+)')
+ directory = None
+ for line in child.stdout.readlines():
+ match = pattern.search(line)
+ if match and match.lastindex == 1:
+ directory = match.group(1)
+ break
+ child.stdout.close()
+ child.wait()
+
+ return (child.returncode, directory)
+
+
+def check_call_and_report(analyzer_cmd, build_cmd):
+ exit_code, result = call_and_report(analyzer_cmd, build_cmd)
+ if exit_code != 0:
+ raise subprocess.CalledProcessError(
+ exit_code, analyzer_cmd + build_cmd, None)
+ else:
+ return result
+
+
+def create_empty_file(filename):
+ with open(filename, 'a') as handle:
+ pass
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_create_cdb.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
new file mode 100644
index 00000000000..692a489b611
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+from . import make_args, silent_check_call, silent_call, create_empty_file
+import unittest
+
+import os.path
+import json
+
+
+class CompilationDatabaseTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + args
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_successful_build(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_with_wrapper(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ '--override-compiler'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu make return -11')
+ def test_successful_build_parallel(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = self.run_intercept(tmpdir, ['-j', '4', 'build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu env remove clang from path')
+ def test_successful_build_on_empty_env(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['CC=clang', 'build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ 'env', '-'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_all_in_one(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_all_in_one'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_not_successful_build(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_broken']
+ silent_call(
+ ['intercept-build', '--cdb', result] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+
+class ExitCodeTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ return silent_call(
+ ['intercept-build', '--cdb', result] + make)
+
+ def test_successful_build(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_clean')
+ self.assertFalse(exitcode)
+
+ def test_not_successful_build(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_broken')
+ self.assertTrue(exitcode)
+
+
+class ResumeFeatureTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + args + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_overwrite_existing_cdb(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', [])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+ def test_append_to_existing_cdb(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', ['--append'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+
+class ResultFormatingTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, command):
+ result = os.path.join(tmpdir, 'cdb.json')
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + command,
+ cwd=tmpdir)
+ with open(result, 'r') as handler:
+ content = json.load(handler)
+ return content
+
+ def assert_creates_number_of_entries(self, command, count):
+ with libear.TemporaryDirectory() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ create_empty_file(filename)
+ command.append(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(count, len(cdb))
+
+ def test_filter_preprocessor_only_calls(self):
+ self.assert_creates_number_of_entries(['cc', '-c'], 1)
+ self.assert_creates_number_of_entries(['cc', '-c', '-E'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-M'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-MM'], 0)
+
+ def assert_command_creates_entry(self, command, expected):
+ with libear.TemporaryDirectory() as tmpdir:
+ filename = os.path.join(tmpdir, command[-1])
+ create_empty_file(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(' '.join(expected), cdb[0]['command'])
+
+ def test_filter_preprocessor_flags(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MMD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', '-MF', 'test.d', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_language_flag(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-x', 'c', 'test.c'],
+ ['cc', '-c', '-x', 'c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_arch_flags(self):
+ self.assert_command_creates_entry(
+ ['clang', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'])
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
new file mode 100644
index 00000000000..b0fec3db0c9
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+import unittest
+
+import os.path
+import subprocess
+import json
+
+
+def run(source_dir, target_dir):
+ def execute(cmd):
+ return subprocess.check_call(cmd,
+ cwd=target_dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ execute(['cmake', source_dir])
+ execute(['make'])
+
+ result_file = os.path.join(target_dir, 'result.json')
+ expected_file = os.path.join(target_dir, 'expected.json')
+ execute(['intercept-build', '--cdb', result_file, './exec',
+ expected_file])
+ return (expected_file, result_file)
+
+
+class ExecAnatomyTest(unittest.TestCase):
+ def assertEqualJson(self, expected, result):
+ def read_json(filename):
+ with open(filename) as handler:
+ return json.load(handler)
+
+ lhs = read_json(expected)
+ rhs = read_json(result)
+ for item in lhs:
+ self.assertTrue(rhs.count(item))
+ for item in rhs:
+ self.assertTrue(lhs.count(item))
+
+ def test_all_exec_calls(self):
+ this_dir, _ = os.path.split(__file__)
+ source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
+ with libear.TemporaryDirectory() as tmp_dir:
+ expected, result = run(source_dir, tmp_dir)
+ self.assertEqualJson(expected, result)
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
new file mode 100644
index 00000000000..7af3eea4dd5
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+from . import call_and_report
+import unittest
+
+import os.path
+import string
+import glob
+
+
+def prepare_cdb(name, target_dir):
+ target_file = 'build_{0}.json'.format(name)
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ source_dir = os.path.join(path, 'compilation_database')
+ source_file = os.path.join(source_dir, target_file + '.in')
+ target_file = os.path.join(target_dir, 'compile_commands.json')
+ with open(source_file, 'r') as in_handle:
+ with open(target_file, 'w') as out_handle:
+ for line in in_handle:
+ temp = string.Template(line)
+ out_handle.write(temp.substitute(path=path))
+ return target_file
+
+
+def run_analyzer(directory, cdb, args):
+ cmd = ['analyze-build', '--cdb', cdb, '--output', directory] \
+ + args
+ return call_and_report(cmd, [])
+
+
+class OutputDirectoryTest(unittest.TestCase):
+ def test_regular_keeps_report_dir(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(os.path.isdir(reportdir))
+
+ def test_clear_deletes_report_dir(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(os.path.isdir(reportdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--keep-empty'])
+ self.assertTrue(os.path.isdir(reportdir))
+
+
+class ExitCodeTest(unittest.TestCase):
+ def test_regular_does_not_set_exit_code(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_clear_does_not_set_exit_code(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked_from_plist(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked_from_plist(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertFalse(exit_code)
+
+
+class OutputFormatTest(unittest.TestCase):
+ @staticmethod
+ def get_html_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.html')))
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_default_creates_html_report(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 0)
+
+ def test_plist_and_html_creates_html_report(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist-html'])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+ def test_plist_does_not_creates_html_report(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist'])
+ self.assertFalse(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 0)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+
+class FailureReportTest(unittest.TestCase):
+ def test_broken_creates_failure_reports(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+ def test_broken_does_not_creates_failure_reports(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--no-failure-reports'])
+ self.assertFalse(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+
+class TitleTest(unittest.TestCase):
+ def assertTitleEqual(self, directory, expected):
+ import re
+ patterns = [
+ re.compile(r'<title>(?P<page>.*)</title>'),
+ re.compile(r'<h1>(?P<head>.*)</h1>')
+ ]
+ result = dict()
+
+ index = os.path.join(directory, 'index.html')
+ with open(index, 'r') as handler:
+ for line in handler.readlines():
+ for regex in patterns:
+ match = regex.match(line.strip())
+ if match:
+ result.update(match.groupdict())
+ break
+ self.assertEqual(result['page'], result['head'])
+ self.assertEqual(result['page'], expected)
+
+ def test_default_title_in_report(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTitleEqual(reportdir, 'src - analyzer results')
+
+ def test_given_title_in_report(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--html-title', 'this is the title'])
+ self.assertTitleEqual(reportdir, 'this is the title')
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
new file mode 100644
index 00000000000..62e369c7c61
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+from . import make_args, check_call_and_report, create_empty_file
+import unittest
+
+import os
+import os.path
+import glob
+
+
+class OutputDirectoryTest(unittest.TestCase):
+
+ @staticmethod
+ def run_analyzer(outdir, args, cmd):
+ return check_call_and_report(
+ ['scan-build', '--intercept-first', '-o', outdir] + args,
+ cmd)
+
+ def test_regular_keeps_report_dir(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+ def test_clear_deletes_report_dir(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertFalse(os.path.isdir(outdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, ['--keep-empty'], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_interposition_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_wrapper_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
+ '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_library_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ @staticmethod
+ def compile_empty_source_file(target_dir, is_cxx):
+ compiler = '$CXX' if is_cxx else '$CC'
+ src_file_name = 'test.cxx' if is_cxx else 'test.c'
+ src_file = os.path.join(target_dir, src_file_name)
+ obj_file = os.path.join(target_dir, 'test.o')
+ create_empty_file(src_file)
+ command = ' '.join([compiler, '-c', src_file, '-o', obj_file])
+ return ['sh', '-c', command]
+
+ def test_interposition_cc_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_interposition_cxx_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cc_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cxx_works(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
new file mode 100644
index 00000000000..42ee1d11db8
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
@@ -0,0 +1,32 @@
+project(exec C)
+
+cmake_minimum_required(VERSION 3.4.3)
+
+include(CheckCCompilerFlag)
+check_c_compiler_flag("-std=c99" C99_SUPPORTED)
+if (C99_SUPPORTED)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+endif()
+
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+
+add_definitions(-D_GNU_SOURCE)
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+
+check_function_exists(execve HAVE_EXECVE)
+check_function_exists(execv HAVE_EXECV)
+check_function_exists(execvpe HAVE_EXECVPE)
+check_function_exists(execvp HAVE_EXECVP)
+check_function_exists(execvP HAVE_EXECVP2)
+check_function_exists(exect HAVE_EXECT)
+check_function_exists(execl HAVE_EXECL)
+check_function_exists(execlp HAVE_EXECLP)
+check_function_exists(execle HAVE_EXECLE)
+check_function_exists(posix_spawn HAVE_POSIX_SPAWN)
+check_function_exists(posix_spawnp HAVE_POSIX_SPAWNP)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_executable(exec main.c)
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/config.h.in b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/config.h.in
new file mode 100644
index 00000000000..2f07d0cbea9
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/config.h.in
@@ -0,0 +1,19 @@
+/* -*- coding: utf-8 -*-
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+*/
+
+#pragma once
+
+#cmakedefine HAVE_EXECVE
+#cmakedefine HAVE_EXECV
+#cmakedefine HAVE_EXECVPE
+#cmakedefine HAVE_EXECVP
+#cmakedefine HAVE_EXECVP2
+#cmakedefine HAVE_EXECT
+#cmakedefine HAVE_EXECL
+#cmakedefine HAVE_EXECLP
+#cmakedefine HAVE_EXECLE
+#cmakedefine HAVE_POSIX_SPAWN
+#cmakedefine HAVE_POSIX_SPAWNP
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/main.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/main.c
new file mode 100644
index 00000000000..0f5e01fb35c
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/exec/main.c
@@ -0,0 +1,306 @@
+/* -*- coding: utf-8 -*-
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+*/
+
+#include "config.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+// ..:: environment access fixer - begin ::..
+#ifdef HAVE_NSGETENVIRON
+#include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+char **get_environ() {
+#ifdef HAVE_NSGETENVIRON
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+}
+// ..:: environment access fixer - end ::..
+
+// ..:: test fixtures - begin ::..
+static char const *cwd = NULL;
+static FILE *fd = NULL;
+static int need_comma = 0;
+
+void expected_out_open(const char *expected) {
+ cwd = getcwd(NULL, 0);
+ fd = fopen(expected, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "[\n");
+ need_comma = 0;
+}
+
+void expected_out_close() {
+ fprintf(fd, "]\n");
+ fclose(fd);
+ fd = NULL;
+
+ free((void *)cwd);
+ cwd = NULL;
+}
+
+void expected_out(const char *file) {
+ if (need_comma)
+ fprintf(fd, ",\n");
+ else
+ need_comma = 1;
+
+ fprintf(fd, "{\n");
+ fprintf(fd, " \"directory\": \"%s\",\n", cwd);
+ fprintf(fd, " \"command\": \"cc -c %s\",\n", file);
+ fprintf(fd, " \"file\": \"%s/%s\"\n", cwd, file);
+ fprintf(fd, "}\n");
+}
+
+void create_source(char *file) {
+ FILE *fd = fopen(file, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "typedef int score;\n");
+ fclose(fd);
+}
+
+typedef void (*exec_fun)();
+
+void wait_for(pid_t child) {
+ int status;
+ if (-1 == waitpid(child, &status, 0)) {
+ perror("wait");
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE) {
+ fprintf(stderr, "children process has non zero exit code\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+#define FORK(FUNC) \
+ { \
+ pid_t child = fork(); \
+ if (-1 == child) { \
+ perror("fork"); \
+ exit(EXIT_FAILURE); \
+ } else if (0 == child) { \
+ FUNC fprintf(stderr, "children process failed to exec\n"); \
+ exit(EXIT_FAILURE); \
+ } else { \
+ wait_for(child); \
+ } \
+ }
+// ..:: test fixtures - end ::..
+
+#ifdef HAVE_EXECV
+void call_execv() {
+ char *const file = "execv.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {"cc", "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execv(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVE
+void call_execve() {
+ char *const file = "execve.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execve(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECVP
+void call_execvp() {
+ char *const file = "execvp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvp(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+void call_execvP() {
+ char *const file = "execv_p.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvP(compiler, _PATH_DEFPATH, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+void call_execvpe() {
+ char *const file = "execvpe.c";
+ char *const compiler = "cc";
+ char *const argv[] = {"/usr/bin/cc", "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvpe(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECT
+void call_exect() {
+ char *const file = "exect.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(exect(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECL
+void call_execl() {
+ char *const file = "execl.c";
+ char *const compiler = "/usr/bin/cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execl(compiler, "cc", "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLP
+void call_execlp() {
+ char *const file = "execlp.c";
+ char *const compiler = "cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execlp(compiler, compiler, "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLE
+void call_execle() {
+ char *const file = "execle.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execle(compiler, compiler, "-c", file, (char *)0, envp);)
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+void call_posix_spawn() {
+ char *const file = "posix_spawn.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawn(&child, "/usr/bin/cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawn");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+void call_posix_spawnp() {
+ char *const file = "posix_spawnp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawnp(&child, "cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawnp");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+int main(int argc, char *const argv[]) {
+ if (argc != 2)
+ exit(EXIT_FAILURE);
+
+ expected_out_open(argv[1]);
+#ifdef HAVE_EXECV
+ call_execv();
+#endif
+#ifdef HAVE_EXECVE
+ call_execve();
+#endif
+#ifdef HAVE_EXECVP
+ call_execvp();
+#endif
+#ifdef HAVE_EXECVP2
+ call_execvP();
+#endif
+#ifdef HAVE_EXECVPE
+ call_execvpe();
+#endif
+#ifdef HAVE_EXECT
+ call_exect();
+#endif
+#ifdef HAVE_EXECL
+ call_execl();
+#endif
+#ifdef HAVE_EXECLP
+ call_execlp();
+#endif
+#ifdef HAVE_EXECLE
+ call_execle();
+#endif
+#ifdef HAVE_POSIX_SPAWN
+ call_posix_spawn();
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+ call_posix_spawnp();
+#endif
+ expected_out_close();
+ return 0;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-one.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-one.c
new file mode 100644
index 00000000000..f0550238132
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-one.c
@@ -0,0 +1,6 @@
+#include <notexisting.hpp>
+
+int value(int in)
+{
+ return 2 * in;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-two.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-two.c
new file mode 100644
index 00000000000..7b4c12ff5c3
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/broken-two.c
@@ -0,0 +1 @@
+int test() { ;
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/build/Makefile b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/build/Makefile
new file mode 100644
index 00000000000..a8c0aafd0e5
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/build/Makefile
@@ -0,0 +1,42 @@
+SRCDIR := ..
+OBJDIR := .
+
+CFLAGS = -Wall -DDEBUG -Dvariable="value with space" -I $(SRCDIR)/include
+LDFLAGS =
+PROGRAM = $(OBJDIR)/prg
+
+$(OBJDIR)/main.o: $(SRCDIR)/main.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/main.c
+
+$(OBJDIR)/clean-one.o: $(SRCDIR)/clean-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-one.c
+
+$(OBJDIR)/clean-two.o: $(SRCDIR)/clean-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-two.c
+
+$(OBJDIR)/emit-one.o: $(SRCDIR)/emit-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-one.c
+
+$(OBJDIR)/emit-two.o: $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-two.c
+
+$(OBJDIR)/broken-one.o: $(SRCDIR)/broken-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-one.c
+
+$(OBJDIR)/broken-two.o: $(SRCDIR)/broken-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-two.c
+
+$(PROGRAM): $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+ $(CC) $(LDFLAGS) -o $@ $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+
+build_regular: $(PROGRAM)
+
+build_clean: $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o
+
+build_broken: $(OBJDIR)/main.o $(OBJDIR)/broken-one.o $(OBJDIR)/broken-two.o
+
+build_all_in_one: $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+
+clean:
+ rm -f $(PROGRAM) $(OBJDIR)/*.o
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-one.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-one.c
new file mode 100644
index 00000000000..08c5f33609b
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-one.c
@@ -0,0 +1,13 @@
+#include <clean-one.h>
+
+int do_nothing_loop()
+{
+ int i = 32;
+ int idx = 0;
+
+ for (idx = i; idx > 0; --idx)
+ {
+ i += idx;
+ }
+ return i;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-two.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-two.c
new file mode 100644
index 00000000000..73bc288627d
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/clean-two.c
@@ -0,0 +1,11 @@
+#include <clean-one.h>
+
+#include <stdlib.h>
+
+unsigned int another_method()
+{
+ unsigned int const size = do_nothing_loop();
+ unsigned int const square = size * size;
+
+ return square;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
new file mode 100644
index 00000000000..104a4191cb1
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
@@ -0,0 +1,43 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o broken-one.o broken-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/broken-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o broken-two.o broken-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/broken-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
new file mode 100644
index 00000000000..aa4dcde8e5e
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
@@ -0,0 +1,19 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+]
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
new file mode 100644
index 00000000000..0200c1d8624
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
@@ -0,0 +1,31 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-one.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-one.c
new file mode 100644
index 00000000000..6cbd9cea72b
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-one.c
@@ -0,0 +1,23 @@
+#include <assert.h>
+
+int div(int numerator, int denominator)
+{
+ return numerator / denominator;
+}
+
+void div_test()
+{
+ int i = 0;
+ for (i = 0; i < 2; ++i)
+ assert(div(2 * i, i) == 2);
+}
+
+int do_nothing()
+{
+ unsigned int i = 0;
+
+ int k = 100;
+ int j = k + 1;
+
+ return j;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-two.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-two.c
new file mode 100644
index 00000000000..faea77167f4
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/emit-two.c
@@ -0,0 +1,13 @@
+
+int bad_guy(int * i)
+{
+ *i = 9;
+ return *i;
+}
+
+void bad_guy_test()
+{
+ int * ptr = 0;
+
+ bad_guy(ptr);
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/include/clean-one.h b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/include/clean-one.h
new file mode 100644
index 00000000000..695dbd04c65
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/include/clean-one.h
@@ -0,0 +1,6 @@
+#ifndef CLEAN_ONE_H
+#define CLEAN_ONE_H
+
+int do_nothing_loop();
+
+#endif
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/main.c b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/main.c
new file mode 100644
index 00000000000..905869dfa38
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/functional/src/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/__init__.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/__init__.py
new file mode 100644
index 00000000000..83a04743e6a
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+from . import test_libear
+from . import test_compilation
+from . import test_clang
+from . import test_report
+from . import test_analyze
+from . import test_intercept
+from . import test_shell
+
+
+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_report))
+ suite.addTests(loader.loadTestsFromModule(test_analyze))
+ suite.addTests(loader.loadTestsFromModule(test_intercept))
+ suite.addTests(loader.loadTestsFromModule(test_shell))
+ return suite
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_analyze.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_analyze.py
new file mode 100644
index 00000000000..4b6f5d05211
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_analyze.py
@@ -0,0 +1,414 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import unittest
+import re
+import os
+import os.path
+import libear
+import libscanbuild.analyze as sut
+
+
+class ReportDirectoryTest(unittest.TestCase):
+
+ # Test that successive report directory names ascend in lexicographic
+ # order. This is required so that report directories from two runs of
+ # scan-build can be easily matched up to compare results.
+ def test_directory_name_comparison(self):
+ with libear.TemporaryDirectory() as tmpdir, \
+ sut.report_directory(tmpdir, False) as report_dir1, \
+ sut.report_directory(tmpdir, False) as report_dir2, \
+ sut.report_directory(tmpdir, False) as report_dir3:
+ self.assertLess(report_dir1, report_dir2)
+ self.assertLess(report_dir2, report_dir3)
+
+
+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) = 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) = 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) = RunAnalyzerTest.run_analyzer(content, True)
+ self.assertEqual(1, fwds['exit_code'])
+ self.assertTrue(len(fwds['error_output']) > 0)
+
+
+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 libear.TemporaryDirectory() as tmpdir:
+ # create input file
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ uname_msg = ' '.join(os.uname()) + os.linesep
+ error_msg = 'this is my error output'
+ # execute test
+ 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()
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ with open(key, 'r') as handle:
+ result[key] = handle.readlines()
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+
+ # prepocessor file generated
+ self.assertUnderFailures(pp_file)
+ # info file generated and content dumped
+ info_file = pp_file + '.info.txt'
+ 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.assertTrue(error_file in result)
+ self.assertEqual([error_msg], result[error_file])
+
+
+class AnalyzerTest(unittest.TestCase):
+
+ 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_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'])
+
+ 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'])
+
+ flags(['-x', 'c'], {'language': 'c', 'flags': []})
+ flags(['-x', 'c++'], {'language': 'c++', 'flags': []})
+
+ 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'])
+
+ 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([])
+def method_without_expecteds(opts):
+ return 0
+
+
+@sut.require(['this', 'that'])
+def method_with_expecteds(opts):
+ return 0
+
+
+@sut.require([])
+def method_exception_from_inside(opts):
+ raise Exception('here is one')
+
+
+class RequireDecoratorTest(unittest.TestCase):
+
+ def test_method_without_expecteds(self):
+ self.assertEqual(method_without_expecteds(dict()), 0)
+ self.assertEqual(method_without_expecteds({}), 0)
+ self.assertEqual(method_without_expecteds({'this': 2}), 0)
+ self.assertEqual(method_without_expecteds({'that': 3}), 0)
+
+ def test_method_with_expecteds(self):
+ self.assertRaises(KeyError, method_with_expecteds, dict())
+ self.assertRaises(KeyError, method_with_expecteds, {})
+ self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
+ self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
+ self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
+
+ def test_method_exception_not_caught(self):
+ self.assertRaises(Exception, method_exception_from_inside, dict())
+
+
+class PrefixWithTest(unittest.TestCase):
+
+ def test_gives_empty_on_empty(self):
+ res = sut.prefix_with(0, [])
+ self.assertFalse(res)
+
+ def test_interleaves_prefix(self):
+ res = sut.prefix_with(0, [1, 2, 3])
+ self.assertListEqual([0, 1, 0, 2, 0, 3], res)
+
+
+class MergeCtuMapTest(unittest.TestCase):
+
+ def test_no_map_gives_empty(self):
+ pairs = sut.create_global_ctu_extdef_map([])
+ self.assertFalse(pairs)
+
+ def test_multiple_maps_merged(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun3#I# ast/fun3.c.ast']
+ pairs = sut.create_global_ctu_extdef_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun3#I#', 'ast/fun3.c.ast') in pairs)
+ self.assertEqual(3, len(pairs))
+
+ def test_not_unique_func_left_out(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun1#I# ast/fun7.c.ast']
+ pairs = sut.create_global_ctu_extdef_map(concat_map)
+ self.assertFalse(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertFalse(('c:@F@fun1#I#', 'ast/fun7.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertEqual(1, len(pairs))
+
+ def test_duplicates_are_kept(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun1#I# ast/fun1.c.ast']
+ pairs = sut.create_global_ctu_extdef_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertEqual(2, len(pairs))
+
+ def test_space_handled_in_source(self):
+ concat_map = ['c:@F@fun1#I# ast/f un.c.ast']
+ pairs = sut.create_global_ctu_extdef_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/f un.c.ast') in pairs)
+ self.assertEqual(1, len(pairs))
+
+
+class ExtdefMapSrcToAstTest(unittest.TestCase):
+
+ def test_empty_gives_empty(self):
+ fun_ast_lst = sut.extdef_map_list_src_to_ast([])
+ self.assertFalse(fun_ast_lst)
+
+ def test_sources_to_asts(self):
+ fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f1.c'),
+ 'c:@F@f2#I# ' + os.path.join(os.sep + 'path', 'f2.c')]
+ fun_ast_lst = sut.extdef_map_list_src_to_ast(fun_src_lst)
+ self.assertTrue('c:@F@f1#I# ' +
+ os.path.join('ast', 'path', 'f1.c.ast')
+ in fun_ast_lst)
+ self.assertTrue('c:@F@f2#I# ' +
+ os.path.join('ast', 'path', 'f2.c.ast')
+ in fun_ast_lst)
+ self.assertEqual(2, len(fun_ast_lst))
+
+ def test_spaces_handled(self):
+ fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f 1.c')]
+ fun_ast_lst = sut.extdef_map_list_src_to_ast(fun_src_lst)
+ self.assertTrue('c:@F@f1#I# ' +
+ os.path.join('ast', 'path', 'f 1.c.ast')
+ in fun_ast_lst)
+ self.assertEqual(1, len(fun_ast_lst))
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_clang.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_clang.py
new file mode 100644
index 00000000000..80ce61a1fab
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_clang.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+import libscanbuild.clang as sut
+import unittest
+import os.path
+import sys
+
+
+class ClangGetVersion(unittest.TestCase):
+ def test_get_version_is_not_empty(self):
+ self.assertTrue(sut.get_version('clang'))
+
+ def test_get_version_throws(self):
+ with self.assertRaises(OSError):
+ sut.get_version('notexists')
+
+
+class ClangGetArgumentsTest(unittest.TestCase):
+ def test_get_clang_arguments(self):
+ with libear.TemporaryDirectory() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('')
+
+ result = sut.get_arguments(
+ ['clang', '-c', filename, '-DNDEBUG', '-Dvar="this is it"'],
+ tmpdir)
+
+ self.assertTrue('NDEBUG' in result)
+ self.assertTrue('var="this is it"' in result)
+
+ def test_get_clang_arguments_fails(self):
+ with self.assertRaises(Exception):
+ sut.get_arguments(['clang', '-x', 'c', 'notexist.c'], '.')
+
+ def test_get_clang_arguments_fails_badly(self):
+ with self.assertRaises(OSError):
+ sut.get_arguments(['notexist'], '.')
+
+
+class ClangGetCheckersTest(unittest.TestCase):
+ def test_get_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_checkers('clang', [])
+ self.assertTrue(len(result))
+ # do check result types
+ string_type = unicode if sys.version_info < (3,) else str
+ for key, value in result.items():
+ self.assertEqual(string_type, type(key))
+ self.assertEqual(string_type, type(value[0]))
+ self.assertEqual(bool, type(value[1]))
+
+ def test_get_active_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_active_checkers('clang', [])
+ self.assertTrue(len(result))
+ # do check result types
+ for value in result:
+ self.assertEqual(str, type(value))
+
+ def test_is_active(self):
+ test = sut.is_active(['a', 'b.b', 'c.c.c'])
+
+ self.assertTrue(test('a'))
+ self.assertTrue(test('a.b'))
+ self.assertTrue(test('b.b'))
+ self.assertTrue(test('b.b.c'))
+ self.assertTrue(test('c.c.c.p'))
+
+ self.assertFalse(test('ab'))
+ self.assertFalse(test('ba'))
+ self.assertFalse(test('bb'))
+ self.assertFalse(test('c.c'))
+ self.assertFalse(test('b'))
+ self.assertFalse(test('d'))
+
+ def test_parse_checkers(self):
+ lines = [
+ 'OVERVIEW: Clang Static Analyzer Checkers List',
+ '',
+ 'CHECKERS:',
+ ' checker.one Checker One description',
+ ' checker.two',
+ ' Checker Two description']
+ result = dict(sut.parse_checkers(lines))
+ self.assertTrue('checker.one' in result)
+ self.assertEqual('Checker One description', result.get('checker.one'))
+ self.assertTrue('checker.two' in result)
+ self.assertEqual('Checker Two description', result.get('checker.two'))
+
+
+class ClangIsCtuCapableTest(unittest.TestCase):
+ def test_ctu_not_found(self):
+ is_ctu = sut.is_ctu_capable('not-found-clang-extdef-mapping')
+ self.assertFalse(is_ctu)
+
+
+class ClangGetTripleArchTest(unittest.TestCase):
+ def test_arch_is_not_empty(self):
+ arch = sut.get_triple_arch(['clang', '-E', '-'], '.')
+ self.assertTrue(len(arch) > 0)
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_compilation.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_compilation.py
new file mode 100644
index 00000000000..e8ad3d8c99f
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_compilation.py
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+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/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_intercept.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_intercept.py
new file mode 100644
index 00000000000..5473b88d833
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_intercept.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+import libscanbuild.intercept as sut
+import unittest
+import os.path
+
+
+class InterceptUtilTest(unittest.TestCase):
+
+ def test_format_entry_filters_action(self):
+ def test(command):
+ 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']))
+
+ def test_format_entry_normalize_filename(self):
+ parent = os.path.join(os.sep, 'home', 'me')
+ current = os.path.join(parent, 'project')
+
+ 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):
+ content = """#!/usr/bin/env sh
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ echo '{0}'
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ """.format(message)
+ lines = [line.strip() for line in content.split('\n')]
+ with open(filename, 'w') as handle:
+ handle.write('\n'.join(lines))
+ handle.close()
+ os.chmod(filename, 0x1ff)
+
+ def create_csrutil(dest_dir, status):
+ filename = os.path.join(dest_dir, 'csrutil')
+ message = 'System Integrity Protection status: {0}'.format(status)
+ return create_status_report(filename, message)
+
+ def create_sestatus(dest_dir, status):
+ filename = os.path.join(dest_dir, 'sestatus')
+ message = 'SELinux status:\t{0}'.format(status)
+ return create_status_report(filename, message)
+
+ ENABLED = 'enabled'
+ DISABLED = 'disabled'
+
+ OSX = 'darwin'
+
+ with libear.TemporaryDirectory() as tmpdir:
+ saved = os.environ['PATH']
+ try:
+ os.environ['PATH'] = tmpdir + ':' + saved
+
+ create_csrutil(tmpdir, ENABLED)
+ self.assertTrue(sut.is_preload_disabled(OSX))
+
+ create_csrutil(tmpdir, DISABLED)
+ self.assertFalse(sut.is_preload_disabled(OSX))
+ finally:
+ os.environ['PATH'] = saved
+
+ saved = os.environ['PATH']
+ try:
+ os.environ['PATH'] = ''
+ # shall be false when it's not in the path
+ self.assertFalse(sut.is_preload_disabled(OSX))
+
+ self.assertFalse(sut.is_preload_disabled('unix'))
+ finally:
+ os.environ['PATH'] = saved
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_libear.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_libear.py
new file mode 100644
index 00000000000..933da50242f
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_libear.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+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/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_report.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_report.py
new file mode 100644
index 00000000000..60ec0d855ff
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_report.py
@@ -0,0 +1,147 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libear
+import libscanbuild.report as sut
+import unittest
+import os
+import os.path
+
+
+def run_bug_parse(content):
+ with libear.TemporaryDirectory() as tmpdir:
+ file_name = os.path.join(tmpdir, 'test.html')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ for bug in sut.parse_bug_html(file_name):
+ return bug
+
+
+def run_crash_parse(content, preproc):
+ with libear.TemporaryDirectory() as tmpdir:
+ file_name = os.path.join(tmpdir, preproc + '.info.txt')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ return sut.parse_crash(file_name)
+
+
+class ParseFileTest(unittest.TestCase):
+
+ def test_parse_bug(self):
+ content = [
+ "some header\n",
+ "<!-- BUGDESC Division by zero -->\n",
+ "<!-- BUGTYPE Division by zero -->\n",
+ "<!-- BUGCATEGORY Logic error -->\n",
+ "<!-- BUGFILE xx -->\n",
+ "<!-- BUGLINE 5 -->\n",
+ "<!-- BUGCOLUMN 22 -->\n",
+ "<!-- BUGPATHLENGTH 4 -->\n",
+ "<!-- BUGMETAEND -->\n",
+ "<!-- REPORTHEADER -->\n",
+ "some tails\n"]
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Logic error')
+ self.assertEqual(result['bug_path_length'], 4)
+ self.assertEqual(result['bug_line'], 5)
+ self.assertEqual(result['bug_description'], 'Division by zero')
+ self.assertEqual(result['bug_type'], 'Division by zero')
+ self.assertEqual(result['bug_file'], 'xx')
+
+ def test_parse_bug_empty(self):
+ content = []
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Other')
+ self.assertEqual(result['bug_path_length'], 1)
+ self.assertEqual(result['bug_line'], 0)
+
+ def test_parse_crash(self):
+ content = [
+ "/some/path/file.c\n",
+ "Some very serious Error\n",
+ "bla\n",
+ "bla-bla\n"]
+ result = run_crash_parse(content, 'file.i')
+ self.assertEqual(result['source'], content[0].rstrip())
+ self.assertEqual(result['problem'], content[1].rstrip())
+ self.assertEqual(os.path.basename(result['file']),
+ 'file.i')
+ self.assertEqual(os.path.basename(result['info']),
+ 'file.i.info.txt')
+ self.assertEqual(os.path.basename(result['stderr']),
+ 'file.i.stderr.txt')
+
+ def test_parse_real_crash(self):
+ import libscanbuild.analyze as sut2
+ import re
+ 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 = {
+ '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
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+ self.assertIsNot(pp_file, None)
+ # read the failure report back
+ result = sut.parse_crash(pp_file + '.info.txt')
+ self.assertEqual(result['source'], filename)
+ self.assertEqual(result['problem'], 'Other Error')
+ self.assertEqual(result['file'], pp_file)
+ self.assertEqual(result['info'], pp_file + '.info.txt')
+ self.assertEqual(result['stderr'], pp_file + '.stderr.txt')
+
+
+class ReportMethodTest(unittest.TestCase):
+
+ def test_chop(self):
+ self.assertEqual('file', sut.chop('/prefix', '/prefix/file'))
+ self.assertEqual('file', sut.chop('/prefix/', '/prefix/file'))
+ self.assertEqual('lib/file', sut.chop('/prefix/', '/prefix/lib/file'))
+ self.assertEqual('/prefix/file', sut.chop('', '/prefix/file'))
+
+ def test_chop_when_cwd(self):
+ self.assertEqual('../src/file', sut.chop('/cwd', '/src/file'))
+ self.assertEqual('../src/file', sut.chop('/prefix/cwd',
+ '/prefix/src/file'))
+
+
+class GetPrefixFromCompilationDatabaseTest(unittest.TestCase):
+
+ def test_with_different_filenames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c', '/tmp/b.c']), '/tmp')
+
+ def test_with_different_dirnames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/tmp/ack/b.c']), '/tmp')
+
+ def test_no_common_prefix(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/usr/ack/b.c']), '/')
+
+ def test_with_single_file(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c']), '/tmp')
+
+ def test_empty(self):
+ self.assertEqual(
+ sut.commonprefix([]), '')
diff --git a/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_shell.py b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_shell.py
new file mode 100644
index 00000000000..6ffbb8782a9
--- /dev/null
+++ b/gnu/llvm/clang/tools/scan-build-py/tests/unit/test_shell.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+import libscanbuild.shell as sut
+import unittest
+
+
+class ShellTest(unittest.TestCase):
+
+ def test_encode_decode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.encode(sut.decode(value)), value)
+
+ test("")
+ test("clang")
+ test("clang this and that")
+
+ def test_decode_encode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.decode(sut.encode(value)), value)
+
+ test([])
+ test(['clang'])
+ test(['clang', 'this', 'and', 'that'])
+ test(['clang', 'this and', 'that'])
+ test(['clang', "it's me", 'again'])
+ test(['clang', 'some "words" are', 'quoted'])
+
+ def test_encode(self):
+ self.assertEqual(sut.encode(['clang', "it's me", 'again']),
+ 'clang "it\'s me" again')
+ self.assertEqual(sut.encode(['clang', "it(s me", 'again)']),
+ 'clang "it(s me" "again)"')
+ self.assertEqual(sut.encode(['clang', 'redirect > it']),
+ 'clang "redirect > it"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="VALUE"']),
+ 'clang -DKEY=\\"VALUE\\"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="value with spaces"']),
+ 'clang -DKEY=\\"value with spaces\\"')