From 4e7def4d0051dc03984e77c5f2581530f60dc52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Umann?= Date: Fri, 31 Mar 2023 11:30:02 +0200 Subject: [PATCH 1/6] [test] Add cmdline tests for the diff feature We usually test CodeChecker diff by making API calls that one can find in report_server.py. However, `CodeChecker cmd diff` doesn't invoke these plainly, but rather wraps it in various functions, for which we never had proper tests. Until now! I also made sure to include (almost all) cases discussed here: https://github.com/Ericsson/codechecker/issues/3884 --- .../codechecker_server/api/mass_store_run.py | 9 +- web/tests/functional/__init__.py | 3 + web/tests/functional/diff_cmdline/__init__.py | 8 + .../diff_cmdline/test_diff_cmdline.py | 662 ++++++++++++++++++ 4 files changed, 680 insertions(+), 2 deletions(-) create mode 100644 web/tests/functional/diff_cmdline/__init__.py create mode 100644 web/tests/functional/diff_cmdline/test_diff_cmdline.py diff --git a/web/server/codechecker_server/api/mass_store_run.py b/web/server/codechecker_server/api/mass_store_run.py index 0fd4bce90c..afeb63b81d 100644 --- a/web/server/codechecker_server/api/mass_store_run.py +++ b/web/server/codechecker_server/api/mass_store_run.py @@ -1323,10 +1323,15 @@ def store(self) -> int: runtime = round(time.time() - start_time, 2) zip_size_kb = round(zip_size / 1024) + tag_desc = "" + if self.__tag: + tag_desc = f", under tag '{self.__tag}'" + LOG.info("'%s' stored results (%s KB " - "/decompressed/) to run '%s' (id: %d) in " + "/decompressed/) to run '%s' (id: %d) %s in " "%s seconds.", self.user_name, - zip_size_kb, self.__name, run_id, runtime) + zip_size_kb, self.__name, run_id, tag_desc, + runtime) iso_start_time = datetime.fromtimestamp( start_time).isoformat() diff --git a/web/tests/functional/__init__.py b/web/tests/functional/__init__.py index aecdd1cdee..0f4be0aa03 100644 --- a/web/tests/functional/__init__.py +++ b/web/tests/functional/__init__.py @@ -23,4 +23,7 @@ REPO_ROOT = os.path.abspath(os.environ['REPO_ROOT']) PKG_ROOT = os.path.join(REPO_ROOT, 'build', 'CodeChecker') +os.environ["CC_DATA_FILES_DIR"] = PKG_ROOT +os.environ["CC_LIB_DIR"] = os.path.join(PKG_ROOT, "lib", "python3") + sys.path.append(os.path.join(PKG_ROOT, 'lib', 'python3')) diff --git a/web/tests/functional/diff_cmdline/__init__.py b/web/tests/functional/diff_cmdline/__init__.py new file mode 100644 index 0000000000..f30c492687 --- /dev/null +++ b/web/tests/functional/diff_cmdline/__init__.py @@ -0,0 +1,8 @@ +# coding=utf-8 +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- diff --git a/web/tests/functional/diff_cmdline/test_diff_cmdline.py b/web/tests/functional/diff_cmdline/test_diff_cmdline.py new file mode 100644 index 0000000000..836cb095bb --- /dev/null +++ b/web/tests/functional/diff_cmdline/test_diff_cmdline.py @@ -0,0 +1,662 @@ +# +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- + +""" +Test command line diffing (as opposed to natively using API calls). +""" + + +import os +import shutil +import unittest + +from codechecker_api.codeCheckerDBAccess_v6.ttypes import \ + ReviewStatus, DiffType, ReportFilter + +from codechecker_client.cmd_line_client import \ + get_diff_local_dirs, get_diff_remote_run_local_dir, \ + get_diff_local_dir_remote_run, get_diff_remote_runs + +from libtest import codechecker, env +from libtest.thrift_client_to_db import get_all_run_results + + +class TestDiffFromCmdLine(unittest.TestCase): + + def setup_class(self): + """Setup the environment for testing review_status.""" + + workspace_name = 'diff_cmdline' + global TEST_WORKSPACE + TEST_WORKSPACE = env.get_workspace(workspace_name) + + os.environ['TEST_WORKSPACE'] = TEST_WORKSPACE + + test_env = env.test_env(TEST_WORKSPACE) + + codechecker_cfg = { + 'suppress_file': None, + 'skip_list_file': None, + 'check_env': test_env, + 'workspace': TEST_WORKSPACE, + 'checkers': [], + 'analyzers': ['clangsa'] + } + + # Start or connect to the running CodeChecker server and get connection + # details. + print("This test uses a CodeChecker server... connecting...") + server_access = codechecker.start_or_get_server() + server_access['viewer_product'] = workspace_name + codechecker.add_test_package_product(server_access, TEST_WORKSPACE) + + # Extend the checker configuration with the server access. + codechecker_cfg.update(server_access) + + test_config = {} + test_config['codechecker_cfg'] = codechecker_cfg + + env.export_test_cfg(TEST_WORKSPACE, test_config) + + def teardown_class(self): + """Clean up after the test.""" + + # TODO: If environment variable is set keep the workspace + # and print out the path. + global TEST_WORKSPACE + + check_env = env.import_test_cfg(TEST_WORKSPACE)[ + 'codechecker_cfg']['check_env'] + codechecker.remove_test_package_product(TEST_WORKSPACE, check_env) + + print("Removing: " + TEST_WORKSPACE) + shutil.rmtree(TEST_WORKSPACE, ignore_errors=True) + + def setup_method(self, method): + self.test_workspace = os.environ['TEST_WORKSPACE'] + + test_class = self.__class__.__name__ + print('Running ' + test_class + ' tests in ' + self.test_workspace) + + self._cc_client = env.setup_viewer_client(self.test_workspace) + self.assertIsNotNone(self._cc_client) + + def teardown_method(self, method): + """ Remove all review status rules after each test cases. """ + self.__remove_all_runs() + self.__remove_all_rules() + + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + shutil.rmtree(dir1, ignore_errors=True) + shutil.rmtree(dir2, ignore_errors=True) + + # ===-----------------------------------------------------------------=== # + + def __remove_all_runs(self): + for run_data in self._cc_client.getRunData(None, None, 0, None): + ret = self._cc_client.removeRun(run_data.runId, None) + self.assertTrue(ret) + print(f"Successfully removed run '{run_data.name}'.") + + def __remove_all_rules(self): + """ Removes all review status rules from the database. """ + self._cc_client.removeReviewStatusRules(None) + + # Check that there is no review status rule in the database. + self.assertFalse(self._cc_client.getReviewStatusRulesCount(None)) + + rules = self._cc_client.getReviewStatusRules(None, None, None, 0) + self.assertFalse(rules) + + def __analyze(self, file_dir, source_code): + build_json_path = os.path.join(file_dir, "build.json") + + build_json = f""" +[{{ + "directory": "{file_dir}", + "file": "main.c", + "command": "gcc main.c -o /dev/null" +}}] +""" + os.makedirs(file_dir, exist_ok=True) + + with open(os.path.join(file_dir, "main.c"), "w") as f: + f.write(source_code) + + with open(build_json_path, "w") as f: + f.write(build_json) + + codechecker_cfg = env.import_codechecker_cfg(self.test_workspace) + codechecker_cfg["workspace"] = file_dir + codechecker_cfg["reportdir"] = os.path.join(file_dir, "reports") + codechecker_cfg['analyzers'] = ['clangsa', 'clang-tidy'] + + codechecker.analyze(codechecker_cfg, file_dir) + + def __store(self, file_dir, store_name, tag=None): + codechecker_cfg = env.import_codechecker_cfg(self.test_workspace) + codechecker_cfg["workspace"] = file_dir + codechecker_cfg["reportdir"] = \ + os.path.join(file_dir, "reports") + codechecker_cfg["tag"] = tag + codechecker.store(codechecker_cfg, store_name) + + def __analyze_and_store(self, file_dir, store_name, source_code, tag=None): + self.__analyze(file_dir, source_code) + self.__store(file_dir, store_name, tag) + + def __get_run_id(self, run_name): + runs = self._cc_client.getRunData(None, None, 0, None) + self.assertEqual(len(runs), 1) + test_run = [run for run in runs if run.name == run_name] + self.assertEqual(len(test_run), 1) + return test_run[0].runid + + # ===-----------------------------------------------------------------=== # + # Local-local tests. + # ===-----------------------------------------------------------------=== # + + def test_local_local_different(self): + # Diff two different, local runs. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + + src_nullptr_deref = """ +void b() { + int *i = 0; + *i = 5; +} +""" + self.__analyze(dir1, src_div_by_zero) + self.__analyze(dir2, src_nullptr_deref) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + reports, _ = get_diff_local_dirs( + report_filter, diff_type, [dir1], [], [dir2], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + def get_run_diff_count_reverse(diff_type: DiffType): + reports, _ = get_diff_local_dirs( + report_filter, diff_type, [dir2], [], [dir1], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + def test_local_local_identical(self): + # Diff two identical, local runs. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze(dir1, src_div_by_zero) + self.__analyze(dir2, src_div_by_zero) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + reports, _ = get_diff_local_dirs( + report_filter, diff_type, [dir1], [], [dir2], []) + return len(reports) + + # No new reports appeared. + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + + # No reports disappeared. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) + + # There is a single report that has remained. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 1) + + def test_localFPAnnotated_local_identical(self): + # Diff identical, local runs, where the baseline report is suppressed + # via //codechecker_suppress. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero_FP = """ +void a() { + int i = 0; + // codechecker_false_positive [all] SUPPRESS ALL + (void)(10 / i); +} +""" + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze(dir1, src_div_by_zero_FP) + self.__analyze(dir2, src_div_by_zero) + + def get_run_diff_count(diff_type: DiffType): + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + reports, _ = get_diff_local_dirs( + report_filter, diff_type, [dir1], [], [dir2], []) + return len(reports) + + # FIXME: The report turned from source code suppressed to no longer + # suppressed, so it should be in this set. + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + + # No reports disappeared. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) + + # FIXME: The report should not appear here. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 1) + + def get_run_diff_count_reverse(diff_type: DiffType): + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + reports, _ = get_diff_local_dirs( + report_filter, diff_type, [dir2], [], [dir1], []) + return len(reports) + + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 0) + + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 1) + + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + # ===-----------------------------------------------------------------=== # + # Local-Remote tests. + # ===-----------------------------------------------------------------=== # + + def test_local_remote_different(self): + # Create two non-identical runs, store one on the server, leave one + # locally. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + + src_nullptr_deref = """ +void b() { + int *i = 0; + *i = 5; +} +""" + self.__analyze_and_store(dir1, "run1", src_div_by_zero) + self.__analyze(dir2, src_nullptr_deref) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + # Observe that the remote run is the baseline, and the local run + # is new. + reports, _, _ = get_diff_remote_run_local_dir( + self._cc_client, report_filter, diff_type, [], + ["run1"], [dir2], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + def get_run_diff_count_reverse(diff_type: DiffType): + # Note how this isn't the same function!! + reports, _, _ = get_diff_local_dir_remote_run( + self._cc_client, report_filter, diff_type, [], + [dir2], [], ["run1"]) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + def test_local_remote_identical(self): + # Create two identical runs, store one on the server, leave one + # locally. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze_and_store(dir1, "run1", src_div_by_zero) + self.__analyze(dir2, src_div_by_zero) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + # Observe that the remote run is the baseline, and the local run + # is new. + reports, _, _ = get_diff_remote_run_local_dir( + self._cc_client, report_filter, diff_type, [], + ["run1"], [dir2], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + + # a() is the old report. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) + + # There are no common reports. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 1) + + def get_run_diff_count_reverse(diff_type: DiffType): + # Note how this isn't the same function!! + reports, _, _ = get_diff_local_dir_remote_run( + self._cc_client, report_filter, diff_type, [], + [dir2], [], ["run1"]) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 0) + + # a() is the old report. + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 0) + + # There are no common reports. + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 1) + + def test_localFPAnnotated_remote_identical(self): + # Create two identical runs, store one on the server, leave one + # locally. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero_FP = """ +void a() { + int i = 0; + // codechecker_false_positive [all] SUPPRESS ALL + (void)(10 / i); +} +""" + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze(dir1, src_div_by_zero_FP) + self.__analyze_and_store(dir2, "run2", src_div_by_zero) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + # Observe that the remote run is the baseline, and the local run + # is new. + reports, _, _ = get_diff_remote_run_local_dir( + self._cc_client, report_filter, diff_type, [], + ["run2"], [dir1], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + + # a() is the old report. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + def get_run_diff_count_reverse(diff_type: DiffType): + # Note how this isn't the same function!! + reports, _, _ = get_diff_local_dir_remote_run( + self._cc_client, report_filter, diff_type, [], + [dir1], [], ["run2"]) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 0) + + # There are no common reports. + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + def test_local_remoteFPAnnotated_identical(self): + # Create two identical runs, store one on the server with a FP source + # code suppression, leave one locally. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero_FP = """ +void a() { + int i = 0; + // codechecker_false_positive [all] SUPPRESS ALL + (void)(10 / i); +} +""" + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze(dir1, src_div_by_zero) + self.__analyze_and_store(dir2, "run2", src_div_by_zero_FP) + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + + def get_run_diff_count(diff_type: DiffType): + # Observe that the remote run is the baseline, and the local run + # is new. + reports, _, _ = get_diff_remote_run_local_dir( + self._cc_client, report_filter, diff_type, [], + ["run2"], [dir1], []) + return len(reports) + + # b() is a new report. + self.assertEqual(get_run_diff_count(DiffType.NEW), 1) + + # FIXME: This should be 0 -- the "before" set is suppressed, the + # "after" set is no longer, so it should only be in the NEW set. + # Not to mention that these sets must be disjointed. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + def get_run_diff_count_reverse(diff_type: DiffType): + # Note how this isn't the same function!! + reports, _, _ = get_diff_local_dir_remote_run( + self._cc_client, report_filter, diff_type, [], + [dir1], [], ["run2"]) + return len(reports) + + # FIXME: This should be 0 -- the "before" set is suppressed, the + # "after" set is no longer, so it should only be in the RESOLVED set. + # Not to mention that these sets must be disjointed. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 1) + + # a() is the old report. + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 1) + + # There are no common reports. + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + def test_local_remoteReviewStatusRule_identical(self): + """ + Even though the local report is not marked as a false positive, we + expect the review status rule on the server to affect it. + Note that the remote run is the baseline, which suggests that the + review status rule is also a part of the baseline (it precedes the + local run), yet the rule still affects the local run. + This implies that review status rules are a timeless property -- once + a hash has a rule, all reports matching it before or after the rule + was made are affected. As a result, it should be in the UNRESOLVED set. + """ + # Create two identical runs, store one on the server, leave one + # locally. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + self.__analyze_and_store(dir1, "run1", src_div_by_zero) + + # Add a "false positive" review status rule on the stored report. + results = get_all_run_results(self._cc_client) + self.assertEqual(len(results), 1) + self._cc_client.addReviewStatusRule( + results[0].bugHash, ReviewStatus.FALSE_POSITIVE, "") + + self.__analyze(dir2, src_div_by_zero) + + def get_run_diff_count(diff_type: DiffType): + report_filter = ReportFilter() + # Observe that the remote run is the baseline, and the local run + # is new. + report_filter.reviewStatus = [] + reports, _, _ = get_diff_remote_run_local_dir( + self._cc_client, report_filter, diff_type, [], + ["run1"], [dir2], []) + return len(reports) + + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + # FIXME: This should be in the UNRESOLVED set. + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 1) + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + def get_run_diff_count_reverse(diff_type: DiffType): + report_filter = ReportFilter() + report_filter.reviewStatus = [] + # Note how this isn't the same function!! + reports, _, _ = get_diff_local_dir_remote_run( + self._cc_client, report_filter, diff_type, [], + [dir2], [], ["run1"]) + return len(reports) + + # FIXME: This should be in the UNRESOLVED set. + self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 1) + self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 0) + self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) + + # TODO: source code suppression and review status rule conflict resolution + # TODO: diff against a tag on the server, not just a run + + # ===-----------------------------------------------------------------=== # + # Remote-Remote tests. + # ===-----------------------------------------------------------------=== # + + # TODO: remote-remote diffs not concerning tags + + # ===--- Remote-Remote tests in between tags. ------------------------=== # + + # TODO: remote-remote diffs concerning tags + + def test_remote_remote_tag_FixedAtDate(self): + """ + When a run disappears from one tag to the next, we regard it as fixed, + and set it fixed_at date. Test whether just because the fixed_at date + is set, we still regard it as an outstanding report if we diff it in + a context where the bug still isn't fixed yet. + + You can read more about this bug here: + https://github.com/Ericsson/codechecker/pull/3853 + """ + # Diff two different, local runs. + dir1 = os.path.join(self.test_workspace, "dir1") + dir2 = os.path.join(self.test_workspace, "dir2") + + src_div_by_zero = """ +void a() { + int i = 0; + (void)(10 / i); +} +""" + + src_nullptr_deref = """ +void b() { + int *i = 0; + *i = 5; +} +""" + # Note that we're storing under the same run. + self.__analyze_and_store(dir1, "run1", src_div_by_zero, "tag1") + self.__analyze_and_store(dir2, "run1", src_nullptr_deref, "tag2") + + report_filter = ReportFilter() + report_filter.reviewStatus = [] + report_filter.detection_status = [] + + def get_run_diff_count(diff_type: DiffType): + reports, _, _ = get_diff_remote_runs( + self._cc_client, report_filter, diff_type, [], + ["run1:tag1"], ["run1:tag2"]) + return len(reports) + + self.assertEqual(get_run_diff_count(DiffType.NEW), 1) + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) + + # NOTE that we store the first report dir again. The report in tag2 is + # abscent, so its fixed_at date will be set. Still, the diff in between + # tag1 and tag2 shouldn't change. + self.__analyze_and_store(dir1, "run1", src_div_by_zero, "tag3") + + # FIXME: This report should not have disappeared! + self.assertEqual(get_run_diff_count(DiffType.NEW), 0) + self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 1) From 586962a29e5842207b1d3a10d4eb2b87da440697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Umann?= Date: Tue, 27 Jun 2023 13:57:36 +0200 Subject: [PATCH 2/6] [cmd] Fix a bug where src code suppression was ignored for baseline local-local diffs Pretty much what it says on the tin. --- web/client/codechecker_client/cmd_line_client.py | 9 ++++++--- .../functional/diff_cmdline/test_diff_cmdline.py | 12 ++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/web/client/codechecker_client/cmd_line_client.py b/web/client/codechecker_client/cmd_line_client.py index 9cede31eea..a14aeecb89 100644 --- a/web/client/codechecker_client/cmd_line_client.py +++ b/web/client/codechecker_client/cmd_line_client.py @@ -1025,13 +1025,16 @@ def get_diff_local_dirs( filtered_report_hashes = [] context = webserver_context.get_context() + statuses_str = [ttypes.ReviewStatus._VALUES_TO_NAMES[x].lower() + for x in report_filter.reviewStatus] + base_results = get_report_dir_results( report_dirs, report_filter, context.checker_labels) + base_results = [res for res in base_results + if res.check_source_code_comments(statuses_str)] + new_results = get_report_dir_results( new_report_dirs, report_filter, context.checker_labels) - - statuses_str = [ttypes.ReviewStatus._VALUES_TO_NAMES[x].lower() - for x in report_filter.reviewStatus] new_results = [res for res in new_results if res.check_source_code_comments(statuses_str)] diff --git a/web/tests/functional/diff_cmdline/test_diff_cmdline.py b/web/tests/functional/diff_cmdline/test_diff_cmdline.py index 836cb095bb..2dd934e666 100644 --- a/web/tests/functional/diff_cmdline/test_diff_cmdline.py +++ b/web/tests/functional/diff_cmdline/test_diff_cmdline.py @@ -276,15 +276,9 @@ def get_run_diff_count(diff_type: DiffType): report_filter, diff_type, [dir1], [], [dir2], []) return len(reports) - # FIXME: The report turned from source code suppressed to no longer - # suppressed, so it should be in this set. - self.assertEqual(get_run_diff_count(DiffType.NEW), 0) - - # No reports disappeared. + self.assertEqual(get_run_diff_count(DiffType.NEW), 1) self.assertEqual(get_run_diff_count(DiffType.RESOLVED), 0) - - # FIXME: The report should not appear here. - self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 1) + self.assertEqual(get_run_diff_count(DiffType.UNRESOLVED), 0) def get_run_diff_count_reverse(diff_type: DiffType): report_filter = ReportFilter() @@ -295,9 +289,7 @@ def get_run_diff_count_reverse(diff_type: DiffType): return len(reports) self.assertEqual(get_run_diff_count_reverse(DiffType.NEW), 0) - self.assertEqual(get_run_diff_count_reverse(DiffType.RESOLVED), 1) - self.assertEqual(get_run_diff_count_reverse(DiffType.UNRESOLVED), 0) # ===-----------------------------------------------------------------=== # From 89a8942aa79e8cd78f3e9eb7c7d3a125cd102927 Mon Sep 17 00:00:00 2001 From: bruntib Date: Wed, 12 Jul 2023 15:40:04 +0200 Subject: [PATCH 3/6] [GUI] Feature highlights in 6.22.0 in the GUI --- web/server/vue-cli/src/views/NewFeatures.vue | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/web/server/vue-cli/src/views/NewFeatures.vue b/web/server/vue-cli/src/views/NewFeatures.vue index d9ae2606cc..0993720f61 100644 --- a/web/server/vue-cli/src/views/NewFeatures.vue +++ b/web/server/vue-cli/src/views/NewFeatures.vue @@ -2,6 +2,31 @@ + + + + + + + CodeChecker failed to build on Ubuntu 22.04 in its previous release + because of two issues: some of our dependencies broke with the + release of python3.9, and we didn't support GNU Make-s new way of + creating build jobs. These issues are all fixed now, so CodeChecker + should work with the latest version of python and GNU Make! + + + +