catch_run_context.cpp
1 2 // Copyright Catch2 Authors 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE.txt or copy at 5 // https://www.boost.org/LICENSE_1_0.txt) 6 7 // SPDX-License-Identifier: BSL-1.0 8 #include <catch2/internal/catch_run_context.hpp> 9 10 #include <catch2/catch_user_config.hpp> 11 #include <catch2/interfaces/catch_interfaces_config.hpp> 12 #include <catch2/interfaces/catch_interfaces_generatortracker.hpp> 13 #include <catch2/interfaces/catch_interfaces_reporter.hpp> 14 #include <catch2/internal/catch_compiler_capabilities.hpp> 15 #include <catch2/internal/catch_context.hpp> 16 #include <catch2/internal/catch_enforce.hpp> 17 #include <catch2/internal/catch_fatal_condition_handler.hpp> 18 #include <catch2/internal/catch_random_number_generator.hpp> 19 #include <catch2/catch_timer.hpp> 20 #include <catch2/internal/catch_output_redirect.hpp> 21 #include <catch2/internal/catch_assertion_handler.hpp> 22 #include <catch2/internal/catch_test_failure_exception.hpp> 23 #include <catch2/internal/catch_result_type.hpp> 24 25 #include <cassert> 26 #include <algorithm> 27 28 namespace Catch { 29 30 namespace Generators { 31 namespace { 32 struct GeneratorTracker final : TestCaseTracking::TrackerBase, 33 IGeneratorTracker { 34 GeneratorBasePtr m_generator; 35 36 GeneratorTracker( 37 TestCaseTracking::NameAndLocation&& nameAndLocation, 38 TrackerContext& ctx, 39 ITracker* parent ): 40 TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {} 41 ~GeneratorTracker() override = default; 42 43 static GeneratorTracker* 44 acquire( TrackerContext& ctx, 45 TestCaseTracking::NameAndLocationRef const& 46 nameAndLocation ) { 47 GeneratorTracker* tracker; 48 49 ITracker& currentTracker = ctx.currentTracker(); 50 // Under specific circumstances, the generator we want 51 // to acquire is also the current tracker. If this is 52 // the case, we have to avoid looking through current 53 // tracker's children, and instead return the current 54 // tracker. 55 // A case where this check is important is e.g. 56 // for (int i = 0; i < 5; ++i) { 57 // int n = GENERATE(1, 2); 58 // } 59 // 60 // without it, the code above creates 5 nested generators. 61 if ( currentTracker.nameAndLocation() == nameAndLocation ) { 62 auto thisTracker = currentTracker.parent()->findChild( 63 nameAndLocation ); 64 assert( thisTracker ); 65 assert( thisTracker->isGeneratorTracker() ); 66 tracker = static_cast<GeneratorTracker*>( thisTracker ); 67 } else if ( ITracker* childTracker = 68 currentTracker.findChild( 69 nameAndLocation ) ) { 70 assert( childTracker ); 71 assert( childTracker->isGeneratorTracker() ); 72 tracker = 73 static_cast<GeneratorTracker*>( childTracker ); 74 } else { 75 return nullptr; 76 } 77 78 if ( !tracker->isComplete() ) { tracker->open(); } 79 80 return tracker; 81 } 82 83 // TrackerBase interface 84 bool isGeneratorTracker() const override { return true; } 85 auto hasGenerator() const -> bool override { 86 return !!m_generator; 87 } 88 void close() override { 89 TrackerBase::close(); 90 // If a generator has a child (it is followed by a section) 91 // and none of its children have started, then we must wait 92 // until later to start consuming its values. 93 // This catches cases where `GENERATE` is placed between two 94 // `SECTION`s. 95 // **The check for m_children.empty cannot be removed**. 96 // doing so would break `GENERATE` _not_ followed by 97 // `SECTION`s. 98 const bool should_wait_for_child = [&]() { 99 // No children -> nobody to wait for 100 if ( m_children.empty() ) { return false; } 101 // If at least one child started executing, don't wait 102 if ( std::find_if( 103 m_children.begin(), 104 m_children.end(), 105 []( TestCaseTracking::ITrackerPtr const& 106 tracker ) { 107 return tracker->hasStarted(); 108 } ) != m_children.end() ) { 109 return false; 110 } 111 112 // No children have started. We need to check if they 113 // _can_ start, and thus we should wait for them, or 114 // they cannot start (due to filters), and we shouldn't 115 // wait for them 116 ITracker* parent = m_parent; 117 // This is safe: there is always at least one section 118 // tracker in a test case tracking tree 119 while ( !parent->isSectionTracker() ) { 120 parent = parent->parent(); 121 } 122 assert( parent && 123 "Missing root (test case) level section" ); 124 125 auto const& parentSection = 126 static_cast<SectionTracker const&>( *parent ); 127 auto const& filters = parentSection.getFilters(); 128 // No filters -> no restrictions on running sections 129 if ( filters.empty() ) { return true; } 130 131 for ( auto const& child : m_children ) { 132 if ( child->isSectionTracker() && 133 std::find( filters.begin(), 134 filters.end(), 135 static_cast<SectionTracker const&>( 136 *child ) 137 .trimmedName() ) != 138 filters.end() ) { 139 return true; 140 } 141 } 142 return false; 143 }(); 144 145 // This check is a bit tricky, because m_generator->next() 146 // has a side-effect, where it consumes generator's current 147 // value, but we do not want to invoke the side-effect if 148 // this generator is still waiting for any child to start. 149 assert( m_generator && "Tracker without generator" ); 150 if ( should_wait_for_child || 151 ( m_runState == CompletedSuccessfully && 152 m_generator->countedNext() ) ) { 153 m_children.clear(); 154 m_runState = Executing; 155 } 156 } 157 158 // IGeneratorTracker interface 159 auto getGenerator() const -> GeneratorBasePtr const& override { 160 return m_generator; 161 } 162 void setGenerator( GeneratorBasePtr&& generator ) override { 163 m_generator = CATCH_MOVE( generator ); 164 } 165 }; 166 } // namespace 167 } 168 169 RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) 170 : m_runInfo(_config->name()), 171 m_config(_config), 172 m_reporter(CATCH_MOVE(reporter)), 173 m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, 174 m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) 175 { 176 getCurrentMutableContext().setResultCapture( this ); 177 m_reporter->testRunStarting(m_runInfo); 178 } 179 180 RunContext::~RunContext() { 181 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); 182 } 183 184 Totals RunContext::runTest(TestCaseHandle const& testCase) { 185 const Totals prevTotals = m_totals; 186 187 auto const& testInfo = testCase.getTestCaseInfo(); 188 m_reporter->testCaseStarting(testInfo); 189 m_activeTestCase = &testCase; 190 191 192 ITracker& rootTracker = m_trackerContext.startRun(); 193 assert(rootTracker.isSectionTracker()); 194 static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); 195 196 // We intentionally only seed the internal RNG once per test case, 197 // before it is first invoked. The reason for that is a complex 198 // interplay of generator/section implementation details and the 199 // Random*Generator types. 200 // 201 // The issue boils down to us needing to seed the Random*Generators 202 // with different seed each, so that they return different sequences 203 // of random numbers. We do this by giving them a number from the 204 // shared RNG instance as their seed. 205 // 206 // However, this runs into an issue if the reseeding happens each 207 // time the test case is entered (as opposed to first time only), 208 // because multiple generators could get the same seed, e.g. in 209 // ```cpp 210 // TEST_CASE() { 211 // auto i = GENERATE(take(10, random(0, 100)); 212 // SECTION("A") { 213 // auto j = GENERATE(take(10, random(0, 100)); 214 // } 215 // SECTION("B") { 216 // auto k = GENERATE(take(10, random(0, 100)); 217 // } 218 // } 219 // ``` 220 // `i` and `j` would properly return values from different sequences, 221 // but `i` and `k` would return the same sequence, because their seed 222 // would be the same. 223 // (The reason their seeds would be the same is that the generator 224 // for k would be initialized when the test case is entered the second 225 // time, after the shared RNG instance was reset to the same value 226 // it had when the generator for i was initialized.) 227 seedRng( *m_config ); 228 229 uint64_t testRuns = 0; 230 std::string redirectedCout; 231 std::string redirectedCerr; 232 do { 233 m_trackerContext.startCycle(); 234 m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); 235 236 m_reporter->testCasePartialStarting(testInfo, testRuns); 237 238 const auto beforeRunTotals = m_totals; 239 std::string oneRunCout, oneRunCerr; 240 runCurrentTest(oneRunCout, oneRunCerr); 241 redirectedCout += oneRunCout; 242 redirectedCerr += oneRunCerr; 243 244 const auto singleRunTotals = m_totals.delta(beforeRunTotals); 245 auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting()); 246 247 m_reporter->testCasePartialEnded(statsForOneRun, testRuns); 248 ++testRuns; 249 } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); 250 251 Totals deltaTotals = m_totals.delta(prevTotals); 252 if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { 253 deltaTotals.assertions.failed++; 254 deltaTotals.testCases.passed--; 255 deltaTotals.testCases.failed++; 256 } 257 m_totals.testCases += deltaTotals.testCases; 258 m_reporter->testCaseEnded(TestCaseStats(testInfo, 259 deltaTotals, 260 CATCH_MOVE(redirectedCout), 261 CATCH_MOVE(redirectedCerr), 262 aborting())); 263 264 m_activeTestCase = nullptr; 265 m_testCaseTracker = nullptr; 266 267 return deltaTotals; 268 } 269 270 271 void RunContext::assertionEnded(AssertionResult&& result) { 272 if (result.getResultType() == ResultWas::Ok) { 273 m_totals.assertions.passed++; 274 m_lastAssertionPassed = true; 275 } else if (result.getResultType() == ResultWas::ExplicitSkip) { 276 m_totals.assertions.skipped++; 277 m_lastAssertionPassed = true; 278 } else if (!result.succeeded()) { 279 m_lastAssertionPassed = false; 280 if (result.isOk()) { 281 } 282 else if( m_activeTestCase->getTestCaseInfo().okToFail() ) 283 m_totals.assertions.failedButOk++; 284 else 285 m_totals.assertions.failed++; 286 } 287 else { 288 m_lastAssertionPassed = true; 289 } 290 291 m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); 292 293 if ( result.getResultType() != ResultWas::Warning ) { 294 m_messageScopes.clear(); 295 } 296 297 // Reset working state. assertion info will be reset after 298 // populateReaction is run if it is needed 299 m_lastResult = CATCH_MOVE( result ); 300 } 301 void RunContext::resetAssertionInfo() { 302 m_lastAssertionInfo.macroName = StringRef(); 303 m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; 304 m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal; 305 } 306 307 void RunContext::notifyAssertionStarted( AssertionInfo const& info ) { 308 m_reporter->assertionStarting( info ); 309 } 310 311 bool RunContext::sectionStarted( StringRef sectionName, 312 SourceLineInfo const& sectionLineInfo, 313 Counts& assertions ) { 314 ITracker& sectionTracker = 315 SectionTracker::acquire( m_trackerContext, 316 TestCaseTracking::NameAndLocationRef( 317 sectionName, sectionLineInfo ) ); 318 319 if (!sectionTracker.isOpen()) 320 return false; 321 m_activeSections.push_back(§ionTracker); 322 323 SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) ); 324 m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; 325 326 m_reporter->sectionStarting(sectionInfo); 327 328 assertions = m_totals.assertions; 329 330 return true; 331 } 332 IGeneratorTracker* 333 RunContext::acquireGeneratorTracker( StringRef generatorName, 334 SourceLineInfo const& lineInfo ) { 335 using namespace Generators; 336 GeneratorTracker* tracker = GeneratorTracker::acquire( 337 m_trackerContext, 338 TestCaseTracking::NameAndLocationRef( 339 generatorName, lineInfo ) ); 340 m_lastAssertionInfo.lineInfo = lineInfo; 341 return tracker; 342 } 343 344 IGeneratorTracker* RunContext::createGeneratorTracker( 345 StringRef generatorName, 346 SourceLineInfo lineInfo, 347 Generators::GeneratorBasePtr&& generator ) { 348 349 auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo ); 350 auto& currentTracker = m_trackerContext.currentTracker(); 351 assert( 352 currentTracker.nameAndLocation() != nameAndLoc && 353 "Trying to create tracker for a genreator that already has one" ); 354 355 auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>( 356 CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); 357 auto ret = newTracker.get(); 358 currentTracker.addChild( CATCH_MOVE( newTracker ) ); 359 360 ret->setGenerator( CATCH_MOVE( generator ) ); 361 ret->open(); 362 return ret; 363 } 364 365 bool RunContext::testForMissingAssertions(Counts& assertions) { 366 if (assertions.total() != 0) 367 return false; 368 if (!m_config->warnAboutMissingAssertions()) 369 return false; 370 if (m_trackerContext.currentTracker().hasChildren()) 371 return false; 372 m_totals.assertions.failed++; 373 assertions.failed++; 374 return true; 375 } 376 377 void RunContext::sectionEnded(SectionEndInfo&& endInfo) { 378 Counts assertions = m_totals.assertions - endInfo.prevAssertions; 379 bool missingAssertions = testForMissingAssertions(assertions); 380 381 if (!m_activeSections.empty()) { 382 m_activeSections.back()->close(); 383 m_activeSections.pop_back(); 384 } 385 386 m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions)); 387 m_messages.clear(); 388 m_messageScopes.clear(); 389 } 390 391 void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) { 392 if ( m_unfinishedSections.empty() ) { 393 m_activeSections.back()->fail(); 394 } else { 395 m_activeSections.back()->close(); 396 } 397 m_activeSections.pop_back(); 398 399 m_unfinishedSections.push_back(CATCH_MOVE(endInfo)); 400 } 401 402 void RunContext::benchmarkPreparing( StringRef name ) { 403 m_reporter->benchmarkPreparing(name); 404 } 405 void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { 406 m_reporter->benchmarkStarting( info ); 407 } 408 void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { 409 m_reporter->benchmarkEnded( stats ); 410 } 411 void RunContext::benchmarkFailed( StringRef error ) { 412 m_reporter->benchmarkFailed( error ); 413 } 414 415 void RunContext::pushScopedMessage(MessageInfo const & message) { 416 m_messages.push_back(message); 417 } 418 419 void RunContext::popScopedMessage(MessageInfo const & message) { 420 m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); 421 } 422 423 void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { 424 m_messageScopes.emplace_back( CATCH_MOVE(builder) ); 425 } 426 427 std::string RunContext::getCurrentTestName() const { 428 return m_activeTestCase 429 ? m_activeTestCase->getTestCaseInfo().name 430 : std::string(); 431 } 432 433 const AssertionResult * RunContext::getLastResult() const { 434 return &(*m_lastResult); 435 } 436 437 void RunContext::exceptionEarlyReported() { 438 m_shouldReportUnexpected = false; 439 } 440 441 void RunContext::handleFatalErrorCondition( StringRef message ) { 442 // First notify reporter that bad things happened 443 m_reporter->fatalErrorEncountered(message); 444 445 // Don't rebuild the result -- the stringification itself can cause more fatal errors 446 // Instead, fake a result data. 447 AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); 448 tempResult.message = static_cast<std::string>(message); 449 AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); 450 451 assertionEnded(CATCH_MOVE(result) ); 452 resetAssertionInfo(); 453 454 handleUnfinishedSections(); 455 456 // Recreate section for test case (as we will lose the one that was in scope) 457 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); 458 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); 459 460 Counts assertions; 461 assertions.failed = 1; 462 SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false); 463 m_reporter->sectionEnded(testCaseSectionStats); 464 465 auto const& testInfo = m_activeTestCase->getTestCaseInfo(); 466 467 Totals deltaTotals; 468 deltaTotals.testCases.failed = 1; 469 deltaTotals.assertions.failed = 1; 470 m_reporter->testCaseEnded(TestCaseStats(testInfo, 471 deltaTotals, 472 std::string(), 473 std::string(), 474 false)); 475 m_totals.testCases.failed++; 476 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); 477 } 478 479 bool RunContext::lastAssertionPassed() { 480 return m_lastAssertionPassed; 481 } 482 483 void RunContext::assertionPassed() { 484 m_lastAssertionPassed = true; 485 ++m_totals.assertions.passed; 486 resetAssertionInfo(); 487 m_messageScopes.clear(); 488 } 489 490 bool RunContext::aborting() const { 491 return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter()); 492 } 493 494 void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { 495 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); 496 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); 497 m_reporter->sectionStarting(testCaseSection); 498 Counts prevAssertions = m_totals.assertions; 499 double duration = 0; 500 m_shouldReportUnexpected = true; 501 m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; 502 503 Timer timer; 504 CATCH_TRY { 505 if (m_reporter->getPreferences().shouldRedirectStdOut) { 506 #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) 507 RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); 508 509 timer.start(); 510 invokeActiveTestCase(); 511 #else 512 OutputRedirect r(redirectedCout, redirectedCerr); 513 timer.start(); 514 invokeActiveTestCase(); 515 #endif 516 } else { 517 timer.start(); 518 invokeActiveTestCase(); 519 } 520 duration = timer.getElapsedSeconds(); 521 } CATCH_CATCH_ANON (TestFailureException&) { 522 // This just means the test was aborted due to failure 523 } CATCH_CATCH_ANON (TestSkipException&) { 524 // This just means the test was explicitly skipped 525 } CATCH_CATCH_ALL { 526 // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions 527 // are reported without translation at the point of origin. 528 if( m_shouldReportUnexpected ) { 529 AssertionReaction dummyReaction; 530 handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); 531 } 532 } 533 Counts assertions = m_totals.assertions - prevAssertions; 534 bool missingAssertions = testForMissingAssertions(assertions); 535 536 m_testCaseTracker->close(); 537 handleUnfinishedSections(); 538 m_messages.clear(); 539 m_messageScopes.clear(); 540 541 SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); 542 m_reporter->sectionEnded(testCaseSectionStats); 543 } 544 545 void RunContext::invokeActiveTestCase() { 546 // We need to engage a handler for signals/structured exceptions 547 // before running the tests themselves, or the binary can crash 548 // without failed test being reported. 549 FatalConditionHandlerGuard _(&m_fatalConditionhandler); 550 // We keep having issue where some compilers warn about an unused 551 // variable, even though the type has non-trivial constructor and 552 // destructor. This is annoying and ugly, but it makes them stfu. 553 (void)_; 554 555 m_activeTestCase->invoke(); 556 } 557 558 void RunContext::handleUnfinishedSections() { 559 // If sections ended prematurely due to an exception we stored their 560 // infos here so we can tear them down outside the unwind process. 561 for (auto it = m_unfinishedSections.rbegin(), 562 itEnd = m_unfinishedSections.rend(); 563 it != itEnd; 564 ++it) 565 sectionEnded(CATCH_MOVE(*it)); 566 m_unfinishedSections.clear(); 567 } 568 569 void RunContext::handleExpr( 570 AssertionInfo const& info, 571 ITransientExpression const& expr, 572 AssertionReaction& reaction 573 ) { 574 bool negated = isFalseTest( info.resultDisposition ); 575 bool result = expr.getResult() != negated; 576 577 if( result ) { 578 if (!m_includeSuccessfulResults) { 579 assertionPassed(); 580 } 581 else { 582 reportExpr(info, ResultWas::Ok, &expr, negated); 583 } 584 } 585 else { 586 reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); 587 populateReaction( reaction ); 588 } 589 resetAssertionInfo(); 590 } 591 void RunContext::reportExpr( 592 AssertionInfo const &info, 593 ResultWas::OfType resultType, 594 ITransientExpression const *expr, 595 bool negated ) { 596 597 m_lastAssertionInfo = info; 598 AssertionResultData data( resultType, LazyExpression( negated ) ); 599 600 AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; 601 assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; 602 603 assertionEnded( CATCH_MOVE(assertionResult) ); 604 } 605 606 void RunContext::handleMessage( 607 AssertionInfo const& info, 608 ResultWas::OfType resultType, 609 StringRef message, 610 AssertionReaction& reaction 611 ) { 612 m_lastAssertionInfo = info; 613 614 AssertionResultData data( resultType, LazyExpression( false ) ); 615 data.message = static_cast<std::string>(message); 616 AssertionResult assertionResult{ m_lastAssertionInfo, 617 CATCH_MOVE( data ) }; 618 619 const auto isOk = assertionResult.isOk(); 620 assertionEnded( CATCH_MOVE(assertionResult) ); 621 if ( !isOk ) { 622 populateReaction( reaction ); 623 } else if ( resultType == ResultWas::ExplicitSkip ) { 624 // TODO: Need to handle this explicitly, as ExplicitSkip is 625 // considered "OK" 626 reaction.shouldSkip = true; 627 } 628 resetAssertionInfo(); 629 } 630 void RunContext::handleUnexpectedExceptionNotThrown( 631 AssertionInfo const& info, 632 AssertionReaction& reaction 633 ) { 634 handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); 635 } 636 637 void RunContext::handleUnexpectedInflightException( 638 AssertionInfo const& info, 639 std::string&& message, 640 AssertionReaction& reaction 641 ) { 642 m_lastAssertionInfo = info; 643 644 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); 645 data.message = CATCH_MOVE(message); 646 AssertionResult assertionResult{ info, CATCH_MOVE(data) }; 647 assertionEnded( CATCH_MOVE(assertionResult) ); 648 populateReaction( reaction ); 649 resetAssertionInfo(); 650 } 651 652 void RunContext::populateReaction( AssertionReaction& reaction ) { 653 reaction.shouldDebugBreak = m_config->shouldDebugBreak(); 654 reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); 655 } 656 657 void RunContext::handleIncomplete( 658 AssertionInfo const& info 659 ) { 660 using namespace std::string_literals; 661 m_lastAssertionInfo = info; 662 663 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); 664 data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; 665 AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; 666 assertionEnded( CATCH_MOVE(assertionResult) ); 667 resetAssertionInfo(); 668 } 669 void RunContext::handleNonExpr( 670 AssertionInfo const &info, 671 ResultWas::OfType resultType, 672 AssertionReaction &reaction 673 ) { 674 m_lastAssertionInfo = info; 675 676 AssertionResultData data( resultType, LazyExpression( false ) ); 677 AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; 678 679 const auto isOk = assertionResult.isOk(); 680 assertionEnded( CATCH_MOVE(assertionResult) ); 681 if ( !isOk ) { populateReaction( reaction ); } 682 resetAssertionInfo(); 683 } 684 685 686 IResultCapture& getResultCapture() { 687 if (auto* capture = getCurrentContext().getResultCapture()) 688 return *capture; 689 else 690 CATCH_INTERNAL_ERROR("No result capture instance"); 691 } 692 693 void seedRng(IConfig const& config) { 694 sharedRng().seed(config.rngSeed()); 695 } 696 697 unsigned int rngSeed() { 698 return getCurrentContext().getConfig()->rngSeed(); 699 } 700 701 }