mirror of
https://github.com/catchorg/Catch2.git
synced 2025-11-12 13:30:19 +01:00
Compare commits
15 Commits
devel-gene
...
devel-cond
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1968b3114 | ||
|
|
5ed9c45e5f | ||
|
|
950ad70f4c | ||
|
|
d7c67270af | ||
|
|
c748569310 | ||
|
|
cd7e43489e | ||
|
|
f6fd079aa3 | ||
|
|
22d54b36e0 | ||
|
|
a9116c2142 | ||
|
|
2e3214709a | ||
|
|
41ed8b702a | ||
|
|
93ef2b4cb8 | ||
|
|
a1faad9315 | ||
|
|
31ee3beb0a | ||
|
|
3b853aa9fb |
36
.github/workflows/mac-other-builds.yml
vendored
Normal file
36
.github/workflows/mac-other-builds.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Mac Sanitizer Builds
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
CXXFLAGS: -fsanitize=thread,undefined
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# From macos-14 forward, the baseline "macos-X" image is Arm based,
|
||||
# and not Intel based.
|
||||
runs-on: ${{matrix.image}}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [macos-13, macos-14]
|
||||
build_type: [Debug, Release]
|
||||
std: [14, 17]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure
|
||||
|
||||
run: |
|
||||
cmake --preset all-tests -GNinja \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCATCH_BUILD_EXTRA_TESTS=ON \
|
||||
-DCATCH_ENABLE_WERROR=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build
|
||||
|
||||
- name: Test
|
||||
run: ctest --test-dir build -R ThreadSafetyTests --timeout 21600 --verbose
|
||||
@@ -10,7 +10,7 @@ in-memory logs if they are not needed (the test case passed).
|
||||
Unlike reporters, each registered event listener is always active. Event
|
||||
listeners are always notified before reporter(s).
|
||||
|
||||
To write your own event listener, you should derive from `Catch::TestEventListenerBase`,
|
||||
To write your own event listener, you should derive from `Catch::EventListenerBase`,
|
||||
as it provides empty stubs for all reporter events, allowing you to
|
||||
only override events you care for. Afterwards you have to register it
|
||||
with Catch2 using `CATCH_REGISTER_LISTENER` macro, so that Catch2 knows
|
||||
|
||||
@@ -275,7 +275,7 @@ There are two ways to handle this, depending on whether you want this
|
||||
to be an error or not.
|
||||
|
||||
* If empty generator **is** an error, throw an exception in constructor.
|
||||
* If empty generator **is not** an error, use the [`SKIP`](skipping-passing-failing.md#skipping-test-cases-at-runtime) in constructor.
|
||||
* If empty generator **is not** an error, use the [`SKIP` macro](skipping-passing-failing.md#skipping-test-cases-at-runtime) in constructor.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ TEST_CASE("complex test case") {
|
||||
```
|
||||
|
||||
This test case will report 5 passing assertions; one for each of the three
|
||||
values in section `a1`, and then two in section `a2`, from values 2 and 4.
|
||||
values in section `a1`, and then two in section `a2`, from values 2 and 6.
|
||||
|
||||
Note that as soon as one section is skipped, the entire test case will
|
||||
be reported as _skipped_ (unless there is a failing assertion, in which
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Catch {
|
||||
( "list all listeners" )
|
||||
| Opt( setTestOrder, "decl|lex|rand" )
|
||||
["--order"]
|
||||
( "test case order (defaults to decl)" )
|
||||
( "test case order (defaults to rand)" )
|
||||
| Opt( setRngSeed, "'time'|'random-device'|number" )
|
||||
["--rng-seed"]
|
||||
( "set a specific seed for random numbers" )
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_JSONWRITER_HPP_INCLUDED
|
||||
#define CATCH_JSONWRITER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
@@ -27,8 +28,8 @@ namespace Catch {
|
||||
|
||||
class JsonValueWriter {
|
||||
public:
|
||||
JsonValueWriter( std::ostream& os );
|
||||
JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonObjectWriter writeObject() &&;
|
||||
JsonArrayWriter writeArray() &&;
|
||||
@@ -62,8 +63,8 @@ namespace Catch {
|
||||
|
||||
class JsonObjectWriter {
|
||||
public:
|
||||
JsonObjectWriter( std::ostream& os );
|
||||
JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
|
||||
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
||||
@@ -81,8 +82,8 @@ namespace Catch {
|
||||
|
||||
class JsonArrayWriter {
|
||||
public:
|
||||
JsonArrayWriter( std::ostream& os );
|
||||
JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
|
||||
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||
|
||||
JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
|
||||
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace Catch {
|
||||
using Mutex = std::mutex;
|
||||
using LockGuard = std::lock_guard<std::mutex>;
|
||||
struct AtomicCounts {
|
||||
std::atomic<std::uint64_t> passed = 0;
|
||||
std::atomic<std::uint64_t> failed = 0;
|
||||
std::atomic<std::uint64_t> failedButOk = 0;
|
||||
std::atomic<std::uint64_t> skipped = 0;
|
||||
std::atomic<std::uint64_t> passed{ 0 };
|
||||
std::atomic<std::uint64_t> failed{ 0 };
|
||||
std::atomic<std::uint64_t> failedButOk{ 0 };
|
||||
std::atomic<std::uint64_t> skipped{ 0 };
|
||||
};
|
||||
#else // ^^ Use actual mutex, lock and atomics
|
||||
// vv Dummy implementations for single-thread performance
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef CATCH_XMLWRITER_HPP_INCLUDED
|
||||
#define CATCH_XMLWRITER_HPP_INCLUDED
|
||||
|
||||
#include <catch2/internal/catch_lifetimebound.hpp>
|
||||
#include <catch2/internal/catch_reusable_string_stream.hpp>
|
||||
#include <catch2/internal/catch_stringref.hpp>
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace Catch {
|
||||
public:
|
||||
enum ForWhat { ForTextNodes, ForAttributes };
|
||||
|
||||
constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
|
||||
constexpr XmlEncode( StringRef str CATCH_ATTR_LIFETIMEBOUND, ForWhat forWhat = ForTextNodes ):
|
||||
m_str( str ), m_forWhat( forWhat ) {}
|
||||
|
||||
|
||||
@@ -61,7 +62,7 @@ namespace Catch {
|
||||
|
||||
class ScopedElement {
|
||||
public:
|
||||
ScopedElement( XmlWriter* writer, XmlFormatting fmt );
|
||||
ScopedElement( XmlWriter* writer CATCH_ATTR_LIFETIMEBOUND, XmlFormatting fmt );
|
||||
|
||||
ScopedElement( ScopedElement&& other ) noexcept;
|
||||
ScopedElement& operator=( ScopedElement&& other ) noexcept;
|
||||
@@ -93,7 +94,7 @@ namespace Catch {
|
||||
XmlFormatting m_fmt;
|
||||
};
|
||||
|
||||
XmlWriter( std::ostream& os );
|
||||
XmlWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||
~XmlWriter();
|
||||
|
||||
XmlWriter( XmlWriter const& ) = delete;
|
||||
|
||||
@@ -553,3 +553,17 @@ set_tests_properties(AmalgamatedFileTest
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "All tests passed \\(14 assertions in 3 test cases\\)"
|
||||
)
|
||||
|
||||
add_executable(ThreadSafetyTests
|
||||
${TESTS_DIR}/X94-ThreadSafetyTests.cpp
|
||||
)
|
||||
target_link_libraries(ThreadSafetyTests Catch2_buildall_interface)
|
||||
target_compile_definitions(ThreadSafetyTests PUBLIC CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS)
|
||||
add_test(NAME ThreadSafetyTests
|
||||
COMMAND ThreadSafetyTests -r compact
|
||||
)
|
||||
set_tests_properties(ThreadSafetyTests
|
||||
PROPERTIES
|
||||
PASS_REGULAR_EXPRESSION "assertions: 801 | 400 passed | 401 failed"
|
||||
RUN_SERIAL ON
|
||||
)
|
||||
|
||||
44
tests/ExtraTests/X94-ThreadSafetyTests.cpp
Normal file
44
tests/ExtraTests/X94-ThreadSafetyTests.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
// 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
|
||||
* Test that assertions and messages are thread-safe.
|
||||
*
|
||||
* This is done by spamming assertions and messages on multiple subthreads.
|
||||
* In manual, this reliably causes segfaults if the test is linked against
|
||||
* a non-thread-safe version of Catch2.
|
||||
*
|
||||
* The CTest test definition should also verify that the final assertion
|
||||
* count is correct.
|
||||
*/
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
TEST_CASE( "Failed REQUIRE in the main thread is fine" ) {
|
||||
std::vector<std::thread> threads;
|
||||
for ( size_t t = 0; t < 4; ++t) {
|
||||
threads.emplace_back( [t]() {
|
||||
CAPTURE(t);
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
CAPTURE(i);
|
||||
CHECK( false );
|
||||
CHECK( true );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
REQUIRE( false );
|
||||
}
|
||||
Reference in New Issue
Block a user