The forward iteration logic already bounds-check for m_it != m_string->end(),
do the same for the backward iteration. The issue with the assert is
that the assert() might not be compiled in, and it is happening after
the dereference, so it was too late.
To make this all work, I had to remove the stringification cache
from matchers. In theory, this can cause performance penalty in
cases where single matcher instance is stringified multiple times,
but in practice this does not happen much, and the difference is
surprisingly small anyway, because the performance of stringification
is already horrible and full of allocating strings just to throw
them away.
The matcher combinators need P2738 from C++26 to be `constexpr`.
Closes#3091
P3168 turned `std::optional` into a range type, so the partial specialization
of `StringMaker` for `std::optional<T>` conflicted with the partial
specialization for range types. Ideally we will fix this in the future
to support user-provided partial specializations for range-like types,
but for now we just disable the partial specialization for `std::optional<T>`
if P3168 is implemented.
The old internals reached into the global hub to stash the allocation(s)
for enum value -> string value there, then kept around a potentially
invalid (in case the hub was cleaned up) reference into it, going through
whole bunch of virtual dispatch in the process.
The new internals just store the data in a static variable inside the
`StringMaker` specialization. This avoids potential lifetime issues,
avoids all virtual dispatch and (almost) reduces the include bloat in
the main header path.
The reason for (almost) there is that for full include correctness,
`EnumInfo` needs `<utility>` include for `std::pair`. However, this brings
in things like `std::relops`, because the std headers in C++ are dumb.
As this was not included before, and instead we relied on `std::pair`
existing in an internal stdlib header that we transitively included, the
full include size ends up bigger than before.
The thread-safety changes in assertions & messages turned whether
the last assertion passed or failed into thread-local state,
instead of being member of the `RunContext`. However, this change
was not reflected in the API `CHECKED_IF`/`CHECKED_ELSE` used,
which in turn required `catch_test_macro_impl.hpp` to include
`catch_interfaces_capture.hpp` for it.
Thanks to the combination of this commit and the previous similar
commit for the message stack handling, the main include path does
not need to include `catch_interfaces_capture.hpp` anymore.
The thread-safety changes in assertions & messages turned the message
stacks into thread-local state, instead of it being member of `RunContext`.
The relevant {push,pop}(Un)ScopedMessage functions were turned from member
functions into static functions, but this left `catch_message.hpp` with
dependency on `IResultCapture`'s definition for the functions, and thus
it still had to include `catch_interfaces_capture.hpp`.
With this change, `catch_message.hpp` no longer needs
`catch_interfaces_capture.hpp`.
This has two advantages
1) Removing the include of `catch_interfaces_capture.hpp` from the
header and potentially allowing further pruning later.
2) Providing small-but-measurable 1-2% speedup for assertions.
When using catch_discover_tests() with DISCOVERY_MODE PRE_TEST and a
multi-config generator (e.g. Ninja Multi-Config), if a test target has
zero discoverable tests (e.g. all tests tagged with [.]), ctest fails:
CMake Error: include could not find requested file:
.../test-hidden-b12d07c_tests-Release.cmake
The early return added in #2962 (76f70b14) correctly prevented a JSON
parsing crash for zero tests, but skipped writing the ctest file. The
PRE_TEST include script unconditionally includes this file, so the
missing file causes a hard error that aborts all test discovery.
Write an empty file before returning early so the include always
succeeds.
For line-wrapping bytes were counted instead of codepoints. This
resulted in line-breaks being inserted at the wrong position and also
breaking UTF-8 characters.
Fixes#1022.
Ideally we could suppress the warning locally in the `UNIQUE_NAME` macro,
but that runs into at least 2 issues:
1) Clang actually does not consider the warning as coming from inside the
`UNIQUE_NAME` macro, even though it correctly points to its expansion
as the problem. This means that adding `_Pragma`s inside the macro
around the __COUNTER__ usage does not actually silence the warning.
2) Adding the local suppressions anyway breaks the expansion of
`MAKE_NAMESPACE` macro inside the templated test case macros. This can
be fixed for the newest clang version by removing its use and using
the uniqued `TestName` for the namespace name directly, but this breaks
compilation on GCC, and older Clang versions.
Because of these issues, we introduce global warning suppression for
`-Wc2y-extensions` to be done with it. We should revisit this if Clang 23
fixes the local pragma based suppression, when it might be worth the effort
to rework the templated test case macros to support it.
Closes#3076
Previously the mapping was eager on construction and calls to
`next()`. This was fine when generators were always exhausted fully,
but with the new generator filtering, we might not want to call
the map function eagerly; rather we want to call it only once,
after the generator is moved to the target element.