From 2aaac23d3c02237af589b7bf52c984a986b60a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 20 Nov 2025 20:44:57 +0100 Subject: [PATCH 1/9] Fix #13645 (fail to load platform when executing Cppcheck in PATH) --- cli/cmdlineparser.cpp | 2 +- test/cli/lookup_test.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 86130ddc977..f8df46a31fa 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -421,7 +421,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a std::vector lookupPaths{ Path::getCurrentPath(), // TODO: do we want to look in CWD? - Path::getPathFromFilename(argv[0]) + Path::getPathFromFilename(mSettings.exename), }; bool executorAuto = true; diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 602119aa357..ffe67e273a3 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -381,6 +381,27 @@ def test_platform_lookup_ext(tmpdir): ] +def test_platform_lookup_path(tmpdir): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + c = 'cppcheck.exe' if sys.platform == 'win32' else 'cppcheck' + path = os.path.dirname(__lookup_cppcheck_exe()) + env = os.environ.copy() + env['PATH'] = path + exitcode, stdout, stderr, exe = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=c, cwd=str(tmpdir), env=env) + assert exitcode == 0, stdout if stdout else stderr + lines = stdout.splitlines() + assert lines == [ + "looking for platform 'avr8.xml'", + "try to load platform file '{}/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/avr8.xml".format(tmpdir, tmpdir), + "try to load platform file '{}/platforms/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/avr8.xml".format(tmpdir, tmpdir), + "try to load platform file '{}/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/avr8.xml".format(path, path), + "try to load platform file '{}/platforms/avr8.xml' ... Success".format(path), + 'Checking {} ...'.format(test_file) + ] + def test_platform_lookup_notfound(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): From 8f415549ab509f03d7673080bbf7d082bf49925a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 20 Nov 2025 21:34:18 +0100 Subject: [PATCH 2/9] fix --- test/cli/lookup_test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index ffe67e273a3..5e740abbd1c 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -390,9 +390,9 @@ def test_platform_lookup_path(tmpdir): path = os.path.dirname(__lookup_cppcheck_exe()) env = os.environ.copy() env['PATH'] = path - exitcode, stdout, stderr, exe = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=c, cwd=str(tmpdir), env=env) + exitcode, stdout, stderr, _ = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=c, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr - lines = stdout.splitlines() + lines = stdout.replace('\\', '/').splitlines() assert lines == [ "looking for platform 'avr8.xml'", "try to load platform file '{}/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/avr8.xml".format(tmpdir, tmpdir), @@ -402,6 +402,7 @@ def test_platform_lookup_path(tmpdir): 'Checking {} ...'.format(test_file) ] + def test_platform_lookup_notfound(tmpdir): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): From 146046ec133a334df7c687dae171f7fe498e10f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Thu, 20 Nov 2025 23:28:52 +0100 Subject: [PATCH 3/9] test --- test/cli/lookup_test.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 5e740abbd1c..4c45cdda368 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -386,19 +386,23 @@ def test_platform_lookup_path(tmpdir): with open(test_file, 'wt'): pass - c = 'cppcheck.exe' if sys.platform == 'win32' else 'cppcheck' + cppcheck = 'cppcheck' # No path path = os.path.dirname(__lookup_cppcheck_exe()) env = os.environ.copy() env['PATH'] = path - exitcode, stdout, stderr, _ = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=c, cwd=str(tmpdir), env=env) + exitcode, stdout, stderr, _ = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr - lines = stdout.replace('\\', '/').splitlines() + lookup1 = os.path.join(tmpdir, 'avr8.xml') + lookup2 = os.path.join(tmpdir, 'platforms', 'avr8.xml') + lookup3 = os.path.join(path, 'avr8.xml') + lookup4 = os.path.join(path, 'platforms', 'avr8.xml') + lines = stdout.splitlines() assert lines == [ "looking for platform 'avr8.xml'", - "try to load platform file '{}/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/avr8.xml".format(tmpdir, tmpdir), - "try to load platform file '{}/platforms/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/platforms/avr8.xml".format(tmpdir, tmpdir), - "try to load platform file '{}/avr8.xml' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}/avr8.xml".format(path, path), - "try to load platform file '{}/platforms/avr8.xml' ... Success".format(path), + "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup1, lookup1), + "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup2, lookup2), + "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup3, lookup3), + "try to load platform file '{}' ... Success".format(lookup4), 'Checking {} ...'.format(test_file) ] From 62f21bc6c7763839d9947dc7c2fd45b149056e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 08:14:31 +0100 Subject: [PATCH 4/9] test --- test/cli/lookup_test.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 4c45cdda368..5f34644cc40 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -392,17 +392,19 @@ def test_platform_lookup_path(tmpdir): env['PATH'] = path exitcode, stdout, stderr, _ = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr - lookup1 = os.path.join(tmpdir, 'avr8.xml') - lookup2 = os.path.join(tmpdir, 'platforms', 'avr8.xml') - lookup3 = os.path.join(path, 'avr8.xml') - lookup4 = os.path.join(path, 'platforms', 'avr8.xml') - lines = stdout.splitlines() + def try_fail(f): + f = f.replace('\\', '/').replace('"', '\'') + return "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(f, f) + def try_success(f): + f = f.replace('\\', '/').replace('"', '\'') + return "try to load platform file '{}' ... Success".format(f) + lines = stdout.replace('\\', '/').replace('"', '\'').splitlines() assert lines == [ "looking for platform 'avr8.xml'", - "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup1, lookup1), - "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup2, lookup2), - "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(lookup3, lookup3), - "try to load platform file '{}' ... Success".format(lookup4), + try_fail(os.path.join(tmpdir, 'avr8.xml')), + try_fail(os.path.join(tmpdir, 'platforms', 'avr8.xml')), + try_fail(os.path.join(path, 'avr8.xml')), + try_success(os.path.join(path, 'platforms', 'avr8.xml')), 'Checking {} ...'.format(test_file) ] From 85e352cdcc9b00922cd37c3e7aadd4d8cb5864d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 09:10:33 +0100 Subject: [PATCH 5/9] format_path --- test/cli/lookup_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 5f34644cc40..4cef7a43d0b 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -392,11 +392,13 @@ def test_platform_lookup_path(tmpdir): env['PATH'] = path exitcode, stdout, stderr, _ = cppcheck_ex(args=['--debug-lookup=platform', '--platform=avr8.xml', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr + def format_path(p): + return p.replace('\\', '/').replace('"', '\'') def try_fail(f): - f = f.replace('\\', '/').replace('"', '\'') + f = format_path(f) return "try to load platform file '{}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={}".format(f, f) def try_success(f): - f = f.replace('\\', '/').replace('"', '\'') + f = format_path(f) return "try to load platform file '{}' ... Success".format(f) lines = stdout.replace('\\', '/').replace('"', '\'').splitlines() assert lines == [ @@ -405,7 +407,7 @@ def try_success(f): try_fail(os.path.join(tmpdir, 'platforms', 'avr8.xml')), try_fail(os.path.join(path, 'avr8.xml')), try_success(os.path.join(path, 'platforms', 'avr8.xml')), - 'Checking {} ...'.format(test_file) + 'Checking {} ...'.format(format_path(test_file)) ] From 3e0b25665177e8ce76d7c8fa3fed5964baa09bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 10:49:26 +0100 Subject: [PATCH 6/9] lib+platform --- test/cli/lookup_test.py | 52 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 4cef7a43d0b..418e8f21525 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -927,4 +927,54 @@ def test_config_invalid(tmpdir): 'cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: ' ] -# TODO: test with FILESDIR \ No newline at end of file +# TODO: test with FILESDIR + +@pytest.mark.parametrize("type,file", [("library", "gnu.cfg"), ("platform", "avr8.xml")]) +def test_lookup_path(tmpdir, type, file): + test_file = os.path.join(tmpdir, 'test.c') + with open(test_file, 'wt'): + pass + + cppcheck = 'cppcheck' # No path + path = os.path.dirname(__lookup_cppcheck_exe()) + env = os.environ.copy() + env['PATH'] = path + exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', f'--{type}={file}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) + assert exitcode == 0, stdout if stdout else stderr + def format_path(p): + return p.replace('\\', '/').replace('"', '\'') + lines = format_path(stdout).splitlines() + + # TODO make lookups consistent between library and platform and add --debug-lookup={type} option + + if type == 'platform': + def try_fail(f): + f = format_path(f) + return f"try to load {type} file '{f}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={f}" + def try_success(f): + f = format_path(f) + return f"try to load {type} file '{f}' ... Success" + assert lines == [ + f"looking for {type} '{file}'", + try_fail(os.path.join(tmpdir, file)), + try_fail(os.path.join(tmpdir, 'platforms', file)), + try_fail(os.path.join(path, file)), + try_success(os.path.join(path, 'platforms', file)), + f'Checking {format_path(test_file)} ...' + ] + elif type == 'library': + def try_fail(f): + return f"looking for {type} '{format_path(f)}'" + def try_success(f): + return f"looking for {type} '{format_path(f)}'" + assert lines == [ + f"looking for {type} 'std.cfg'", + try_fail(os.path.join(path, 'std.cfg')), + try_success(os.path.join(path, 'cfg', 'std.cfg')), + f"looking for {type} '{file}'", + try_fail(os.path.join(path, file)), + try_success(os.path.join(path, 'cfg', file)), + f'Checking {format_path(test_file)} ...' + ] + else: + assert False, type + " not tested properly" \ No newline at end of file From 4bc9b2c2270451b4c1e439f26cc66ae25d8309b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 13:47:21 +0100 Subject: [PATCH 7/9] add addon test --- test/cli/lookup_test.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 418e8f21525..58f8058592a 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -929,7 +929,7 @@ def test_config_invalid(tmpdir): # TODO: test with FILESDIR -@pytest.mark.parametrize("type,file", [("library", "gnu.cfg"), ("platform", "avr8.xml")]) +@pytest.mark.parametrize("type,file", [("addon", "misra.py"), ("library", "gnu.cfg"), ("platform", "avr8.xml")]) def test_lookup_path(tmpdir, type, file): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -938,16 +938,25 @@ def test_lookup_path(tmpdir, type, file): cppcheck = 'cppcheck' # No path path = os.path.dirname(__lookup_cppcheck_exe()) env = os.environ.copy() - env['PATH'] = path + env['PATH'] = path + (';' if sys.platform == 'win32' else ':') + env.get('PATH', '') exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', f'--{type}={file}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr def format_path(p): return p.replace('\\', '/').replace('"', '\'') lines = format_path(stdout).splitlines() - # TODO make lookups consistent between library and platform and add --debug-lookup={type} option - - if type == 'platform': + if type == 'addon': + def try_fail(f): + return f"looking for {type} '{format_path(f)}'" + def try_success(f): + return f"looking for {type} '{format_path(f)}'" + assert lines == [ + f"looking for {type} '{file}'", + try_fail(os.path.join(path, file)), + try_success(os.path.join(path, 'addons', file)), + f'Checking {format_path(test_file)} ...' + ] + elif type == 'platform': def try_fail(f): f = format_path(f) return f"try to load {type} file '{f}' ... Error=XML_ERROR_FILE_NOT_FOUND ErrorID=3 (0x3) Line number=0: filename={f}" From 73aa8963219a47ab5fdde79cea48d554b92d1cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 15:40:31 +0100 Subject: [PATCH 8/9] config --- test/cli/lookup_test.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index 58f8058592a..c113fe93b3c 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -929,7 +929,7 @@ def test_config_invalid(tmpdir): # TODO: test with FILESDIR -@pytest.mark.parametrize("type,file", [("addon", "misra.py"), ("library", "gnu.cfg"), ("platform", "avr8.xml")]) +@pytest.mark.parametrize("type,file", [("addon", "misra.py"), ("config", "cppcheck.cfg"), ("library", "gnu.cfg"), ("platform", "avr8.xml")]) def test_lookup_path(tmpdir, type, file): test_file = os.path.join(tmpdir, 'test.c') with open(test_file, 'wt'): @@ -939,7 +939,12 @@ def test_lookup_path(tmpdir, type, file): path = os.path.dirname(__lookup_cppcheck_exe()) env = os.environ.copy() env['PATH'] = path + (';' if sys.platform == 'win32' else ':') + env.get('PATH', '') - exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', f'--{type}={file}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) + if type == 'config': + with open(os.path.join(path, "cppcheck.cfg"), 'wt') as f: + f.write('{}') + exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) + else: + exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', f'--{type}={file}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr def format_path(p): return p.replace('\\', '/').replace('"', '\'') @@ -956,6 +961,13 @@ def try_success(f): try_success(os.path.join(path, 'addons', file)), f'Checking {format_path(test_file)} ...' ] + elif type == 'config': + def try_success(f): + return f"looking for '{format_path(f)}'" + assert lines == [ + try_success(os.path.join(path, file)), + f'Checking {format_path(test_file)} ...' + ] elif type == 'platform': def try_fail(f): f = format_path(f) From 04e15e333f128844aac97ef9fd1b19ed22ece687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Fri, 21 Nov 2025 15:50:34 +0100 Subject: [PATCH 9/9] cleanup --- test/cli/lookup_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cli/lookup_test.py b/test/cli/lookup_test.py index c113fe93b3c..cab96a7f6bb 100644 --- a/test/cli/lookup_test.py +++ b/test/cli/lookup_test.py @@ -943,6 +943,7 @@ def test_lookup_path(tmpdir, type, file): with open(os.path.join(path, "cppcheck.cfg"), 'wt') as f: f.write('{}') exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) + os.remove(os.path.join(path, "cppcheck.cfg")) # clean up otherwise other tests may fail else: exitcode, stdout, stderr, _ = cppcheck_ex(args=[f'--debug-lookup={type}', f'--{type}={file}', test_file], cppcheck_exe=cppcheck, cwd=str(tmpdir), env=env) assert exitcode == 0, stdout if stdout else stderr