11from __future__ import annotations
22
3+ import enum
34import os
45import subprocess
56import tempfile
7+ from typing import Optional
68from typing import Sequence
79from xml .etree import ElementTree
810
1416from pytest_cpp .helpers import make_cmdline
1517
1618
19+ class Catch2Version (enum .Enum ):
20+ V2 = "v2"
21+ V3 = "v3"
22+
23+
1724class 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" )
0 commit comments