diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/.travis.yml b/.travis.yml index 9791de5..0e43863 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,10 +20,18 @@ addons: - clang-3.7 install: - - pip install pep8 + - pip install pep8 lit script: - - pep8 libear libscanbuild tests + - lit -v tests - python setup.py check - python setup.py install - - python setup.py test + - python setup.py sdist + +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/c3b71470714f6eaa03bc + on_success: change + on_failure: always + on_start: never diff --git a/setup.py b/setup.py index 63b52db..3a7bdf1 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,5 @@ setup( "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Compilers", "Topic :: Software Development :: Quality Assurance" - ], - test_suite="tests.suite" + ] ) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 94dc69d..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1,18 +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 unittest - -import tests.unit -import tests.functional.cases - - -def suite(): - loader = unittest.TestLoader() - ts = unittest.TestSuite() - ts.addTests(loader.loadTestsFromModule(tests.unit)) - ts.addTests(loader.loadTestsFromModule(tests.functional.cases)) - return ts diff --git a/tests/functional/src/broken-one.c b/tests/functional/Input/broken/one.c similarity index 100% rename from tests/functional/src/broken-one.c rename to tests/functional/Input/broken/one.c diff --git a/tests/functional/src/broken-two.c b/tests/functional/Input/broken/two.c similarity index 100% rename from tests/functional/src/broken-two.c rename to tests/functional/Input/broken/two.c diff --git a/tests/functional/src/include/clean-one.h b/tests/functional/Input/clean/include/one.h similarity index 100% rename from tests/functional/src/include/clean-one.h rename to tests/functional/Input/clean/include/one.h diff --git a/tests/functional/src/clean-one.c b/tests/functional/Input/clean/one.c similarity index 85% rename from tests/functional/src/clean-one.c rename to tests/functional/Input/clean/one.c index 08c5f33..907ec66 100644 --- a/tests/functional/src/clean-one.c +++ b/tests/functional/Input/clean/one.c @@ -1,4 +1,4 @@ -#include +#include int do_nothing_loop() { diff --git a/tests/functional/src/clean-two.c b/tests/functional/Input/clean/two.c similarity index 88% rename from tests/functional/src/clean-two.c rename to tests/functional/Input/clean/two.c index 73bc288..613a373 100644 --- a/tests/functional/src/clean-two.c +++ b/tests/functional/Input/clean/two.c @@ -1,4 +1,4 @@ -#include +#include "one.h" #include diff --git a/tests/functional/src/emit-one.c b/tests/functional/Input/dirty/one.c similarity index 100% rename from tests/functional/src/emit-one.c rename to tests/functional/Input/dirty/one.c diff --git a/tests/functional/src/emit-two.c b/tests/functional/Input/dirty/two.c similarity index 100% rename from tests/functional/src/emit-two.c rename to tests/functional/Input/dirty/two.c diff --git a/tests/functional/src/main.c b/tests/functional/Input/main.c similarity index 100% rename from tests/functional/src/main.c rename to tests/functional/Input/main.c diff --git a/tests/functional/bin/cdb_diff b/tests/functional/bin/cdb_diff new file mode 100755 index 0000000..4bc6bb1 --- /dev/null +++ b/tests/functional/bin/cdb_diff @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- 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 sys +import argparse +import json + + +def diff(lhs, rhs): + def create_hash(entry): + return entry['file'][::-1] + entry['command'] + entry['directory'] + + left = {create_hash(entry): entry for entry in lhs} + right = {create_hash(entry): entry for entry in rhs} + result = [] + for key in left.keys(): + if key not in right: + result.append('> {}'.format(left[key])) + for key in right.keys(): + if key not in left: + result.append('< {}'.format(right[key])) + return result + + +def main(): + """ Semantically diff two compilation databases. """ + parser = argparse.ArgumentParser() + parser.add_argument('left', type=argparse.FileType('r')) + parser.add_argument('right', type=argparse.FileType('r')) + args = parser.parse_args() + # files are open, parse the json content + lhs = json.load(args.left) + rhs = json.load(args.right) + # run the diff and print the result + results = diff(lhs, rhs) + for result in results: + print(result) + return len(results) + + +sys.exit(main()) diff --git a/tests/functional/bin/cdb_run b/tests/functional/bin/cdb_run new file mode 100755 index 0000000..37afb0a --- /dev/null +++ b/tests/functional/bin/cdb_run @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- 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 os +import sys +import argparse +import json +import shlex +import multiprocessing +import subprocess + + +def run(entry): + command = shlex.split(entry['command']) + # do respect 'CC' and 'CXX' environment variables for compiler + env_name = 'CC' if command[0] == 'cc' else 'CXX' + if env_name in os.environ: + command[0] = os.environ[env_name] + # execute the command in the given directory + # map exit code to 0/1 to get the correct fail count + print('exec {0} in {1}'.format(command, entry['directory'])) + return 1 if subprocess.call(command, cwd=entry['directory']) else 0 + + +def main(): + """ Execute compilation commands from a given compilation database. """ + parser = argparse.ArgumentParser() + parser.add_argument('--parallel', type=int, default=1) + parser.add_argument('cdb', type=argparse.FileType('r')) + args = parser.parse_args() + # execute compilation database entry + failures = 0 + pool = multiprocessing.Pool(args.parallel) + for current in pool.imap_unordered(run, json.load(args.cdb)): + failures += current + pool.close() + pool.join() + return failures + + +sys.exit(main()) diff --git a/tests/functional/bin/cdb_substitute b/tests/functional/bin/cdb_substitute new file mode 100755 index 0000000..5482022 --- /dev/null +++ b/tests/functional/bin/cdb_substitute @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- 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 os +import re +import sys +import random + + +def comment(line): + return re.match(r'^(#|//).*', line) + + +def random_filename(): + def random_char(): + return random.choice([chr(random.randrange(ord('a'), ord('z'), 1)), + chr(random.randrange(ord('A'), ord('Z'), 1))]) + + return ''.join(random_char() for _ in range(12)) + + +def substitute(line): + + def lookup(key): + return random_filename() if key == 'random' else os.environ[key] + + requests = re.findall(r'\$\{([^\}]+)\}', line) + if requests: + replace = {re.escape(request): lookup(request) for request in requests} + for key, value in replace.items(): + line = re.sub(r'\$\{' + key + r'\}', value, line) + return line + + +def main(): + """ Substitute environment literals in a given compilation database. """ + inputs = (line for line in sys.stdin) + outputs = (substitute(line) for line in inputs if not comment(line)) + for line in outputs: + sys.stdout.write(line) + return 0 + + +sys.exit(main()) diff --git a/tests/functional/cases/__init__.py b/tests/functional/cases/__init__.py deleted file mode 100644 index 6c78760..0000000 --- a/tests/functional/cases/__init__.py +++ /dev/null @@ -1,71 +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 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/tests/functional/__init__.py b/tests/functional/cases/analyze/analyze_architecture_specified.ft similarity index 100% rename from tests/functional/__init__.py rename to tests/functional/cases/analyze/analyze_architecture_specified.ft diff --git a/tests/functional/cases/analyze/analyze_debug_code.ft b/tests/functional/cases/analyze/analyze_debug_code.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_enable_checkers.ft b/tests/functional/cases/analyze/analyze_enable_checkers.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_exclude_files.ft b/tests/functional/cases/analyze/analyze_exclude_files.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_intercept_library.ft b/tests/functional/cases/analyze/analyze_intercept_library.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_intercept_wrapper.ft b/tests/functional/cases/analyze/analyze_intercept_wrapper.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_interposition.ft b/tests/functional/cases/analyze/analyze_interposition.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/analyze_language_specified.ft b/tests/functional/cases/analyze/analyze_language_specified.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/exit_code_failed.ft b/tests/functional/cases/analyze/exit_code_failed.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/exit_code_failed_shows_bugs.ft b/tests/functional/cases/analyze/exit_code_failed_shows_bugs.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/exit_code_failed_shows_bugs_on_plist.ft b/tests/functional/cases/analyze/exit_code_failed_shows_bugs_on_plist.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/src/compilation_database/build_clean.json.in b/tests/functional/cases/analyze/exit_code_success.ft similarity index 100% rename from tests/functional/src/compilation_database/build_clean.json.in rename to tests/functional/cases/analyze/exit_code_success.ft diff --git a/tests/functional/cases/analyze/exit_code_success_shows_bugs.ft b/tests/functional/cases/analyze/exit_code_success_shows_bugs.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/analyze/exit_code_success_shows_bugs_on_plist.ft b/tests/functional/cases/analyze/exit_code_success_shows_bugs_on_plist.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/intercept/broken_build.sh b/tests/functional/cases/intercept/broken_build.sh new file mode 100644 index 0000000..44e6afd --- /dev/null +++ b/tests/functional/cases/intercept/broken_build.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# RUN: intercept-build --override-compiler --cdb %t.json.wrapper sh %s +# RUN: cdb_diff %t.json.wrapper %T/broken_build.json.expected +# +# when library preload disabled, it falls back to use compiler wrapper +# +# RUN: intercept-build --cdb %t.json.preload sh %s +# RUN: cdb_diff %t.json.preload %T/broken_build.json.expected + +set -o errexit +set -o nounset +set -o xtrace + +cd "${test_input_dir}" +${CC} -c -o ${test_output_dir}/main.o main.c +cd "${test_input_dir}/clean" +${CC} -c -o ${test_output_dir}/clean_one.o -Iinclude one.c +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c +cd "${test_input_dir}/broken" +${CC} -c -o ${test_output_dir}/broken_one.o one.c || true +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/broken_two.o broken/two.c || true + +cat > ${test_output_dir}/broken_build.json.expected << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/main.o main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}/clean", + "command": "cc -c -o ${test_output_dir}/clean_one.o -Iinclude one.c", + "file": "${test_input_dir}/clean/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c", + "file": "${test_input_dir}/clean/two.c" +} +, +{ + "directory": "${test_input_dir}/broken", + "command": "cc -c -o ${test_output_dir}/broken_one.o one.c", + "file": "${test_input_dir}/broken/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/broken_two.o broken/two.c", + "file": "${test_input_dir}/broken/two.c" +} +] +EOF diff --git a/tests/functional/cases/intercept/clean_env_build_intercept.sh b/tests/functional/cases/intercept/clean_env_build_intercept.sh new file mode 100644 index 0000000..6af968b --- /dev/null +++ b/tests/functional/cases/intercept/clean_env_build_intercept.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# REQUIRES: preload +# RUN: intercept-build --cdb %t.json.result sh %s +# RUN: cdb_diff %T/clean_env_build_intercept.sh.json %t.json.result + +set -o errexit +set -o nounset +set -o xtrace + +CC=$(which clang) + +cd ${test_input_dir} +env - ${CC} -c -o ${test_output_dir}/clean_env_main.o main.c + +cat > ${test_output_dir}/clean_env_build_intercept.sh.json << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/clean_env_main.o main.c", + "file": "${test_input_dir}/main.c" +} +] +EOF diff --git a/tests/functional/cases/intercept/deal_with_existing_database.sh b/tests/functional/cases/intercept/deal_with_existing_database.sh new file mode 100644 index 0000000..b8b1541 --- /dev/null +++ b/tests/functional/cases/intercept/deal_with_existing_database.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# RUN: sh %s +# this script run the whole test, not other control from lit + +set -o errexit +set -o nounset +set -o xtrace + +PREFIX="${test_output_dir}/output_handling" + +cat > ${PREFIX}.compile_main.sh << EOF +set -o errexit +set -o nounset +set -o xtrace + +cd "${test_input_dir}" +\${CC} -c -o ${test_output_dir}/main.o main.c +EOF + +cat > ${PREFIX}.compile_dirty.sh << EOF +set -o errexit +set -o nounset +set -o xtrace + +cd "${test_input_dir}/dirty" +\${CC} -c -o ${test_output_dir}/dirty_one.o one.c +\${CC} -c -o ${test_output_dir}/dirty_two.o two.c +EOF + +cat > ${PREFIX}.main.json << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/main.o main.c", + "file": "${test_input_dir}/main.c" +} +] +EOF + +cat > ${PREFIX}.dirty.json << EOF +[ +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_one.o one.c", + "file": "${test_input_dir}/dirty/one.c" +} +, +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_two.o two.c", + "file": "${test_input_dir}/dirty/two.c" +} +] +EOF + +cat > ${PREFIX}.final.json << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/main.o main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_one.o one.c", + "file": "${test_input_dir}/dirty/one.c" +} +, +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_two.o two.c", + "file": "${test_input_dir}/dirty/two.c" +} +] +EOF + +# preparation: create a simple compilation database +intercept-build --cdb ${PREFIX}.json sh ${PREFIX}.compile_main.sh +cdb_diff ${PREFIX}.main.json ${PREFIX}.json +# overwrite the previously created compilation database +intercept-build --cdb ${PREFIX}.json sh ${PREFIX}.compile_dirty.sh +cdb_diff ${PREFIX}.dirty.json ${PREFIX}.json +# append to the previously created compilation database +intercept-build --cdb ${PREFIX}.json --append sh ${PREFIX}.compile_main.sh +cdb_diff ${PREFIX}.final.json ${PREFIX}.json diff --git a/tests/functional/exec/CMakeLists.txt b/tests/functional/cases/intercept/exec/CMakeLists.txt similarity index 100% rename from tests/functional/exec/CMakeLists.txt rename to tests/functional/cases/intercept/exec/CMakeLists.txt diff --git a/tests/functional/exec/config.h.in b/tests/functional/cases/intercept/exec/config.h.in similarity index 100% rename from tests/functional/exec/config.h.in rename to tests/functional/cases/intercept/exec/config.h.in diff --git a/tests/functional/exec/main.c b/tests/functional/cases/intercept/exec/main.c similarity index 87% rename from tests/functional/exec/main.c rename to tests/functional/cases/intercept/exec/main.c index 830cf37..465e771 100644 --- a/tests/functional/exec/main.c +++ b/tests/functional/cases/intercept/exec/main.c @@ -8,9 +8,10 @@ #include "config.h" #include -#include +#include #include #include +#include #include #if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP @@ -265,10 +266,39 @@ void call_posix_spawnp() { #endif int main(int argc, char *const argv[]) { - if (argc != 2) - exit(EXIT_FAILURE); - expected_out_open(argv[1]); + char *workdir = NULL; + char *output = NULL; + int c = 0; + + opterr = 0; + while ((c = getopt (argc, argv, "C:o:")) != -1) { + switch (c) { + case 'C': + workdir = optarg; + break; + case 'o': + output = optarg; + break; + case '?': + if (optopt == 'C' || optopt == 'o') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); + return 1; + default: + abort(); + } + } + for (int index = optind; index < argc; ++index) + printf ("Non-option argument %s\n", argv[index]); + + if (workdir != NULL) { + chdir(workdir); + } + expected_out_open(output); #ifdef HAVE_EXECV call_execv(); #endif diff --git a/tests/functional/cases/intercept/exec/run_exec_test.sh b/tests/functional/cases/intercept/exec/run_exec_test.sh new file mode 100644 index 0000000..7e889b5 --- /dev/null +++ b/tests/functional/cases/intercept/exec/run_exec_test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# REQUIRES: preload +# RUN: cmake -B%T -H%S +# RUN: make -C %T +# RUN: intercept-build --cdb %T/result.json %T/exec -C %T -o expected.json +# RUN: cdb_diff %T/result.json %T/expected.json diff --git a/tests/functional/cases/intercept/flags_are_filtered.sh b/tests/functional/cases/intercept/flags_are_filtered.sh new file mode 100644 index 0000000..7171e5b --- /dev/null +++ b/tests/functional/cases/intercept/flags_are_filtered.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# RUN: intercept-build --cdb %t.json.result sh %s +# RUN: cdb_diff %T/flags_are_filtered.sh.json %t.json.result + +set -o errexit +set -o nounset +set -o xtrace + +# set up unique names for this test +PREFIX=flagfiltering +# set up platform specific linker options +if [ `uname -o | grep -i linux` ]; then + LD_FLAGS="-o ${test_output_dir}/lib${PREFIX}.so -shared -Wl,-soname,${PREFIX}" +elif [ `uname -o | grep -i darwin` ]; then + LD_FLAGS="-o ${test_output_dir}/lib${PREFIX}.dylib -dynamiclib -install_name @rpath/${PREFIX}" +fi + +cd ${test_input_dir} + +# non compilation calls shall not be in the result +${CC} -### -c main.c 2> /dev/null +${CC} -E -o "${test_output_dir}/$$.i" main.c +${CC} -S -o "${test_output_dir}/$$.asm" main.c +${CC} -c -o "${test_output_dir}/$$.d" -M main.c +${CC} -c -o "${test_output_dir}/$$.d" -MM main.c + +# preprocessor flags shall be filtered +${CC} -c -o "${test_output_dir}/${PREFIX}_clean_one.o" -fpic -Iclean/include -MD -MT target -MF "${test_output_dir}/${PREFIX}_clean_one.d" clean/one.c +${CC} -c -o "${test_output_dir}/${PREFIX}_clean_two.o" -fpic -Iclean/include -MMD -MQ target -MF "${test_output_dir}/${PREFIX}_clean_two.d" clean/two.c + +# linking shall not in the result +${CC} ${LD_FLAGS} "${test_output_dir}/${PREFIX}_clean_one.o" "${test_output_dir}/${PREFIX}_clean_two.o" + +# linker flags shall be filtered +${CC} -o "${test_output_dir}/${PREFIX}_one" "-l${PREFIX}" "-L${test_output_dir}" main.c +${CC} -o "${test_output_dir}/${PREFIX}_two" -l ${PREFIX} -L ${test_output_dir} main.c + +cat > ${test_output_dir}/flags_are_filtered.sh.json << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/${PREFIX}_clean_one.o -fpic -Iclean/include clean/one.c", + "file": "${test_input_dir}/clean/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/${PREFIX}_clean_two.o -fpic -Iclean/include clean/two.c", + "file": "${test_input_dir}/clean/two.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/${PREFIX}_one main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/${PREFIX}_two main.c", + "file": "${test_input_dir}/main.c" +} +] +EOF diff --git a/tests/functional/cases/intercept/lit.local.cfg b/tests/functional/cases/intercept/lit.local.cfg new file mode 100644 index 0000000..c64c663 --- /dev/null +++ b/tests/functional/cases/intercept/lit.local.cfg @@ -0,0 +1,13 @@ +# -*- 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 os.path +import lit.util + +# test_source_root: The root path where tests are located. +this_dir = os.path.dirname(__file__) + +config.environment['test_output_dir'] = os.path.join(this_dir, 'Output') diff --git a/tests/functional/cases/intercept/multiple_source_single_command.sh b/tests/functional/cases/intercept/multiple_source_single_command.sh new file mode 100644 index 0000000..64834e9 --- /dev/null +++ b/tests/functional/cases/intercept/multiple_source_single_command.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# RUN: intercept-build --cdb %t.json.result sh %s +# RUN: cdb_diff %T/multiple_source_single_command.sh.json %t.json.result + +set -o errexit +set -o nounset +set -o xtrace + +cd ${test_input_dir} +${CC} -o ${test_output_dir}/all_in_one main.c dirty/one.c dirty/two.c + +cat > ${test_output_dir}/multiple_source_single_command.sh.json << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/all_in_one main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/all_in_one dirty/one.c", + "file": "${test_input_dir}/dirty/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/all_in_one dirty/two.c", + "file": "${test_input_dir}/dirty/two.c" +} +] +EOF diff --git a/tests/functional/cases/intercept/parallel_build.sh b/tests/functional/cases/intercept/parallel_build.sh new file mode 100644 index 0000000..d8b39da --- /dev/null +++ b/tests/functional/cases/intercept/parallel_build.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# RUN: intercept-build --override-compiler --cdb %t.json.wrapper sh %s +# RUN: cdb_diff %t.json.wrapper %T/parallel_build.json.expected +# +# when library preload disabled, it falls back to use compiler wrapper +# +# RUN: intercept-build --cdb %t.json.preload sh %s +# RUN: cdb_diff %t.json.preload %T/parallel_build.json.expected + +set -o errexit +set -o nounset +set -o xtrace + +cd "${test_input_dir}" +${CC} -c -o ${test_output_dir}/main.o main.c & +cd "${test_input_dir}/clean" +${CC} -c -o ${test_output_dir}/clean_one.o -Iinclude one.c & +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c & +cd "${test_input_dir}/dirty" +${CC} -c -o ${test_output_dir}/dirty_one.o -Wall one.c & +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/dirty_two.o -Wall dirty/two.c & + +wait + +cat > ${test_output_dir}/parallel_build.json.expected << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/main.o main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}/clean", + "command": "cc -c -o ${test_output_dir}/clean_one.o -Iinclude one.c", + "file": "${test_input_dir}/clean/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c", + "file": "${test_input_dir}/clean/two.c" +} +, +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_one.o -Wall one.c", + "file": "${test_input_dir}/dirty/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/dirty_two.o -Wall dirty/two.c", + "file": "${test_input_dir}/dirty/two.c" +} +] +EOF \ No newline at end of file diff --git a/tests/functional/cases/intercept/successful_build.sh b/tests/functional/cases/intercept/successful_build.sh new file mode 100644 index 0000000..77978cd --- /dev/null +++ b/tests/functional/cases/intercept/successful_build.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# RUN: intercept-build --override-compiler --cdb %t.json.wrapper sh %s +# RUN: cdb_diff %t.json.wrapper %T/successful_build.json.expected +# +# when library preload disabled, it falls back to use compiler wrapper +# +# RUN: intercept-build --cdb %t.json.preload sh %s +# RUN: cdb_diff %t.json.preload %T/successful_build.json.expected + +set -o errexit +set -o nounset +set -o xtrace + +cd "${test_input_dir}" +${CC} -c -o ${test_output_dir}/main.o main.c +cd "${test_input_dir}/clean" +${CC} -c -o ${test_output_dir}/clean_one.o -Iinclude one.c +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c +cd "${test_input_dir}/dirty" +${CC} -c -o ${test_output_dir}/dirty_one.o -Wall one.c +cd "${test_input_dir}" +${CXX} -c -o ${test_output_dir}/dirty_two.o -Wall dirty/two.c + +cat > ${test_output_dir}/successful_build.json.expected << EOF +[ +{ + "directory": "${test_input_dir}", + "command": "cc -c -o ${test_output_dir}/main.o main.c", + "file": "${test_input_dir}/main.c" +} +, +{ + "directory": "${test_input_dir}/clean", + "command": "cc -c -o ${test_output_dir}/clean_one.o -Iinclude one.c", + "file": "${test_input_dir}/clean/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/clean_two.o -I ./clean/include clean/two.c", + "file": "${test_input_dir}/clean/two.c" +} +, +{ + "directory": "${test_input_dir}/dirty", + "command": "cc -c -o ${test_output_dir}/dirty_one.o -Wall one.c", + "file": "${test_input_dir}/dirty/one.c" +} +, +{ + "directory": "${test_input_dir}", + "command": "c++ -c -o ${test_output_dir}/dirty_two.o -Wall dirty/two.c", + "file": "${test_input_dir}/dirty/two.c" +} +] +EOF \ No newline at end of file diff --git a/tests/functional/cases/report/report_dir_empty_cleaned.ft b/tests/functional/cases/report/report_dir_empty_cleaned.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_dir_empty_kept.ft b/tests/functional/cases/report/report_dir_empty_kept.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_dir_kept.ft b/tests/functional/cases/report/report_dir_kept.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_failures.ft b/tests/functional/cases/report/report_failures.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_failures_disabled.ft b/tests/functional/cases/report/report_failures_disabled.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_file_for_html.ft b/tests/functional/cases/report/report_file_for_html.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_file_for_plist.ft b/tests/functional/cases/report/report_file_for_plist.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_file_for_plist_html.ft b/tests/functional/cases/report/report_file_for_plist_html.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_tile_default.ft b/tests/functional/cases/report/report_tile_default.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/report/report_title_set.ft b/tests/functional/cases/report/report_title_set.ft new file mode 100644 index 0000000..e69de29 diff --git a/tests/functional/cases/test_create_cdb.py b/tests/functional/cases/test_create_cdb.py deleted file mode 100644 index c90cbee..0000000 --- a/tests/functional/cases/test_create_cdb.py +++ /dev/null @@ -1,195 +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 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() as tmpdir: - exitcode = self.run_intercept(tmpdir, 'build_clean') - self.assertFalse(exitcode) - - def test_not_successful_build(self): - with libear.temporary_directory() as tmpdir: - exitcode = self.run_intercept(tmpdir, 'build_broken') - self.assertTrue(exitcode) - - def test_intercept_help(self): - exitcode = silent_call(['intercept-build', '--help']) - self.assertFalse(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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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/tests/functional/cases/test_exec_anatomy.py b/tests/functional/cases/test_exec_anatomy.py deleted file mode 100644 index 89ec51e..0000000 --- a/tests/functional/cases/test_exec_anatomy.py +++ /dev/null @@ -1,50 +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 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.temporary_directory() as tmp_dir: - expected, result = run(source_dir, tmp_dir) - self.assertEqualJson(expected, result) diff --git a/tests/functional/cases/test_from_cdb.py b/tests/functional/cases/test_from_cdb.py deleted file mode 100644 index 33f0c34..0000000 --- a/tests/functional/cases/test_from_cdb.py +++ /dev/null @@ -1,182 +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 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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'(?P<page>.*)'), - re.compile(r'

