Skip to content

Commit bd997b4

Browse files
authored
Catch2: support v3 (#115)
Closes #107
1 parent 9f677bd commit bd997b4

File tree

8 files changed

+24035
-32
lines changed

8 files changed

+24035
-32
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# UNRELEASED
2+
3+
- Catch2: add support for catch version 3 ([#115](https://github.com/pytest-dev/pytest-cpp/pull/115))
4+
15
# 2.4.0 (2023-09-08)
26

37
- Catch2: fix issue with multiple test failures, and support multiple "SECTION" tests. ([#112](https://github.com/pytest-dev/pytest-cpp/pull/112))

src/pytest_cpp/catch2.py

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from __future__ import annotations
22

3+
import enum
34
import os
45
import subprocess
56
import tempfile
7+
from typing import Optional
68
from typing import Sequence
79
from xml.etree import ElementTree
810

@@ -14,17 +16,22 @@
1416
from pytest_cpp.helpers import make_cmdline
1517

1618

19+
class Catch2Version(enum.Enum):
20+
V2 = "v2"
21+
V3 = "v3"
22+
23+
1724
class Catch2Facade(AbstractFacade):
1825
"""
1926
Facade for Catch2.
2027
"""
2128

2229
@classmethod
23-
def is_test_suite(
30+
def get_catch_version(
2431
cls,
2532
executable: str,
2633
harness_collect: Sequence[str] = (),
27-
) -> bool:
34+
) -> Optional[Catch2Version]:
2835
args = make_cmdline(harness_collect, executable, ["--help"])
2936
try:
3037
output = subprocess.check_output(
@@ -33,25 +40,47 @@ def is_test_suite(
3340
universal_newlines=True,
3441
)
3542
except (subprocess.CalledProcessError, OSError):
36-
return False
43+
return None
3744
else:
38-
return "--list-test-names-only" in output
45+
return (
46+
Catch2Version.V2
47+
if "--list-test-names-only" in output
48+
else Catch2Version.V3
49+
if "--list-tests" in output
50+
else None
51+
)
52+
53+
@classmethod
54+
def is_test_suite(
55+
cls,
56+
executable: str,
57+
harness_collect: Sequence[str] = (),
58+
) -> bool:
59+
return cls.get_catch_version(executable, harness_collect) in [
60+
Catch2Version.V2,
61+
Catch2Version.V3,
62+
]
3963

4064
def list_tests(
4165
self,
4266
executable: str,
4367
harness_collect: Sequence[str] = (),
4468
) -> list[str]:
4569
"""
46-
Executes test with "--list-test-names-only" and gets list of tests
70+
Executes test with "--list-test-names-only" (v2) or "--list-tests --verbosity quiet" (v3) and gets list of tests
4771
parsing output like this:
4872
4973
1: All test cases reside in other .cpp files (empty)
5074
2: Factorial of 0 is 1 (fail)
5175
2: Factorials of 1 and higher are computed (pass)
5276
"""
5377
# This will return an exit code with the number of tests available
54-
args = make_cmdline(harness_collect, executable, ["--list-test-names-only"])
78+
exec_args = (
79+
["--list-test-names-only"]
80+
if self.get_catch_version(executable, harness_collect) == Catch2Version.V2
81+
else ["--list-tests", "--verbosity quiet"]
82+
)
83+
args = make_cmdline(harness_collect, executable, exec_args)
5584
try:
5685
output = subprocess.check_output(
5786
args,
@@ -77,6 +106,11 @@ def run_test(
77106
On Windows, ValueError is raised when path and start are on different drives.
78107
In this case failing back to the absolute path.
79108
"""
109+
catch_version = self.get_catch_version(executable, harness)
110+
111+
if catch_version is None:
112+
raise Exception("Invalid Catch Version")
113+
80114
try:
81115
xml_filename = os.path.join(os.path.relpath(temp_dir), "cpp-report.xml")
82116
except ValueError:
@@ -97,7 +131,7 @@ def run_test(
97131
except subprocess.CalledProcessError as e:
98132
output = e.output
99133

100-
results = self._parse_xml(xml_filename)
134+
results = self._parse_xml(xml_filename, catch_version)
101135

102136
for executed_test_id, failures, skipped in results:
103137
if executed_test_id == test_id:
@@ -123,11 +157,16 @@ def run_test(
123157
return [failure], output
124158

125159
def _parse_xml(
126-
self, xml_filename: str
160+
self, xml_filename: str, catch_version: Catch2Version
127161
) -> Sequence[tuple[str, Sequence[tuple[str, int, str]], bool]]:
128162
root = ElementTree.parse(xml_filename)
129163
result = []
130-
for test_suite in root.findall("Group"):
164+
test_suites = (
165+
root.findall("Group")
166+
if catch_version == Catch2Version.V2
167+
else root.iter("Catch2TestRun")
168+
)
169+
for test_suite in test_suites:
131170
for test_case in test_suite.findall("TestCase"):
132171
test_name = test_case.attrib["name"]
133172
test_result = test_case.find("OverallResult")

tests/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
!.gitignore
55
!*.h
66
!*.cpp
7+
!*.hpp
78
!*.cc
89
!*.py
910
!*.xml
1011
!README*
1112
!SCons*
12-
!catch.hpp
13+
14+
!catch2_v2
15+
!catch2_v3

tests/SConstruct

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ if 'CXX' in os.environ:
1919

2020
env = Environment(**kwargs)
2121
genv = env.Clone(LIBS=['gtest'] + LIBS)
22-
c2env = env.Clone(CPPPATH=['.'])
22+
c2env = env.Clone(CPPPATH=['.', 'catch2_v2'])
2323

24-
Export('env genv c2env')
24+
catch2_v3 = env.Library('catch2_v3', ['catch2_v3/catch.cpp'])
25+
26+
c3env = env.Clone(CPPPATH=['.', 'catch2_v3'], LIBS=[catch2_v3])
27+
28+
Export('env genv c2env c3env')
2529

2630
genv.Program('gtest.cpp')
2731
genv.Program('gtest_args.cpp')
@@ -39,8 +43,12 @@ boost_files = [
3943
for filename in boost_files:
4044
env.Program(filename)
4145

42-
c2env.Program('catch2_success.cpp')
43-
c2env.Program('catch2_failure.cpp')
46+
for env, label in [(c3env, "_v3"), (c2env, "")]:
47+
catch2_success = env.Object(f'catch2_success{label}', 'catch2_success.cpp')
48+
catch2_failure = env.Object(f'catch2_failure{label}', 'catch2_failure.cpp')
49+
50+
env.Program(catch2_success)
51+
env.Program(catch2_failure)
4452

4553
SConscript('acceptance/googletest-samples/SConscript')
4654
SConscript('acceptance/boosttest-samples/SConscript')
File renamed without changes.

0 commit comments

Comments
 (0)