diff --git a/.pylintrc b/.pylintrc index 8edda601..a8a353ac 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,6 +1,6 @@ [MASTER] # To find common lib for tests -init-hook='import sys; sys.path.append("test")' +init-hook='import sys; import os; sys.path.append("test"); sys.path.append(os.getcwd())' ignore = test_template.py [FORMAT] diff --git a/src/codechecker_script.py b/src/codechecker_script.py index 4860a283..ce63f26b 100644 --- a/src/codechecker_script.py +++ b/src/codechecker_script.py @@ -205,6 +205,19 @@ def analyze(): fail("Make sure that the target can be built first") +def fix_path_with_regex(data:str) -> str: + """ + The absolute paths of the analyzed source files found in the plist files + do not point to their original location, but rather wherever bazel copied + them. This might either be in a subdirectory in bazel-bin on the + local machine, or somewhere unrelated if the analysis was executed on a + remote worker. This function tries to replace these paths to the location + of the original location of the source file. + """ + for pattern, replace in BAZEL_PATHS.items(): + data = re.sub(pattern, replace, data) + return data + def fix_bazel_paths(): """ Remove Bazel leading paths in all files """ stage("Fix CodeChecker output:") @@ -215,9 +228,7 @@ def fix_bazel_paths(): for filename in files: fullpath = os.path.join(root, filename) with open(fullpath, "rt", encoding="utf-8") as data_file: - data = data_file.read() - for pattern, replace in BAZEL_PATHS.items(): - data = re.sub(pattern, replace, data) + data = fix_path_with_regex(data_file.read()) with open(fullpath, "w", encoding="utf-8") as data_file: data_file.write(data) counter += 1 diff --git a/test/unit/plist_res/__init__.py b/test/unit/plist_res/__init__.py new file mode 100644 index 00000000..5fecda68 --- /dev/null +++ b/test/unit/plist_res/__init__.py @@ -0,0 +1,25 @@ +# Copyright 2023 Ericsson AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Setup module paths for testing directly on `codechecker_script.py` +""" + +import os +import sys + +# Allow relative imports within the test project to work as expected +# Without it we wouldn't be able to include the fix_bazel_paths function +src = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", '..') +sys.path.append(src) diff --git a/test/unit/plist_res/test_path_resolution.py b/test/unit/plist_res/test_path_resolution.py new file mode 100644 index 00000000..df2e76c9 --- /dev/null +++ b/test/unit/plist_res/test_path_resolution.py @@ -0,0 +1,75 @@ +# Copyright 2023 Ericsson AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Tests regex resolution from remote executor absolute path +to local relative paths +""" + +import os +import unittest +from typing import Dict +from common.base import TestBase +from src.codechecker_script import fix_path_with_regex + + +class TestPathResolve(TestBase): + """Test regex resolution of remote execution paths""" + + # Set working directory + __test_path__ = os.path.dirname(os.path.abspath(__file__)) + BAZEL_BIN_DIR = os.path.join( + "../../..", "bazel-bin", "test", "unit", "plist_res" + ) + BAZEL_TESTLOGS_DIR = os.path.join( + "../../..", "bazel-testlogs", "test", "unit", "plist_res" + ) + dir = os.path.dirname(os.path.abspath(__file__)) + "/tmp" + + def test_remote_worker_path_resolution(self): + """ + Test: Resolve absolute path of remote worker + to a relative path of the original project + """ + test_path_collection: Dict[str, str] = { + # {Remote execution absolute path}: {project relative path} + ( + "/worker/build/5d2c60d87885b089" + "/root/test/unit/legacy/src/lib.cc" + ): "test/unit/legacy/src/lib.cc", + ( + "/worker/build/a0ed5e04f7c3b444" + "/root/test/unit/legacy/src/ctu.cc" + ): "test/unit/legacy/src/ctu.cc", + ( + "/worker/build/a0ed5e04f7c3b444" + "/root/test/unit/legacy/src/fail.cc" + ): "test/unit/legacy/src/fail.cc", + # This resolution is impossible, + # because "test_inc" => "inc" cannot be resolved + #( + # "/worker/build/28e82627f5078a2d" + # "/root/bazel-out/k8-fastbuild/bin/test/unit" + # "/virtual_include/_virtual_includes/test_inc/zeroDiv.h" + #): "test/unit/virtual_include/inc/zeroDiv.h", + } + test_on: Dict[str, str] = test_path_collection.copy() + for before, res in test_on.items(): + after: str = fix_path_with_regex(before[:]) + # FIXME: change to assertEqual + self.assertNotEqual(after, res) + + +if __name__ == "__main__": + unittest.main(buffer=True)