2022-09-06 23:11:39 +02:00
# python -m pytest test-other.py
import os
import pytest
from testutils import cppcheck
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def __test_missing_include ( tmpdir , use_j ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
#include "test.h"
""" )
2023-03-04 09:02:35 +01:00
args = [ ' --enable=missingInclude ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
2022-09-06 23:11:39 +02:00
if use_j :
2023-03-04 09:02:35 +01:00
args . insert ( 0 , ' -j2 ' )
2022-09-06 23:11:39 +02:00
2023-03-04 09:02:35 +01:00
_ , _ , stderr = cppcheck ( args )
assert stderr == ' {} :2:0: information: Include file: " test.h " not found. [missingInclude] \n ' . format ( test_file )
2022-09-06 23:11:39 +02:00
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def test_missing_include ( tmpdir ) :
__test_missing_include ( tmpdir , False )
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def test_missing_include_j ( tmpdir ) : #11283
__test_missing_include ( tmpdir , True )
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def __test_missing_include_check_config ( tmpdir , use_j ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
#include "test.h"
""" )
# TODO: -rp is not working requiring the full path in the assert
args = ' --check-config -rp= {} {} ' . format ( tmpdir , test_file )
if use_j :
args = ' -j2 ' + args
_ , _ , stderr = cppcheck ( args . split ( ) )
2023-03-04 09:02:35 +01:00
assert stderr == ' ' # --check-config no longer reports the missing includes
2022-09-06 23:11:39 +02:00
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def test_missing_include_check_config ( tmpdir ) :
__test_missing_include_check_config ( tmpdir , False )
2023-08-23 11:20:20 +02:00
2022-09-06 23:11:39 +02:00
def test_missing_include_check_config_j ( tmpdir ) :
2023-04-21 10:14:34 +02:00
__test_missing_include_check_config ( tmpdir , True )
2023-08-23 11:20:20 +02:00
2023-04-21 10:14:34 +02:00
def test_missing_include_inline_suppr ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
/ / cppcheck - suppress missingInclude
#include "missing.h"
/ / cppcheck - suppress missingIncludeSystem
#include <missing2.h>
""" )
args = [ ' --enable=missingInclude ' , ' --inline-suppr ' , test_file ]
_ , _ , stderr = cppcheck ( args )
2023-08-07 19:48:11 +02:00
assert stderr == ' '
2023-08-23 11:20:20 +02:00
2023-08-07 19:48:11 +02:00
def test_invalid_library ( tmpdir ) :
2023-09-11 11:08:23 +02:00
args = [ ' --library=none ' , ' --library=posix ' , ' --library=none2 ' , ' file.c ' ]
2023-08-07 19:48:11 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 1
assert ( stdout == " cppcheck: Failed to load library configuration file ' none ' . File not found \n "
" cppcheck: Failed to load library configuration file ' none2 ' . File not found \n " )
assert stderr == " "
2023-08-21 12:17:08 +02:00
def test_message_j ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( " " )
2023-09-11 11:08:23 +02:00
args = [ ' -j2 ' , test_file ]
2023-08-21 12:17:08 +02:00
_ , stdout , _ = cppcheck ( args )
assert stdout == " Checking {} ... \n " . format ( test_file ) # we were adding stray \0 characters at the end
2023-08-23 11:20:20 +02:00
# TODO: test missing std.cfg
def test_progress ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
int main ( int argc )
{
}
""" )
2023-09-11 11:08:23 +02:00
args = [ ' --report-progress=0 ' , ' --enable=all ' , ' --inconclusive ' , test_file ]
2023-08-23 11:20:20 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
pos = stdout . find ( ' \n ' )
assert ( pos != - 1 )
pos + = 1
assert stdout [ : pos ] == " Checking {} ... \n " . format ( test_file )
assert ( stdout [ pos : ] ==
" progress: Tokenize (typedef) 0 % \n "
" progress: Tokenize (typedef) 12 % \n "
" progress: Tokenize (typedef) 25 % \n "
" progress: Tokenize (typedef) 37 % \n "
" progress: Tokenize (typedef) 50 % \n "
" progress: Tokenize (typedef) 62 % \n "
" progress: Tokenize (typedef) 75 % \n "
" progress: Tokenize (typedef) 87 % \n "
" progress: SymbolDatabase 0 % \n "
" progress: SymbolDatabase 12 % \n "
" progress: SymbolDatabase 87 % \n "
)
assert stderr == " "
def test_progress_j ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.c ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
int main ( int argc )
{
}
""" )
2023-09-11 11:08:23 +02:00
args = [ ' --report-progress=0 ' , ' --enable=all ' , ' --inconclusive ' , ' -j2 ' , ' --disable=unusedFunction ' , test_file ]
2023-08-23 11:20:20 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
assert stdout == " Checking {} ... \n " . format ( test_file )
assert stderr == " "
2023-08-30 19:35:43 +02:00
2023-08-31 16:46:20 +02:00
@pytest.mark.timeout ( 10 )
def test_slow_array_many_floats ( tmpdir ) :
# 11649
# cppcheck valueflow takes a long time when an array has many floats
filename = os . path . join ( tmpdir , ' hang.c ' )
with open ( filename , ' wt ' ) as f :
f . write ( " const float f[] = { \n " )
for i in range ( 20000 ) :
f . write ( ' 13.6f, \n ' )
f . write ( " }; \n " )
cppcheck ( [ filename ] ) # should not take more than ~1 second
2023-08-30 19:35:43 +02:00
@pytest.mark.timeout ( 10 )
def test_slow_array_many_strings ( tmpdir ) :
# 11901
# cppcheck valueflow takes a long time when analyzing a file with many strings
filename = os . path . join ( tmpdir , ' hang.c ' )
with open ( filename , ' wt ' ) as f :
f . write ( " const char *strings[] = { \n " )
for i in range ( 20000 ) :
f . write ( ' " abc " , \n ' )
f . write ( " }; \n " )
cppcheck ( [ filename ] ) # should not take more than ~1 second
2023-08-31 13:33:29 +02:00
2023-09-14 09:41:39 +02:00
@pytest.mark.timeout ( 10 )
def test_slow_long_line ( tmpdir ) :
# simplecpp #314
filename = os . path . join ( tmpdir , ' hang.c ' )
with open ( filename , ' wt ' ) as f :
f . write ( " #define A() static const int a[] = { \\ \n " )
for i in range ( 5000 ) :
f . write ( " -123, 456, -789, \\ \n " )
f . write ( " }; \n " )
cppcheck ( [ filename ] ) # should not take more than ~1 second
2023-08-31 13:33:29 +02:00
def test_execute_addon_failure ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
void f ( ) ;
""" )
args = [ ' --addon=naming ' , test_file ]
# provide empty PATH environment variable so python is not found and execution of addon fails
env = { ' PATH ' : ' ' }
_ , _ , stderr = cppcheck ( args , env )
assert stderr == ' {} :0:0: error: Bailing out from analysis: Checking file failed: Failed to auto detect python [internalError] \n \n ^ \n ' . format ( test_file )
def test_execute_addon_failure_2 ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
void f ( ) ;
""" )
# specify non-existent python executbale so execution of addon fails
args = [ ' --addon=naming ' , ' --addon-python=python5.x ' , test_file ]
_ , _ , stderr = cppcheck ( args )
2023-09-20 10:40:57 +02:00
ec = 1 if os . name == ' nt ' else 127
assert stderr == " {} :0:0: error: Bailing out from analysis: Checking file failed: Failed to execute addon ' naming ' - exitcode is {} [internalError] \n \n ^ \n " . format ( test_file , ec )
2023-08-31 13:33:29 +02:00
# TODO: find a test case which always fails
@pytest.mark.skip
def test_internal_error ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
#include <cstdio>
void f ( ) {
double gc = 3333.3333 ;
char stat [ 80 ] ;
sprintf ( stat , " ' %2.1f ' " , gc ) ;
}
""" )
args = [ test_file ]
_ , _ , stderr = cppcheck ( args )
2023-09-14 09:41:39 +02:00
assert stderr == ' {} :0:0: error: Bailing from out analysis: Checking file failed: converting \' 1f \' to integer failed - not an integer [internalError] \n \n ^ \n ' . format ( test_file )
2023-09-20 10:40:57 +02:00
def test_addon_misra ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
args = [ ' --addon=misra ' , ' --enable=all ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == ' {} :2:1: style: misra violation (use --rule-texts=<file> to get proper output) [misra-c2012-2.3] \n typedef int MISRA_5_6_VIOLATION; \n ^ \n ' . format ( test_file )
def test_addon_y2038 ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
# TODO: trigger warning
with open ( test_file , ' wt ' ) as f :
f . write ( """
2023-09-25 13:39:17 +02:00
extern void f ( )
{
time_t t = std : : time ( nullptr ) ;
( void ) t ;
}
2023-09-20 10:40:57 +02:00
""" )
2023-09-25 13:39:17 +02:00
args = [ ' --addon=y2038 ' , ' --enable=all ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
2023-09-20 10:40:57 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
2023-09-25 13:39:17 +02:00
assert stderr == ' {} :4:21: warning: time is Y2038-unsafe [y2038-unsafe-call] \n ' . format ( test_file )
2023-09-20 10:40:57 +02:00
def test_addon_threadsafety ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
2023-09-25 13:39:17 +02:00
extern const char * f ( )
{
return strerror ( 1 ) ;
}
2023-09-20 10:40:57 +02:00
""" )
2023-09-25 13:39:17 +02:00
args = [ ' --addon=threadsafety ' , ' --enable=all ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
2023-09-20 10:40:57 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
2023-09-25 13:39:17 +02:00
assert stderr == ' {} :4:12: warning: strerror is MT-unsafe [threadsafety-unsafe-call] \n ' . format ( test_file )
2023-09-20 10:40:57 +02:00
def test_addon_naming ( tmpdir ) :
2023-09-25 13:39:17 +02:00
# the addon does nothing without a config
addon_file = os . path . join ( tmpdir , ' naming1.json ' )
with open ( addon_file , ' wt ' ) as f :
f . write ( """
{
" script " : " addons/naming.py " ,
" args " : [
" --var=[_a-z].* "
]
}
""" )
2023-09-20 10:40:57 +02:00
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
2023-09-25 13:39:17 +02:00
int Var ;
2023-09-20 10:40:57 +02:00
""" )
2023-09-25 13:39:17 +02:00
args = [ ' --addon= {} ' . format ( addon_file ) , ' --enable=all ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
2023-09-20 10:40:57 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
2023-09-25 13:39:17 +02:00
assert stderr == ' {} :2:1: style: Variable Var violates naming convention [naming-varname] \n ' . format ( test_file )
2023-09-20 10:40:57 +02:00
2023-09-25 13:39:17 +02:00
# the namingng addon only works standalone and not in CLI mode - see #12005
@pytest.mark.skip
2023-09-20 10:40:57 +02:00
def test_addon_namingng ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
# TODO: trigger warning
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
2023-09-25 13:39:17 +02:00
args = [ ' --addon=namingng ' , ' --enable=all ' , test_file ]
2023-09-20 10:40:57 +02:00
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == ' '
2023-09-25 13:39:17 +02:00
def test_addon_findcasts ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
extern void f ( char c )
{
int i = ( int ) c ;
( void ) i ;
}
""" )
args = [ ' --addon=findcasts ' , ' --enable=all ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == ' {} :4:21: information: found a cast [findcasts-cast] \n ' . format ( test_file )
def test_addon_misc ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
extern void f ( )
{
char char * [ ] = { " a " " b " }
}
""" )
args = [ ' --addon=misc ' , ' --enable=all ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == ' {} :4:26: style: String concatenation in array initialization, missing comma? [misc-stringConcatInArrayInit] \n ' . format ( test_file )
2023-09-20 10:40:57 +02:00
def test_invalid_addon_json ( tmpdir ) :
addon_file = os . path . join ( tmpdir , ' addon1.json ' )
with open ( addon_file , ' wt ' ) as f :
f . write ( """
""" )
test_file = os . path . join ( tmpdir , ' file.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
args = [ ' --addon= {} ' . format ( addon_file ) , ' --enable=all ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0 # TODO: needs to be 1
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file ) ,
' Loading {} failed. syntax error at line 2 near: ' . format ( addon_file ) ,
' Loading {} failed. syntax error at line 2 near: ' . format ( addon_file )
]
assert stderr == ' '
def test_invalid_addon_py ( tmpdir ) :
addon_file = os . path . join ( tmpdir , ' addon1.py ' )
with open ( addon_file , ' wt ' ) as f :
f . write ( """
raise Exception ( )
""" )
test_file = os . path . join ( tmpdir , ' file.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
args = [ ' --addon= {} ' . format ( addon_file ) , ' --enable=all ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0 # TODO: needs to be 1
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == " {} :0:0: error: Bailing out from analysis: Checking file failed: Failed to execute addon ' addon1 ' - exitcode is 1 [internalError] \n \n ^ \n " . format ( test_file )
def test_invalid_addon_py_verbose ( tmpdir ) :
addon_file = os . path . join ( tmpdir , ' addon1.py ' )
with open ( addon_file , ' wt ' ) as f :
f . write ( """
raise Exception ( )
""" )
test_file = os . path . join ( tmpdir , ' file.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
args = [ ' --addon= {} ' . format ( addon_file ) , ' --enable=all ' , ' --verbose ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0 # TODO: needs to be 1
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file ) ,
' Defines: ' ,
' Undefines: ' ,
' Includes: ' ,
' Platform:native '
]
"""
/ tmp / pytest - of - user / pytest - 11 / test_invalid_addon_py_20 / file . cpp : 0 : 0 : error : Bailing out from analysis : Checking file failed : Failed to execute addon ' addon1 ' - exitcode is 1 : python3 / home / user / CLionProjects / cppcheck / addons / runaddon . py / tmp / pytest - of - user / pytest - 11 / test_invalid_addon_py_20 / addon1 . py - - cli / tmp / pytest - of - user / pytest - 11 / test_invalid_addon_py_20 / file . cpp .24762 . dump
Output :
Traceback ( most recent call last ) :
File " /home/user/CLionProjects/cppcheck/addons/runaddon.py " , line 8 , in < module >
runpy . run_path ( addon , run_name = ' __main__ ' )
File " <frozen runpy> " , line 291 , in run_path
File " <frozen runpy> " , line 98 , in _run_module_code
File " <frozen runpy> " , line 88 , in _run_code
File " /tmp/pytest-of-user/pytest-11/test_invalid_addon_py_20/addon1.py " , line 2 , in < module >
raise Exception ( )
Exceptio [ internalError ]
"""
# /tmp/pytest-of-user/pytest-10/test_invalid_addon_py_20/file.cpp:0:0: error: Bailing out from analysis: Checking file failed: Failed to execute addon 'addon1' - exitcode is 256.: python3 /home/user/CLionProjects/cppcheck/addons/runaddon.py /tmp/pytest-of-user/pytest-10/test_invalid_addon_py_20/addon1.py --cli /tmp/pytest-of-user/pytest-10/test_invalid_addon_py_20/file.cpp.24637.dump
assert stderr . startswith ( " {} :0:0: error: Bailing out from analysis: Checking file failed: Failed to execute addon ' addon1 ' - exitcode is 1: " . format ( test_file ) )
assert stderr . count ( ' Output: \n Traceback ' )
assert stderr . endswith ( ' raise Exception() \n Exception [internalError] \n \n ^ \n ' )
def test_addon_result ( tmpdir ) :
addon_file = os . path . join ( tmpdir , ' addon1.py ' )
with open ( addon_file , ' wt ' ) as f :
f . write ( """
print ( " Checking ... " )
print ( " " )
print ( ' { " file " : " test.cpp " , " linenr " : 1, " column " : 1, " severity " : " style " , " message " : " msg " , " addon " : " addon1 " , " errorId " : " id " , " extra " : " " } ' )
print ( ' { " loc " : [ { " file " : " test.cpp " , " linenr " : 1, " column " : 1, " info " : " " }], " severity " : " style " , " message " : " msg " , " addon " : " addon1 " , " errorId " : " id " , " extra " : " " } ' )
""" )
test_file = os . path . join ( tmpdir , ' file.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
typedef int MISRA_5_6_VIOLATION ;
""" )
args = [ ' --addon= {} ' . format ( addon_file ) , ' --enable=all ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0 # TODO: needs to be 1
lines = stdout . splitlines ( )
assert lines == [
' Checking {} ... ' . format ( test_file )
]
assert stderr == ' test.cpp:1:1: style: msg [addon1-id] \n \n ^ \n '
2023-09-20 14:45:44 +02:00
# #11483
def test_unused_function_include ( tmpdir ) :
test_cpp_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_cpp_file , ' wt ' ) as f :
f . write ( """
#include "test.h"
""" )
test_h_file = os . path . join ( tmpdir , ' test.h ' )
with open ( test_h_file , ' wt ' ) as f :
f . write ( """
class A {
public :
void f ( ) { }
/ / cppcheck - suppress unusedFunction
void f2 ( ) { }
} ;
""" )
args = [ ' --enable=unusedFunction ' , ' --inline-suppr ' , ' --template= {file} : {line} : {column} : {severity} : { inconclusive:inconclusive:} {message} [ {id} ] ' , test_cpp_file ]
_ , _ , stderr = cppcheck ( args )
assert stderr == " {} :4:0: style: The function ' f ' is never used. [unusedFunction] \n " . format ( test_h_file )
2023-10-05 19:04:06 +02:00
# TODO: test with -j and all other types
def test_showtime_top5_file ( tmpdir ) :
test_file = os . path . join ( tmpdir , ' test.cpp ' )
with open ( test_file , ' wt ' ) as f :
f . write ( """
int main ( int argc )
{
}
""" )
args = [ ' --showtime=top5_file ' , ' --quiet ' , test_file ]
exitcode , stdout , stderr = cppcheck ( args )
assert exitcode == 0 # TODO: needs to be 1
lines = stdout . splitlines ( )
assert len ( lines ) == 7
assert lines [ 0 ] == ' '
for i in range ( 1 , 5 ) :
assert lines [ i ] . endswith ( ' - 1 result(s)) ' )
assert lines [ 6 ] . startswith ( ' Overall time: ' )
assert stderr == ' '