Compare commits

...

41 Commits
v1.1 ... master

Author SHA1 Message Date
Marius Bancila
3afe7193fa
Merge pull request #67 from chaorunrun/compile-for-c++17
Fix errors on compilation with c++17
2022-06-16 12:21:45 +03:00
Adam Jiang
e5da05d8de
Use <gsl/span> 2022-05-25 09:47:48 +08:00
Adam Jiang
30b95f9c8f
Merge branch 'master' into compile-for-c++17 2022-05-19 16:30:40 +08:00
Marius Bancila
3dca9d816c
Merge pull request #64 from OlivierLDff/optional-install
Optional install
2022-05-19 09:32:09 +03:00
Marius Bancila
d1f0f7f0ba
Merge pull request #69 from sid-dahiya/sid-dahiya/FixMsvcHiddenFriendError
Fix hidden friend issue for MSVC
2022-05-19 09:05:40 +03:00
Marius Bancila
cd9ca5e7d7
build with VS 2019 & 2022 2022-05-19 09:04:50 +03:00
Sid Dahiya
dfe3d39c10
Fix hidden friend issue for MSVC
This change is adding the `/Zc:hiddenFriend` option to address strict validation in MSVC 19.32.31328.0
2022-05-18 15:24:41 -07:00
Adam Jiang
979ba59e41 Fix errors on compilation with c++17 2022-05-18 22:17:02 +08:00
Marius Bancila
db4963048d merged 2022-05-10 09:09:42 +03:00
Olivier Le Doeuff
44160cca3f Deactivate unit test by default when stduuid is not the main CMake project 2022-05-06 17:22:56 +02:00
Olivier Le Doeuff
2ff6222e9f Make install optional (expected behavior in CMake FetchContent) 2022-05-06 17:22:11 +02:00
Marius Bancila
c1e1c144af
Merge pull request #62 from NovaSmoof/fixing-static-analysis
I believe this fixes an alignment issue.
2022-04-11 10:27:34 +03:00
Marius Bancila
9341e579f7
Merge pull request #61 from NovaSmoof/master
Added Appropriate nodiscards
2022-04-11 10:25:28 +03:00
Arthur.e
39b505ee95 I believe this fixes an alignment issue.
Casting the uint8_t array to a uint32_t pointer may cause it to become misaligned. So making it alignas a uint32 array should remove the undefined behavior.
2022-04-04 10:58:40 -07:00
Arthur.e
11a678d7fe Merge branch 'same-thing' 2022-04-04 10:00:21 -07:00
Arthur.e
02e2989771 Made all the things nodiscard
They should be.
2022-04-04 10:00:02 -07:00
Marius Bancila
1d3720fbcd whitespaces 2022-02-23 18:28:39 +02:00
Marius Bancila
cdebc5b78d pragma once replaced
added constexpr
2022-02-23 18:24:00 +02:00
Marius Bancila
5c538cca02
Merge pull request #57 from rickyviking/windows_defines
Restored Windows related defines
2022-01-14 17:29:34 +02:00
Riccardo Corsi
f58993d041 Restored Windows related defines, which might be needed even now, with fewer Windows headers included 2022-01-14 15:10:07 +01:00
Marius Bancila
66a4adec66
Merge pull request #56 from sketchylizard/FixTemplateParameters
Forward declare to_string function
2022-01-14 08:40:12 +02:00
Jason
c4728ee83b Forward declare to_string function
Forward declare to_string function before it is used in a friend
declaration and deleted the default template parameters from the
definition to prevent warnings in GCC.

Also add "if constexp" to an if statement that was constant.
2022-01-13 13:52:16 -08:00
Marius Bancila
1da3294a8b
Merge pull request #54 from sketchylizard/sketchylizard/FixInlineVariables
Declare variables as inline
2022-01-13 10:10:23 +02:00
Jason
76c4651202 Removed clang.format changes 2022-01-10 13:44:58 -08:00
Jason
5f739d3e26 Declare variables as inline
Declare empty_guid and guid_encoder as inline to fix multiple defined
symbol errors when compiling with clang++.
2022-01-04 07:26:47 -08:00
Marius Bancila
9357e5280c
Merge pull request #53 from kcsaul/master
Fix operator<< compiler error when c++20 enabled
2021-12-30 12:16:56 +02:00
Kevin Saul
8723ae1a33 Fix operator<< compiler error when c++20 enabled 2021-12-30 17:51:08 +13:00
Marius Bancila
4400e13797
Merge pull request #52 from sketchylizard/master
Fix compiler warnings for gcc & clang
2021-12-24 00:20:03 +02:00
Jason
d393e00037 Fix compiler warnings for gcc & clang
When compiling with -Wimplicit-int-conversion and -Wsign-conversion
gcc/clang give warnings for a handful of lines. Silence the warnings
by adding explicit casts.
2021-12-23 08:44:37 -08:00
Marius Bancila
487f364da7
Merge pull request #51 from rickyviking/stream_operator
Implement stream operator<< in terms of the faster to_string() method.
2021-12-23 14:03:03 +02:00
Riccardo Corsi
b6f1515be5 Implement stream operator<< in terms of the faster to_string() method. 2021-12-23 10:56:25 +01:00
Marius Bancila
7a3e380c21 specified size 2021-12-23 01:05:33 +02:00
Marius Bancila
5458877f2c faster std::hash<uuid> implementation 2021-12-23 01:00:23 +02:00
Marius Bancila
8e9d0f87f5 fast to_string() implementation 2021-12-23 00:33:04 +02:00
Marius Bancila
c6ad65304b note about mingw 2021-12-22 23:43:35 +02:00
Marius Bancila
9857cd372a note about std::random_device 2021-12-22 23:34:09 +02:00
Marius Bancila
50482c3c07 improved documentation 2021-12-22 23:21:32 +02:00
Marius Bancila
8068131ec3 check CoCreateGuid return value 2021-12-22 19:41:06 +02:00
Marius Bancila
889fffda69 updated catch with v2.13.7 2021-12-22 19:28:39 +02:00
Marius Bancila
197905e841
Merge pull request #50 from sketchylizard/master
Remove old style casts to avoid warnings
2021-12-19 23:59:35 +02:00
Jason
5baab46e60 Remove old style casts to avoid warnings
When compiling with -Wold-style-cast clang warns about the old style
 casts in uuid.h. Replace them with static_cast to avoid the warnings.
2021-12-17 08:12:20 -08:00
11 changed files with 753 additions and 382 deletions

