diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 854e5d5bf5f..341b273a6fe 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -355,6 +355,12 @@ jobs: env: TEST_CPPCHECK_INJECT_CLANG: clang + - name: Run test/cli (--cppcheck-build-dir) + run: | + python3 -m pytest -Werror --strict-markers -vv test/cli + env: + TEST_CPPCHECK_INJECT_BUILDDIR: injected + - name: Run cfg tests if: matrix.os != 'ubuntu-22.04' run: | diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index 7234d55aa23..1610ab426d3 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -193,6 +193,13 @@ jobs: env: TEST_CPPCHECK_INJECT_CLANG: clang + - name: Run test/cli (--cppcheck-build-dir) + if: matrix.config == 'release' + run: | + python -m pytest -Werror --strict-markers -vv test/cli || exit /b !errorlevel! + env: + TEST_CPPCHECK_INJECT_BUILDDIR: injected + - name: Test addons if: matrix.config == 'release' run: | diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index 6e4e77de580..478b7ffba3c 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -119,6 +119,13 @@ jobs: env: TEST_CPPCHECK_INJECT_CLANG: clang + - name: Run test/cli (--cppcheck-build-dir) + run: | + pwd=$(pwd) + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli + env: + TEST_CPPCHECK_INJECT_BUILDDIR: injected + - name: Generate dependencies if: false run: | diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml index b681217b3b3..9a568f583d5 100644 --- a/.github/workflows/tsan.yml +++ b/.github/workflows/tsan.yml @@ -120,6 +120,13 @@ jobs: env: TEST_CPPCHECK_INJECT_CLANG: clang + - name: Run test/cli (--cppcheck-build-dir) + run: | + pwd=$(pwd) + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli + env: + TEST_CPPCHECK_INJECT_BUILDDIR: injected + - name: Generate dependencies if: false run: | diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml index 921cbaee27c..e662ee1c7a3 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/ubsan.yml @@ -118,6 +118,13 @@ jobs: env: TEST_CPPCHECK_INJECT_CLANG: clang + - name: Run test/cli (--cppcheck-build-dir) + run: | + pwd=$(pwd) + TEST_CPPCHECK_EXE_LOOKUP_PATH="$pwd/cmake.output" python3 -m pytest -Werror --strict-markers -vv test/cli + env: + TEST_CPPCHECK_INJECT_BUILDDIR: injected + - name: Generate dependencies run: | # make sure auto-generated GUI files exist diff --git a/test/cli/helloworld_test.py b/test/cli/helloworld_test.py index 73cc30647ef..7d269694972 100644 --- a/test/cli/helloworld_test.py +++ b/test/cli/helloworld_test.py @@ -291,24 +291,25 @@ def test_checkers_report(tmpdir): filename = os.path.join(tmpdir, '1.txt') args = [ f'--checkers-report={filename}', + '--no-cppcheck-build-dir', # TODO: remove this 'helloworld' ] cppcheck(args, cwd=__script_dir) with open(filename, 'rt') as f: - data = f.read() - assert 'No CheckAutoVariables::assignFunctionArg' in data - assert 'Yes CheckAutoVariables::autoVariables' in data + data = f.read().splitlines() + assert 'No CheckAutoVariables::assignFunctionArg require:style,warning' in data, json.dumps(data, indent=4) + assert 'Yes CheckAutoVariables::autoVariables' in data, json.dumps(data, indent=4) args += [ '--enable=style' ] cppcheck(args, cwd=__script_dir) with open(filename, 'rt') as f: - data = f.read() + data = f.read().splitlines() # checker has been activated by --enable=style - assert 'Yes CheckAutoVariables::assignFunctionArg' in data + assert 'Yes CheckAutoVariables::assignFunctionArg' in data, json.dumps(data, indent=4) def test_missing_include_system(): # #11283 diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 829e9f2c7d7..69bc5f00214 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -820,13 +820,6 @@ def test_unused_function_include(tmpdir): __test_unused_function_include(tmpdir, []) -# TODO: remove when we inject builddir -def test_unused_function_include_builddir(tmpdir): - builddir = os.path.join(tmpdir, 'injected') - os.makedirs(builddir) - __test_unused_function_include(tmpdir, ['--cppcheck-build-dir={}'.format(builddir)]) - - # TODO: test with all other types def test_showtime_top5_file(tmpdir): test_file = os.path.join(tmpdir, 'test.cpp') diff --git a/test/cli/qml_test.py b/test/cli/qml_test.py index 7e09d5360e2..56b04ee9553 100644 --- a/test/cli/qml_test.py +++ b/test/cli/qml_test.py @@ -35,7 +35,7 @@ def __test_unused_functions(extra_args): def test_unused_functions(): - __test_unused_functions(['-j1']) + __test_unused_functions(['-j1', '--no-cppcheck-build-dir']) def test_unused_functions_j(): @@ -45,6 +45,7 @@ def test_unused_functions_j(): '--library=qt', '--enable=unusedFunction', '-j2', + '--no-cppcheck-build-dir', __project_dir ] ret, stdout, stderr = cppcheck(args) diff --git a/test/cli/testutils.py b/test/cli/testutils.py index f5faf9304fa..effa0b2f905 100644 --- a/test/cli/testutils.py +++ b/test/cli/testutils.py @@ -4,6 +4,7 @@ import select import subprocess import time +import tempfile # Create Cppcheck project file import sys @@ -187,6 +188,19 @@ def cppcheck_ex(args, env=None, remove_checkers_report=True, cwd=None, cppcheck_ arg_executor = '--executor=' + str(os.environ['TEST_CPPCHECK_INJECT_EXECUTOR']) args.append(arg_executor) + builddir_tmp = None + + if 'TEST_CPPCHECK_INJECT_BUILDDIR' in os.environ: + found_builddir = False + for arg in args: + if arg.startswith('--cppcheck-build-dir=') or arg == '--no-cppcheck-build-dir': + found_builddir = True + break + if not found_builddir: + builddir_tmp = tempfile.TemporaryDirectory(prefix=str(os.environ['TEST_CPPCHECK_INJECT_BUILDDIR'])) + arg_clang = '--cppcheck-build-dir=' + builddir_tmp.name + args.append(arg_clang) + logging.info(exe + ' ' + ' '.join(args)) run_subprocess = __run_subprocess_tty if tty else __run_subprocess @@ -195,6 +209,9 @@ def cppcheck_ex(args, env=None, remove_checkers_report=True, cwd=None, cppcheck_ stdout = stdout.decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n') stderr = stderr.decode(encoding='utf-8', errors='ignore').replace('\r\n', '\n') + if builddir_tmp: + builddir_tmp.cleanup() + if remove_checkers_report: if stderr.find('[checkersReport]\n') > 0: start_id = stderr.find('[checkersReport]\n') diff --git a/test/cli/unused_function_test.py b/test/cli/unused_function_test.py index 3a6efcc6b66..25172f6f801 100644 --- a/test/cli/unused_function_test.py +++ b/test/cli/unused_function_test.py @@ -3,6 +3,7 @@ import os import json +import pytest from testutils import cppcheck __script_dir = os.path.dirname(os.path.abspath(__file__)) @@ -30,8 +31,10 @@ def __create_compdb(tmpdir, projpath): return compile_commands -def test_unused_functions(): - ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '-j1', __project_dir]) +def __test_unused_functions(extra_args): + args = ['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', __project_dir] + args += extra_args + ret, stdout, stderr = cppcheck(args) assert stdout.splitlines() == [] assert stderr.splitlines() == [ "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) @@ -39,8 +42,12 @@ def test_unused_functions(): assert ret == 0, stdout +def test_unused_functions(): + __test_unused_functions(['-j1', '--no-cppcheck-build-dir']) + + def test_unused_functions_j(): - ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '-j2', __project_dir]) + ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '-j2', '--no-cppcheck-build-dir', __project_dir]) assert stdout.splitlines() == [ "cppcheck: unusedFunction check requires --cppcheck-build-dir to be active with -j." ] @@ -48,13 +55,28 @@ def test_unused_functions_j(): assert ret == 0, stdout -def test_unused_functions_project(): - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(os.path.join(__project_dir, 'unusedFunction.cppcheck')), - '-j1']) +def test_unused_functions_builddir(tmpdir): + build_dir = os.path.join(tmpdir, 'b1') + os.mkdir(build_dir) + __test_unused_functions(['-j1', '--cppcheck-build-dir={}'.format(build_dir)]) + + +@pytest.mark.xfail(strict=True) +def test_unused_functions_builddir_j(tmpdir): + build_dir = os.path.join(tmpdir, 'b1') + os.mkdir(build_dir) + __test_unused_functions(['-j2', '--cppcheck-build-dir={}'.format(build_dir)]) + +def __test_unused_functions_project(extra_args): + project_file = os.path.join(__project_dir, 'unusedFunction.cppcheck') + args = ['-q', + '--template=simple', + '--enable=unusedFunction', + '--inline-suppr', + '--project={}'.format(project_file), + ] + args += extra_args + ret, stdout, stderr = cppcheck(args) assert stdout.splitlines() == [] assert [ "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) @@ -62,88 +84,51 @@ def test_unused_functions_project(): assert ret == 0, stdout -def test_unused_functions_project_j(): - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(os.path.join(__project_dir, 'unusedFunction.cppcheck')), - '-j2']) - assert stdout.splitlines() == [ - "cppcheck: unusedFunction check requires --cppcheck-build-dir to be active with -j." - ] - assert [] == stderr.splitlines() - assert ret == 0, stdout - - -def test_unused_functions_compdb(tmpdir): - compdb_file = __create_compdb(tmpdir, __project_dir) - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(compdb_file), - '-j1' - ]) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) - ] - assert ret == 0, stdout +def test_unused_functions_project(): + __test_unused_functions_project(['-j1', '--no-cppcheck-build-dir']) -def test_unused_functions_compdb_j(tmpdir): - compdb_file = __create_compdb(tmpdir, __project_dir) +def test_unused_functions_project_j(): + project_file = os.path.join(__project_dir, 'unusedFunction.cppcheck') ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', - '--project={}'.format(compdb_file), - '-j2' + '--project={}'.format(project_file), + '-j2', + '--no-cppcheck-build-dir' ]) assert stdout.splitlines() == [ "cppcheck: unusedFunction check requires --cppcheck-build-dir to be active with -j." ] - assert stderr.splitlines() == [] + assert [] == stderr.splitlines() assert ret == 0, stdout -def test_unused_functions_builddir(tmpdir): +def test_unused_functions_project_builddir(tmpdir): build_dir = os.path.join(tmpdir, 'b1') os.mkdir(build_dir) - ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '-j1', '--cppcheck-build-dir={}'.format(build_dir), __project_dir]) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) - ] - assert ret == 0, stdout + __test_unused_functions_project(['-j1', '--cppcheck-build-dir={}'.format(build_dir)]) -# TODO: only f3_3 is unused -def test_unused_functions_builddir_j(tmpdir): +@pytest.mark.xfail(strict=True) +def test_unused_functions_project_builddir_j(tmpdir): build_dir = os.path.join(tmpdir, 'b1') os.mkdir(build_dir) - ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '-j2', '--cppcheck-build-dir={}'.format(build_dir), __project_dir]) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}1.c:4:0: style: The function 'f1' is never used. [unusedFunction]".format(__project_dir_sep), - "{}2.c:4:0: style: The function 'f2' is never used. [unusedFunction]".format(__project_dir_sep), - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep), - "{}4.c:4:0: style: The function 'f4_1' is never used. [unusedFunction]".format(__project_dir_sep) - ] - assert ret == 0, stdout + __test_unused_functions_project(['-j2', '--cppcheck-build-dir={}'.format(build_dir)]) -def test_unused_functions_builddir_project(tmpdir): - build_dir = os.path.join(tmpdir, 'b1') - os.mkdir(build_dir) - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(os.path.join(__project_dir, 'unusedFunction.cppcheck')), - '--cppcheck-build-dir={}'.format(build_dir), - '-j1']) +def __test_unused_functions_compdb(tmpdir, extra_args): + compdb_file = __create_compdb(tmpdir, __project_dir) + args = ['-q', + '--template=simple', + '--enable=unusedFunction', + '--inline-suppr', + '--project={}'.format(compdb_file), + '-j1' + ] + args += extra_args + ret, stdout, stderr = cppcheck(args) assert stdout.splitlines() == [] assert stderr.splitlines() == [ "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) @@ -151,64 +136,35 @@ def test_unused_functions_builddir_project(tmpdir): assert ret == 0, stdout -# TODO: only f3_3 is unused -def test_unused_functions_builddir_project_j(tmpdir): - build_dir = os.path.join(tmpdir, 'b1') - os.mkdir(build_dir) - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(os.path.join(__project_dir, 'unusedFunction.cppcheck')), - '--cppcheck-build-dir={}'.format(build_dir), - '-j2']) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}1.c:4:0: style: The function 'f1' is never used. [unusedFunction]".format(__project_dir_sep), - "{}2.c:4:0: style: The function 'f2' is never used. [unusedFunction]".format(__project_dir_sep), - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep), - "{}4.c:4:0: style: The function 'f4_1' is never used. [unusedFunction]".format(__project_dir_sep) - ] - assert ret == 0, stdout +def test_unused_functions_compdb(tmpdir): + __test_unused_functions_compdb(tmpdir, ['-j1', '--no-cppcheck-build-dir']) -def test_unused_functions_builddir_compdb(tmpdir): +def test_unused_functions_compdb_j(tmpdir): compdb_file = __create_compdb(tmpdir, __project_dir) - build_dir = os.path.join(tmpdir, 'b1') - os.mkdir(build_dir) ret, stdout, stderr = cppcheck(['-q', '--template=simple', '--enable=unusedFunction', '--inline-suppr', '--project={}'.format(compdb_file), - '--cppcheck-build-dir={}'.format(build_dir), - '-j1' + '-j2', + '--no-cppcheck-build-dir' ]) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep) + assert stdout.splitlines() == [ + "cppcheck: unusedFunction check requires --cppcheck-build-dir to be active with -j." ] + assert stderr.splitlines() == [] assert ret == 0, stdout -# TODO: only f3_3 is unused -def test_unused_functions_builddir_compdb_j(tmpdir): - compdb_file = __create_compdb(tmpdir, __project_dir) +def test_unused_functions_compdb_builddir(tmpdir): build_dir = os.path.join(tmpdir, 'b1') os.mkdir(build_dir) - ret, stdout, stderr = cppcheck(['-q', - '--template=simple', - '--enable=unusedFunction', - '--inline-suppr', - '--project={}'.format(compdb_file), - '--cppcheck-build-dir={}'.format(build_dir), - '-j2' - ]) - assert stdout.splitlines() == [] - assert stderr.splitlines() == [ - "{}1.c:4:0: style: The function 'f1' is never used. [unusedFunction]".format(__project_dir_sep), - "{}2.c:4:0: style: The function 'f2' is never used. [unusedFunction]".format(__project_dir_sep), - "{}3.c:3:0: style: The function 'f3_3' is never used. [unusedFunction]".format(__project_dir_sep), - "{}4.c:4:0: style: The function 'f4_1' is never used. [unusedFunction]".format(__project_dir_sep) - ] - assert ret == 0, stdout + __test_unused_functions_compdb(tmpdir, ['-j1', '--cppcheck-build-dir={}'.format(build_dir)]) + + +@pytest.mark.xfail(strict=True) +def test_unused_functions_compdb_buildir_j(tmpdir): + build_dir = os.path.join(tmpdir, 'b1') + os.mkdir(build_dir) + __test_unused_functions_compdb(tmpdir, ['-j2', '--cppcheck-build-dir={}'.format(build_dir)]) diff --git a/test/cli/whole-program_test.py b/test/cli/whole-program_test.py index d167a87371e..c8115f06d19 100644 --- a/test/cli/whole-program_test.py +++ b/test/cli/whole-program_test.py @@ -220,8 +220,11 @@ def test_addon_rerun(tmp_path, builddir): '--enable=style', '--template={id}', 'whole-program'] + # do not use the injection because the directory needs to survive runs if builddir: args.append('--cppcheck-build-dir=' + str(tmp_path)) + else: + args.append('--no-cppcheck-build-dir') _, _, stderr = cppcheck(args, cwd=__script_dir) assert 'misra-c2012-5.8' in stderr _, _, stderr = cppcheck(args, cwd=__script_dir) @@ -293,10 +296,9 @@ def test_checkclass(): __test_checkclass(['-j1']) -# whole program analysis requires a build dir with -j -@pytest.mark.xfail(strict=True) +@pytest.mark.xfail(strict=True) # TODO: check error def test_checkclass_j(): - __test_checkclass(['-j2']) + __test_checkclass(['-j2', '--no-cppcheck-build-dir']) def test_checkclass_builddir(tmpdir): @@ -305,6 +307,11 @@ def test_checkclass_builddir(tmpdir): __test_checkclass(['--cppcheck-build-dir={}'.format(build_dir)]) +def test_checkclass_builddir_j(tmpdir): + build_dir = os.path.join(tmpdir, 'b1') + os.mkdir(build_dir) + __test_checkclass(['-j2', '--cppcheck-build-dir={}'.format(build_dir)]) + def __test_checkclass_project(tmpdir, extra_args): odr_file_1 = os.path.join(__script_dir, 'whole-program', 'odr1.cpp') @@ -336,10 +343,9 @@ def test_checkclass_project(tmpdir): __test_checkclass_project(tmpdir, ['-j1']) -# whole program analysis requires a build dir with -j -@pytest.mark.xfail(strict=True) +@pytest.mark.xfail(strict=True) # TODO: check error def test_checkclass_project_j(tmpdir): - __test_checkclass_project(tmpdir, ['-j2']) + __test_checkclass_project(tmpdir, ['-j2', '--no-cppcheck-build-dir']) def test_checkclass_project_builddir(tmpdir): @@ -347,3 +353,8 @@ def test_checkclass_project_builddir(tmpdir): os.mkdir(build_dir) __test_checkclass_project(tmpdir, ['-j1', '--cppcheck-build-dir={}'.format(build_dir)]) + +def test_checkclass_project_builddir_j(tmpdir): + build_dir = os.path.join(tmpdir, 'b1') + os.mkdir(build_dir) + __test_checkclass_project(tmpdir, ['-j2', '--cppcheck-build-dir={}'.format(build_dir)])