mirror of
https://github.com/catchorg/Catch2.git
synced 2025-11-12 21:40:30 +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
|
Unlike reporters, each registered event listener is always active. Event
|
||||||
listeners are always notified before reporter(s).
|
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
|
as it provides empty stubs for all reporter events, allowing you to
|
||||||
only override events you care for. Afterwards you have to register it
|
only override events you care for. Afterwards you have to register it
|
||||||
with Catch2 using `CATCH_REGISTER_LISTENER` macro, so that Catch2 knows
|
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.
|
to be an error or not.
|
||||||
|
|
||||||
* If empty generator **is** an error, throw an exception in constructor.
|
* 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
|
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
|
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
|
be reported as _skipped_ (unless there is a failing assertion, in which
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ namespace Catch {
|
|||||||
( "list all listeners" )
|
( "list all listeners" )
|
||||||
| Opt( setTestOrder, "decl|lex|rand" )
|
| Opt( setTestOrder, "decl|lex|rand" )
|
||||||
["--order"]
|
["--order"]
|
||||||
( "test case order (defaults to decl)" )
|
( "test case order (defaults to rand)" )
|
||||||
| Opt( setRngSeed, "'time'|'random-device'|number" )
|
| Opt( setRngSeed, "'time'|'random-device'|number" )
|
||||||
["--rng-seed"]
|
["--rng-seed"]
|
||||||
( "set a specific seed for random numbers" )
|
( "set a specific seed for random numbers" )
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#ifndef CATCH_JSONWRITER_HPP_INCLUDED
|
#ifndef CATCH_JSONWRITER_HPP_INCLUDED
|
||||||
#define 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_reusable_string_stream.hpp>
|
||||||
#include <catch2/internal/catch_stringref.hpp>
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
@@ -27,8 +28,8 @@ namespace Catch {
|
|||||||
|
|
||||||
class JsonValueWriter {
|
class JsonValueWriter {
|
||||||
public:
|
public:
|
||||||
JsonValueWriter( std::ostream& os );
|
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||||
JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
|
JsonValueWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||||
|
|
||||||
JsonObjectWriter writeObject() &&;
|
JsonObjectWriter writeObject() &&;
|
||||||
JsonArrayWriter writeArray() &&;
|
JsonArrayWriter writeArray() &&;
|
||||||
@@ -62,8 +63,8 @@ namespace Catch {
|
|||||||
|
|
||||||
class JsonObjectWriter {
|
class JsonObjectWriter {
|
||||||
public:
|
public:
|
||||||
JsonObjectWriter( std::ostream& os );
|
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||||
JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
|
JsonObjectWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||||
|
|
||||||
JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
|
JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
|
||||||
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
|
||||||
@@ -81,8 +82,8 @@ namespace Catch {
|
|||||||
|
|
||||||
class JsonArrayWriter {
|
class JsonArrayWriter {
|
||||||
public:
|
public:
|
||||||
JsonArrayWriter( std::ostream& os );
|
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||||
JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
|
JsonArrayWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND, std::uint64_t indent_level );
|
||||||
|
|
||||||
JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
|
JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
|
||||||
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ namespace Catch {
|
|||||||
using Mutex = std::mutex;
|
using Mutex = std::mutex;
|
||||||
using LockGuard = std::lock_guard<std::mutex>;
|
using LockGuard = std::lock_guard<std::mutex>;
|
||||||
struct AtomicCounts {
|
struct AtomicCounts {
|
||||||
std::atomic<std::uint64_t> passed = 0;
|
std::atomic<std::uint64_t> passed{ 0 };
|
||||||
std::atomic<std::uint64_t> failed = 0;
|
std::atomic<std::uint64_t> failed{ 0 };
|
||||||
std::atomic<std::uint64_t> failedButOk = 0;
|
std::atomic<std::uint64_t> failedButOk{ 0 };
|
||||||
std::atomic<std::uint64_t> skipped = 0;
|
std::atomic<std::uint64_t> skipped{ 0 };
|
||||||
};
|
};
|
||||||
#else // ^^ Use actual mutex, lock and atomics
|
#else // ^^ Use actual mutex, lock and atomics
|
||||||
// vv Dummy implementations for single-thread performance
|
// vv Dummy implementations for single-thread performance
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#ifndef CATCH_XMLWRITER_HPP_INCLUDED
|
#ifndef CATCH_XMLWRITER_HPP_INCLUDED
|
||||||
#define 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_reusable_string_stream.hpp>
|
||||||
#include <catch2/internal/catch_stringref.hpp>
|
#include <catch2/internal/catch_stringref.hpp>
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ namespace Catch {
|
|||||||
public:
|
public:
|
||||||
enum ForWhat { ForTextNodes, ForAttributes };
|
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 ) {}
|
m_str( str ), m_forWhat( forWhat ) {}
|
||||||
|
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ namespace Catch {
|
|||||||
|
|
||||||
class ScopedElement {
|
class ScopedElement {
|
||||||
public:
|
public:
|
||||||
ScopedElement( XmlWriter* writer, XmlFormatting fmt );
|
ScopedElement( XmlWriter* writer CATCH_ATTR_LIFETIMEBOUND, XmlFormatting fmt );
|
||||||
|
|
||||||
ScopedElement( ScopedElement&& other ) noexcept;
|
ScopedElement( ScopedElement&& other ) noexcept;
|
||||||
ScopedElement& operator=( ScopedElement&& other ) noexcept;
|
ScopedElement& operator=( ScopedElement&& other ) noexcept;
|
||||||
@@ -93,7 +94,7 @@ namespace Catch {
|
|||||||
XmlFormatting m_fmt;
|
XmlFormatting m_fmt;
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlWriter( std::ostream& os );
|
XmlWriter( std::ostream& os CATCH_ATTR_LIFETIMEBOUND );
|
||||||
~XmlWriter();
|
~XmlWriter();
|
||||||
|
|
||||||
XmlWriter( XmlWriter const& ) = delete;
|
XmlWriter( XmlWriter const& ) = delete;
|
||||||
|
|||||||
@@ -553,3 +553,17 @@ set_tests_properties(AmalgamatedFileTest
|
|||||||
PROPERTIES
|
PROPERTIES
|
||||||
PASS_REGULAR_EXPRESSION "All tests passed \\(14 assertions in 3 test cases\\)"
|
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