Skip to content

Commit

Permalink
Escape special characters in Catch2 test names (#124)
Browse files Browse the repository at this point in the history
Fixes #123
  • Loading branch information
gmgunter authored Nov 1, 2023
1 parent c046f19 commit bcbc184
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 10 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# UNRELEASED

- Catch2: add support for catch version 3 ([#115](https://github.com/pytest-dev/pytest-cpp/pull/115))
- Catch2: support exception handling ([#117](https://github.com/pytest-dev/pytest-cpp/pull/117))
- Catch2: add support for catch version 3 ([#115](https://github.com/pytest-dev/pytest-cpp/pull/115)).
- Catch2: support exception handling ([#117](https://github.com/pytest-dev/pytest-cpp/pull/117)).
- Catch2: Correctly handle test names that contain special characters ([#123](https://github.com/pytest-dev/pytest-cpp/issues/123)).
- Added support for Python 3.12.

# 2.4.0 (2023-09-08)
Expand Down
25 changes: 17 additions & 8 deletions src/pytest_cpp/catch2.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
from pytest_cpp.helpers import make_cmdline


# Map each special character's Unicode ordinal to the escaped character.
_special_chars_map: dict[int, str] = {i: "\\" + chr(i) for i in b'[]*,~\\"'}


def escape(test_id: str) -> str:
"""Escape special characters in test names (see #123)."""
return test_id.translate(_special_chars_map)


class Catch2Version(enum.Enum):
V2 = "v2"
V3 = "v3"
Expand Down Expand Up @@ -115,14 +124,14 @@ def run_test(
xml_filename = os.path.join(os.path.relpath(temp_dir), "cpp-report.xml")
except ValueError:
xml_filename = os.path.join(temp_dir, "cpp-report.xml")
args = list(
make_cmdline(
harness,
executable,
[test_id, "--success", "--reporter=xml", f"--out {xml_filename}"],
)
)
args.extend(test_args)
exec_args = [
escape(test_id),
"--success",
"--reporter=xml",
f"--out={xml_filename}",
]
exec_args.extend(test_args)
args = make_cmdline(harness, executable, exec_args)

try:
output = subprocess.check_output(
Expand Down
5 changes: 5 additions & 0 deletions tests/SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,15 @@ for env, label in [(c3env, "_v3"), (c2env, "")]:
catch2_success = env.Object(f'catch2_success{label}', 'catch2_success.cpp')
catch2_failure = env.Object(f'catch2_failure{label}', 'catch2_failure.cpp')
catch2_error = env.Object(f'catch2_error{label}', 'catch2_error.cpp')
catch2_special_chars = env.Object(
f'catch2_special_chars{label}',
'catch2_special_chars.cpp'
)

env.Program(catch2_success)
env.Program(catch2_failure)
env.Program(catch2_error)
env.Program(catch2_special_chars)

SConscript('acceptance/googletest-samples/SConscript')
SConscript('acceptance/boosttest-samples/SConscript')
Expand Down
26 changes: 26 additions & 0 deletions tests/catch2_special_chars.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"

TEST_CASE( "Brackets in [test] name" ) {
REQUIRE( true );
}

TEST_CASE( "**Star in test name**" ) {
REQUIRE( true );
}

TEST_CASE( "~Tilde in test name" ) {
REQUIRE( true );
}

TEST_CASE( "Comma, in, test, name" ) {
REQUIRE( true );
}

TEST_CASE( R"(Backslash\ in\ test\ name)" ) {
REQUIRE( true );
}

TEST_CASE( "\"Quotes\" in test name" ) {
REQUIRE( true );
}
18 changes: 18 additions & 0 deletions tests/test_pytest_cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,24 @@ def test_catch2_failure(exes):
assert_catch2_failure(fail1.get_lines()[1], "a runtime error", colors)


@pytest.mark.parametrize("suffix", ["", "_v3"])
@pytest.mark.parametrize(
"test_id",
[
"Brackets in [test] name",
"**Star in test name**",
"~Tilde in test name",
"Comma, in, test, name",
r"Backslash\ in\ test\ name",
'"Quotes" in test name',
],
)
def test_catch2_special_chars(suffix, test_id, exes):
facade = Catch2Facade()
exe = exes.get("catch2_special_chars" + suffix)
assert facade.run_test(exe, test_id)[0] is None


class TestError:
def test_get_whitespace(self):
assert error.get_left_whitespace(" foo") == " "
Expand Down

0 comments on commit bcbc184

Please sign in to comment.