From b7bb3621c2029cf31a0f71a3831e60a4e36a9d64 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Sun, 5 Jul 2026 14:55:05 +0200 Subject: [PATCH 1/4] Extend unit test with the ability to assert certain files not existing --- test/unit/basic/BUILD | 2 ++ test/unit/grep_check.py | 48 ++++++++++++++++++++++++++++++++++------- test/unit/unit_test.bzl | 9 ++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/test/unit/basic/BUILD b/test/unit/basic/BUILD index 80918c4b..e061c4b4 100644 --- a/test/unit/basic/BUILD +++ b/test/unit/basic/BUILD @@ -50,6 +50,7 @@ codechecker_test( unit_test( name = "basic_codechecker_test", + absent_files = "this/file/definitely/does/not.exists", contains = ["core.DivideZero"], data = [":basic_codechecker"], excludes = ["Text not in file"], @@ -59,6 +60,7 @@ unit_test( unit_test( name = "basic_per_file_test", + absent_files = "this/file/definitely/does/not.exists", contains = ["Division by zero"], data = [":basic_per_file"], excludes = ["Text not in file"], diff --git a/test/unit/grep_check.py b/test/unit/grep_check.py index 6c4839de..406aa4c7 100644 --- a/test/unit/grep_check.py +++ b/test/unit/grep_check.py @@ -44,6 +44,12 @@ def parse_args() -> argparse.Namespace: required=True, help="Path or glob pattern to the file(s) to search within.", ) + parser.add_argument( + "--no_files", + nargs="+", + required=False, + help="Path or glob pattern to the file(s) that shouldn't exists.", + ) parser.add_argument( "--contains", nargs="+", @@ -75,8 +81,7 @@ def parse_args() -> argparse.Namespace: def check_args(args): """Checks wether the arguments are correct, aborts if not""" if not args.contains and not args.excludes and not args.regex_patterns: - print(" [ERROR] Must define at least one pattern or negative pattern.") - sys.exit(1) + fail(" [ERROR] Must define at least one pattern or negative pattern.") def exact_match(pattern: str, content: str) -> bool: @@ -143,25 +148,53 @@ def check_file(content: str, args) -> tuple[bool, set[str], set[str]]: return all_passed, found_patterns, missing_patterns +def assert_files_missing(files): + """ + Asserts that the list of file paths given as parameter, doesn't exists. + """ + for file_pattern in files: + matched_files = glob.glob(file_pattern, recursive=True) + if matched_files: + print(f"\n{file_pattern} exists, however it shouldn't.") + sys.exit(1) + + +def fail(msg: str, exit_code: int = 1): + """ + Exits the program, with a message + """ + print(msg) + sys.exit(exit_code) + def main() -> None: """Entry point for the pattern-matching test.""" args = parse_args() check_args(args) + assert_files_missing(args.no_files) + + files_to_check = [x for x in args.files if x not in args.no_files] + if not files_to_check: + print( + "There is no files to check, " + "since all files are expected to not exits" + ) + sys.exit(0) + all_passed = True found_patterns = set() missing_patterns = set() file_paths = [] - for file_pattern in args.files: + for file_pattern in files_to_check: matched_files = glob.glob(file_pattern, recursive=True) if not matched_files: - print(f" [WARN] No files matched pattern/path: '{file_pattern}'") + # Each file pattern must match at least a file + fail(f" [WARN] No files matched pattern/path: '{file_pattern}'") file_paths.extend(matched_files) if not file_paths: - print(" [ERR] No file collected to be checked.") - sys.exit(1) + fail(" [ERR] No file collected to be checked.") for file in file_paths: with open(file, "r", encoding="utf-8") as f: @@ -186,8 +219,7 @@ def main() -> None: if not all_passed: for file, pattern in missing_patterns: print(f"Missing pattern {pattern} in file {file}") - print("\nOne or more patterns missing. Test FAILED.") - sys.exit(1) + fail("\nOne or more patterns missing. Test FAILED.") if __name__ == "__main__": diff --git a/test/unit/unit_test.bzl b/test/unit/unit_test.bzl index 0079ea08..c09c9130 100644 --- a/test/unit/unit_test.bzl +++ b/test/unit/unit_test.bzl @@ -31,6 +31,7 @@ Example: def unit_test( name, files, + absent_files = [], contains = None, excludes = None, regex_patterns = None, @@ -43,6 +44,9 @@ def unit_test( Args: name: Test name. files: Path or glob to the files to be checked. + absent_files: Path or glob that should not exists. + If these are in the `files` list too, + disregard the missing file error. contains: Text that should be inside the files. excludes: Text that shouldn't be inside the files. regex_patterns: Regex patterns that should be found inside the files. @@ -53,6 +57,8 @@ def unit_test( """ if type(files) == "string": files = [files] + if type(absent_files) == "string": + absent_files = [absent_files] if type(contains) == "string": contains = [contains] if type(excludes) == "string": @@ -61,6 +67,9 @@ def unit_test( regex_patterns = [regex_patterns] python_args = ["--files"] + files + if absent_files: + python_args.append("--no_files") + python_args.extend(absent_files) if contains: python_args.append("--contains") python_args.extend(["\"{}\"".format(pat) for pat in contains]) From 463a59b3443e8a00c88dd016e0363d95d58887e4 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Sun, 5 Jul 2026 15:16:21 +0200 Subject: [PATCH 2/4] create function for collecting real file paths --- test/unit/grep_check.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/test/unit/grep_check.py b/test/unit/grep_check.py index 406aa4c7..f1ff6e8a 100644 --- a/test/unit/grep_check.py +++ b/test/unit/grep_check.py @@ -166,6 +166,22 @@ def fail(msg: str, exit_code: int = 1): print(msg) sys.exit(exit_code) + +def collect_file_paths(glob_list: list[str]) -> list[str]: + """Convert the glob patterns into a list of file paths""" + file_paths = [] + for file_pattern in glob_list: + matched_files = glob.glob(file_pattern, recursive=True) + if not matched_files: + # Each file pattern must match at least a file + fail(f" [WARN] No files matched pattern/path: '{file_pattern}'") + file_paths.extend(matched_files) + + if not file_paths: + fail(" [ERR] No file collected to be checked.") + return file_paths + + def main() -> None: """Entry point for the pattern-matching test.""" args = parse_args() @@ -181,21 +197,12 @@ def main() -> None: ) sys.exit(0) + file_paths = collect_file_paths(files_to_check) + all_passed = True found_patterns = set() missing_patterns = set() - file_paths = [] - for file_pattern in files_to_check: - matched_files = glob.glob(file_pattern, recursive=True) - if not matched_files: - # Each file pattern must match at least a file - fail(f" [WARN] No files matched pattern/path: '{file_pattern}'") - file_paths.extend(matched_files) - - if not file_paths: - fail(" [ERR] No file collected to be checked.") - for file in file_paths: with open(file, "r", encoding="utf-8") as f: content = f.read() From 7f4ef48e22951987ee6630c832f66aab54708329 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Sun, 5 Jul 2026 15:42:53 +0200 Subject: [PATCH 3/4] Update test/unit/grep_check.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kristóf Umann --- test/unit/grep_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/grep_check.py b/test/unit/grep_check.py index f1ff6e8a..98d90f03 100644 --- a/test/unit/grep_check.py +++ b/test/unit/grep_check.py @@ -150,7 +150,7 @@ def check_file(content: str, args) -> tuple[bool, set[str], set[str]]: def assert_files_missing(files): """ - Asserts that the list of file paths given as parameter, doesn't exists. + Asserts that none of the files exist in `files`. """ for file_pattern in files: matched_files = glob.glob(file_pattern, recursive=True) From 3a7b5f3ccc6ef738cfb352488a109e813e5a8102 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Sun, 5 Jul 2026 15:45:04 +0200 Subject: [PATCH 4/4] Rename to expectedly_missing --- test/unit/basic/BUILD | 4 ++-- test/unit/grep_check.py | 2 +- test/unit/unit_test.bzl | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/unit/basic/BUILD b/test/unit/basic/BUILD index e061c4b4..ef026542 100644 --- a/test/unit/basic/BUILD +++ b/test/unit/basic/BUILD @@ -50,20 +50,20 @@ codechecker_test( unit_test( name = "basic_codechecker_test", - absent_files = "this/file/definitely/does/not.exists", contains = ["core.DivideZero"], data = [":basic_codechecker"], excludes = ["Text not in file"], + expected_missing_files = "this/file/definitely/does/not.exists", files = "test/unit/basic/basic_codechecker/codechecker.log", regex_patterns = ["[a-z]"], ) unit_test( name = "basic_per_file_test", - absent_files = "this/file/definitely/does/not.exists", contains = ["Division by zero"], data = [":basic_per_file"], excludes = ["Text not in file"], + expected_missing_files = "this/file/definitely/does/not.exists", files = "test/unit/basic/basic_per_file/**/*.plist", regex_patterns = ["[a-z]"], require_patterns_in_each_file = False, diff --git a/test/unit/grep_check.py b/test/unit/grep_check.py index 98d90f03..72f0e1d7 100644 --- a/test/unit/grep_check.py +++ b/test/unit/grep_check.py @@ -155,7 +155,7 @@ def assert_files_missing(files): for file_pattern in files: matched_files = glob.glob(file_pattern, recursive=True) if matched_files: - print(f"\n{file_pattern} exists, however it shouldn't.") + print(f"\n{file_pattern} unexpectedly exists.") sys.exit(1) diff --git a/test/unit/unit_test.bzl b/test/unit/unit_test.bzl index c09c9130..d8d86b92 100644 --- a/test/unit/unit_test.bzl +++ b/test/unit/unit_test.bzl @@ -31,7 +31,7 @@ Example: def unit_test( name, files, - absent_files = [], + expected_missing_files = [], contains = None, excludes = None, regex_patterns = None, @@ -44,9 +44,9 @@ def unit_test( Args: name: Test name. files: Path or glob to the files to be checked. - absent_files: Path or glob that should not exists. - If these are in the `files` list too, - disregard the missing file error. + expected_missing_files: Path or glob that should not exists. + If these are in the `files` list too, + disregard the missing file error. contains: Text that should be inside the files. excludes: Text that shouldn't be inside the files. regex_patterns: Regex patterns that should be found inside the files. @@ -57,8 +57,8 @@ def unit_test( """ if type(files) == "string": files = [files] - if type(absent_files) == "string": - absent_files = [absent_files] + if type(expected_missing_files) == "string": + expected_missing_files = [expected_missing_files] if type(contains) == "string": contains = [contains] if type(excludes) == "string": @@ -67,9 +67,9 @@ def unit_test( regex_patterns = [regex_patterns] python_args = ["--files"] + files - if absent_files: + if expected_missing_files: python_args.append("--no_files") - python_args.extend(absent_files) + python_args.extend(expected_missing_files) if contains: python_args.append("--contains") python_args.extend(["\"{}\"".format(pat) for pat in contains])