diff --git a/tests/misra/.gitignore b/tests/misra/.gitignore index 8432f605..fc9ac228 100644 --- a/tests/misra/.gitignore +++ b/tests/misra/.gitignore @@ -1,4 +1,5 @@ *.pdf *.txt +.output.log new_table cppcheck/ diff --git a/tests/misra/test_misra.sh b/tests/misra/test_misra.sh index 5504e3cd..cfc53bac 100755 --- a/tests/misra/test_misra.sh +++ b/tests/misra/test_misra.sh @@ -29,16 +29,19 @@ if [ -z "${SKIP_BUILD}" ]; then fi cppcheck() { - hashed_args=$(echo -n "$@$DIR" | md5sum | awk '{print $1}') - build_dir=/tmp/cppcheck_build/$hashed_args - mkdir -p $build_dir - + # note that cppcheck build cache results in inconsistent results as of v2.13.0 + OUTPUT=$DIR/.output.log $CPPCHECK_DIR/cppcheck --enable=all --force --inline-suppr -I $PANDA_DIR/board/ \ -I $gcc_inc "$(arm-none-eabi-gcc -print-file-name=include)" \ --suppressions-list=$DIR/suppressions.txt --suppress=*:*inc/* \ --suppress=*:*include/* --error-exitcode=2 --addon=misra \ - --check-level=exhaustive --cppcheck-build-dir=$build_dir \ - "$@" + --check-level=exhaustive "$@" |& tee $OUTPUT + + # cppcheck bug: some MISRA errors won't result in the error exit code, + # so check the output (https://trac.cppcheck.net/ticket/12440#no1) + if grep "misra violation" $OUTPUT > /dev/null; then + exit 1 + fi } printf "\n${GREEN}** PANDA F4 CODE **${NC}\n" diff --git a/tests/misra/test_mutation.py b/tests/misra/test_mutation.py index f50d27c7..cc3666f1 100755 --- a/tests/misra/test_mutation.py +++ b/tests/misra/test_mutation.py @@ -5,7 +5,6 @@ import pytest import shutil import subprocess import tempfile -import hashlib import random HERE = os.path.abspath(os.path.dirname(__file__)) @@ -68,25 +67,18 @@ for p in patterns: @pytest.mark.parametrize("fn, patch, should_fail", mutations) def test_misra_mutation(fn, patch, should_fail): - key = hashlib.md5((str(fn) + str(patch)).encode()).hexdigest() - tmp = os.path.join(tempfile.gettempdir(), key) + with tempfile.TemporaryDirectory() as tmp: + shutil.copytree(ROOT, tmp, dirs_exist_ok=True) - if os.path.exists(tmp): - shutil.rmtree(tmp) - shutil.copytree(ROOT, tmp) + # apply patch + if fn is not None: + r = os.system(f"cd {tmp} && sed -i '{patch}' {fn}") + assert r == 0 - # apply patch - if fn is not None: - r = os.system(f"cd {tmp} && sed -i '{patch}' {fn}") - assert r == 0 - - # run test - env = {'SKIP_BUILD': '1'} | os.environ.copy() - r = subprocess.run("tests/misra/test_misra.sh", cwd=tmp, shell=True, env=env) - failed = r.returncode != 0 - assert failed == should_fail - - shutil.rmtree(tmp) + # run test + r = subprocess.run("tests/misra/test_misra.sh", cwd=tmp, shell=True) + failed = r.returncode != 0 + assert failed == should_fail if __name__ == "__main__": pytest.main([__file__, "-n 8"])