Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/Progmasoft/Catch3/Interfaces
diff options
context:
space:
mode:
authorLeitwolf2026-10-25 10:31:36 +0300
committerGitHub2026-10-25 10:31:36 +0300
commitd2e3e074bb2e1b8ffd9fc990d0b87667ea602f58 (patch)
tree0bce4462b2e190c39b3e1c5f697e3e4abd1a5e2a /src/Progmasoft/Catch3/Interfaces
parent13f81a480a93807c14dddb5abdb97355ced4d4c5 (diff)
parent126dc333564cb72b5115d9a9242d66694694b6d0 (diff)
downloadcatch3-d2e3e074bb2e1b8ffd9fc990d0b87667ea602f58.tar.gz
Merge pull request #18 from Progmasoft/build/catch3-identity
Give Catch3 its own build names and headers
Diffstat (limited to 'src/Progmasoft/Catch3/Interfaces')
-rw-r--r--src/Progmasoft/Catch3/Interfaces/All.hpp34
-rw-r--r--src/Progmasoft/Catch3/Interfaces/EventListenerFactory.cpp13
-rw-r--r--src/Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp31
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IConfig.cpp13
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IConfig.hpp103
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IEventListener.cpp68
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IEventListener.hpp183
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.cpp14
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp34
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.cpp61
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp111
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IRegistryHub.cpp14
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IRegistryHub.hpp62
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IResultCapture.cpp20
-rw-r--r--src/Progmasoft/Catch3/Interfaces/IResultCapture.hpp107
-rw-r--r--src/Progmasoft/Catch3/Interfaces/ITagAliasRegistry.hpp27
-rw-r--r--src/Progmasoft/Catch3/Interfaces/ITestCaseRegistry.cpp13
-rw-r--r--src/Progmasoft/Catch3/Interfaces/ITestCaseRegistry.hpp27
-rw-r--r--src/Progmasoft/Catch3/Interfaces/ITestInvoker.hpp21
19 files changed, 956 insertions, 0 deletions
diff --git a/src/Progmasoft/Catch3/Interfaces/All.hpp b/src/Progmasoft/Catch3/Interfaces/All.hpp
new file mode 100644
index 00000000..dd2f77f5
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/All.hpp
@@ -0,0 +1,34 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+/** \file
+ * This is a convenience header for Catch2's interfaces. It includes
+ * **all** of Catch2 headers related to interfaces.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of somewhat increased compilation
+ * times.
+ *
+ * When a new header is added to either the `interfaces` folder, or to
+ * the corresponding internal subfolder, it should be added here.
+ */
+
+
+#pragma once
+
+#include <Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Interfaces/IEventListener.hpp>
+#include <Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp>
+#include <Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp>
+#include <Progmasoft/Catch3/Interfaces/IRegistryHub.hpp>
+#include <Progmasoft/Catch3/Interfaces/IResultCapture.hpp>
+#include <Progmasoft/Catch3/Interfaces/ITagAliasRegistry.hpp>
+#include <Progmasoft/Catch3/Interfaces/ITestCaseRegistry.hpp>
+#include <Progmasoft/Catch3/Interfaces/ITestInvoker.hpp>
+
diff --git a/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.cpp b/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.cpp
new file mode 100644
index 00000000..f4bde4fb
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.cpp
@@ -0,0 +1,13 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp>
+
+namespace Catch {
+ EventListenerFactory::~EventListenerFactory() = default;
+}
diff --git a/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp b/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp
new file mode 100644
index 00000000..ae06dea1
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/EventListenerFactory.hpp
@@ -0,0 +1,31 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#pragma once
+
+#include <Progmasoft/Catch3/Internal/UniquePtr.hpp>
+#include <Progmasoft/Catch3/Internal/StringRef.hpp>
+
+#include <string>
+
+namespace Catch {
+
+ class IConfig;
+ class IEventListener;
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+
+ class EventListenerFactory {
+ public:
+ virtual ~EventListenerFactory(); // = default
+ virtual IEventListenerPtr create( IConfig const* config ) const = 0;
+ //! Return a meaningful name for the listener, e.g. its type name
+ virtual StringRef getName() const = 0;
+ //! Return listener's description if available
+ virtual std::string getDescription() const = 0;
+ };
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Interfaces/IConfig.cpp b/src/Progmasoft/Catch3/Interfaces/IConfig.cpp
new file mode 100644
index 00000000..70d1a435
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IConfig.cpp
@@ -0,0 +1,13 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+
+namespace Catch {
+ IConfig::~IConfig() = default;
+}
diff --git a/src/Progmasoft/Catch3/Interfaces/IConfig.hpp b/src/Progmasoft/Catch3/Interfaces/IConfig.hpp
new file mode 100644
index 00000000..18ce3315
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IConfig.hpp
@@ -0,0 +1,103 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#pragma once
+
+#include <Progmasoft/Catch3/Internal/NonCopyable.hpp>
+#include <Progmasoft/Catch3/Internal/StringRef.hpp>
+
+#include <chrono>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ enum class Verbosity {
+ Quiet = 0,
+ Normal,
+ High
+ };
+
+ struct WarnAbout { enum What {
+ Nothing = 0x00,
+ //! A test case or leaf section did not run any assertions
+ NoAssertions = 0x01,
+ //! A command line test spec matched no test cases
+ UnmatchedTestSpec = 0x02,
+ //! The resulting generator in GENERATE is infinite
+ InfiniteGenerator = 0x04,
+ }; };
+
+ enum class ShowDurations {
+ DefaultForReporter,
+ Always,
+ Never
+ };
+ enum class TestRunOrder {
+ Declared,
+ LexicographicallySorted,
+ Randomized
+ };
+ enum class ColourMode : std::uint8_t {
+ //! Let Catch2 pick implementation based on platform detection
+ PlatformDefault,
+ //! Use ANSI colour code escapes
+ ANSI,
+ //! Use Win32 console colour API
+ Win32,
+ //! Don't use any colour
+ None
+ };
+ struct WaitForKeypress { enum When {
+ Never,
+ BeforeStart = 1,
+ BeforeExit = 2,
+ BeforeStartAndExit = BeforeStart | BeforeExit
+ }; };
+
+ class TestSpec;
+ class IStream;
+ struct PathFilter;
+
+ class IConfig : Detail::NonCopyable {
+ public:
+ virtual ~IConfig();
+
+ virtual bool allowThrows() const = 0;
+ virtual StringRef name() const = 0;
+ virtual bool includeSuccessfulResults() const = 0;
+ virtual bool shouldDebugBreak() const = 0;
+ virtual bool warnAboutMissingAssertions() const = 0;
+ virtual bool warnAboutUnmatchedTestSpecs() const = 0;
+ virtual bool warnAboutInfiniteGenerators() const = 0;
+ virtual bool zeroTestsCountAsSuccess() const = 0;
+ virtual int abortAfter() const = 0;
+ virtual bool showInvisibles() const = 0;
+ virtual ShowDurations showDurations() const = 0;
+ virtual double minDuration() const = 0;
+ virtual TestSpec const& testSpec() const = 0;
+ virtual bool hasTestFilters() const = 0;
+ virtual std::vector<std::string> const& getTestsOrTags() const = 0;
+ virtual TestRunOrder runOrder() const = 0;
+ virtual uint32_t rngSeed() const = 0;
+ virtual unsigned int shardCount() const = 0;
+ virtual unsigned int shardIndex() const = 0;
+ virtual ColourMode defaultColourMode() const = 0;
+ virtual std::vector<PathFilter> const& getPathFilters() const = 0;
+ virtual bool useNewFilterBehaviour() const = 0;
+
+ virtual Verbosity verbosity() const = 0;
+
+ virtual bool skipBenchmarks() const = 0;
+ virtual bool benchmarkNoAnalysis() const = 0;
+ virtual unsigned int benchmarkSamples() const = 0;
+ virtual double benchmarkConfidenceInterval() const = 0;
+ virtual unsigned int benchmarkResamples() const = 0;
+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
+ };
+}
+
diff --git a/src/Progmasoft/Catch3/Interfaces/IEventListener.cpp b/src/Progmasoft/Catch3/Interfaces/IEventListener.cpp
new file mode 100644
index 00000000..933e90ce
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IEventListener.cpp
@@ -0,0 +1,68 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#include <Progmasoft/Catch3/Interfaces/IEventListener.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Message.hpp>
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+
+#include <cassert>
+
+namespace Catch {
+
+ AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals )
+ : assertionResult( _assertionResult ),
+ infoMessages( _infoMessages ),
+ totals( _totals )
+ {
+ if( assertionResult.hasMessage() ) {
+ // Copy message into messages list.
+ // !TBD This should have been done earlier, somewhere
+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+ builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
+
+ infoMessages.push_back( CATCH_MOVE(builder.m_info) );
+ }
+ }
+
+ SectionStats::SectionStats( SectionInfo&& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions )
+ : sectionInfo( CATCH_MOVE(_sectionInfo) ),
+ assertions( _assertions ),
+ durationInSeconds( _durationInSeconds ),
+ missingAssertions( _missingAssertions )
+ {}
+
+
+ TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string&& _stdOut,
+ std::string&& _stdErr,
+ bool _aborting )
+ : testInfo( &_testInfo ),
+ totals( _totals ),
+ stdOut( CATCH_MOVE(_stdOut) ),
+ stdErr( CATCH_MOVE(_stdErr) ),
+ aborting( _aborting )
+ {}
+
+
+ TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting )
+ : runInfo( _runInfo ),
+ totals( _totals ),
+ aborting( _aborting )
+ {}
+
+ IEventListener::~IEventListener() = default;
+
+} // end namespace Catch
diff --git a/src/Progmasoft/Catch3/Interfaces/IEventListener.hpp b/src/Progmasoft/Catch3/Interfaces/IEventListener.hpp
new file mode 100644
index 00000000..2d7a04dd
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IEventListener.hpp
@@ -0,0 +1,183 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#pragma once
+
+#include <Progmasoft/Catch3/SectionInfo.hpp>
+#include <Progmasoft/Catch3/TestRunInfo.hpp>
+#include <Progmasoft/Catch3/Totals.hpp>
+#include <Progmasoft/Catch3/AssertionResult.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Internal/MessageInfo.hpp>
+#include <Progmasoft/Catch3/Internal/StringRef.hpp>
+#include <Progmasoft/Catch3/Internal/UniquePtr.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkStats.hpp>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+ struct TestCaseInfo;
+ class TestCaseHandle;
+ class IConfig;
+ enum class ColourMode : std::uint8_t;
+
+ struct AssertionStats {
+ AssertionStats( AssertionResult const& _assertionResult,
+ std::vector<MessageInfo> const& _infoMessages,
+ Totals const& _totals );
+
+ AssertionStats( AssertionStats const& ) = default;
+ AssertionStats( AssertionStats && ) = default;
+ AssertionStats& operator = ( AssertionStats const& ) = delete;
+ AssertionStats& operator = ( AssertionStats && ) = delete;
+
+ AssertionResult assertionResult;
+ std::vector<MessageInfo> infoMessages;
+ Totals totals;
+ };
+
+ struct SectionStats {
+ SectionStats( SectionInfo&& _sectionInfo,
+ Counts const& _assertions,
+ double _durationInSeconds,
+ bool _missingAssertions );
+
+ SectionInfo sectionInfo;
+ Counts assertions;
+ double durationInSeconds;
+ bool missingAssertions;
+ };
+
+ struct TestCaseStats {
+ TestCaseStats( TestCaseInfo const& _testInfo,
+ Totals const& _totals,
+ std::string&& _stdOut,
+ std::string&& _stdErr,
+ bool _aborting );
+
+ TestCaseInfo const * testInfo;
+ Totals totals;
+ std::string stdOut;
+ std::string stdErr;
+ bool aborting;
+ };
+
+ struct TestRunStats {
+ TestRunStats( TestRunInfo const& _runInfo,
+ Totals const& _totals,
+ bool _aborting );
+
+ TestRunInfo runInfo;
+ Totals totals;
+ bool aborting;
+ };
+
+ //! By setting up its preferences, a reporter can modify Catch2's behaviour
+ //! in some regards, e.g. it can request Catch2 to capture writes to
+ //! stdout/stderr during test execution, and pass them to the reporter.
+ struct ReporterPreferences {
+ //! Catch2 should redirect writes to stdout and pass them to the
+ //! reporter
+ bool shouldRedirectStdOut = false;
+ //! Catch2 should call `Reporter::assertionEnded` even for passing
+ //! assertions
+ bool shouldReportAllAssertions = false;
+ //! Catch2 should call `Reporter::assertionStarting` for all assertions
+ // Defaults to true for backwards compatibility, but none of our current
+ // reporters actually want this, and it enables a fast path in assertion
+ // handling.
+ bool shouldReportAllAssertionStarts = true;
+ };
+
+ /**
+ * The common base for all reporters and event listeners
+ *
+ * Implementing classes must also implement:
+ *
+ * //! User-friendly description of the reporter/listener type
+ * static std::string getDescription()
+ *
+ * Generally shouldn't be derived from by users of Catch2 directly,
+ * instead they should derive from one of the utility bases that
+ * derive from this class.
+ */
+ class IEventListener {
+ protected:
+ //! Derived classes can set up their preferences here
+ ReporterPreferences m_preferences;
+ //! The test run's config as filled in from CLI and defaults
+ IConfig const* m_config;
+
+ public:
+ IEventListener( IConfig const* config ): m_config( config ) {}
+
+ virtual ~IEventListener(); // = default;
+
+ // Implementing class must also provide the following static methods:
+ // static std::string getDescription();
+
+ ReporterPreferences const& getPreferences() const {
+ return m_preferences;
+ }
+
+ //! Called when no test cases match provided test spec
+ virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0;
+ //! Called for all invalid test specs from the cli
+ virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0;
+
+ /**
+ * Called once in a testing run before tests are started
+ *
+ * Not called if tests won't be run (e.g. only listing will happen)
+ */
+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+
+ //! Called _once_ for each TEST_CASE, no matter how many times it is entered
+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+ //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
+ virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0;
+ //! Called when a `SECTION` is being entered. Not called for skipped sections
+ virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+ //! Called when user-code is being probed before the actual benchmark runs
+ virtual void benchmarkPreparing( StringRef benchmarkName ) = 0;
+ //! Called after probe but before the user-code is being benchmarked
+ virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0;
+ //! Called with the benchmark results if benchmark successfully finishes
+ virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0;
+ //! Called if running the benchmarks fails for any reason
+ virtual void benchmarkFailed( StringRef benchmarkName ) = 0;
+
+ //! Called before assertion success/failure is evaluated
+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+ //! Called after assertion was fully evaluated
+ virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
+
+ //! Called after a `SECTION` has finished running
+ virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+ //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
+ virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0;
+ //! Called _once_ for each TEST_CASE, no matter how many times it is entered
+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+ /**
+ * Called once after all tests in a testing run are finished
+ *
+ * Not called if tests weren't run (e.g. only listings happened)
+ */
+ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+
+ //! Called if a fatal error (signal/structured exception) occurred
+ virtual void fatalErrorEncountered( StringRef error ) = 0;
+ };
+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
+
+} // end namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.cpp b/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.cpp
new file mode 100644
index 00000000..56f87dd6
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.cpp
@@ -0,0 +1,14 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp>
+
+namespace Catch {
+ IExceptionTranslator::~IExceptionTranslator() = default;
+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
+}
diff --git a/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp b/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp
new file mode 100644
index 00000000..a47c0f3b
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IExceptionTranslator.hpp
@@ -0,0 +1,34 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#pragma once
+
+#include <Progmasoft/Catch3/Internal/UniquePtr.hpp>
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+ using exceptionTranslateFunction = std::string(*)();
+
+ class IExceptionTranslator;
+ using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
+
+ class IExceptionTranslator {
+ public:
+ virtual ~IExceptionTranslator(); // = default
+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
+ };
+
+ class IExceptionTranslatorRegistry {
+ public:
+ virtual ~IExceptionTranslatorRegistry(); // = default
+ virtual std::string translateActiveException() const = 0;
+ };
+
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.cpp b/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.cpp
new file mode 100644
index 00000000..c0a8afad
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.cpp
@@ -0,0 +1,61 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp>
+#include <Progmasoft/Catch3/Generators/Generators.hpp>
+
+#include <string>
+
+namespace Catch {
+ namespace Generators {
+
+ bool GeneratorUntypedBase::countedNext() {
+ auto ret = next();
+ if ( ret ) {
+ m_stringReprCache.clear();
+ ++m_currentElementIndex;
+ }
+ return ret;
+ }
+
+ void GeneratorUntypedBase::skipToNthElementImpl( std::size_t n ) {
+ for ( size_t i = m_currentElementIndex; i < n; ++i ) {
+ bool isValid = next();
+ if ( !isValid ) {
+ Detail::throw_generator_exception(
+ "Could not jump to Nth element: not enough elements" );
+ }
+ }
+ }
+
+ void GeneratorUntypedBase::skipToNthElement( std::size_t n ) {
+ if ( n < m_currentElementIndex ) {
+ Detail::throw_generator_exception(
+ "Tried to jump generator backwards" );
+ }
+ if ( n == m_currentElementIndex ) { return; }
+
+ skipToNthElementImpl(n);
+ // Fixup tracking after moving the generator forward
+ // * Ensure that the correct element index is set after skipping
+ // * Invalidate cache
+ m_currentElementIndex = n;
+ m_stringReprCache.clear();
+ }
+
+ StringRef GeneratorUntypedBase::currentElementAsString() const {
+ if ( m_stringReprCache.empty() ) {
+ m_stringReprCache = stringifyImpl();
+ }
+ return m_stringReprCache;
+ }
+
+ bool GeneratorUntypedBase::isFinite() const { return true; }
+
+ } // namespace Generators
+} // namespace Catch
diff --git a/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp b/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp
new file mode 100644
index 00000000..8977e32f
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IGeneratorTracker.hpp
@@ -0,0 +1,111 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+#pragma once
+
+#include <Progmasoft/Catch3/Internal/UniquePtr.hpp>
+#include <Progmasoft/Catch3/Internal/StringRef.hpp>
+
+#include <string>
+
+namespace Catch {
+
+ namespace Generators {
+ class GeneratorUntypedBase {
+ // Caches result from `toStringImpl`, assume that when it is an
+ // empty string, the cache is invalidated.
+ mutable std::string m_stringReprCache;
+
+ // Counts based on `next` returning true
+ std::size_t m_currentElementIndex = 0;
+
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Returns true iff the move succeeded (and a valid element
+ * can be retrieved).
+ */
+ virtual bool next() = 0;
+
+ //! Customization point for `currentElementAsString`
+ virtual std::string stringifyImpl() const = 0;
+
+ /**
+ * Customization point for skipping to the n-th element
+ *
+ * Defaults to successively calling `countedNext`. If there
+ * are not enough elements to reach the nth one, will throw
+ * an error.
+ */
+ virtual void skipToNthElementImpl( std::size_t n );
+
+ public:
+ GeneratorUntypedBase() = default;
+ // Generation of copy ops is deprecated (and Clang will complain)
+ // if there is a user destructor defined
+ GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
+ GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
+
+ virtual ~GeneratorUntypedBase(); // = default;
+
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Serves as a non-virtual interface to `next`, so that the
+ * top level interface can provide sanity checking and shared
+ * features.
+ *
+ * As with `next`, returns true iff the move succeeded and
+ * the generator has new valid element to provide.
+ */
+ bool countedNext();
+
+ std::size_t currentElementIndex() const { return m_currentElementIndex; }
+
+ /**
+ * Moves the generator forward **to** the n-th element
+ *
+ * Cannot move backwards. Can stay in place.
+ */
+ void skipToNthElement( std::size_t n );
+
+ /**
+ * Returns generator's current element as user-friendly string.
+ *
+ * By default returns string equivalent to calling
+ * `Catch::Detail::stringify` on the current element, but generators
+ * can customize their implementation as needed.
+ *
+ * Not thread-safe due to internal caching.
+ *
+ * The returned ref is valid only until the generator instance
+ * is destructed, or it moves onto the next element, whichever
+ * comes first.
+ */
+ StringRef currentElementAsString() const;
+
+ /**
+ * Returns true if calls to `next` will eventually return false
+ *
+ * Note that for backwards compatibility this is currently defaulted
+ * to return `true`, but in the future all generators will have to
+ * provide their own implementation.
+ */
+ virtual bool isFinite() const;
+ };
+ using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
+
+ } // namespace Generators
+
+ class IGeneratorTracker {
+ public:
+ virtual ~IGeneratorTracker(); // = default;
+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+ };
+
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Interfaces/IRegistryHub.cpp b/src/Progmasoft/Catch3/Interfaces/IRegistryHub.cpp
new file mode 100644
index 00000000..fee2b7e9
--- /dev/null
+++ b/src/Progmasoft/Catch3/Interfaces/IRegistryHub.cpp
@@ -0,0 +1,14 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost