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

summaryrefslogtreecommitdiffhomepage
path: root/src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp
diff options
context:
space:
mode:
authorLeitwolf112026-10-25 02:37:35 +0300
committerLeitwolf112026-10-25 02:37:35 +0300
commit126dc333564cb72b5115d9a9242d66694694b6d0 (patch)
tree0bce4462b2e190c39b3e1c5f697e3e4abd1a5e2a /src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp
parent13f81a480a93807c14dddb5abdb97355ced4d4c5 (diff)
downloadcatch3-126dc333564cb72b5115d9a9242d66694694b6d0.tar.gz
Give Catch3 its own build names and headers
Catch2 compatibility means the API tests are written in: the macros, such as TEST_CASE and REQUIRE, and the Catch:: namespace. It does not mean Catch2's build names or header paths. find_package(Catch2) found Catch3, and a project using both frameworks met two packages, two sets of targets, two Catch.cmake modules and two catch2/ header trees with the same names. Build names: - CMake: project and package Catch3, targets Catch3::Catch3 and Catch3::Catch3WithMain, libraries Catch3 and Catch3Main, options CATCH3_*, lib/cmake/Catch3 with Catch3Config, and pkg-config catch3 and catch3-with-main. The version is Catch3's, 0.3.0, compatible within a minor version. - The CMake scripts are Catch3.cmake (catch3_discover_tests), Catch3AddTests.cmake and Catch3ShardTests.cmake (catch3_add_sharded_tests); the helpers they define at ctest time have a catch3_ prefix. ParseAndAddCatchTests.cmake, deprecated upstream, is gone. - Bazel //:catch3 and //:catch3_main, Meson catch3 and catch3-with-main (with override_dependency), Xmake catch3 and catch3_main, Premake Catch3 and Catch3WithMain. Visual Studio projects get GUIDs of their own. - The Progmasoft::Catch3 target and package are gone: property testing and snapshots are part of Catch3::Catch3. Their sources now build with the library's warning flags, so property failures are built field by field (no missing initializers) and the default property name is a thread-local pointer to the name its scope owns (no global destructor). Headers: the engine moved from src/catch2 to src/Progmasoft/Catch3 with Progmasoft names, so <catch2/catch_test_macros.hpp> is <Progmasoft/Catch3/TestMacros.hpp>, <catch2/matchers/catch_matchers_string.hpp> is <Progmasoft/Catch3/Matchers/String.hpp>, and interface headers are named after their interface, such as Interfaces/IConfig.hpp. Include guards became #pragma once. The installed headers go to include/Progmasoft. src/Progmasoft/Context.cpp is StrategyContext.cpp, so no two sources share a file name. tools/scripts/upstreamFiles.txt lists the files that come from Catch2. The license check expects BSL-1.0 on them and Progmasoft's header on the rest of src/Progmasoft; the convenience-header check, the amalgamation script and the surrogate tests take the engine's headers from it. The amalgamated files are regenerated. The header-guard workflow checks for #pragma once instead of checkguard. Documents, the README and the release notes describe the new names.
Diffstat (limited to 'src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp')
-rw-r--r--src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp b/src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp
new file mode 100644
index 00000000..3adf00eb
--- /dev/null
+++ b/src/Progmasoft/Catch3/Internal/TestCaseRegistryImpl.cpp
@@ -0,0 +1,180 @@
+
+// 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/Internal/TestCaseRegistryImpl.hpp>
+
+#include <Progmasoft/Catch3/Internal/Enforce.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Interfaces/IRegistryHub.hpp>
+#include <Progmasoft/Catch3/TestCaseInfo.hpp>
+#include <Progmasoft/Catch3/TestSpec.hpp>
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+#include <Progmasoft/Catch3/Internal/TestCaseInfoHasher.hpp>
+
+#include <algorithm>
+
+namespace Catch {
+
+ namespace {
+ // Picked small-ish number at random
+ static size_t kInitialTestCount = 120;
+
+ static void enforceNoDuplicateTestCases(
+ std::vector<TestCaseHandle> const& tests ) {
+ // Flat set instead of std::set for performance.
+ std::vector<TestCaseInfo const*> seenTests;
+ seenTests.reserve( tests.size() );
+ for ( auto const& test : tests ) {
+ seenTests.push_back( &test.getTestCaseInfo() );
+ }
+ // We want to keep order of ~equal~ tests
+ // stable_sort so that duplicates are reported with the
+ // registration order preserved ("first seen" really is first)
+ std::stable_sort(
+ seenTests.begin(),
+ seenTests.end(),
+ []( TestCaseInfo const* lhs, TestCaseInfo const* rhs ) {
+ return *lhs < *rhs;
+ }
+ );
+ const auto duplicate = std::adjacent_find(
+ seenTests.begin(),
+ seenTests.end(),
+ []( TestCaseInfo const* lhs, TestCaseInfo const* rhs ) {
+ return *lhs == *rhs;
+ }
+ );
+
+ if ( duplicate != seenTests.end() ) {
+ const auto infoPtr = *std::next( duplicate );
+ CATCH_ERROR( "error: test case \""
+ << infoPtr->name << "\", with tags \""
+ << infoPtr->tagsAsString()
+ << "\" already defined.\n"
+ << "\tFirst seen at "
+ << ( *duplicate )->lineInfo << "\n"
+ << "\tRedefined at " << infoPtr->lineInfo );
+ }
+ }
+
+ static bool matchTest( TestCaseHandle const& testCase,
+ TestSpec const& testSpec,
+ IConfig const& config ) {
+ return testSpec.matches( testCase.getTestCaseInfo() ) &&
+ isThrowSafe( testCase, config );
+ }
+
+ } // end unnamed namespace
+
+ std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
+ switch (config.runOrder()) {
+ case TestRunOrder::Declared:
+ return unsortedTestCases;
+
+ case TestRunOrder::LexicographicallySorted: {
+ std::vector<TestCaseHandle> sorted = unsortedTestCases;
+ std::sort(
+ sorted.begin(),
+ sorted.end(),
+ []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
+ return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
+ }
+ );
+ return sorted;
+ }
+ case TestRunOrder::Randomized: {
+ using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
+
+ TestCaseInfoHasher h{ config.rngSeed() };
+ std::vector<TestWithHash> indexed_tests;
+ indexed_tests.reserve(unsortedTestCases.size());
+
+ for (auto const& handle : unsortedTestCases) {
+ indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
+ }
+
+ std::sort( indexed_tests.begin(),
+ indexed_tests.end(),
+ []( TestWithHash const& lhs, TestWithHash const& rhs ) {
+ if ( lhs.first == rhs.first ) {
+ return lhs.second.getTestCaseInfo() <
+ rhs.second.getTestCaseInfo();
+ }
+ return lhs.first < rhs.first;
+ } );
+
+ std::vector<TestCaseHandle> randomized;
+ randomized.reserve(indexed_tests.size());
+
+ for (auto const& indexed : indexed_tests) {
+ randomized.push_back(indexed.second);
+ }
+
+ return randomized;
+ }
+ }
+
+ CATCH_INTERNAL_ERROR("Unknown test order value!");
+ }
+
+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
+ return !testCase.getTestCaseInfo().throws() || config.allowThrows();
+ }
+
+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
+ std::vector<TestCaseHandle> filtered;
+ filtered.reserve( testCases.size() );
+ for (auto const& testCase : testCases) {
+ if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
+ (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
+ filtered.push_back(testCase);
+ }
+ }
+ // The Catch3 runner shards the run itself.
+ return filtered;
+ }
+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
+ }
+
+
+ TestRegistry::TestRegistry() {
+ // We pre-reserve some reasonable number of tests to avoid the
+ // initial geometric growth churning during test registration.
+ m_handles.reserve( kInitialTestCount );
+ m_test_infos.reserve( kInitialTestCount );
+ m_invokers.reserve( kInitialTestCount );
+ }
+ TestRegistry::~TestRegistry() = default;
+
+ void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
+ m_handles.emplace_back(testInfo.get(), testInvoker.get());
+ m_test_infos.push_back(CATCH_MOVE(testInfo));
+ m_invokers.push_back(CATCH_MOVE(testInvoker));
+ }
+
+ void TestRegistry::enableFilenameTags() {
+ for (auto& info : m_test_infos) {
+ info->addFilenameTag();
+ }
+ }
+
+ std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
+ return m_handles;
+ }
+ std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
+ if( m_sortedFunctions.empty() )
+ enforceNoDuplicateTestCases( m_handles );
+
+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
+ m_sortedFunctions = sortTests( config, m_handles );
+ m_currentSortOrder = config.runOrder();
+ }
+ return m_sortedFunctions;
+ }
+
+} // end namespace Catch