View File

@ -1,11 +1,18 @@
cmake_minimum_required(VERSION 3.7.0)
set(UUID_MAIN_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(UUID_MAIN_PROJECT ON)
endif()
project(stduuid CXX)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
option(UUID_BUILD_TESTS "Build the unit tests" ON)
option(UUID_BUILD_TESTS "Build the unit tests" ${UUID_MAIN_PROJECT})
option(UUID_SYSTEM_GENERATOR "Enable operating system uuid generator" OFF)
option(UUID_TIME_GENERATOR "Enable experimental time-based uuid generator" OFF)
option(UUID_USING_CXX20_SPAN "Using span from std instead of gsl" OFF)
option(UUID_ENABLE_INSTALL "Create an install target" ${UUID_MAIN_PROJECT})
# Library target
add_library(${PROJECT_NAME} INTERFACE)
@ -38,36 +45,38 @@ endif()
# Using span from std
if (NOT UUID_USING_CXX20_SPAN)
target_include_directories(${PROJECT_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/gsl>
$<INSTALL_INTERFACE:include/gsl>)
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
install(DIRECTORY gsl DESTINATION include)
endif ()
# Install step and imported target
install(FILES include/uuid.h DESTINATION include)
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets)
install(EXPORT ${PROJECT_NAME}-targets
DESTINATION lib/cmake/${PROJECT_NAME})
if(UUID_ENABLE_INSTALL)
# Install step and imported target
install(FILES include/uuid.h DESTINATION include)
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets)
install(EXPORT ${PROJECT_NAME}-targets
DESTINATION lib/cmake/${PROJECT_NAME})
# Config files for find_package()
include(CMakePackageConfigHelpers)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME})
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake"
VERSION "1.0"
COMPATIBILITY AnyNewerVersion)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindLibuuid.cmake"
DESTINATION lib/cmake/${PROJECT_NAME})
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}-targets.cmake")
# Config files for find_package()
include(CMakePackageConfigHelpers)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME})
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake"
VERSION "1.0"
COMPATIBILITY AnyNewerVersion)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-version.cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindLibuuid.cmake"
DESTINATION lib/cmake/${PROJECT_NAME})
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}-targets.cmake")
endif()
# Tests
if (UUID_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif ()
endif ()

View File

@ -105,6 +105,7 @@ P0959R2 was discussed by LEWGI in Kona with the following feedback:
Based on this feedback and further considerations, the following changes have been done in this version:
* Added detailed explanation of the algorithms for generating uuids.
* `from_string()` and non-member `swap()` declared with `noexcept`.
* `from_string()` and `is_valid_uuid()` declared with `constexpr`.
* The `uuid` type is now defined as a class.
* Added an exposition-only member to hint and the possible internal representation of the uuid data.
* Added `uuid` constructors from arrays.
@ -506,21 +507,11 @@ namespace std {
constexpr std::strong_ordering operator<=>(uuid const&) const noexcept = default;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<typename StringType>
constexpr static bool is_valid_uuid(StringType const & str) noexcept;
template<typename StringType>
constexpr static uuid from_string(StringType const & str) noexcept;
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
@ -598,13 +589,8 @@ namespace std {
public:
explicit uuid_name_generator(uuid const& namespace_uuid) noexcept;
template<class CharT = char>
uuid operator()(CharT const * name);
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
uuid operator()(std::basic_string<CharT, Traits, Allocator> const & name);
template<typename StringType>
uuid operator()(StringType const & name);
};
}
```
@ -714,21 +700,11 @@ namespace std {
constexpr std::span<std::byte const, 16> as_bytes() const;
template<class CharT = char>
static bool is_valid_uuid(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static bool is_valid_uuid(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<class CharT = char>
static uuid from_string(CharT const * str) noexcept;
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
static uuid from_string(std::basic_string<CharT, Traits, Allocator> const & str) noexcept;
template<typename StringType>
constexpr static bool is_valid_uuid(StringType const & str) noexcept;
template<typename StringType>
constexpr static uuid from_string(StringType const & str) noexcept;
private:
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
@ -841,6 +817,12 @@ auto id1 = uuid::from_string<char, std::char_traits<char>>(
std::string str{ "47183823-2574-4bfd-b411-99ed177d3e43" };
auto id2 = uuid::from_string<char, std::char_traits<char>>(str); // [2]
```
However, to simplify the definition, these two overloads have been replaced with a single one:
```
template <typename StringType>
constexpr static std::optional<uuid> from_string(StringType const & str);
```
The `is_valid_uuid()` function and the `uuid_name_generator`'s call operator are now defined in the same manner.
#### Need more explanations about the choices of ordering and how the RFC works in that regard.

View File

@ -27,6 +27,7 @@ Generators:
| `uuid_random_generator` | a `basic_uuid_random_generator` using the Mersenne Twister engine (`basic_uuid_random_generator<std::mt19937>`) |
| `uuid_name_generator` | a function object that generates version 5, name-based UUIDs using SHA1 hashing. |
| `uuid_system_generator` | a function object that generates new UUIDs using operating system resources (`CoCreateGuid` on Windows, `uuid_generate` on Linux, `CFUUIDCreate` on Mac) <br><br> **Note**: This is not part of the standard proposal. It is available only if the `UUID_SYSTEM_GENERATOR` macro is defined. |
| `uuid_time_generator` | an experimental function object that generates time-based UUIDs.<br><br> **Note**:This is an experimental feature and should not be used in any production code. It is available only if the `UUID_TIME_GENERATOR` macro is defined. |
Utilities:
@ -255,12 +256,28 @@ The following is a list of examples for using the library:
auto h2 = std::hash<uuid>{};
assert(h1(str) == h2(id));
```
### Random uuids
If you generate uuids using the `basic_uuid_random_generator` and [std::random_device](https://en.cppreference.com/w/cpp/numeric/random/random_device) to seed a generator, keep in mind that this might not be non-deterministic and actually generate the same sequence of numbers:
> std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.
This could be a problem with MinGW. See [Bug 85494 - implementation of random_device on mingw is useless](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85494). This was fixed in GCC 9.2.
A portable alternative is to use the [Boost.Random](https://www.boost.org/doc/libs/1_78_0/doc/html/boost_random.html) library.
## Support
The library is supported on all major operating systems: Windows, Linux and Mac OS.
## Dependencies
Because no major compiler supports `std::span` yet the [Microsoft Guidelines Support Library](https://github.com/Microsoft/GSL) (aka GSL) is used for its span implementation (from which the standard version was defined).
If you use the library in a project built with C++20, then you can use `std::span`. This is used by default, if the header is supported by your compiler. The check is done with the [__cpp_lib_span](https://en.cppreference.com/w/cpp/utility/feature_test) feature-test macro.
Otherwise, such as when building with C++17, `std::span` is not available. However, the [Microsoft Guidelines Support Library](https://github.com/Microsoft/GSL) (aka GSL) can be used for its `span` implementation (from which the standard version was defined). The stduuid library defaults to use this implementation if `std::span` is not available.
To ensure `gsl::span` can be used, make sure the GSL library is available, and the GSL include directory is listed in the include directories for the project.
If you use cmake to build the test project, make sure the variable called `UUID_USING_CXX20_SPAN` is not defined, or it's value is `OFF` (this is the default value). This will ensure the `gsl` directory will be included in the search list of header directories.
## Testing
A testing project is available in the sources. To build and execute the tests do the following:
@ -270,5 +287,25 @@ A testing project is available in the sources. To build and execute the tests do
* Build the project created in the previous step
* Run the executable.
**Examples**
To generate a project files for Visual Studio 2019, you can run the following commands:
```
cd build
cmake -G "Visual Studio 17" -A x64 ..
```
To enable the operating system uuid generator set the `UUID_SYSTEM_GENERATOR` variable to `ON`.
```
cd build
cmake -G "Visual Studio 17" -A x64 -DUUID_SYSTEM_GENERATOR=ON ..
```
To enable the experimental time-based uuid generator set the `UUID_TIME_GENERATOR` variable to `ON`.
```
cd build
cmake -G "Visual Studio 17" -A x64 -DUUID_TIME_GENERATOR=ON ..
```
## Credits
The SHA1 implementation is based on the [TinySHA1](https://github.com/mohaps/TinySHA1) library.

View File

@ -2,12 +2,21 @@ version: '{build}'
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMAKE_GENERATOR: Visual Studio 16 2019
CMAKE_GENERATOR_PLATFORM: Win32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
CMAKE_GENERATOR: Visual Studio 16 2019
CMAKE_GENERATOR_PLATFORM: x64
CMAKE_CLI_FLAGS: -DUUID_SYSTEM_GENERATOR=ON -DUUID_TIME_GENERATOR=ON
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_GENERATOR_PLATFORM: Win32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
CMAKE_GENERATOR: Visual Studio 17 2022
CMAKE_GENERATOR_PLATFORM: x64
CMAKE_CLI_FLAGS: -DUUID_SYSTEM_GENERATOR=ON -DUUID_TIME_GENERATOR=ON

View File

@ -1,9 +1,9 @@
/*
* Catch v2.13.3
* Generated: 2020-10-31 18:20:31.045274
* Catch v2.13.7
* Generated: 2021-07-28 20:29:27.753164
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
* Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@ -15,7 +15,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 3
#define CATCH_VERSION_PATCH 7
#ifdef __clang__
# pragma clang system_header
@ -66,13 +66,16 @@
#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
// See e.g.:
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
# endif
# include <TargetConditionals.h>
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
(defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
# define CATCH_PLATFORM_MAC
# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
# define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
@ -132,9 +135,9 @@ namespace Catch {
#endif
// We have to avoid both ICC and Clang, because they try to mask themselves
// as gcc, and we want only GCC in this block
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__)
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@ -323,7 +326,7 @@ namespace Catch {
// Check if byte is available and usable
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
# include <cstddef>
# if __cpp_lib_byte > 0
# if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
# endif
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
@ -5455,6 +5458,8 @@ namespace Catch {
} // namespace Catch
// end catch_outlier_classification.hpp
#include <iterator>
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
#include <string>
@ -6339,9 +6344,10 @@ namespace Catch {
void writeTestCase(TestCaseNode const& testCaseNode);
void writeSection(std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode);
void writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode,
bool testOkToFail );
void writeAssertions(SectionNode const& sectionNode);
void writeAssertion(AssertionStats const& stats);
@ -6876,7 +6882,7 @@ namespace Catch {
}
iters *= 2;
}
throw optimized_away_error{};
Catch::throw_exception(optimized_away_error{});
}
} // namespace Detail
} // namespace Benchmark
@ -6884,6 +6890,7 @@ namespace Catch {
// end catch_run_for_at_least.hpp
#include <algorithm>
#include <iterator>
namespace Catch {
namespace Benchmark {
@ -7054,8 +7061,8 @@ namespace Catch {
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
auto lo = std::max(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1);
auto lo = (std::max)(cumn(a1), 0);
auto hi = (std::min)(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level };
}
@ -7124,7 +7131,9 @@ namespace Catch {
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_limit = (std::min)(
resolution * clock_cost_estimation_tick_limit,
FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_clock = [](int k) {
return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) {
@ -7771,7 +7780,7 @@ namespace Catch {
double sb = stddev.point;
double mn = mean.point / n;
double mg_min = mn / 2.;
double sg = std::min(mg_min / 4., sb / std::sqrt(n));
double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
@ -7790,7 +7799,7 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2);
};
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
}
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
@ -7980,86 +7989,58 @@ namespace Catch {
// start catch_fatal_condition.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#if defined( CATCH_CONFIG_WINDOWS_SEH )
#include <cassert>
namespace Catch {
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
FatalConditionHandler();
static void reset();
~FatalConditionHandler();
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
} // namespace Catch
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];
static stack_t oldSigStack;
static char altStackMem[];
static void handleSignal( int sig );
// Wrapper for platform-specific fatal error (signals/SEH) handlers
//
// Tries to be cooperative with other handlers, and not step over
// other handlers. This means that unknown structured exceptions
// are passed on, previous signal handlers are called, and so on.
//
// Can only be instantiated once, and assumes that once a signal
// is caught, the binary will end up terminating. Thus, there
class FatalConditionHandler {
bool m_started = false;
// Install/disengage implementation for specific platform.
// Should be if-defed to work on current platform, can assume
// engage-disengage 1:1 pairing.
void engage_platform();
void disengage_platform();
public:
// Should also have platform-specific implementations as needed
FatalConditionHandler();
~FatalConditionHandler();
static void reset();
void engage() {
assert(!m_started && "Handler cannot be installed twice.");
m_started = true;
engage_platform();
}
void disengage() {
assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false;
disengage_platform();
}
};
} // namespace Catch
#else
namespace Catch {
struct FatalConditionHandler {
void reset();
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
class FatalConditionHandlerGuard {
FatalConditionHandler* m_handler;
public:
FatalConditionHandlerGuard(FatalConditionHandler* handler):
m_handler(handler) {
m_handler->engage();
}
~FatalConditionHandlerGuard() {
m_handler->disengage();
}
};
}
#endif
} // end namespace Catch
// end catch_fatal_condition.h
#include <string>
@ -8185,6 +8166,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
@ -10057,6 +10039,36 @@ namespace Catch {
}
// end catch_errno_guard.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#include <sstream>
namespace Catch {
@ -10573,7 +10585,7 @@ namespace Catch {
// Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":"
// Find last occurrence of ":"
size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start;
@ -10735,25 +10747,47 @@ namespace Catch {
// end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#include <algorithm>
#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace Catch {
// If neither SEH nor signal handling is required, the handler impls
// do not have to do anything, and can be empty.
void FatalConditionHandler::engage_platform() {}
void FatalConditionHandler::disengage_platform() {}
FatalConditionHandler::FatalConditionHandler() = default;
FatalConditionHandler::~FatalConditionHandler() = default;
} // end namespace Catch
#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
// Report the error condition
//! Signals fatal error message to the run context
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
}
#endif // signals/SEH handling
//! Minimal size Catch2 needs for its own fatal error handling.
//! Picked anecdotally, so it might not be sufficient on all
//! platforms, and for all configurations.
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
} // end unnamed namespace
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
@ -10766,7 +10800,7 @@ namespace Catch {
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
};
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
@ -10777,38 +10811,50 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
// Since we do not support multiple instantiations, we put these
// into global variables and rely on cleaning them up in outlined
// constructors/destructors
static PVOID exceptionHandlerHandle = nullptr;
void FatalConditionHandler::reset() {
if (isSet) {
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
isSet = false;
// For MSVC, we reserve part of the stack memory for handling
// memory overflow structured exception.
FatalConditionHandler::FatalConditionHandler() {
ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
if (!SetThreadStackGuarantee(&guaranteeSize)) {
// We do not want to fully error out, because needing
// the stack reserve should be rare enough anyway.
Catch::cerr()
<< "Failed to reserve piece of stack."
<< " Stack overflows will not be reported successfully.";
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
// We do not attempt to unset the stack guarantee, because
// Windows does not support lowering the stack size guarantee.
FatalConditionHandler::~FatalConditionHandler() = default;
void FatalConditionHandler::engage_platform() {
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
if (!exceptionHandlerHandle) {
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
}
}
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
void FatalConditionHandler::disengage_platform() {
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
exceptionHandlerHandle = nullptr;
}
} // namespace Catch
} // end namespace Catch
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
#endif // CATCH_CONFIG_WINDOWS_SEH
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
@ -10817,10 +10863,6 @@ namespace Catch {
const char* name;
};
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
@ -10830,7 +10872,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
void FatalConditionHandler::handleSignal( int sig ) {
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
// which is zero initialization, but not explicit. We want to avoid
// that.
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
static char* altStackMem = nullptr;
static std::size_t altStackSize = 0;
static stack_t oldSigStack{};
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
static void restorePreviousSignalHandlers() {
// We set signal handlers back to the previous ones. Hopefully
// nobody overwrote them in the meantime, and doesn't expect
// their signal handlers to live past ours given that they
// installed them after ours..
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
}
static void handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
@ -10838,16 +10905,33 @@ namespace Catch {
break;
}
}
reset();
reportFatal(name);
// We need to restore previous signal handlers and let them do
// their thing, so that the users can have the debugger break
// when a signal is raised, and so on.
restorePreviousSignalHandlers();
reportFatal( name );
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
if (altStackSize == 0) {
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
}
altStackMem = new char[altStackSize]();
}
FatalConditionHandler::~FatalConditionHandler() {
delete[] altStackMem;
// We signal that another instance can be constructed by zeroing
// out the pointer.
altStackMem = nullptr;
}
void FatalConditionHandler::engage_platform() {
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = sigStackSize;
sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
@ -10859,40 +10943,17 @@ namespace Catch {
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
void FatalConditionHandler::reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
isSet = false;
}
}
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[sigStackSize] = {};
} // namespace Catch
#else
namespace Catch {
void FatalConditionHandler::reset() {}
}
#endif // signals/SEH handling
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
void FatalConditionHandler::disengage_platform() {
restorePreviousSignalHandlers();
}
} // end namespace Catch
#endif // CATCH_CONFIG_POSIX_SIGNALS
// end catch_fatal_condition.cpp
// start catch_generators.cpp
@ -11447,7 +11508,8 @@ namespace {
return lhs == rhs;
}
auto ulpDiff = std::abs(lc - rc);
// static cast as a workaround for IBM XLC
auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
@ -11621,7 +11683,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
} // namespace Matchers
} // namespace Catch
// end catch_matchers_floating.cpp
// start catch_matchers_generic.cpp
@ -12955,9 +13016,8 @@ namespace Catch {
}
void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {
@ -14126,24 +14186,28 @@ namespace Catch {
namespace {
struct TestHasher {
explicit TestHasher(Catch::SimplePcg32& rng_instance) {
basis = rng_instance();
basis <<= 32;
basis |= rng_instance();
}
using hash_t = uint64_t;
uint64_t basis;
explicit TestHasher( hash_t hashSuffix ):
m_hashSuffix{ hashSuffix } {}
uint64_t operator()(TestCase const& t) const {
// Modified FNV-1a hash
static constexpr uint64_t prime = 1099511628211;
uint64_t hash = basis;
for (const char c : t.name) {
uint32_t operator()( TestCase const& t ) const {
// FNV-1a hash with multiplication fold.
const hash_t prime = 1099511628211u;
hash_t hash = 14695981039346656037u;
for ( const char c : t.name ) {
hash ^= c;
hash *= prime;
}
return hash;
hash ^= m_hashSuffix;
hash *= prime;
const uint32_t low{ static_cast<uint32_t>( hash ) };
const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
return low * high;
}
private:
hash_t m_hashSuffix;
};
} // end unnamed namespace
@ -14161,9 +14225,9 @@ namespace Catch {
case RunTests::InRandomOrder: {
seedRng( config );
TestHasher h( rng() );
TestHasher h{ config.rngSeed() };
using hashedTest = std::pair<uint64_t, TestCase const*>;
using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;
std::vector<hashedTest> indexed_tests;
indexed_tests.reserve( unsortedTestCases.size() );
@ -15316,7 +15380,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 13, 3, "", 0 );
static Version version( 2, 13, 7, "", 0 );
return version;
}
@ -16729,6 +16793,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#include <sstream>
#include <ctime>
#include <algorithm>
#include <iomanip>
namespace Catch {
@ -16756,7 +16821,7 @@ namespace Catch {
#else
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
#endif
return std::string(timeStamp);
return std::string(timeStamp, timeStampSize-1);
}
std::string fileNameTag(const std::vector<std::string> &tags) {
@ -16767,6 +16832,17 @@ namespace Catch {
return it->substr(1);
return std::string();
}
// Formats the duration in seconds to 3 decimal places.
// This is done because some genius defined Maven Surefire schema
// in a way that only accepts 3 decimal places, and tools like
// Jenkins use that schema for validation JUnit reporter output.
std::string formatDuration( double seconds ) {
ReusableStringStream rss;
rss << std::fixed << std::setprecision( 3 ) << seconds;
return rss.str();
}
} // anonymous namespace
JunitReporter::JunitReporter( ReporterConfig const& _config )
@ -16836,7 +16912,7 @@ namespace Catch {
if( m_config->showDurations() == ShowDurations::Never )
xml.writeAttribute( "time", "" );
else
xml.writeAttribute( "time", suiteTime );
xml.writeAttribute( "time", formatDuration( suiteTime ) );
xml.writeAttribute( "timestamp", getCurrentTimestamp() );
// Write properties if there are any
@ -16881,12 +16957,13 @@ namespace Catch {
if ( !m_config->name().empty() )
className = m_config->name() + "." + className;
writeSection( className, "", rootSection );
writeSection( className, "", rootSection, stats.testInfo.okToFail() );
}
void JunitReporter::writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode ) {
void JunitReporter::writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode,
bool testOkToFail) {
std::string name = trim( sectionNode.stats.sectionInfo.name );
if( !rootName.empty() )
name = rootName + '/' + name;
@ -16903,13 +16980,18 @@ namespace Catch {
xml.writeAttribute( "classname", className );
xml.writeAttribute( "name", name );
}
xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );
// This is not ideal, but it should be enough to mimic gtest's
// junit output.
// Ideally the JUnit reporter would also handle `skipTest`
// events and write those out appropriately.
xml.writeAttribute( "status", "run" );
if (sectionNode.stats.assertions.failedButOk) {
xml.scopedElement("skipped")
.writeAttribute("message", "TEST_CASE tagged with !mayfail");
}
writeAssertions( sectionNode );
if( !sectionNode.stdOut.empty() )
@ -16919,9 +17001,9 @@ namespace Catch {
}
for( auto const& childNode : sectionNode.childSections )
if( className.empty() )
writeSection( name, "", *childNode );
writeSection( name, "", *childNode, testOkToFail );
else
writeSection( className, name, *childNode );
writeSection( className, name, *childNode, testOkToFail );
}
void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {

View File

@ -0,0 +1,181 @@
/*
* Created by Daniel Garcia on 2018-12-04.
* Copyright Social Point SL. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
// Don't #include any Catch headers here - we can assume they are already
// included before this header.
// This is not good practice in general but is necessary in this case so this
// file can be distributed as a single header that works with the main
// Catch single header.
#include <map>
namespace Catch {
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
SonarQubeReporter(ReporterConfig const& config)
: CumulativeReporterBase(config)
, xml(config.stream()) {
m_reporterPrefs.shouldRedirectStdOut = true;
m_reporterPrefs.shouldReportAllAssertions = true;
}
~SonarQubeReporter() override;
static std::string getDescription() {
return "Reports test results in the Generic Test Data SonarQube XML format";
}
static std::set<Verbosity> getSupportedVerbosities() {
return { Verbosity::Normal };
}
void noMatchingTestCases(std::string const& /*spec*/) override {}
void testRunStarting(TestRunInfo const& testRunInfo) override {
CumulativeReporterBase::testRunStarting(testRunInfo);
xml.startElement("testExecutions");
xml.writeAttribute("version", "1");
}
void testGroupEnded(TestGroupStats const& testGroupStats) override {
CumulativeReporterBase::testGroupEnded(testGroupStats);
writeGroup(*m_testGroups.back());
}
void testRunEndedCumulative() override {
xml.endElement();
}
void writeGroup(TestGroupNode const& groupNode) {
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
for(auto const& child : groupNode.children)
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
for(auto const& kv : testsPerFile)
writeTestFile(kv.first.c_str(), kv.second);
}
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
XmlWriter::ScopedElement e = xml.scopedElement("file");
xml.writeAttribute("path", filename);
for(auto const& child : testCaseNodes)
writeTestCase(*child);
}
void writeTestCase(TestCaseNode const& testCaseNode) {
// All test cases have exactly one section - which represents the
// test case itself. That section may have 0-n nested sections
assert(testCaseNode.children.size() == 1);
SectionNode const& rootSection = *testCaseNode.children.front();
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
}
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
std::string name = trim(sectionNode.stats.sectionInfo.name);
if(!rootName.empty())
name = rootName + '/' + name;
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
XmlWriter::ScopedElement e = xml.scopedElement("testCase");
xml.writeAttribute("name", name);
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
writeAssertions(sectionNode, okToFail);
}
for(auto const& childNode : sectionNode.childSections)
writeSection(name, *childNode, okToFail);
}
void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
for(auto const& assertion : sectionNode.assertions)
writeAssertion( assertion, okToFail);
}
void writeAssertion(AssertionStats const& stats, bool okToFail) {
AssertionResult const& result = stats.assertionResult;
if(!result.isOk()) {
std::string elementName;
if(okToFail) {
elementName = "skipped";
}
else {
switch(result.getResultType()) {
case ResultWas::ThrewException:
case ResultWas::FatalErrorCondition:
elementName = "error";
break;
case ResultWas::ExplicitFailure:
elementName = "failure";
break;
case ResultWas::ExpressionFailed:
elementName = "failure";
break;
case ResultWas::DidntThrowException:
elementName = "failure";
break;
// We should never see these here:
case ResultWas::Info:
case ResultWas::Warning:
case ResultWas::Ok:
case ResultWas::Unknown:
case ResultWas::FailureBit:
case ResultWas::Exception:
elementName = "internalError";
break;
}
}
XmlWriter::ScopedElement e = xml.scopedElement(elementName);
ReusableStringStream messageRss;
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
xml.writeAttribute("message", messageRss.str());
ReusableStringStream textRss;
if (stats.totals.assertions.total() > 0) {
textRss << "FAILED:\n";
if (result.hasExpression()) {
textRss << "\t" << result.getExpressionInMacro() << "\n";
}
if (result.hasExpandedExpression()) {
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
}
}
if(!result.getMessage().empty())
textRss << result.getMessage() << "\n";
for(auto const& msg : stats.infoMessages)
if(msg.type == ResultWas::Info)
textRss << msg.message << "\n";
textRss << "at " << result.getSourceInfo();
xml.writeText(textRss.str(), XmlFormatting::Newline);
}
}
private:
XmlWriter xml;
};
#ifdef CATCH_IMPL
SonarQubeReporter::~SonarQubeReporter() {}
#endif
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
} // end namespace Catch
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED

View File

@ -23,18 +23,17 @@ namespace Catch {
using StreamingReporterBase::StreamingReporterBase;
TAPReporter( ReporterConfig const& config ):
StreamingReporterBase( config ) {
m_reporterPrefs.shouldReportAllAssertions = true;
}
~TAPReporter() override;
static std::string getDescription() {
return "Reports test results in TAP format, suitable for test harnesses";
}
ReporterPreferences getPreferences() const override {
ReporterPreferences prefs;
prefs.shouldRedirectStdOut = false;
return prefs;
}
void noMatchingTestCases( std::string const& spec ) override {
stream << "# No test cases matched '" << spec << "'" << std::endl;
}
@ -44,9 +43,9 @@ namespace Catch {
bool assertionEnded( AssertionStats const& _assertionStats ) override {
++counter;
stream << "# " << currentTestCaseInfo->name << std::endl;
AssertionPrinter printer( stream, _assertionStats, counter );
printer.print();
stream << " # " << currentTestCaseInfo->name ;
stream << std::endl;
return true;
@ -205,16 +204,15 @@ namespace Catch {
return;
}
// using messages.end() directly (or auto) yields compilation error:
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
const auto itEnd = messages.cend();
const auto N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
{
Colour colourGuard( colour );
stream << " with " << pluralise( N, "message" ) << ":";
}
for(; itMessage != itEnd; ) {
while( itMessage != itEnd ) {
// If this assertion is a warning ignore any INFO messages
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
stream << " '" << itMessage->message << "'";
@ -222,7 +220,9 @@ namespace Catch {
Colour colourGuard( dimColour() );
stream << " and";
}
continue;
}
++itMessage;
}
}
@ -236,10 +236,9 @@ namespace Catch {
};
void printTotals( const Totals& totals ) const {
stream << "1.." << totals.assertions.total();
if( totals.testCases.total() == 0 ) {
stream << "1..0 # Skipped: No tests ran.";
} else {
stream << "1.." << counter;
stream << " # Skipped: No tests ran.";
}
}
};

View File

@ -97,12 +97,12 @@ namespace Catch {
case ResultWas::Ok:
case ResultWas::Info:
case ResultWas::Warning:
throw std::domain_error( "Internal error in TeamCity reporter" );
CATCH_ERROR( "Internal error in TeamCity reporter" );
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
case ResultWas::Exception:
throw std::domain_error( "Not implemented" );
CATCH_ERROR( "Not implemented" );
}
if( assertionStats.infoMessages.size() == 1 )
msg << " with message:";
@ -183,8 +183,7 @@ namespace Catch {
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
if( !lineInfo.empty() )
os << lineInfo << "\n";
os << lineInfo << "\n";
os << getLineOfChars<'.'>() << "\n\n";
}

View File

@ -1,4 +1,5 @@
#pragma once
#ifndef STDUUID_H
#define STDUUID_H
#include <cstring>
#include <string>
@ -15,10 +16,31 @@
#include <chrono>
#include <numeric>
#include <atomic>
#ifdef __cplusplus
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
# define LIBUUID_CPP20_OR_GREATER
# endif
#endif
#ifdef LIBUUID_CPP20_OR_GREATER
#include <span>
#else
#include <gsl/span>
#endif
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifdef UUID_SYSTEM_GENERATOR
#include <objbase.h>
#endif
@ -55,19 +77,19 @@ namespace uuids
namespace detail
{
template <typename TChar>
constexpr inline unsigned char hex2char(TChar const ch)
[[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
{
if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
return ch - static_cast<TChar>('0');
return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
return 10 + ch - static_cast<TChar>('a');
return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a'));
if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
return 10 + ch - static_cast<TChar>('A');
return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
return 0;
}
template <typename TChar>
constexpr inline bool is_hex(TChar const ch)
[[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
{
return
(ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
@ -76,17 +98,18 @@ namespace uuids
}
template <typename TChar>
constexpr std::basic_string_view<TChar> to_string_view(TChar const * str)
[[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const * str) noexcept
{
if (str) return str;
return {};
}
template <typename StringType>
[[nodiscard]]
constexpr std::basic_string_view<
typename StringType::value_type,
typename StringType::traits_type>
to_string_view(StringType const & str)
to_string_view(StringType const & str) noexcept
{
return str;
}
@ -99,14 +122,14 @@ namespace uuids
static constexpr unsigned int block_bytes = 64;
inline static uint32_t left_rotate(uint32_t value, size_t const count)
[[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
{
return (value << count) ^ (value >> (32 - count));
}
sha1() { reset(); }
void reset()
void reset() noexcept
{
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
@ -180,30 +203,30 @@ namespace uuids
digest32_t d32;
get_digest(d32);
size_t di = 0;
digest[di++] = (uint8_t)(d32[0] >> 24);
digest[di++] = (uint8_t)(d32[0] >> 16);
digest[di++] = (uint8_t)(d32[0] >> 8);
digest[di++] = (uint8_t)(d32[0] >> 0);
digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
digest[di++] = static_cast<uint8_t>(d32[0] >> 0);
digest[di++] = (uint8_t)(d32[1] >> 24);
digest[di++] = (uint8_t)(d32[1] >> 16);
digest[di++] = (uint8_t)(d32[1] >> 8);
digest[di++] = (uint8_t)(d32[1] >> 0);
digest[di++] = static_cast<uint8_t>(d32[1] >> 24);
digest[di++] = static_cast<uint8_t>(d32[1] >> 16);
digest[di++] = static_cast<uint8_t>(d32[1] >> 8);
digest[di++] = static_cast<uint8_t>(d32[1] >> 0);
digest[di++] = (uint8_t)(d32[2] >> 24);
digest[di++] = (uint8_t)(d32[2] >> 16);
digest[di++] = (uint8_t)(d32[2] >> 8);
digest[di++] = (uint8_t)(d32[2] >> 0);
digest[di++] = static_cast<uint8_t>(d32[2] >> 24);
digest[di++] = static_cast<uint8_t>(d32[2] >> 16);
digest[di++] = static_cast<uint8_t>(d32[2] >> 8);
digest[di++] = static_cast<uint8_t>(d32[2] >> 0);
digest[di++] = (uint8_t)(d32[3] >> 24);
digest[di++] = (uint8_t)(d32[3] >> 16);
digest[di++] = (uint8_t)(d32[3] >> 8);
digest[di++] = (uint8_t)(d32[3] >> 0);
digest[di++] = static_cast<uint8_t>(d32[3] >> 24);
digest[di++] = static_cast<uint8_t>(d32[3] >> 16);
digest[di++] = static_cast<uint8_t>(d32[3] >> 8);
digest[di++] = static_cast<uint8_t>(d32[3] >> 0);
digest[di++] = (uint8_t)(d32[4] >> 24);
digest[di++] = (uint8_t)(d32[4] >> 16);
digest[di++] = (uint8_t)(d32[4] >> 8);
digest[di++] = (uint8_t)(d32[4] >> 0);
digest[di++] = static_cast<uint8_t>(d32[4] >> 24);
digest[di++] = static_cast<uint8_t>(d32[4] >> 16);
digest[di++] = static_cast<uint8_t>(d32[4] >> 8);
digest[di++] = static_cast<uint8_t>(d32[4] >> 0);
return digest;
}
@ -213,10 +236,10 @@ namespace uuids
{
uint32_t w[80];
for (size_t i = 0; i < 16; i++) {
w[i] = (m_block[i * 4 + 0] << 24);
w[i] |= (m_block[i * 4 + 1] << 16);
w[i] |= (m_block[i * 4 + 2] << 8);
w[i] |= (m_block[i * 4 + 3]);
w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]);
}
for (size_t i = 16; i < 80; i++) {
w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
@ -270,6 +293,18 @@ namespace uuids
size_t m_blockByteIndex;
size_t m_byteCount;
};
template <typename CharT>
inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
template <>
inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
template <typename CharT>
inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
template <>
inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
}
// --------------------------------------------------------------------------------------------------------------------------
@ -340,6 +375,13 @@ namespace uuids
name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
};
// Forward declare uuid & to_string so that we can declare to_string as a friend later.
class uuid;
template <class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
std::basic_string<CharT, Traits, Allocator> to_string(uuid const &id);
// --------------------------------------------------------------------------------------------------------------------------
// uuid class
// --------------------------------------------------------------------------------------------------------------------------
@ -369,7 +411,7 @@ namespace uuids
std::copy(first, last, std::begin(data));
}
constexpr uuid_variant variant() const noexcept
[[nodiscard]] constexpr uuid_variant variant() const noexcept
{
if ((data[8] & 0x80) == 0x00)
return uuid_variant::ncs;
@ -381,7 +423,7 @@ namespace uuids
return uuid_variant::reserved;
}
constexpr uuid_version version() const noexcept
[[nodiscard]] constexpr uuid_version version() const noexcept
{
if ((data[6] & 0xF0) == 0x10)
return uuid_version::time_based;
@ -397,7 +439,7 @@ namespace uuids
return uuid_version::none;
}
constexpr bool is_nil() const noexcept
[[nodiscard]] constexpr bool is_nil() const noexcept
{
for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
return true;
@ -408,17 +450,17 @@ namespace uuids
data.swap(other.data);
}
inline span<std::byte const, 16> as_bytes() const
[[nodiscard]] inline span<std::byte const, 16> as_bytes() const
{
return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
}
template <typename StringType>
constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
[[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
{
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
int hasBraces = 0;
size_t hasBraces = 0;
size_t index = 0;
if (str.empty())
@ -458,11 +500,11 @@ namespace uuids
}
template <typename StringType>
constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
[[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
{
auto str = detail::to_string_view(in_str);
bool firstDigit = true;
int hasBraces = 0;
size_t hasBraces = 0;
size_t index = 0;
std::array<uint8_t, 16> data{ { 0 } };
@ -485,12 +527,13 @@ namespace uuids
if (firstDigit)
{
data[index] = detail::hex2char(str[i]) << 4;
data[index] = static_cast<uint8_t>(detail::hex2char(str[i]) << 4);
firstDigit = false;
}
else
{
data[index++] |= detail::hex2char(str[i]);
data[index] = static_cast<uint8_t>(data[index] | detail::hex2char(str[i]));
index++;
firstDigit = true;
}
}
@ -510,71 +553,59 @@ namespace uuids
friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
template <class Elem, class Traits>
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
template<class CharT, class Traits, class Allocator>
friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
friend std::hash<uuid>;
};
// --------------------------------------------------------------------------------------------------------------------------
// operators and non-member functions
// --------------------------------------------------------------------------------------------------------------------------
inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
[[nodiscard]] inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
{
return lhs.data == rhs.data;
}
inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
[[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
[[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
{
return lhs.data < rhs.data;
}
template <class Elem, class Traits>
std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id)
template <class CharT,
class Traits,
class Allocator>
[[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
{
// save current flags
std::ios_base::fmtflags f(s.flags());
// manipulate stream as needed
s << std::hex << std::setfill(static_cast<Elem>('0'))
<< std::setw(2) << (int)id.data[0]
<< std::setw(2) << (int)id.data[1]
<< std::setw(2) << (int)id.data[2]
<< std::setw(2) << (int)id.data[3]
<< '-'
<< std::setw(2) << (int)id.data[4]
<< std::setw(2) << (int)id.data[5]
<< '-'
<< std::setw(2) << (int)id.data[6]
<< std::setw(2) << (int)id.data[7]
<< '-'
<< std::setw(2) << (int)id.data[8]
<< std::setw(2) << (int)id.data[9]
<< '-'
<< std::setw(2) << (int)id.data[10]
<< std::setw(2) << (int)id.data[11]
<< std::setw(2) << (int)id.data[12]
<< std::setw(2) << (int)id.data[13]
<< std::setw(2) << (int)id.data[14]
<< std::setw(2) << (int)id.data[15];
std::basic_string<CharT, Traits, Allocator> uustr{detail::empty_guid<CharT>};
// restore original flags
s.flags(f);
return s;
for (size_t i = 0, index = 0; i < 36; ++i)
{
if (i == 8 || i == 13 || i == 18 || i == 23)
{
continue;
}
uustr[i] = detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
uustr[++i] = detail::guid_encoder<CharT>[id.data[index] & 0x0f];
index++;
}
return uustr;
}
template<class CharT = char,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
template <class Elem, class Traits>
std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id)
{
std::basic_stringstream<CharT, Traits, Allocator> sstr;
sstr << id;
return sstr.str();
s << to_string(id);
return s;
}
inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
@ -613,14 +644,19 @@ namespace uuids
#ifdef _WIN32
GUID newId;
::CoCreateGuid(&newId);
HRESULT hr = ::CoCreateGuid(&newId);
if (FAILED(hr))
{
throw std::system_error(hr, std::system_category(), "CoCreateGuid failed");
}
std::array<uint8_t, 16> bytes =
{ {
(unsigned char)((newId.Data1 >> 24) & 0xFF),
(unsigned char)((newId.Data1 >> 16) & 0xFF),
(unsigned char)((newId.Data1 >> 8) & 0xFF),
(unsigned char)((newId.Data1) & 0xFF),
static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
static_cast<unsigned char>((newId.Data1) & 0xFF),
(unsigned char)((newId.Data2 >> 8) & 0xFF),
(unsigned char)((newId.Data2) & 0xFF),
@ -700,7 +736,7 @@ namespace uuids
#endif
template <typename UniformRandomNumberGenerator>
class basic_uuid_random_generator
class basic_uuid_random_generator
{
public:
using engine_type = UniformRandomNumberGenerator;
@ -710,9 +746,9 @@ namespace uuids
explicit basic_uuid_random_generator(engine_type* gen) :
generator(gen, [](auto) {}) {}
uuid operator()()
[[nodiscard]] uuid operator()()
{
uint8_t bytes[16];
alignas(uint32_t) uint8_t bytes[16];
for (int i = 0; i < 16; i += 4)
*reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
@ -742,7 +778,7 @@ namespace uuids
{}
template <typename StringType>
uuid operator()(StringType const & name)
[[nodiscard]] uuid operator()(StringType const & name)
{
reset();
process_characters(detail::to_string_view(name));
@ -774,7 +810,7 @@ namespace uuids
}
}
uuid make_uuid()
[[nodiscard]] uuid make_uuid()
{
detail::sha1::digest8_t digest;
hasher.get_digest_bytes(digest);
@ -804,7 +840,7 @@ namespace uuids
std::optional<mac_address> device_address;
bool get_mac_address()
[[nodiscard]] bool get_mac_address()
{
if (device_address.has_value())
{
@ -827,7 +863,7 @@ namespace uuids
return device_address.has_value();
}
long long get_time_intervals()
[[nodiscard]] long long get_time_intervals()
{
auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
auto diff = std::chrono::system_clock::now() - start;
@ -835,7 +871,7 @@ namespace uuids
return ns / 100;
}
static unsigned short get_clock_sequence()
[[nodiscard]] static unsigned short get_clock_sequence()
{
static std::mt19937 clock_gen(std::random_device{}());
static std::uniform_int_distribution<unsigned short> clock_dis;
@ -844,7 +880,7 @@ namespace uuids
}
public:
uuid operator()()
[[nodiscard]] uuid operator()()
{
if (get_mac_address())
{
@ -889,10 +925,43 @@ namespace std
using argument_type = uuids::uuid;
using result_type = std::size_t;
result_type operator()(argument_type const &uuid) const
[[nodiscard]] result_type operator()(argument_type const &uuid) const
{
#ifdef UUID_HASH_STRING_BASED
std::hash<std::string> hasher;
return static_cast<result_type>(hasher(uuids::to_string(uuid)));
#else
uint64_t l =
static_cast<uint64_t>(uuid.data[0]) << 56 |
static_cast<uint64_t>(uuid.data[1]) << 48 |
static_cast<uint64_t>(uuid.data[2]) << 40 |
static_cast<uint64_t>(uuid.data[3]) << 32 |
static_cast<uint64_t>(uuid.data[4]) << 24 |
static_cast<uint64_t>(uuid.data[5]) << 16 |
static_cast<uint64_t>(uuid.data[6]) << 8 |
static_cast<uint64_t>(uuid.data[7]);
uint64_t h =
static_cast<uint64_t>(uuid.data[8]) << 56 |
static_cast<uint64_t>(uuid.data[9]) << 48 |
static_cast<uint64_t>(uuid.data[10]) << 40 |
static_cast<uint64_t>(uuid.data[11]) << 32 |
static_cast<uint64_t>(uuid.data[12]) << 24 |
static_cast<uint64_t>(uuid.data[13]) << 16 |
static_cast<uint64_t>(uuid.data[14]) << 8 |
static_cast<uint64_t>(uuid.data[15]);
if constexpr (sizeof(result_type) > 4)
{
return result_type(l ^ h);
}
else
{
uint64_t hash64 = l ^ h;
return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
}
#endif
}
};
}
#endif /* STDUUID_H */

View File

@ -8,7 +8,7 @@ else ()
set_target_properties(test_${PROJECT_NAME} PROPERTIES CXX_STANDARD 17)
endif ()
if (WIN32)
target_compile_options(test_${PROJECT_NAME} PRIVATE /EHc)
target_compile_options(test_${PROJECT_NAME} PRIVATE /EHc /Zc:hiddenFriend)
target_compile_definitions(test_${PROJECT_NAME} PRIVATE _SCL_SECURE_NO_WARNINGS)
elseif (APPLE)
target_compile_options(test_${PROJECT_NAME} PRIVATE -fexceptions -g -Wall)
@ -28,4 +28,4 @@ set_tests_properties("test_${PROJECT_NAME}"
FAIL_REGULAR_EXPRESSION "Failed \\d+ test cases")
set_tests_properties("test_${PROJECT_NAME}"
PROPERTIES
TIMEOUT 120)
TIMEOUT 120)

View File

@ -525,7 +525,11 @@ TEST_CASE("Test hashing", "[ops]")
auto h1 = std::hash<std::string>{};
auto h2 = std::hash<uuid>{};
#ifdef UUID_HASH_STRING_BASED
REQUIRE(h1(str) == h2(guid));
#else
REQUIRE(h1(str) != h2(guid));
#endif
auto engine = uuids::uuid_random_generator::engine_type{};
seed_rng(engine);