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

@@ -56,7 +56,7 @@
##teamcity[testIgnored name='#2615 - Throwing in constructor generator fails test case but does not abort' message='Generators.tests.cpp:<line number>|n...............................................................................|n|nGenerators.tests.cpp:<line number>|nunexpected exception with message:|n "failure to init"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
##teamcity[testFinished name='#2615 - Throwing in constructor generator fails test case but does not abort' duration="{duration}"]
##teamcity[testStarted name='#748 - captures with unexpected exceptions']
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|noutside assertions|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with message:|n "expected exception"|n {Unknown expression after the reported line}|nwith expansion:|n {Unknown expression after the reported line}|n- failure ignore as test marked as |'ok to fail|'|n']
##teamcity[testIgnored name='#748 - captures with unexpected exceptions' message='-------------------------------------------------------------------------------|ninside REQUIRE_NOTHROW|n-------------------------------------------------------------------------------|nException.tests.cpp:<line number>|n...............................................................................|n|nException.tests.cpp:<line number>|nunexpected exception with messages:|n "answer := 42"|n "expected exception"|n REQUIRE_NOTHROW( thisThrows() )|nwith expansion:|n thisThrows()|n- failure ignore as test marked as |'ok to fail|'|n']
##teamcity[testFinished name='#748 - captures with unexpected exceptions' duration="{duration}"]
##teamcity[testStarted name='#809']
@@ -239,6 +239,12 @@
##teamcity[testFinished name='CAPTURE parses string and character constants' duration="{duration}"]
##teamcity[testStarted name='Capture and info messages']
##teamcity[testFinished name='Capture and info messages' duration="{duration}"]
##teamcity[testStarted name='Captures do not leave block with an exception']
##teamcity[testFailed name='Captures do not leave block with an exception' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexpression failed with message:|n "a := 1"|n REQUIRE( false )|nwith expansion:|n false|n']
##teamcity[testFinished name='Captures do not leave block with an exception' duration="{duration}"]
##teamcity[testStarted name='Captures outlive section end']
##teamcity[testFailed name='Captures outlive section end' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexpression failed with message:|n "a := 1"|n REQUIRE( false )|nwith expansion:|n false|n']
##teamcity[testFinished name='Captures outlive section end' duration="{duration}"]
##teamcity[testStarted name='CaseInsensitiveEqualsTo is case insensitive']
##teamcity[testFinished name='CaseInsensitiveEqualsTo is case insensitive' duration="{duration}"]
##teamcity[testStarted name='CaseInsensitiveLess is case insensitive']
@@ -566,6 +572,16 @@
##teamcity[testFinished name='Scenario: This is a really long scenario name to see how the list command deals with wrapping' duration="{duration}"]
##teamcity[testStarted name='Scenario: Vector resizing affects size and capacity']
##teamcity[testFinished name='Scenario: Vector resizing affects size and capacity' duration="{duration}"]
##teamcity[testStarted name='Scoped message applies to all assertions in scope']
##teamcity[testFailed name='Scoped message applies to all assertions in scope' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexpression failed with message:|n "This will be reported multiple times"|n CHECK( false )|nwith expansion:|n false|n']
##teamcity[testFailed name='Scoped message applies to all assertions in scope' message='Message.tests.cpp:<line number>|nexpression failed with message:|n "This will be reported multiple times"|n CHECK( false )|nwith expansion:|n false|n']
##teamcity[testFinished name='Scoped message applies to all assertions in scope' duration="{duration}"]
##teamcity[testStarted name='Scoped messages do not leave block with an exception']
##teamcity[testFailed name='Scoped messages do not leave block with an exception' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexpression failed with message:|n "Should be in scope at the end"|n REQUIRE( false )|nwith expansion:|n false|n']
##teamcity[testFinished name='Scoped messages do not leave block with an exception' duration="{duration}"]
##teamcity[testStarted name='Scoped messages outlive section end']
##teamcity[testFailed name='Scoped messages outlive section end' message='Message.tests.cpp:<line number>|n...............................................................................|n|nMessage.tests.cpp:<line number>|nexpression failed with message:|n "Should survive a section end"|n REQUIRE( false )|nwith expansion:|n false|n']
##teamcity[testFinished name='Scoped messages outlive section end' duration="{duration}"]
##teamcity[testStarted name='Sends stuff to stdout and stderr']
##teamcity[testStdOut name='Sends stuff to stdout and stderr' out='A string sent directly to stdout|n']
##teamcity[testStdErr name='Sends stuff to stdout and stderr' out='A string sent directly to stderr|nA string sent to stderr via clog|n']