Compare commits

...
6 Commits
Author SHA1 Message Date
Martin Hořeňovský 97ec4e8e2e catch_discover_tests: Escape test-invariant parts of CTest script only once
Previously, the `catch_discover_tests` would prepare the entire CTest
command (e.g. `add_test(...)` or `set_tests_properties(...)`) first, and
then escape it when finished. However, this caused lot of the command args
to be escaped over and over again (e.g. executable name or Catch2's reporter
args), for no reason, as they were always the same, and thus their escaping
was always the same.

Until recently, the performance overhead didn't matter as there were many
spots which had quadratic runtime in number of tests. However, the recent
refactorings fixed these, and this commit now improves the throughput by
10-20%.

Also extended the benchmarked COUNTS in `benchmark_discovery.py`,
because the performance is now good enough that it is reasonable
to benchmark 16k tests.
2026-08-10 11:53:22 +02:00
Martin Hořeňovský 0136276e15 Avoid n**2 runtime when creating list of tests in catch_discover_tests
This was another place where the script triggered the quadratic runtime
from calling `string(APPEND` (or `list(APPEND`) repeatedly. As in
60c8b87, we avoid this by flushing the test list into a file every
50kB of text input.

As the string with the test list never grew quite as much as the
string that contains all the test definitions, this only provides
significant savings for high number of tests. It starts being
properly measurable around 4k tests at ~100ms, but grows to ~4s at
32k tests.
2026-08-10 10:36:04 +02:00
Martin Hořeňovský 630840c500 Fix <target>_TESTS variable generated by catch_discover_tests
There were 2 separate bugs, one recently added and one ancient
(since roughly the first version of the registration script).

1) The recent refactoring of how the JSON output from Catch2 is
   parsed caused shadowing between the variable containing the
   per-test JSON fragments and the accumulator of test names for
   <target>_TESTS variable. This led to the variable containing
   both the names and the JSON fragments, and thus being completely
   wrong.

2) The test name accumulation has never accounted for characters
   that need escaping to be present in a CMake list. This means
   that e.g. test names with semicolon in them would end up with
   two elements in the test list.

Both of these are now fixed, at the cost of extra complexity and
my sanity as I had to learn more about CMake escaping rules.

(CMake escaping rules are dumb)
2026-08-10 00:17:26 +02:00
Martin Hořeňovský 4cde128517 JSONReporter considers verbosity when listing tests
* Quiet verbosity provides just the test names
* Normal verbosity adds tags
* High verbosity add the source location of the tests

Listing tests with the quiet verbosity results in about 1/4 of the
previous output, which leads to measurably faster execution of
`catch_discover_tests` when it does not need tags for labels.
(If it does need tags, the output is about 1/2 of previous).
2026-08-08 00:05:18 +02:00
Martin Hořeňovský 0b4d7a5a16 JSONReporter's listTests only lists class-name if it is non-empty 2026-08-07 23:07:46 +02:00
Martin Hořeňovský a0eba50e9d Make verbosity per-reporter 2026-08-07 20:57:42 +02:00
32 changed files with 571 additions and 316 deletions
@@ -8,6 +8,7 @@
# SPDX-License-Identifier: BSL-1.0
import argparse
import copy
import json
import os
import re
@@ -20,7 +21,7 @@ import time
HERE = os.path.dirname(os.path.abspath(__file__))
TEMPLATE = os.path.join(HERE, "listing_template.json")
SHIM = os.path.join(HERE, "copy_shim.cmake")
COUNTS = [1, 10, 500, 1000, 2000, 4000, 8000]
COUNTS = [1, 10, 500, 1000, 2000, 4000, 8000, 16000]
#COUNTS = [1, 10, 100]
REPEATS = 5
@@ -33,14 +34,19 @@ def load_template(path: str) -> dict:
return catch_out
def synthesize_listing(template_doc: dict, count: int, file) -> str:
def synthesize_listing(template_doc: dict, count: int, file, with_tags: bool) -> str:
"""Writes JSON listing with exactly `count` test cases into `file`.
The template entries are cycled through, and each name is made unique by
appending an index, so that every registered CTest test has a distinct name.
"""
doc_copy = template_doc.copy()
template_tests = template_doc['listings']['tests']
# To avoid messing up the template tests by deletion, we have
# to take a deepcopy before the changes.
doc_copy = copy.deepcopy(template_doc)
template_tests = doc_copy['listings']['tests']
if not with_tags:
for test in template_tests:
del test['tags']
num_original = len(template_tests)
out_tests = []
@@ -176,10 +182,10 @@ def main():
os.makedirs(workdir, exist_ok=True)
for count in COUNTS:
listing_path = os.path.join(workdir, f"listing-{count}.json")
with open(listing_path, "w", encoding="utf-8") as f:
synthesize_listing(template_doc, count, f)
for add_tags in tag_modes:
with open(listing_path, "w", encoding="utf-8") as f:
synthesize_listing(template_doc, count, f, add_tags)
mode = "on" if add_tags else "off"
ctest_file = os.path.join(workdir, f"ctest-{count}-{mode}.cmake")
cmd = build_command(args, listing_path, ctest_file, add_tags)
+11 -60
View File
@@ -1,5 +1,5 @@
{
"version": 1,
"version": 2,
"metadata": {
"name": "benchmark-template",
"catch2-version": "3.15.2"
@@ -8,66 +8,41 @@
"tests": [
{
"name": "Comparing function pointers",
"class-name": "",
"tags": [
"function pointer",
"Tricky"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Tricky.tests.cpp",
"line": 266
}
]
},
{
"name": "Testing checked-if 4",
"class-name": "",
"tags": [
"!shouldfail",
"checked-if"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Misc.tests.cpp",
"line": 216
}
]
},
{
"name": "count_equidistant_floats - double",
"class-name": "",
"tags": [
"approvals",
"distance",
"floating-point"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/IntrospectiveTests/FloatingPoint.tests.cpp",
"line": 103
}
]
},
{
"name": "Usage of AllTrue range matcher",
"class-name": "",
"tags": [
"matchers",
"quantifiers",
"templated"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/MatchersRanges.tests.cpp",
"line": 372
}
]
},
{
"name": "Exception matchers that succeed",
"class-name": "",
"tags": [
"!throws",
"exceptions",
"matchers"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Matchers.tests.cpp",
"line": 428
}
]
},
{
"name": "A TEMPLATE_TEST_CASE_METHOD based test run that succeeds - float",
@@ -75,59 +50,35 @@
"tags": [
"class",
"template"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Class.tests.cpp",
"line": 82
}
]
},
{
"name": "Approximate PI",
"class-name": "",
"tags": [
"Approx",
"PI"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Approx.tests.cpp",
"line": 134
}
]
},
{
"name": "TextFlow::Column respects width setting",
"class-name": "",
"tags": [
"approvals",
"column",
"TextFlow"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/IntrospectiveTests/TextFlow.tests.cpp",
"line": 38
}
]
},
{
"name": "Generators internals",
"class-name": "",
"tags": [
"generators",
"internals"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp",
"line": 24
}
]
},
{
"name": "Mayfail test case with nested sections",
"class-name": "",
"tags": [
"!mayfail"
],
"source-location": {
"filename": "/mnt/c/ubuntu/Catch2/tests/SelfTest/UsageTests/Condition.tests.cpp",
"line": 83
}
]
}
]
}
+7 -2
View File
@@ -202,8 +202,13 @@ as many times as you want, e.g. `--reporter xml::out=someFile.xml` or
The keys must either be prefixed by "X", in which case they are not parsed
by Catch2 and are only passed down to the reporter, or one of options
hardcoded into Catch2. Currently there are only 2,
["out"](#sending-output-to-a-file), and ["colour-mode"](#colour-mode).
hardcoded into Catch2. Currently there are 3 supported options:
* ["out"](#sending-output-to-a-file)
* ["colour-mode"](#colour-mode)
* ["verbosity"](#output-verbosity)
> Support for per-reporter verbosity option was added in Catch2 vX.Y.Z
_Note that the reporter might still check the X-prefixed options for
validity, and throw an error if they are wrong._
+4 -4
View File
@@ -43,13 +43,13 @@ them write into different destinations. The two main uses of this are
Specifying multiple reporter looks like this:
```
--reporter JUnit::out=result-junit.xml --reporter console::out=-::colour-mode=ansi
--reporter JUnit::out=result-junit.xml --reporter console::out=-::colour-mode=ansi::verbosity=quiet
```
This tells Catch2 to use two reporters, `JUnit` reporter that writes
its machine-readable XML output to file `result-junit.xml`, and the
`console` reporter that writes its user-friendly output to stdout and
uses ANSI colour codes for colouring the output.
`console` reporter that writes its user-friendly output to stdout, uses
ANSI colour codes for colouring the output and is set to "quiet" verbosity.
Using multiple reporters (or one reporter and one-or-more [event
listeners](event-listeners.md#top)) can have surprisingly complex semantics
@@ -110,7 +110,7 @@ passing and failing assertions.
_Generally we recommend that if you override a member function from either
of the bases, you call into the base's implementation first. This is not
necessarily in all cases, but it is safer and easier._
necessary in all cases, but it is safer and easier._
Writing your own reporter then looks like this:
+5
View File
@@ -58,6 +58,11 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
Note that ``<target>_TESTS`` variable contains test names with brackets
("[", "]") escaped into ASCII char 2, 3 respectively, to work around CMake's
list parsing rules. You have to unescape them back for each element to get
the original names.
The options are:
``target``
+150 -66
View File
@@ -12,14 +12,28 @@
# exist in JSON unescaped.
#
# 0x01 <=> ';' (CMake list separator)
# 0x02 == element boundary marker used while splitting the tests array
# 0x03 <-> '[' (opens a CMake bracket-argument context)
# 0x04 <-> ']' (closes a CMake bracket-argument context)
# 0x02 <-> '[' (opens a CMake bracket-argument context)
# 0x03 <-> ']' (closes a CMake bracket-argument context)
# 0x04 == element boundary marker used while splitting the tests array
#
string(ASCII 1 _SemicolonEscape)
string(ASCII 2 _BoundaryEscape)
string(ASCII 3 _OpenBracketEscape)
string(ASCII 4 _CloseBracketEscape)
string(ASCII 2 _OpenBracketEscape)
string(ASCII 3 _CloseBracketEscape)
string(ASCII 4 _BoundaryEscape)
# As far as I can tell, the only way of having unclosed '[' or ']' in the
# list of test names we define for CTest, is to escape them into completely
# different characters. Otherwise, they will break parsing of unrelated
# semicolons (inserted by CMake after parsing the list from the user-facing
# space separated format). This means that the consumers of the list have
# to unescape them back, but that's CMake :v
#
# 0x02 <-> '['
# 0x03 <-> ']'
#
string(ASCII 2 _OpenBracketListingEscape)
string(ASCII 3 _CloseBracketListingEscape)
# Placeholder bytes in the listing would break our parsing hack, so
@@ -126,35 +140,28 @@ function(split_json_array json_array_var out_var)
set(${out_var} "${array_elements}" PARENT_SCOPE)
endfunction()
# TBD: Further possible optimization is that most arguments for per-test
# `prepare_command` call are constant across one invocation of
# `catch_discover_tests`, and thus need checking and escaping only
# once, instead of for each test.
# This would provide nice speed-up of the actual command preparation,
# but it will make the script much harder to read, and it is utterly
# dwarfed by the quadratic scaling of parsing JSON arrays in CMake.
# Prepare command with escaped (bracketed) arguments and return it via `_Command` out variable.
# Prepare (a part of) command with bracketed arguments and return it via `out_var`.
#
# To avoid quadratic performance when concatenating all commands together,
# the actual concatenation must be done by the caller, by appending it
# into a string of all other commands.
function(prepare_command NAME)
# This allows the registration script to escape parts of the test script
# only once, instead of escaping the unchanged arguments over and over again.
function(prepare_command_fragment out_var)
set(_args "")
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
math(EXPR _last_arg ${ARGC}-1)
foreach(_n RANGE 1 ${_last_arg})
set(_arg "${ARGV${_n}}")
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(_Command "${NAME}(${_args})\n" PARENT_SCOPE)
if(_last_arg GREATER_EQUAL 1)
foreach(_n RANGE 1 ${_last_arg})
set(_arg "${ARGV${_n}}")
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
endif()
set(${out_var} "${_args}" PARENT_SCOPE)
endfunction()
# Generates random filename in the temp folder.
# Temp folder is retrieved by checking env vars from various platforms.
function(make_temp_file_path OUT_VARIABLE FALLBACK_PATH)
@@ -190,6 +197,23 @@ function(make_temp_file_path OUT_VARIABLE FALLBACK_PATH)
set(${OUT_VARIABLE} "${FINAL_TEMP_PATH}" PARENT_SCOPE)
endfunction()
# Computes the path of the test-list file based on the path for the main
# CTest script file (passed in `CTEST_FILE`).
#
# It works by replacing the `_tests` part of the original name with
# `_test-list`, or failing that, it appends `-list.cmake` instead.
#
# <base>_tests.cmake -> <base>_test-list.cmake
# <base>_tests-Debug.cmake -> <base>_test-list-Debug.cmake
function(make_test_list_file_path CTEST_FILE OUT_VARIABLE)
if("${CTEST_FILE}" MATCHES "_tests(.*)\\.cmake$")
string(REGEX REPLACE "_tests(.*)\\.cmake$" "_test-list\\1.cmake" list_file "${CTEST_FILE}")
else()
set(list_file "${CTEST_FILE}-list.cmake")
endif()
set(${OUT_VARIABLE} "${list_file}" PARENT_SCOPE)
endfunction()
function(catch_discover_tests_impl)
cmake_parse_arguments(
""
@@ -199,9 +223,14 @@ function(catch_discover_tests_impl)
${ARGN}
)
# We periodically append to the output file below, so we have to ensure
# We write the list of all discovered tests into a separate file
make_test_list_file_path("${_CTEST_FILE}" _CTEST_LIST_FILE)
# We periodically append to the output files below, so we have to ensure
# that it is empty at the start, or we get duplicated test scripts.
file(REMOVE "${_CTEST_FILE}")
file(REMOVE "${_CTEST_LIST_FILE}")
# Size (in Bytes) at which the intermediate `script` var is dumped to file.
set(_WriteToFileThreshold 50000)
@@ -221,6 +250,10 @@ function(catch_discover_tests_impl)
set(script)
set(suite)
set(tests)
# Holds the list of all registered test names **as a string**, not list.
# This avoids issue of CMake removing semicolon escapes even inside
# bracket-quoted strings.
set(_test_names)
if(WIN32)
set(dl_paths_variable_name PATH)
@@ -253,10 +286,15 @@ function(catch_discover_tests_impl)
make_temp_file_path(listing_output_path "${_TEST_WORKING_DIR}")
set(_Verbosity "quiet")
if (add_tags)
set(_Verbosity "normal")
endif()
execute_process(
COMMAND ${_TEST_EXECUTOR} "${_TEST_EXECUTABLE}" ${spec}
--list-tests
--reporter json
--reporter "json::verbosity=${_Verbosity}"
--out "${listing_output_path}"
--order lex # Make sure the output order, and thus test registration order, is consistent across runs.
OUTPUT_VARIABLE listing_output
@@ -326,7 +364,7 @@ function(catch_discover_tests_impl)
# Parse JSON output for list of tests/class names/tags
string(JSON version GET "${listing_output}" "version")
if(NOT version STREQUAL "1")
if(NOT version STREQUAL "2")
message(FATAL_ERROR "Unsupported catch output version: '${version}'")
endif()
@@ -337,10 +375,54 @@ function(catch_discover_tests_impl)
# Exit early if no tests are detected
if(NOT tests)
file(WRITE "${_CTEST_FILE}" "")
# Still emit an (empty) test list file and have the main script include
# it, so that consumers relying on the `${_TEST_LIST}` variable and on the
# include structure get consistent behavior regardless of test count.
file(WRITE "${_CTEST_LIST_FILE}" "set(${_TEST_LIST})\n")
file(WRITE "${_CTEST_FILE}" "include(\"${_CTEST_LIST_FILE}\")\n")
return()
endif()
# The 'set(VAR` header for the test list has to be written separately,
# so that each test name can be appended file without further processing.
set(test_names "set(${_TEST_LIST}")
# Most of the commands/arguments in the CTest script are identical
# for every test registered with one `catch_discover_tests` call.
# To avoid repeating the work in escaping them, we escape them before
# the per-test loop and reuse the escaped fragments.
#
# `add_test` calls are
# add_test(<name><exec><exe><escaped_name><extra_args><reporter><out_dir>)
# Of these, <exec>,<exe>,<extra_args>, and <reporter> are the same between
# all tests.
prepare_command_fragment(_exec_exe_fragment
${_TEST_EXECUTOR}
"${_TEST_EXECUTABLE}"
)
prepare_command_fragment(_args_reporter_fragment
${extra_args}
"${reporter_arg}"
)
# `set_tests_properties` calls are
# set_tests_properties(<name> PROPERTIES WORKING_DIRECTORY <dir> <properties>)
# set_tests_properties(<name> PROPERTIES ENVIRONMENT_MODIFICATION <env_mod>)
# Of these, only the <name> changes between tests.
prepare_command_fragment(_properties_fragment
PROPERTIES
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
${properties}
)
# Env modification is optional, so we prepare it in a separate command
if(environment_modifications)
prepare_command_fragment(_env_modification_fragment
PROPERTIES
ENVIRONMENT_MODIFICATION "${environment_modifications}"
)
endif()
# Each element in the tests is JSON-string representing one test object.
# We have to parse it and then turn it into CTest script commands.
foreach(single_test IN LISTS tests)
@@ -351,6 +433,11 @@ function(catch_discover_tests_impl)
file(APPEND "${_CTEST_FILE}" "${script}")
set(script "")
endif()
string(LENGTH "${test_names}" names_len)
if (names_len GREATER _WriteToFileThreshold)
file(APPEND "${_CTEST_LIST_FILE}" "${test_names}")
set(test_names "")
endif()
# The elements are still escaped and contain JSON-invalid characters,
# they have to be unescaped before parsing them as JSON.
@@ -372,24 +459,15 @@ function(catch_discover_tests_impl)
set(output_dir_arg "--out ${output_dir}/${output_prefix}${escaped_name_clean}${output_suffix}")
endif()
# ...and add to script
prepare_command(add_test
"${prefix}${plain_name}${suffix}"
${_TEST_EXECUTOR}
"${_TEST_EXECUTABLE}"
"${escaped_name}"
${extra_args}
"${reporter_arg}"
"${output_dir_arg}"
)
string(APPEND script "${_Command}")
prepare_command(set_tests_properties
"${prefix}${plain_name}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${_TEST_WORKING_DIR}"
${properties}
)
string(APPEND script "${_Command}")
set(full_name "${prefix}${plain_name}${suffix}")
prepare_command_fragment(_full_name_fragment "${full_name}")
prepare_command_fragment(_escaped_name_fragment "${escaped_name}")
prepare_command_fragment(_outdir_fragment "${output_dir_arg}")
string(APPEND script
"add_test(${_full_name_fragment}${_exec_exe_fragment}${_escaped_name_fragment}${_args_reporter_fragment}${_outdir_fragment})\n")
string(APPEND script
"set_tests_properties(${_full_name_fragment}${_properties_fragment})\n")
if(add_tags)
string(JSON num_tags LENGTH "${test_tags}")
@@ -409,33 +487,39 @@ function(catch_discover_tests_impl)
list(APPEND tag_list "${a_tag}")
endforeach()
prepare_command(set_tests_properties
"${prefix}${plain_name}${suffix}"
prepare_command_fragment(_labels_fragment
PROPERTIES
LABELS "${tag_list}"
)
string(APPEND script "${_Command}")
string(APPEND script "set_tests_properties(${_full_name_fragment}${_labels_fragment})\n")
endif()
endif(add_tags)
if(environment_modifications)
prepare_command(set_tests_properties
"${prefix}${plain_name}${suffix}"
PROPERTIES
ENVIRONMENT_MODIFICATION "${environment_modifications}")
string(APPEND script "${_Command}")
string(APPEND script "set_tests_properties(${_full_name_fragment}${_env_modification_fragment})\n")
endif()
list(APPEND tests "${prefix}${plain_name}${suffix}")
# The test name has to be escaped using the same rules as prepare_command
# uses for the arguments, so that it keeps being single element in list
# even with weird characters and semicolons.
set(full_list_name "${prefix}${plain_name}${suffix}")
string(REPLACE ";" "\\;" full_list_name "${full_list_name}")
string(REPLACE "[" "${_OpenBracketListingEscape}" full_list_name "${full_list_name}")
string(REPLACE "]" "${_CloseBracketListingEscape}" full_list_name "${full_list_name}")
if(full_list_name MATCHES "[^-./:a-zA-Z0-9_]")
# The space before the start of quote is important, so that we get
# space-separated list in the final file.
string(APPEND test_names " [==[${full_list_name}]==]")
else()
string(APPEND test_names " ${full_list_name}")
endif()
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
prepare_command(set ${_TEST_LIST} ${tests})
string(APPEND script "${_Command}")
# Write any script leftovers we have
# Write any test names leftovers we have
file(APPEND "${_CTEST_LIST_FILE}" "${test_names})\n")
# Write any main script leftovers we have, and append the include of test names
file(APPEND "${_CTEST_FILE}" "${script}")
file(APPEND "${_CTEST_FILE}" "include(\"${_CTEST_LIST_FILE}\")\n")
endfunction()
# To enable `include`ing this file in the unit test scripts, we only run
+3 -1
View File
@@ -89,6 +89,7 @@ namespace Catch {
return lhs.name == rhs.name &&
lhs.outputFilename == rhs.outputFilename &&
lhs.colourMode == rhs.colourMode &&
lhs.verbosity == rhs.verbosity &&
lhs.customOptions == rhs.customOptions;
}
@@ -157,6 +158,7 @@ namespace Catch {
reporterSpec.outputFile() ? *reporterSpec.outputFile()
: data.defaultOutputFilename,
reporterSpec.colourMode().valueOr( data.defaultColourMode ),
reporterSpec.verbosity().valueOr( data.verbosity ),
reporterSpec.customOptions() } );
}
}
@@ -232,7 +234,7 @@ namespace Catch {
if ( bazelOutputFile ) {
m_data.reporterSpecifications.push_back(
{ "junit", std::string( bazelOutputFile ), {}, {} } );
{ "junit", std::string( bazelOutputFile ), {}, {}, {} } );
}
const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
+1
View File
@@ -35,6 +35,7 @@ namespace Catch {
std::string name;
std::string outputFilename;
ColourMode colourMode;
Verbosity verbosity;
std::map<std::string, std::string> customOptions;
friend bool operator==( ProcessedReporterSpec const& lhs,
ProcessedReporterSpec const& rhs );
+2
View File
@@ -52,6 +52,7 @@ namespace Catch {
ReporterConfig( config,
makeStream( spec.outputFilename ),
spec.colourMode,
spec.verbosity,
spec.customOptions ) );
}
@@ -68,6 +69,7 @@ namespace Catch {
ReporterConfig( config,
makeStream( reporterSpec.outputFilename ),
reporterSpec.colourMode,
reporterSpec.verbosity,
reporterSpec.customOptions ) ) );
}
@@ -19,10 +19,12 @@ namespace Catch {
IConfig const* _fullConfig,
Detail::unique_ptr<IStream> _stream,
ColourMode colourMode,
Verbosity verbosity,
std::map<std::string, std::string> customOptions ):
m_stream( CATCH_MOVE(_stream) ),
m_fullConfig( _fullConfig ),
m_colourMode( colourMode ),
m_verbosity( verbosity ),
m_customOptions( CATCH_MOVE( customOptions ) ) {}
Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
@@ -31,6 +33,7 @@ namespace Catch {
}
IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
Verbosity ReporterConfig::verbosity() const { return m_verbosity; }
std::map<std::string, std::string> const&
ReporterConfig::customOptions() const {
@@ -12,6 +12,7 @@
#include <catch2/catch_test_run_info.hpp>
#include <catch2/catch_totals.hpp>
#include <catch2/catch_assertion_result.hpp>
#include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/internal/catch_message_info.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_unique_ptr.hpp>
@@ -36,6 +37,7 @@ namespace Catch {
ReporterConfig( IConfig const* _fullConfig,
Detail::unique_ptr<IStream> _stream,
ColourMode colourMode,
Verbosity verbosity,
std::map<std::string, std::string> customOptions );
ReporterConfig( ReporterConfig&& ) = default;
@@ -45,12 +47,14 @@ namespace Catch {
Detail::unique_ptr<IStream> takeStream() &&;
IConfig const* fullConfig() const;
ColourMode colourMode() const;
Verbosity verbosity() const;
std::map<std::string, std::string> const& customOptions() const;
private:
Detail::unique_ptr<IStream> m_stream;
IConfig const* m_fullConfig;
ColourMode m_colourMode;
Verbosity m_verbosity;
std::map<std::string, std::string> m_customOptions;
};
@@ -93,6 +93,18 @@ namespace Catch {
return {};
}
}
Optional<Verbosity> stringToVerbosity( StringRef verbosity ) {
if (verbosity == "quiet") { return Verbosity::Quiet;
} else if ( verbosity == "normal" ) {
return Verbosity::Normal;
} else if ( verbosity == "high" ) {
return Verbosity::High;
} else {
return {};
}
}
} // namespace Detail
@@ -100,6 +112,7 @@ namespace Catch {
return lhs.m_name == rhs.m_name &&
lhs.m_outputFileName == rhs.m_outputFileName &&
lhs.m_colourMode == rhs.m_colourMode &&
lhs.m_verbosity == rhs.m_verbosity &&
lhs.m_customOptions == rhs.m_customOptions;
}
@@ -111,6 +124,7 @@ namespace Catch {
std::map<std::string, std::string> kvPairs;
Optional<std::string> outputFileName;
Optional<ColourMode> colourMode;
Optional<Verbosity> verbosity;
// First part is always reporter name, so we skip it
for ( size_t i = 1; i < parts.size(); ++i ) {
@@ -148,6 +162,12 @@ namespace Catch {
if ( !colourMode ) {
return {};
}
} else if ( key == "verbosity" ) {
// Duplicated key
if ( verbosity ) { return {}; }
verbosity = Detail::stringToVerbosity( value );
// Parsing failed
if ( !verbosity ) { return {}; }
} else {
// Unrecognized option
return {};
@@ -157,6 +177,7 @@ namespace Catch {
return ReporterSpec{ CATCH_MOVE( parts[0] ),
CATCH_MOVE( outputFileName ),
CATCH_MOVE( colourMode ),
CATCH_MOVE( verbosity),
CATCH_MOVE( kvPairs ) };
}
@@ -164,10 +185,12 @@ ReporterSpec::ReporterSpec(
std::string name,
Optional<std::string> outputFileName,
Optional<ColourMode> colourMode,
Optional<Verbosity> verbosity,
std::map<std::string, std::string> customOptions ):
m_name( CATCH_MOVE( name ) ),
m_outputFileName( CATCH_MOVE( outputFileName ) ),
m_colourMode( CATCH_MOVE( colourMode ) ),
m_verbosity( CATCH_MOVE( verbosity ) ),
m_customOptions( CATCH_MOVE( customOptions ) ) {}
} // namespace Catch
@@ -25,6 +25,7 @@ namespace Catch {
std::vector<std::string> splitReporterSpec( StringRef reporterSpec );
Optional<ColourMode> stringToColourMode( StringRef colourMode );
Optional<Verbosity> stringToVerbosity( StringRef verbosity );
}
/**
@@ -39,6 +40,7 @@ namespace Catch {
std::string m_name;
Optional<std::string> m_outputFileName;
Optional<ColourMode> m_colourMode;
Optional<Verbosity> m_verbosity;
std::map<std::string, std::string> m_customOptions;
friend bool operator==( ReporterSpec const& lhs,
@@ -53,6 +55,7 @@ namespace Catch {
std::string name,
Optional<std::string> outputFileName,
Optional<ColourMode> colourMode,
Optional<Verbosity> verbosity,
std::map<std::string, std::string> customOptions );
std::string const& name() const { return m_name; }
@@ -63,13 +66,15 @@ namespace Catch {
Optional<ColourMode> const& colourMode() const { return m_colourMode; }
Optional<Verbosity> const& verbosity() const { return m_verbosity; }
std::map<std::string, std::string> const& customOptions() const {
return m_customOptions;
}
};
/**
* Parses provided reporter spec string into
* Parses provided reporter spec string into actual `ReporterSpec`
*
* Returns empty optional on errors, e.g.
* * field that is not first and not a key+value pair
@@ -19,6 +19,7 @@ namespace Catch {
m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
m_stream( m_wrapped_stream->stream() ),
m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ),
m_verbosity( config.verbosity() ),
m_customOptions( config.customOptions() )
{}
@@ -26,12 +27,12 @@ namespace Catch {
void ReporterBase::listReporters(
std::vector<ReporterDescription> const& descriptions ) {
defaultListReporters( m_stream, descriptions, m_config->verbosity() );
defaultListReporters( m_stream, descriptions, m_verbosity );
}
void ReporterBase::listListeners(
std::vector<ListenerDescription> const& descriptions ) {
defaultListListeners( m_stream, descriptions, m_config->verbosity() );
defaultListListeners( m_stream, descriptions, m_verbosity );
}
void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
@@ -39,11 +40,11 @@ namespace Catch {
m_colour.get(),
tests,
m_config->hasTestFilters(),
m_config->verbosity());
m_verbosity);
}
void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
defaultListTags( m_stream, tags, m_config->hasTestFilters(), m_config->verbosity() );
defaultListTags( m_stream, tags, m_config->hasTestFilters(), m_verbosity );
}
} // namespace Catch
@@ -35,6 +35,8 @@ namespace Catch {
std::ostream& m_stream;
//! Colour implementation this reporter was configured for
Detail::unique_ptr<ColourImpl> m_colour;
//! Verbosity configured for this reporter
Verbosity m_verbosity;
//! The custom reporter options user passed down to the reporter
std::map<std::string, std::string> m_customOptions;
+10 -4
View File
@@ -16,6 +16,8 @@
namespace Catch {
namespace {
static size_t kJsonOutputVersion = 2;
void writeSourceInfo( JsonObjectWriter& writer,
SourceLineInfo const& sourceInfo ) {
auto source_location_writer =
@@ -58,7 +60,7 @@ namespace Catch {
m_writers.emplace( Writer::Object );
auto& writer = m_objectWriters.top();
writer.write( "version"_sr ).write( 1 );
writer.write( "version"_sr ).write( kJsonOutputVersion );
{
auto metadata_writer = writer.write( "metadata"_sr ).writeObject();
@@ -344,14 +346,18 @@ namespace Catch {
auto const& info = test.getTestCaseInfo();
desc_writer.write( "name"_sr ).write( info.name );
desc_writer.write( "class-name"_sr ).write( info.className );
{
if (!info.className.empty()) {
desc_writer.write( "class-name"_sr ).write( info.className );
}
if ( m_verbosity >= Verbosity::Normal ) {
auto tag_writer = desc_writer.write( "tags"_sr ).writeArray();
for ( auto const& tag : info.tags ) {
tag_writer.write( tag.original );
}
}
writeSourceInfo( desc_writer, info.lineInfo );
if ( m_verbosity >= Verbosity::High) {
writeSourceInfo( desc_writer, info.lineInfo );
}
}
}
void JsonReporter::listTags( std::vector<TagInfo> const& tags ) {
@@ -85,9 +85,6 @@ namespace Catch {
std::stack<Writer> m_writers{};
bool m_startedListing = false;
// std::size_t m_sectionDepth = 0;
// std::size_t m_sectionStarted = 0;
};
} // namespace Catch
+48 -2
View File
@@ -184,6 +184,13 @@ set_tests_properties(List::Tests::Output PROPERTIES
PASS_REGULAR_EXPRESSION "[0-9]+ test cases"
FAIL_REGULAR_EXPRESSION "Hidden Test"
)
add_test(NAME VerbosityIsPerReporter COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high --reporter console::verbosity=quiet)
set_tests_properties(VerbosityIsPerReporter
PROPERTIES
FAIL_REGULAR_EXPRESSION "\.cpp"
)
# This should be equivalent to the old --list-test-names-only and be usable
# with --input-file.
add_test(NAME List::Tests::Quiet COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity quiet)
@@ -193,6 +200,7 @@ set_tests_properties(List::Tests::Quiet PROPERTIES
PASS_REGULAR_EXPRESSION "\"#1905 -- test spec parser properly clears internal state between compound tests\"[\r\n]"
FAIL_REGULAR_EXPRESSION "[ \t]\"#1905 -- test spec parser properly clears internal state between compound tests\""
)
add_test(NAME List::Tests::ExitCode COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
add_test(NAME List::Tests::XmlOutput COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high -r xml)
set_tests_properties(List::Tests::XmlOutput PROPERTIES
@@ -200,6 +208,21 @@ set_tests_properties(List::Tests::XmlOutput PROPERTIES
FAIL_REGULAR_EXPRESSION "[0-9]+ test cases"
)
add_test(NAME List::Tests::Json::Normal COMMAND $<TARGET_FILE:SelfTest> --list-tests -r json)
set_tests_properties(List::Tests::Json::Normal PROPERTIES
PASS_REGULAR_EXPRESSION "\"tags\": \\["
FAIL_REGULAR_EXPRESSION "\"source-location\": {"
)
add_test(NAME List::Tests::Json::Quiet COMMAND $<TARGET_FILE:SelfTest> --list-tests -r json::verbosity=quiet)
set_tests_properties(List::Tests::Json::Quiet PROPERTIES
PASS_REGULAR_EXPRESSION "\"name\": \""
FAIL_REGULAR_EXPRESSION "\"tags\": \\["
)
add_test(NAME List::Tests::Json::High COMMAND $<TARGET_FILE:SelfTest> --list-tests -r json::verbosity=high)
set_tests_properties(List::Tests::Json::High PROPERTIES
PASS_REGULAR_EXPRESSION "\"source-location\": {"
)
add_test(NAME List::Tags::Output COMMAND $<TARGET_FILE:SelfTest> --list-tags)
set_tests_properties(List::Tags::Output PROPERTIES
PASS_REGULAR_EXPRESSION "[0-9]+ tags"
@@ -210,6 +233,11 @@ set_tests_properties(List::Tags::XmlOutput PROPERTIES
PASS_REGULAR_EXPRESSION "<Count>18</Count>"
FAIL_REGULAR_EXPRESSION "[0-9]+ tags"
)
add_test(NAME List::Tags::JsonOutput COMMAND $<TARGET_FILE:SelfTest> --list-tags -r json)
set_tests_properties(List::Tags::JsonOutput PROPERTIES
PASS_REGULAR_EXPRESSION "\"count\": 18"
FAIL_REGULAR_EXPRESSION "[0-9]+ tags"
)
add_test(NAME List::Reporters::Output COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
set_tests_properties(List::Reporters::Output PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
@@ -219,6 +247,12 @@ set_tests_properties(List::Reporters::XmlOutput PROPERTIES
PASS_REGULAR_EXPRESSION "<Name>compact</Name>"
FAIL_REGULAR_EXPRESSION "Available reporters:"
)
add_test(NAME List::Reporters::JsonOutput COMMAND $<TARGET_FILE:SelfTest> --list-reporters -r json)
set_tests_properties(List::Reporters::JsonOutput PROPERTIES
PASS_REGULAR_EXPRESSION "\"name\": \"compact\""
FAIL_REGULAR_EXPRESSION "Available reporters:"
)
add_test(NAME List::Listeners::Output
COMMAND
@@ -243,6 +277,18 @@ set_tests_properties(List::Listeners::XmlOutput
PASS_REGULAR_EXPRESSION "<RegisteredListeners>"
FAIL_REGULAR_EXPRESSION "Registered listeners:"
)
add_test(NAME List::Listeners::JsonOutput
COMMAND
$<TARGET_FILE:SelfTest>
--list-listeners
--reporter json
)
set_tests_properties(List::Listeners::JsonOutput
PROPERTIES
PASS_REGULAR_EXPRESSION "\"listeners\": \\["
FAIL_REGULAR_EXPRESSION "Registered listeners:"
)
add_test(NAME NoAssertions COMMAND $<TARGET_FILE:SelfTest> -w NoAssertions "An empty test with no assertions")
set_tests_properties(NoAssertions PROPERTIES PASS_REGULAR_EXPRESSION "No assertions in test case")
@@ -626,11 +672,11 @@ if(CATCH_ENABLE_CMAKE_HELPER_TESTS)
LABELS "uses-python"
)
add_test(NAME "CMakeHelper::PrepareCommand"
add_test(NAME "CMakeHelper::PrepareCommandFragment"
COMMAND
"${CMAKE_COMMAND}"
"-DCATCH_ADD_TESTS_SCRIPT=${CATCH_DIR}/extras/CatchAddTests.cmake"
-P "${CMAKE_CURRENT_LIST_DIR}/TestScripts/DiscoverTests/TestPrepareCommand.cmake"
-P "${CMAKE_CURRENT_LIST_DIR}/TestScripts/DiscoverTests/TestPrepareCommandFragment.cmake"
)
add_test(NAME "CMakeHelper::DecomposeJsonArray"
@@ -1531,9 +1531,9 @@ CmdLine.tests.cpp:<line number>: passed: config.noThrow == false for: false == f
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications.empty() for: true
CmdLine.tests.cpp:<line number>: passed: !(cfg.hasTestFilters()) for: !false
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs().size() == 1 for: 1 == 1
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs().size() == 1 for: 1 == 1
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("notIncluded")) == false for: false == false
@@ -1547,21 +1547,21 @@ CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("test1")) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")) for: true
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), ContainsSubstring("Unrecognized reporter") for: "Unrecognized reporter, 'unsupported'. Check available with --list-reporters" contains: "Unrecognized reporter"
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), ContainsSubstring("Only one reporter may have unspecified output file.") for: "Only one reporter may have unspecified output file." contains: "Only one reporter may have unspecified output file."
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-b"}) for: {?}
@@ -1696,7 +1696,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fa
" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: console'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fakeTag"s) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1713,7 +1713,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fak
]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fake reporter"s) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1728,7 +1728,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fak
]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1738,14 +1738,9 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fa
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
@@ -1529,9 +1529,9 @@ CmdLine.tests.cpp:<line number>: passed: config.noThrow == false for: false == f
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications.empty() for: true
CmdLine.tests.cpp:<line number>: passed: !(cfg.hasTestFilters()) for: !false
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs().size() == 1 for: 1 == 1
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs().size() == 1 for: 1 == 1
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } for: {?} == {?}
CmdLine.tests.cpp:<line number>: passed: result for: {?}
CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("notIncluded")) == false for: false == false
@@ -1545,21 +1545,21 @@ CmdLine.tests.cpp:<line number>: passed: cfg.hasTestFilters() for: true
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("test1")) == false for: false == false
CmdLine.tests.cpp:<line number>: passed: cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")) for: true
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), ContainsSubstring("Unrecognized reporter") for: "Unrecognized reporter, 'unsupported'. Check available with --list-reporters" contains: "Unrecognized reporter"
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: result for: {?} with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }) for: {?}
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
CmdLine.tests.cpp:<line number>: passed: !result for: true
CmdLine.tests.cpp:<line number>: passed: result.errorMessage(), ContainsSubstring("Only one reporter may have unspecified output file.") for: "Only one reporter may have unspecified output file." contains: "Only one reporter may have unspecified output file."
CmdLine.tests.cpp:<line number>: passed: cli.parse({"test", "-b"}) for: {?}
@@ -1694,7 +1694,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fa
" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: console'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fakeTag"s) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1711,7 +1711,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fak
]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fake reporter"s) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1726,7 +1726,7 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fak
]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -1736,14 +1736,9 @@ Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring( "fa
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
@@ -9977,7 +9977,7 @@ with expansion:
1 == 1
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } )
CHECK( cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } )
with expansion:
{?} == {?}
@@ -9987,7 +9987,7 @@ with expansion:
1 == 1
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } )
CHECK( cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } )
with expansion:
{?} == {?}
@@ -10091,7 +10091,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10113,7 +10113,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10135,7 +10135,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10176,7 +10176,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10198,7 +10198,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10219,7 +10219,7 @@ with expansion:
{?}
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } )
with expansion:
{ {?}, {?} } == { {?}, {?} }
@@ -10238,7 +10238,7 @@ with expansion:
{?}
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } )
with expansion:
{ {?}, {?} } == { {?}, {?} }
@@ -11233,7 +11233,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring("fakeTag"s) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11273,7 +11273,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring("fake reporter"s) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11311,7 +11311,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11321,14 +11321,9 @@ with expansion:
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" )
with message:
@@ -9975,7 +9975,7 @@ with expansion:
1 == 1
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } )
CHECK( cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } )
with expansion:
{?} == {?}
@@ -9985,7 +9985,7 @@ with expansion:
1 == 1
CmdLine.tests.cpp:<line number>: PASSED:
CHECK( cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } )
CHECK( cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } )
with expansion:
{?} == {?}
@@ -10089,7 +10089,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10111,7 +10111,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10133,7 +10133,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10174,7 +10174,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10196,7 +10196,7 @@ with message:
result.errorMessage() := ""
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } )
with expansion:
{ {?} } == { {?} }
with message:
@@ -10217,7 +10217,7 @@ with expansion:
{?}
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } )
with expansion:
{ {?}, {?} } == { {?}, {?} }
@@ -10236,7 +10236,7 @@ with expansion:
{?}
CmdLine.tests.cpp:<line number>: PASSED:
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } )
REQUIRE( config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } )
with expansion:
{ {?}, {?} } == { {?}, {?} }
@@ -11231,7 +11231,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring("fakeTag"s) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11271,7 +11271,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring("fake reporter"s) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11309,7 +11309,7 @@ Reporters.tests.cpp:<line number>: PASSED:
REQUIRE_THAT( listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) )
with expansion:
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -11319,14 +11319,9 @@ with expansion:
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" )
with message:
+12 -12
View File
@@ -2515,11 +2515,11 @@ ok {test-number} - !(cfg.hasTestFilters()) for: !false
# Process can be configured on command line
ok {test-number} - cfg.getReporterSpecs().size() == 1 for: 1 == 1
# Process can be configured on command line
ok {test-number} - cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } for: {?} == {?}
ok {test-number} - cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } for: {?} == {?}
# Process can be configured on command line
ok {test-number} - cfg.getProcessedReporterSpecs().size() == 1 for: 1 == 1
# Process can be configured on command line
ok {test-number} - cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } for: {?} == {?}
ok {test-number} - cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } for: {?} == {?}
# Process can be configured on command line
ok {test-number} - result for: {?}
# Process can be configured on command line
@@ -2547,15 +2547,15 @@ ok {test-number} - cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")) for:
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - !result for: true
# Process can be configured on command line
@@ -2563,19 +2563,19 @@ ok {test-number} - result.errorMessage(), ContainsSubstring("Unrecognized report
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }) for: {?}
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
# Process can be configured on command line
ok {test-number} - cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }) for: {?}
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
# Process can be configured on command line
ok {test-number} - !result for: true
# Process can be configured on command line
@@ -2767,15 +2767,15 @@ ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && Cont
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tests": [ { "name": "fake test name", "class-name": "", "tags": [ "fakeTestTag" ], "source-location": { "filename": "fake-file.cpp", "line": 123456789 } } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tests": [ { "name": "fake test name", "tags": [ "fakeTestTag" ] } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
@@ -2513,11 +2513,11 @@ ok {test-number} - !(cfg.hasTestFilters()) for: !false
# Process can be configured on command line
ok {test-number} - cfg.getReporterSpecs().size() == 1 for: 1 == 1
# Process can be configured on command line
ok {test-number} - cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} } for: {?} == {?}
ok {test-number} - cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } for: {?} == {?}
# Process can be configured on command line
ok {test-number} - cfg.getProcessedReporterSpecs().size() == 1 for: 1 == 1
# Process can be configured on command line
ok {test-number} - cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} } for: {?} == {?}
ok {test-number} - cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} } for: {?} == {?}
# Process can be configured on command line
ok {test-number} - result for: {?}
# Process can be configured on command line
@@ -2545,15 +2545,15 @@ ok {test-number} - cfg.testSpec().matches(*fakeTestCase("alwaysIncluded")) for:
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - !result for: true
# Process can be configured on command line
@@ -2561,19 +2561,19 @@ ok {test-number} - result.errorMessage(), ContainsSubstring("Unrecognized report
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - result for: {?} with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } for: { {?} } == { {?} } with 1 message: 'result.errorMessage() := ""'
# Process can be configured on command line
ok {test-number} - cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }) for: {?}
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
# Process can be configured on command line
ok {test-number} - cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }) for: {?}
# Process can be configured on command line
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
ok {test-number} - config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } } for: { {?}, {?} } == { {?}, {?} }
# Process can be configured on command line
ok {test-number} - !result for: true
# Process can be configured on command line
@@ -2765,15 +2765,15 @@ ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && Cont
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring("fakeTag"s) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tags": [ { "aliases": [ "fakeTag" ], "count": 1 } ]" contains: "fakeTag" with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring("fake reporter"s) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "reporters": [ { "name": "fake reporter", "description": "fake description" } ]" contains: "fake reporter" with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 1, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tests": [ { "name": "fake test name", "class-name": "", "tags": [ "fakeTestTag" ], "source-location": { "filename": "fake-file.cpp", "line": 123456789 } } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
ok {test-number} - listingString, ContainsSubstring( "fake test name"s ) && ContainsSubstring( "fakeTestTag"s ) for: "{ "version": 2, "metadata": { "name": "", "rng-seed": 1234, "catch2-version": "<version>" }, "listings": { "tests": [ { "name": "fake test name", "tags": [ "fakeTestTag" ] } ]" ( contains: "fake test name" and contains: "fakeTestTag" ) with 1 message: 'Tested reporter: JSON'
# Reporter's write listings to provided stream
ok {test-number} - !(factories.empty()) for: !false
# Reporter's write listings to provided stream
+13 -18
View File
@@ -11976,7 +11976,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} }
cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} }
</Original>
<Expanded>
{?} == {?}
@@ -11992,7 +11992,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} }
cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} }
</Original>
<Expanded>
{?} == {?}
@@ -12132,7 +12132,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12160,7 +12160,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12188,7 +12188,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12238,7 +12238,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12266,7 +12266,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12289,7 +12289,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?}, {?} } == { {?}, {?} }
@@ -12314,7 +12314,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?}, {?} } == { {?}, {?} }
@@ -13419,7 +13419,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13456,7 +13456,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13491,7 +13491,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13501,14 +13501,9 @@ Approx( 0.98999999999999999 )
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" )
</Expanded>
@@ -11976,7 +11976,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {} }
cfg.getReporterSpecs()[0] == Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} }
</Original>
<Expanded>
{?} == {?}
@@ -11992,7 +11992,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="CHECK" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, {} }
cfg.getProcessedReporterSpecs()[0] == Catch::ProcessedReporterSpec{ expectedReporter, std::string{}, Catch::ColourMode::PlatformDefault, Catch::Verbosity::Normal, {} }
</Original>
<Expanded>
{?} == {?}
@@ -12132,7 +12132,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12160,7 +12160,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12188,7 +12188,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "junit", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12238,7 +12238,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", "out.txt"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12266,7 +12266,7 @@ Approx( 1.21999999999999997 )
</Info>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?} } == { {?} }
@@ -12289,7 +12289,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "junit", "output-junit.xml"s, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "junit", "output-junit.xml"s, {}, {}, {} } }
</Original>
<Expanded>
{ {?}, {?} } == { {?}, {?} }
@@ -12314,7 +12314,7 @@ Approx( 1.21999999999999997 )
</Expression>
<Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" >
<Original>
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {} }, { "console", {}, {}, {} } }
config.reporterSpecifications == vec_Specs{ { "xml", "output.xml"s, {}, {}, {} }, { "console", {}, {}, {}, {} } }
</Original>
<Expanded>
{ {?}, {?} } == { {?}, {?} }
@@ -13419,7 +13419,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13456,7 +13456,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13491,7 +13491,7 @@ Approx( 0.98999999999999999 )
</Original>
<Expanded>
"{
"version": 1,
"version": 2,
"metadata": {
"name": "",
"rng-seed": 1234,
@@ -13501,14 +13501,9 @@ Approx( 0.98999999999999999 )
"tests": [
{
"name": "fake test name",
"class-name": "",
"tags": [
"fakeTestTag"
],
"source-location": {
"filename": "fake-file.cpp",
"line": 123456789
}
]
}
]" ( contains: "fake test name" and contains: "fakeTestTag" )
</Expanded>
@@ -58,12 +58,13 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK( cfg.getReporterSpecs().size() == 1 );
CHECK( cfg.getReporterSpecs()[0] ==
Catch::ReporterSpec{ expectedReporter, {}, {}, {} } );
Catch::ReporterSpec{ expectedReporter, {}, {}, {}, {} } );
CHECK( cfg.getProcessedReporterSpecs().size() == 1 );
CHECK( cfg.getProcessedReporterSpecs()[0] ==
Catch::ProcessedReporterSpec{ expectedReporter,
std::string{},
Catch::ColourMode::PlatformDefault,
Catch::Verbosity::Normal,
{} } );
}
@@ -108,7 +109,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "console", {}, {}, {} } } );
vec_Specs{ { "console", {}, {}, {}, {} } } );
}
SECTION("-r/xml") {
auto result = cli.parse({"test", "-r", "xml"});
@@ -116,7 +117,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "xml", {}, {}, {} } } );
vec_Specs{ { "xml", {}, {}, {}, {} } } );
}
SECTION("--reporter/junit") {
auto result = cli.parse({"test", "--reporter", "junit"});
@@ -124,7 +125,7 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CHECK(result);
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "junit", {}, {}, {} } } );
vec_Specs{ { "junit", {}, {}, {}, {} } } );
}
SECTION("must match one of the available ones") {
auto result = cli.parse({"test", "--reporter", "unsupported"});
@@ -137,27 +138,27 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]"
CAPTURE(result.errorMessage());
CHECK(result);
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "console", "out.txt"s, {}, {} } } );
vec_Specs{ { "console", "out.txt"s, {}, {}, {} } } );
}
SECTION("With Windows-like absolute path as output file") {
auto result = cli.parse({ "test", "-r", "console::out=C:\\Temp\\out.txt" });
CAPTURE(result.errorMessage());
CHECK(result);
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {} } } );
vec_Specs{ { "console", "C:\\Temp\\out.txt"s, {}, {}, {} } } );
}
SECTION("Multiple reporters") {
SECTION("All with output files") {
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "junit::out=output-junit.xml" }));
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "xml", "output.xml"s, {}, {} },
{ "junit", "output-junit.xml"s, {}, {} } } );
vec_Specs{ { "xml", "output.xml"s, {}, {}, {} },
{ "junit", "output-junit.xml"s, {}, {}, {} } } );
}
SECTION("Mixed output files and default output") {
CHECK(cli.parse({ "test", "-r", "xml::out=output.xml", "-r", "console" }));
REQUIRE( config.reporterSpecifications ==
vec_Specs{ { "xml", "output.xml"s, {}, {} },
{ "console", {}, {}, {} } } );
vec_Specs{ { "xml", "output.xml"s, {}, {}, {} },
{ "console", {}, {}, {}, {} } } );
}
SECTION("cannot have multiple reporters with default output") {
auto result = cli.parse({ "test", "-r", "console", "-r", "xml::out=output.xml", "-r", "junit" });
@@ -63,6 +63,20 @@ TEST_CASE( "Parsing colour mode", "[cli][colour][approvals]" ) {
}
}
TEST_CASE( "Parsing verbosity", "[cli][colour][approvals]" ) {
using Catch::Detail::stringToVerbosity;
using Catch::Verbosity;
SECTION( "Valid strings" ) {
REQUIRE( stringToVerbosity( "quiet" ) == Verbosity::Quiet );
REQUIRE( stringToVerbosity( "normal" ) == Verbosity::Normal );
REQUIRE( stringToVerbosity( "high" ) == Verbosity::High );
}
SECTION( "Wrong strings" ) {
REQUIRE_FALSE( stringToVerbosity( "QUIET" ) );
REQUIRE_FALSE( stringToVerbosity( "medium" ) );
REQUIRE_FALSE( stringToVerbosity( "vvv" ) );
}
}
TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
using Catch::parseReporterSpec;
@@ -71,12 +85,13 @@ TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
SECTION( "Correct specs" ) {
REQUIRE( parseReporterSpec( "someReporter" ) ==
ReporterSpec( "someReporter"s, {}, {}, {} ) );
ReporterSpec( "someReporter"s, {}, {}, {}, {} ) );
REQUIRE( parseReporterSpec( "otherReporter::Xk=v::out=c:\\blah" ) ==
ReporterSpec(
"otherReporter"s, "c:\\blah"s, {}, { { "Xk"s, "v"s } } ) );
"otherReporter"s, "c:\\blah"s, {}, {}, { { "Xk"s, "v"s } } ) );
REQUIRE( parseReporterSpec( "diffReporter::Xk1=v1::Xk2==v2" ) ==
ReporterSpec( "diffReporter",
{},
{},
{},
{ { "Xk1"s, "v1"s }, { "Xk2"s, "=v2"s } } ) );
@@ -85,7 +100,15 @@ TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
ReporterSpec( "Foo:bar:reporter",
{},
Catch::ColourMode::ANSI,
{},
{ { "Xk 1"s, "v 1"s }, { "Xk2"s, "v:3"s } } ) );
REQUIRE(
parseReporterSpec( "my:reporter::X1=V1::verbosity=high::X2=V2" ) ==
ReporterSpec( "my:reporter",
{},
{},
Catch::Verbosity::High,
{ { "X1"s, "V1"s }, { "X2"s, "V2"s } } ) );
}
SECTION( "Bad specs" ) {
@@ -107,5 +130,9 @@ TEST_CASE("Parsing reporter specs", "[cli][reporter-spec][approvals]") {
REQUIRE_FALSE( parseReporterSpec( "reporter::Xa=" ) );
// non-key value later field
REQUIRE_FALSE( parseReporterSpec( "reporter::Xab" ) );
// Invalid verbosity value
REQUIRE_FALSE( parseReporterSpec( "reporter::verbosity=medium" ) );
// Duplicated verbosity
REQUIRE_FALSE( parseReporterSpec( "reporter::verbosity=high::X1=X2::verbosity=high" ) );
}
}
@@ -42,6 +42,7 @@ namespace {
&config,
Catch::Detail::make_unique<StringIStream>(),
Catch::ColourMode::None,
Catch::Verbosity::Normal,
{} };
}
}
@@ -114,7 +115,7 @@ TEST_CASE( "Reporter's write listings to provided stream", "[reporters]" ) {
cfg_data.rngSeed = 1234;
Catch::Config config( cfg_data );
auto reporter = factory.second->create( Catch::ReporterConfig{
&config, CATCH_MOVE( sstream ), Catch::ColourMode::None, {} } );
&config, CATCH_MOVE( sstream ), Catch::ColourMode::None, Catch::Verbosity::Normal, {} } );
DYNAMIC_SECTION( factory.first << " reporter lists tags" ) {
std::vector<Catch::TagInfo> tags(1);
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: BSL-1.0
# Unit tests for `prepare_command` helper in `extras/CatchAddTests.cmake`.
# Unit tests for `prepare_command_fragment` helper in `extras/CatchAddTests.cmake`.
#
# Yes, we are at the stage where the script helpers need unit tests.
#
# Run as
# cmake -DCATCH_ADD_TESTS_SCRIPT=/path/to/extras/CatchAddTests.cmake \
# -P TestPrepareCommand.cmake
# -P TestPrepareCommandFragment.cmake
cmake_minimum_required(VERSION 3.19)
@@ -37,25 +37,25 @@ function(expect_equal description actual expected)
endif()
endfunction()
prepare_command(add_test SimpleName /path/to/tests)
expect_equal("Simple arg, no quotes" "${_Command}" "add_test( SimpleName /path/to/tests)\n")
prepare_command_fragment(test_fragment SimpleName /path/to/tests)
expect_equal("Simple arg, no quotes" "${test_fragment}" " SimpleName /path/to/tests")
prepare_command(add_test "Name with spaces")
expect_equal("Spaces in arg, needs quotes" "${_Command}" "add_test( [==[Name with spaces]==])\n")
prepare_command_fragment(test_fragment "Name with spaces")
expect_equal("Spaces in arg, needs quotes" "${test_fragment}" " [==[Name with spaces]==]")
prepare_command(set_tests_properties Foo PROPERTIES LABELS "tagA\;tagB\;tagC")
prepare_command_fragment(test_fragment Foo PROPERTIES LABELS "tagA\;tagB\;tagC")
expect_equal("semicolons in argument are kept and quoted"
"${_Command}" "set_tests_properties( Foo PROPERTIES LABELS [==[tagA\;tagB\;tagC]==])\n")
"${test_fragment}" " Foo PROPERTIES LABELS [==[tagA\;tagB\;tagC]==]")
set(_Command "PRE-EXISTING")
prepare_command(set_tests_properties Foo PROPERTIES BAR baz)
expect_equal("_Command var does no accumulate commands"
"${_Command}" "set_tests_properties( Foo PROPERTIES BAR baz)\n")
set(test_fragment "PRE-EXISTING")
prepare_command_fragment(test_fragment Foo PROPERTIES BAR baz)
expect_equal("out var does no accumulate commands"
"${test_fragment}" " Foo PROPERTIES BAR baz")
if(_failures GREATER 0)
message(FATAL_ERROR "${_failures} prepare_command test(s) failed")
message(FATAL_ERROR "${_failures} prepare_command_fragment test(s) failed")
else()
message(STATUS "All prepare_command tests passed")
message(STATUS "All prepare_command_fragment tests passed")
endif()
@@ -7,6 +7,7 @@
# SPDX-License-Identifier: BSL-1.0
import glob
import os
import subprocess
import sys
@@ -65,7 +66,6 @@ def build_project(sources_dir, output_base_path, catch2_path):
return build_dir
def get_test_names(build_path: str) -> List[TestInfo]:
# For now we assume that Windows builds are done using MSBuild under
# Debug configuration. This means that we need to add "Debug" folder
@@ -87,7 +87,7 @@ def get_test_names(build_path: str) -> List[TestInfo]:
with open(fname, mode='r', encoding='utf-8') as file:
test_listing = json.load(file)
assert test_listing['version'] == 1
assert test_listing['version'] == 2
tests = []
for test in test_listing['listings']['tests']:
@@ -97,6 +97,7 @@ def get_test_names(build_path: str) -> List[TestInfo]:
return tests
def get_ctest_listing(build_path):
old_path = os.getcwd()
os.chdir(build_path)
@@ -137,6 +138,7 @@ def extract_tests_from_ctest(ctest_output) -> List[TestInfo]:
return test_infos
def check_DL_PATHS(ctest_output):
ctest_response = json.loads(ctest_output)
tests = ctest_response['tests']
@@ -146,6 +148,98 @@ def check_DL_PATHS(ctest_output):
if property['name'] == 'ENVIRONMENT_MODIFICATION':
assert len(property['value']) == 2, f"The test provides 2 arguments to DL_PATHS, but instead found {len(property['value'])}"
def add_test_list_extractor(build_path: str) -> str:
# The actual CTest script file has one of two names:
# * `<target>-<short-hash>_tests.cmake` on single-config generators
# * `<target>-<short-hash>_tests-<Config>.cmake` on multi-config generators
#
# We know the target name (`tests`), so we glob for the hash part
patterns = [
os.path.join(build_path, 'tests-*_tests.cmake'),
os.path.join(build_path, 'tests-*_tests-Debug.cmake'),
]
matches = []
for pattern in patterns:
matches.extend(glob.glob(pattern))
if len(matches) != 1:
print(f"Found {len(matches)} CTest files in '{build_path}'. Expected only 1.")
exit(5)
test_script_file = matches[0]
basename = os.path.basename(test_script_file)
extractor_fname = os.path.join(build_path, 'extractor.cmake')
with open(extractor_fname, 'w') as f:
f.write(fr"""
cmake_minimum_required(VERSION 3.19)
cmake_policy(VERSION 3.19...4.4)
# This dummies out the `add_test` and `set_tests_properties` commands
# inside the CTest script, so we can include it during CMake script call.
macro(add_test)
endmacro()
macro(set_tests_properties)
endmacro()
include(${{CMAKE_CURRENT_LIST_DIR}}/{basename})
list(LENGTH tests_TESTS num_tests)
message(STATUS "NUM TESTS: ${{num_tests}}")
# '[' and ']' were escaped into ASCII 2 and 3 respectively, we have to
# unescape them back here. Note that this has to be done per-element,
# or CMake's list parsing breaks (which is why they were escaped).
string(ASCII 2 _LeftBracketListingEscape)
string(ASCII 3 _RightBracketListingEscape)
foreach(test IN LISTS tests_TESTS)
string(REPLACE "${{_LeftBracketListingEscape}}" "[" test "${{test}}")
string(REPLACE "${{_RightBracketListingEscape}}" "]" test "${{test}}")
string(REPLACE "\\" "\\\\" test "${{test}}")
string(REPLACE "\r" "\\r" test "${{test}}")
string(REPLACE "\n" "\\n" test "${{test}}")
message(STATUS "TEST_NAME: ${{test}}")
endforeach()
""")
return extractor_fname
def extract_tests_list_from_ctest_script(build_path: str) -> List[str]:
extractor = add_test_list_extractor(build_path)
cmd = ['cmake', '-P', extractor]
try:
result = subprocess.run(cmd,
capture_output = True,
check = True,
text = True)
except subprocess.CalledProcessError as err:
print('Error when calling CTest test extractor')
print(f'cmd: {err.cmd}')
print(f'stderr: {err.stderr}')
print(f'stdout: {err.stdout}')
exit(4)
lines = result.stdout.strip().split('\n')
test_num_line = lines[0]
test_lines = lines[1:]
test_num_prefix = '-- NUM TESTS: '
assert test_num_prefix in test_num_line, test_num_line
test_num_line = test_num_line[len(test_num_prefix):]
num_tests = int(test_num_line)
assert num_tests == len(test_lines), len(test_lines)
test_name_prefix = '-- TEST_NAME: '
assert all(test_name_prefix in x for x in test_lines)
test_names = [x[len(test_name_prefix):] for x in test_lines]
# Unescape the names, so that names with literal newlines have newlines in them again
test_names = [x.encode('utf-8').decode('unicode-escape') for x in test_names]
return test_names
def escape_catch2_test_names(infos: List[TestInfo]):
escaped = []
for info in infos:
@@ -155,6 +249,7 @@ def escape_catch2_test_names(infos: List[TestInfo]):
escaped.append(TestInfo(name, info.tags))
return escaped
if __name__ == '__main__':
if len(sys.argv) != 3:
print(f'Usage: {sys.argv[0]} path-to-catch2-cml output-path')
@@ -165,7 +260,8 @@ if __name__ == '__main__':
build_path = build_project(sources_dir, output_base_path, catch2_path)
catch_test_names = escape_catch2_test_names(get_test_names(build_path))
raw_catch_test_names = get_test_names(build_path)
catch_test_names = escape_catch2_test_names(raw_catch_test_names)
ctest_output = get_ctest_listing(build_path)
ctest_test_names = extract_tests_from_ctest(ctest_output)
@@ -182,7 +278,20 @@ if __name__ == '__main__':
if mismatched:
print(f"Found {mismatched} mismatched tests catch test names and ctest test commands!")
exit(1)
print(f"{len(catch_test_names)} tests matched")
print(f"{len(catch_test_names)} tests matched in CTest listing")
test_list_names = sorted(extract_tests_list_from_ctest_script(build_path))
expected_names = sorted(info.name for info in raw_catch_test_names)
if test_list_names != expected_names:
print("TEST_LIST variable (tests_TESTS) does not match Catch2 test listing!")
for name in test_list_names:
if name not in expected_names:
print(f" TEST_LIST name '{name}' not in Catch2 listing")
for name in expected_names:
if name not in test_list_names:
print(f" Catch2 name '{name}' not in TEST_LIST")
exit(1)
print(f"{len(test_list_names)} tests matched in TEST_LIST variable")
cmake_version = get_cmake_version()
if cmake_version >= (3, 27):
@@ -40,7 +40,11 @@ public:
TEST_CASE_METHOD(TestCaseFixture, "A test case as method", "[tagstagstags]") {}
TEST_CASE("Unclosed right ) parenthesis") {}
TEST_CASE("Unclosed left ( parenthesis") {}
TEST_CASE( "Newlines\nAnd\rOther\n\tWhitespace", "[whitespace-going-wild]" ) {}
TEST_CASE( "Escaped \\n newline and \\r other whitespace", "[whitespace-going-wild]") {}
// Some JSON-like and JSON-adjacent characters and substrings in the test names/tags
// This serves to test that the parse-json-via-string-splitting hack in