/ externals / catch / src / catch2 / internal / catch_run_context.cpp
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(&sectionTracker);
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, &currentTracker );
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  }