cppcheck/test/cli/test-helloworld.py

239 lines
9.6 KiB
Python
Raw Normal View History

2019-04-14 10:45:20 +02:00
# python -m pytest test-helloworld.py
import os
import re
import tempfile
import pytest
dump: Fix concurrency problem with dump files (#4757) * dump: Fix concurrency problem with dump files This adds the process ID for the cppcheck process to the filenames of the .dump and .ctu-info files that the process generates. So lib/cppcheck.cpp.dump becomes lib/cppcheck.cpp.<PID>.dump For example: lib/cppcheck.cpp.2637871.dump The reason for this change is that if there is a buildsystem which supports concurrency, multiple instances of cppcheck may be run for the same file. For example, if the same file is compiled in multiple build variants, or for multiple targets. If running the MISRA plugin over such a project with concurrency enabled in the buildsystem, the plugin ends up crashing as multiple jobs attempt to create/trample/delete the same files while other jobs are using them. For more information see: https://sourceforge.net/p/cppcheck/discussion/general/thread/02c757b4af/ * dump: Include pid in filename if dump not explicit Only change the dump and ctu-info filenames to include the PID if they are being generated due to an addon. This means that existing scripts that use `--dump` will still work if they depend on the previous naming behaviour. The more robust filenames containing the pid will be used when the dump files are used as an internal implementation detail for passing data to addons. However this means that anything that does explicitly use `--dump` will be susceptible to concurrency problems. * test: Update addon dump file test to account for pid This test causes a dump file to be created by enabling the misra addon. Since the dump files now include the cppcheck process pid this test had to be updated to account for the change.
2023-02-13 20:54:21 +01:00
import glob
2019-04-15 16:57:16 +02:00
from testutils import create_gui_project_file, cppcheck
2019-04-14 10:45:20 +02:00
2019-04-15 10:01:27 +02:00
# Run Cppcheck from project path
def cppcheck_local(args):
cwd = os.getcwd()
2019-05-03 20:22:35 +02:00
os.chdir('helloworld')
2019-04-15 10:01:27 +02:00
ret, stdout, stderr = cppcheck(args)
os.chdir(cwd)
return ret, stdout, stderr
2019-04-15 10:01:27 +02:00
def getRelativeProjectPath():
2019-05-03 20:22:35 +02:00
return 'helloworld'
2019-04-15 10:01:27 +02:00
def getAbsoluteProjectPath():
2019-05-03 20:22:35 +02:00
return os.path.join(os.getcwd(), 'helloworld')
2019-04-15 10:01:27 +02:00
# Get Visual Studio configurations checking a file
# Checking {file} {config}...
def getVsConfigs(stdout, filename):
ret = []
for line in stdout.split('\n'):
if not line.startswith('Checking %s ' % filename):
continue
if not line.endswith('...'):
continue
res = re.match(r'.* ([A-Za-z0-9|]+)...', line)
if res:
ret.append(res.group(1))
ret.sort()
return ' '.join(ret)
2019-04-14 10:45:20 +02:00
def test_relative_path():
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', 'helloworld'])
2019-05-03 20:22:35 +02:00
filename = os.path.join('helloworld', 'main.c')
assert ret == 0, stdout
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
2019-04-14 10:45:20 +02:00
2019-04-14 10:45:20 +02:00
def test_local_path():
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck_local(['--template=cppcheck1', '.'])
assert ret == 0, stdout
2019-04-14 10:45:20 +02:00
assert stderr == '[main.c:5]: (error) Division by zero.\n'
def test_absolute_path():
2019-04-15 10:01:27 +02:00
prjpath = getAbsoluteProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', prjpath])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
2019-04-14 10:45:20 +02:00
2019-04-14 15:00:03 +02:00
def test_addon_local_path():
ret, stdout, stderr = cppcheck_local(['--addon=misra', '--enable=style', '--template=cppcheck1', '.'])
assert ret == 0, stdout
2019-04-14 15:00:03 +02:00
assert stderr == ('[main.c:5]: (error) Division by zero.\n'
'[main.c:1]: (style) misra violation (use --rule-texts=<file> to get proper output)\n')
def test_addon_local_path_not_enable():
ret, stdout, stderr = cppcheck_local(['--addon=misra', '--template=cppcheck1', '.'])
assert ret == 0, stdout
assert stderr == '[main.c:5]: (error) Division by zero.\n'
2019-04-14 15:00:03 +02:00
def test_addon_absolute_path():
2019-04-15 10:01:27 +02:00
prjpath = getAbsoluteProjectPath()
ret, stdout, stderr = cppcheck(['--addon=misra', '--enable=style', '--template=cppcheck1', prjpath])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert stderr == ('[%s:5]: (error) Division by zero.\n'
'[%s:1]: (style) misra violation (use --rule-texts=<file> to get proper output)\n' % (filename, filename))
2019-04-14 15:00:03 +02:00
def test_addon_relative_path():
2019-04-15 10:01:27 +02:00
prjpath = getRelativeProjectPath()
ret, stdout, stderr = cppcheck(['--addon=misra', '--enable=style', '--template=cppcheck1', prjpath])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert stdout == ('Checking %s ...\n'
'Checking %s: SOME_CONFIG...\n' % (filename, filename))
assert stderr == ('[%s:5]: (error) Division by zero.\n'
'[%s:1]: (style) misra violation (use --rule-texts=<file> to get proper output)\n' % (filename, filename))
2019-04-14 15:00:03 +02:00
def test_addon_with_gui_project():
2019-05-03 20:22:35 +02:00
project_file = 'helloworld/test.cppcheck'
create_gui_project_file(project_file, paths=['.'], addon='misra')
ret, stdout, stderr = cppcheck(['--template=cppcheck1', '--enable=style', '--project=' + project_file])
2019-05-03 20:22:35 +02:00
filename = os.path.join('helloworld', 'main.c')
assert ret == 0, stdout
assert stdout == 'Checking %s ...\n' % filename
assert stderr == ('[%s:5]: (error) Division by zero.\n'
'[%s:1]: (style) misra violation (use --rule-texts=<file> to get proper output)\n' % (filename, filename))
2019-04-14 10:45:20 +02:00
def test_basepath_relative_path():
2019-04-15 10:01:27 +02:00
prjpath = getRelativeProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck([prjpath, '--template=cppcheck1', '-rp=' + prjpath])
assert ret == 0, stdout
2019-04-14 10:45:20 +02:00
assert stderr == '[main.c:5]: (error) Division by zero.\n'
def test_basepath_absolute_path():
2019-04-15 10:01:27 +02:00
prjpath = getAbsoluteProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', prjpath, '-rp=' + prjpath])
assert ret == 0, stdout
2019-04-14 10:45:20 +02:00
assert stderr == '[main.c:5]: (error) Division by zero.\n'
def test_vs_project_local_path():
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck_local(['--template=cppcheck1', '--project=helloworld.vcxproj'])
assert ret == 0, stdout
assert getVsConfigs(stdout, 'main.c') == 'Debug|Win32 Debug|x64 Release|Win32 Release|x64'
assert stderr == '[main.c:5]: (error) Division by zero.\n'
def test_vs_project_relative_path():
2019-04-15 10:01:27 +02:00
prjpath = getRelativeProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', '--project=' + os.path.join(prjpath, 'helloworld.vcxproj')])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert getVsConfigs(stdout, filename) == 'Debug|Win32 Debug|x64 Release|Win32 Release|x64'
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
def test_vs_project_absolute_path():
2019-04-15 10:01:27 +02:00
prjpath = getAbsoluteProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', '--project=' + os.path.join(prjpath, 'helloworld.vcxproj')])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert getVsConfigs(stdout, filename) == 'Debug|Win32 Debug|x64 Release|Win32 Release|x64'
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
def test_cppcheck_project_local_path():
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck_local(['--template=cppcheck1', '--platform=win64', '--project=helloworld.cppcheck'])
assert ret == 0, stdout
assert getVsConfigs(stdout, 'main.c') == 'Debug|x64'
assert stderr == '[main.c:5]: (error) Division by zero.\n'
def test_cppcheck_project_relative_path():
2019-04-15 10:01:27 +02:00
prjpath = getRelativeProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', '--platform=win64', '--project=' + os.path.join(prjpath, 'helloworld.cppcheck')])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert getVsConfigs(stdout, filename) == 'Debug|x64'
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
def test_cppcheck_project_absolute_path():
2019-04-15 10:01:27 +02:00
prjpath = getAbsoluteProjectPath()
2019-08-18 12:51:32 +02:00
ret, stdout, stderr = cppcheck(['--template=cppcheck1', '--platform=win64', '--project=' + os.path.join(prjpath, 'helloworld.cppcheck')])
filename = os.path.join(prjpath, 'main.c')
assert ret == 0, stdout
assert getVsConfigs(stdout, filename) == 'Debug|x64'
assert stderr == '[%s:5]: (error) Division by zero.\n' % filename
2019-04-15 11:11:33 +02:00
def test_suppress_command_line():
prjpath = getRelativeProjectPath()
2019-06-22 19:20:15 +02:00
ret, stdout, stderr = cppcheck(['--suppress=zerodiv:' + os.path.join(prjpath, 'main.c'), prjpath])
assert ret == 0, stdout
2019-04-15 11:11:33 +02:00
assert stderr == ''
prjpath = getAbsoluteProjectPath()
2019-06-22 19:20:15 +02:00
ret, stdout, stderr = cppcheck(['--suppress=zerodiv:' + os.path.join(prjpath, 'main.c'), prjpath])
assert ret == 0, stdout
2019-04-15 11:11:33 +02:00
assert stderr == ''
def test_suppress_project():
2019-05-03 20:22:35 +02:00
project_file = os.path.join('helloworld', 'test.cppcheck')
create_gui_project_file(project_file,
paths=['.'],
suppressions=[{'fileName':'main.c', 'id':'zerodiv'}])
2019-04-15 11:11:33 +02:00
# Relative path
2019-06-22 19:20:15 +02:00
ret, stdout, stderr = cppcheck(['--project=' + project_file])
assert ret == 0, stdout
2019-04-15 11:11:33 +02:00
assert stderr == ''
# Absolute path
2019-06-22 19:20:15 +02:00
ret, stdout, stderr = cppcheck(['--project=' + os.path.join(os.getcwd(), 'helloworld', 'test.cppcheck')])
assert ret == 0, stdout
2019-04-15 11:11:33 +02:00
assert stderr == ''
2019-09-12 09:32:24 +02:00
def test_exclude():
prjpath = getRelativeProjectPath()
ret, stdout, _ = cppcheck(['-i' + prjpath, '--platform=win64', '--project=' + os.path.join(prjpath, 'helloworld.cppcheck')])
assert ret == 1
lines = stdout.splitlines()
assert lines == [
'cppcheck: error: no C or C++ source files found.',
'cppcheck: all paths were ignored'
]
2019-09-12 09:32:24 +02:00
def test_build_dir_dump_output():
with tempfile.TemporaryDirectory() as tempdir:
args = f'--cppcheck-build-dir={tempdir} --addon=misra helloworld'
cppcheck(args.split())
cppcheck(args.split())
dump: Fix concurrency problem with dump files (#4757) * dump: Fix concurrency problem with dump files This adds the process ID for the cppcheck process to the filenames of the .dump and .ctu-info files that the process generates. So lib/cppcheck.cpp.dump becomes lib/cppcheck.cpp.<PID>.dump For example: lib/cppcheck.cpp.2637871.dump The reason for this change is that if there is a buildsystem which supports concurrency, multiple instances of cppcheck may be run for the same file. For example, if the same file is compiled in multiple build variants, or for multiple targets. If running the MISRA plugin over such a project with concurrency enabled in the buildsystem, the plugin ends up crashing as multiple jobs attempt to create/trample/delete the same files while other jobs are using them. For more information see: https://sourceforge.net/p/cppcheck/discussion/general/thread/02c757b4af/ * dump: Include pid in filename if dump not explicit Only change the dump and ctu-info filenames to include the PID if they are being generated due to an addon. This means that existing scripts that use `--dump` will still work if they depend on the previous naming behaviour. The more robust filenames containing the pid will be used when the dump files are used as an internal implementation detail for passing data to addons. However this means that anything that does explicitly use `--dump` will be susceptible to concurrency problems. * test: Update addon dump file test to account for pid This test causes a dump file to be created by enabling the misra addon. Since the dump files now include the cppcheck process pid this test had to be updated to account for the change.
2023-02-13 20:54:21 +01:00
filename = f'{tempdir}/main.a1.*.dump'
filelist = glob.glob(filename)
assert(len(filelist) == 0)
dump: Fix concurrency problem with dump files (#4757) * dump: Fix concurrency problem with dump files This adds the process ID for the cppcheck process to the filenames of the .dump and .ctu-info files that the process generates. So lib/cppcheck.cpp.dump becomes lib/cppcheck.cpp.<PID>.dump For example: lib/cppcheck.cpp.2637871.dump The reason for this change is that if there is a buildsystem which supports concurrency, multiple instances of cppcheck may be run for the same file. For example, if the same file is compiled in multiple build variants, or for multiple targets. If running the MISRA plugin over such a project with concurrency enabled in the buildsystem, the plugin ends up crashing as multiple jobs attempt to create/trample/delete the same files while other jobs are using them. For more information see: https://sourceforge.net/p/cppcheck/discussion/general/thread/02c757b4af/ * dump: Include pid in filename if dump not explicit Only change the dump and ctu-info filenames to include the PID if they are being generated due to an addon. This means that existing scripts that use `--dump` will still work if they depend on the previous naming behaviour. The more robust filenames containing the pid will be used when the dump files are used as an internal implementation detail for passing data to addons. However this means that anything that does explicitly use `--dump` will be susceptible to concurrency problems. * test: Update addon dump file test to account for pid This test causes a dump file to be created by enabling the misra addon. Since the dump files now include the cppcheck process pid this test had to be updated to account for the change.
2023-02-13 20:54:21 +01:00
def test_checkers_report():
with tempfile.TemporaryDirectory() as tempdir:
filename = os.path.join(tempdir, '1.txt')
args = f'--checkers-report={filename} helloworld'
cppcheck(args.split())
with open(filename, 'rt') as f:
data = f.read()
assert 'No CheckAutoVariables::assignFunctionArg' in data
assert 'Yes CheckAutoVariables::autoVariables' in data
args = '--enable=style ' + args
cppcheck(args.split())
with open(filename, 'rt') as f:
data = f.read()
# checker has been activated by --enable=style
assert 'Yes CheckAutoVariables::assignFunctionArg' in data
def __test_missing_include_system(use_j):
args = ['--enable=missingInclude', '--suppress=zerodiv', '--template={file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]', 'helloworld']
if use_j:
args.insert(0, '-j2')
_, _, stderr = cppcheck(args)
assert stderr.replace('\\', '/') == 'helloworld/main.c:1:0: information: Include file: <stdio.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]\n'
def test_missing_include_system():
__test_missing_include_system(False)
def test_missing_include_system_j(): #11283
__test_missing_include_system(True)