(?P.*)

') - ] - 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.temporary_directory() 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.temporary_directory() 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/tests/functional/cases/test_from_cmd.py b/tests/functional/cases/test_from_cmd.py deleted file mode 100644 index e28461d..0000000 --- a/tests/functional/cases/test_from_cmd.py +++ /dev/null @@ -1,118 +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 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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.temporary_directory() 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/tests/functional/lit.local.cfg b/tests/functional/lit.local.cfg new file mode 100644 index 0000000..d247d41 --- /dev/null +++ b/tests/functional/lit.local.cfg @@ -0,0 +1,18 @@ +# -*- 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 os.path +import lit.util + +# test_source_root: The root path where tests are located. +this_dir = os.path.dirname(__file__) +bin_dir = os.path.join(this_dir, 'bin') + +config.environment['PATH'] = ':'.join([bin_dir, config.environment['PATH']]) +config.environment['CC'] = 'cc' +config.environment['CXX'] = 'c++' +config.environment['test_input_dir'] = os.path.join(this_dir, 'Input') +config.environment['test_output_dir'] = os.path.join(this_dir, 'Output') diff --git a/tests/functional/src/build/Makefile b/tests/functional/src/build/Makefile deleted file mode 100644 index a8c0aaf..0000000 --- a/tests/functional/src/build/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -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/tests/functional/src/compilation_database/build_broken.json.in b/tests/functional/src/compilation_database/build_broken.json.in deleted file mode 100644 index 104a419..0000000 --- a/tests/functional/src/compilation_database/build_broken.json.in +++ /dev/null @@ -1,43 +0,0 @@ -[ -{ - "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/tests/functional/src/compilation_database/build_regular.json.in b/tests/functional/src/compilation_database/build_regular.json.in deleted file mode 100644 index 0200c1d..0000000 --- a/tests/functional/src/compilation_database/build_regular.json.in +++ /dev/null @@ -1,31 +0,0 @@ -[ -{ - "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/tests/lit.cfg b/tests/lit.cfg new file mode 100644 index 0000000..a2f1b25 --- /dev/null +++ b/tests/lit.cfg @@ -0,0 +1,43 @@ +# -*- 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 sys +import os +import os.path +import subprocess +import lit.util + +this_dir = os.path.dirname(__file__) +project_dir = os.path.dirname(this_dir) +bin_dir = os.path.join(project_dir, 'bin') + +config.name = 'scan-build' + +config.test_format = lit.formats.ShTest() +config.test_exec_root = this_dir +config.test_source_root = this_dir + +config.suffixes = ['.sh', '.py'] +config.excludes = ['Input'] + +config.substitutions.append(('%{python}', sys.executable)) + +config.environment['PATH'] = ':'.join([bin_dir, os.environ['PATH']]) + + +# check pep8 util is available +try: + subprocess.call(['pep8', '--version'], stdout=subprocess.PIPE) +except: + pass +else: + config.available_features.add('pep8') + +# check for library preload is available +sys.path.append(project_dir) +from libscanbuild.intercept import is_preload_disabled +if not is_preload_disabled(sys.platform): + config.available_features.add('preload') \ No newline at end of file diff --git a/tests/run_pep8.sh b/tests/run_pep8.sh new file mode 100644 index 0000000..14a0fdb --- /dev/null +++ b/tests/run_pep8.sh @@ -0,0 +1,5 @@ +# REQUIRES: pep8 +# RUN: pep8 --show-source --show-pep8 . +# RUN: pep8 --show-source --show-pep8 ../bin +# RUN: pep8 --show-source --show-pep8 ../libscanbuild +# RUN: pep8 --show-source --show-pep8 ../libear diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py deleted file mode 100644 index dc8bf12..0000000 --- a/tests/unit/__init__.py +++ /dev/null @@ -1,26 +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. - -from . import test_libear -from . import test_compilation -from . import test_clang -from . import test_runner -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_runner)) - 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/tests/unit/lit.local.cfg b/tests/unit/lit.local.cfg new file mode 100644 index 0000000..e92d094 --- /dev/null +++ b/tests/unit/lit.local.cfg @@ -0,0 +1,16 @@ +# -*- 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 os.path +import lit.util + +# test_source_root: The root path where tests are located. +this_dir = os.path.dirname(__file__) +parent_dir = os.path.dirname(this_dir) +project_dir = os.path.dirname(parent_dir) + + +config.environment['PYTHONPATH'] = project_dir diff --git a/tests/unit/test_analyze.py b/tests/unit/test_analyze.py deleted file mode 100644 index 481cc0c..0000000 --- a/tests/unit/test_analyze.py +++ /dev/null @@ -1,7 +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.analyze as sut diff --git a/tests/unit/test_clang.py b/tests/unit/test_clang.py index c1fa040..4ad055a 100644 --- a/tests/unit/test_clang.py +++ b/tests/unit/test_clang.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libear import libscanbuild.clang as sut @@ -92,3 +94,7 @@ class ClangGetCheckersTest(unittest.TestCase): self.assertEqual('Checker One description', result.get('checker.one')) self.assertTrue('checker.two' in result) self.assertEqual('Checker Two description', result.get('checker.two')) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_compilation.py b/tests/unit/test_compilation.py index 6e9d7e3..3eeb3aa 100644 --- a/tests/unit/test_compilation.py +++ b/tests/unit/test_compilation.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libscanbuild.compilation as sut import unittest @@ -158,3 +160,7 @@ class SourceClassifierTest(unittest.TestCase): 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)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_intercept.py b/tests/unit/test_intercept.py index 94d67aa..ad24906 100644 --- a/tests/unit/test_intercept.py +++ b/tests/unit/test_intercept.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libear import libscanbuild.intercept as sut @@ -109,3 +111,7 @@ class InterceptUtilTest(unittest.TestCase): self.assertFalse(sut.is_preload_disabled('unix')) finally: os.environ['PATH'] = saved + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_libear.py b/tests/unit/test_libear.py index 2db00d6..a677b2c 100644 --- a/tests/unit/test_libear.py +++ b/tests/unit/test_libear.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libear as sut import unittest @@ -28,3 +30,7 @@ class TemporaryDirectoryTest(unittest.TestCase): except: self.assertIsNotNone(dir_name) self.assertFalse(os.path.exists(dir_name)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_report.py b/tests/unit/test_report.py index 4b19d4c..674187c 100644 --- a/tests/unit/test_report.py +++ b/tests/unit/test_report.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libear import libscanbuild.report as sut @@ -160,3 +162,7 @@ class ReportDirectoryTest(unittest.TestCase): sut.report_directory(tmp_dir, False) as report_dir3: self.assertLess(report_dir1, report_dir2) self.assertLess(report_dir2, report_dir3) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/unit/test_runner.py b/tests/unit/test_runner.py index e0fd89a..d004ebd 100644 --- a/tests/unit/test_runner.py +++ b/tests/unit/test_runner.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libear import libscanbuild.runner as sut diff --git a/tests/unit/test_shell.py b/tests/unit/test_shell.py index 2f696e3..5b33537 100644 --- a/tests/unit/test_shell.py +++ b/tests/unit/test_shell.py @@ -3,6 +3,8 @@ # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. +# +# RUN: %{python} %s import libscanbuild.shell as sut import unittest