From 40d5a38d1b92826c46230e971524053d14a68ae4 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Fri, 30 Jul 2021 11:10:12 +0200 Subject: [PATCH] Escape path in exclude filter passed to gcovr Gcovr interprets exclude filters, as passed to the -e option, as regexes. Since we want to exclude a raw path, the argument must be escaped. --- mesonbuild/scripts/coverage.py | 10 +++++----- test cases/common/243 escape++/meson.build | 4 ++++ test cases/common/243 escape++/test.c | 3 +++ unittests/allplatformstests.py | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 test cases/common/243 escape++/meson.build create mode 100644 test cases/common/243 escape++/test.c diff --git a/mesonbuild/scripts/coverage.py b/mesonbuild/scripts/coverage.py index 2bd93e8a5..a9e83c26f 100644 --- a/mesonbuild/scripts/coverage.py +++ b/mesonbuild/scripts/coverage.py @@ -14,7 +14,7 @@ from mesonbuild import environment, mesonlib -import argparse, sys, os, subprocess, pathlib, stat +import argparse, re, sys, os, subprocess, pathlib, stat import typing as T def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build_root: str, log_dir: str, use_llvm_cov: bool) -> int: @@ -38,7 +38,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build if gcovr_exe: subprocess.check_call(gcovr_base_cmd + ['-x', - '-e', subproject_root, + '-e', re.escape(subproject_root), '-o', os.path.join(log_dir, 'coverage.xml') ] + gcov_exe_args) outfiles.append(('Xml', pathlib.Path(log_dir, 'coverage.xml'))) @@ -51,7 +51,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build subprocess.check_call(gcovr_base_cmd + ['--sonarqube', '-o', os.path.join(log_dir, 'sonarqube.xml'), - '-e', subproject_root + '-e', re.escape(subproject_root) ] + gcov_exe_args) outfiles.append(('Sonarqube', pathlib.Path(log_dir, 'sonarqube.xml'))) elif outputs: @@ -61,7 +61,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build if not outputs or 'text' in outputs: if gcovr_exe: subprocess.check_call(gcovr_base_cmd + - ['-e', subproject_root, + ['-e', re.escape(subproject_root), '-o', os.path.join(log_dir, 'coverage.txt') ] + gcov_exe_args) outfiles.append(('Text', pathlib.Path(log_dir, 'coverage.txt'))) @@ -140,7 +140,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build ['--html', '--html-details', '--print-summary', - '-e', subproject_root, + '-e', re.escape(subproject_root), '-o', os.path.join(htmloutdir, 'index.html'), ]) outfiles.append(('Html', pathlib.Path(htmloutdir, 'index.html'))) diff --git a/test cases/common/243 escape++/meson.build b/test cases/common/243 escape++/meson.build new file mode 100644 index 000000000..5fcc00f5c --- /dev/null +++ b/test cases/common/243 escape++/meson.build @@ -0,0 +1,4 @@ +project('regex escape test', 'c') + +exe = executable('testprog', 'test.c') +test('runtest', exe) diff --git a/test cases/common/243 escape++/test.c b/test cases/common/243 escape++/test.c new file mode 100644 index 000000000..9b6bdc2ec --- /dev/null +++ b/test cases/common/243 escape++/test.c @@ -0,0 +1,3 @@ +int main(void) { + return 0; +} diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index a94d9cbab..bd1e3fa02 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -3434,6 +3434,26 @@ class AllPlatformTests(BasePlatformTests): self.run_target('coverage-xml') self._check_coverage_files(['xml']) + def test_coverage_escaping(self): + if mesonbuild.environment.detect_msys2_arch(): + raise SkipTest('Skipped due to problems with coverage on MSYS2') + gcovr_exe, gcovr_new_rootdir = mesonbuild.environment.detect_gcovr() + if not gcovr_exe: + raise SkipTest('gcovr not found, or too old') + testdir = os.path.join(self.common_test_dir, '243 escape++') + env = get_fake_env(testdir, self.builddir, self.prefix) + cc = detect_c_compiler(env, MachineChoice.HOST) + if cc.get_id() == 'clang': + if not mesonbuild.environment.detect_llvm_cov(): + raise SkipTest('llvm-cov not found') + if cc.get_id() == 'msvc': + raise SkipTest('Test only applies to non-MSVC compilers') + self.init(testdir, extra_args=['-Db_coverage=true']) + self.build() + self.run_tests() + self.run_target('coverage') + self._check_coverage_files() + def test_cross_file_constants(self): with temp_filename() as crossfile1, temp_filename() as crossfile2: with open(crossfile1, 'w', encoding='utf-8') as f: