Regularize scoped message lifetime to only consider the object's scope

This means that:
1) Scoped messages are always removed at the end of their scope,
   even if the scope ended due to an exception.
2) Scoped messages outlive section end, if that section's scope is
   enclosed in their own.

Previously neither of these were true, which has led to a number
of surprising behaviour, where e.g. this:
```cpp
TEST_CASE() {
    try {
        INFO( "some info" );
        throw std::runtime_error( "ex" );
    } catch (std::exception const&) {}

    REQUIRE( false );
}
```
would print "some info" as the message for the assertion, while this:
```cpp
TEST_CASE() {
    INFO("Hello");
    SECTION("dummy") {}
    REQUIRE(false);
}
```
would not print out "Hello" as the message for the assertion.

This had an underlying reason, in that it was trying to helpfully
keep the messages around in case of unexpected exceptions, so that
code like this:
```cpp
TEST_CASE() {
    auto [input, expected] = GENERATE(...);
    CAPTURE(input);
    auto result = transform(input); // throws
    REQUIRE(result == expected);
}
```
would report the value of `input` when `transform` throws. However,
it was surprising in practice and was causing various issues around
handling of messages in other cases.

Closes #1759
Closes #2019
Closes #2959
This commit is contained in:
Martin Hořeňovský
2025-07-21 17:47:59 +02:00
parent 98b4bbb35e
commit 10aef62f21
22 changed files with 831 additions and 73 deletions

View File

@@ -1,32 +1,30 @@
<a id="top"></a>
# Logging macros
Additional messages can be logged during a test case. Note that the messages logged with `INFO` are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
Catch2 provides various macros for logging extra information when
running a test. These macros default to being scoped, and associate with
all assertions in the scope, regardless of whether they pass or fail.
**example**
```cpp
TEST_CASE("Foo") {
TEST_CASE("Simple info") {
INFO("Test case start");
for (int i = 0; i < 2; ++i) {
INFO("The number is " << i);
CHECK(i == 0);
SECTION("A") {
INFO("Section A");
CHECK(false); // 1
}
SECTION("B") {
INFO("Section B");
CHECK(false); // 2
}
CHECK(false); // 3
}
```
The first assertion will report messages "Test case start", and "Section A"
as extra information. The second one will report messages "Test case
started" and "Section B", while the third one will only report "Test case
started" as the extra info.
TEST_CASE("Bar") {
INFO("Test case start");
for (int i = 0; i < 2; ++i) {
INFO("The number is " << i);
CHECK(i == i);
}
CHECK(false);
}
```
When the `CHECK` fails in the "Foo" test case, then two messages will be printed.
```
Test case start
The number is 1
```
When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
## Logging without local scope