Merge pull request #831 from JordanMaples/dev/jomaples/gtest

Migrate from Catch to GoogleTest & always terminate on contract violation
This commit is contained in:
Jordan Maples [MSFT] 2020-01-07 15:41:25 -08:00 committed by GitHub
commit 7786da91c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 3999 additions and 3692 deletions

View File

@ -18,7 +18,7 @@ other platforms. Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for more inform
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
# Usage of Third Party Libraries # Usage of Third Party Libraries
This project makes use of the [Catch](https://github.com/philsquared/catch) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Catch. This project makes use of the [Google Test](https://github.com/google/gooletest) testing library. Please see the [ThirdPartyNotices.txt](./ThirdPartyNotices.txt) file for details regarding the licensing of Google Test.
# Quick Start # Quick Start
## Supported Platforms ## Supported Platforms

View File

@ -2,38 +2,40 @@
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
Do Not Translate or Localize Do Not Translate or Localize
GSL: Guidelines Support Library incorporates third party material from the projects listed below. The original copyright notice and the license under which Microsoft received such third party material are set forth below. Microsoft reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. GSL: Guidelines Support Library incorporates third party material from the projects listed below.
-------------------------------------------------------------------------------
Software: Google Test
Owner: Google Inc.
Source URL: github.com/google/googletest
License: BSD 3 - Clause
Text:
Copyright 2008, Google Inc.
All rights reserved.
1. Catch (https://github.com/philsquared/Catch) Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
%% Catch NOTICES, INFORMATION, AND LICENSE BEGIN HERE
=========================================
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
=========================================
END OF Catch NOTICES, INFORMATION, AND LICENSE
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------

View File

@ -18,7 +18,6 @@
#define GSL_CONTRACTS_H #define GSL_CONTRACTS_H
#include <exception> #include <exception>
#include <stdexcept> // for logic_error
// //
// make suppress attributes parse for some compilers // make suppress attributes parse for some compilers
@ -50,19 +49,6 @@
#endif #endif
//
// There are three configuration options for this GSL implementation's behavior
// when pre/post conditions on the GSL types are violated:
//
// 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
// 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
// 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
//
#if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) || defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) || \
defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
#define GSL_TERMINATE_ON_CONTRACT_VIOLATION
#endif
#define GSL_STRINGIFY_DETAIL(x) #x #define GSL_STRINGIFY_DETAIL(x) #x
#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
@ -94,10 +80,6 @@
namespace gsl namespace gsl
{ {
struct fail_fast : public std::logic_error
{
explicit fail_fast(char const* const message) : std::logic_error(message) {}
};
namespace details namespace details
{ {
@ -128,45 +110,21 @@ namespace details
#endif #endif
} }
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
template <typename Exception> template <typename Exception>
[[deprecated("GSL no longer supports throwing for contract violations. Use gsl::details::terminate() instead.")]]
[[noreturn]] void throw_exception(Exception&&) noexcept [[noreturn]] void throw_exception(Exception&&) noexcept
{ {
gsl::details::terminate(); gsl::details::terminate();
} }
#else
template <typename Exception>
[[noreturn]] void throw_exception(Exception&& exception)
{
throw std::forward<Exception>(exception);
}
#endif // GSL_TERMINATE_ON_CONTRACT_VIOLATION
} // namespace details } // namespace details
} // namespace gsl } // namespace gsl
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) \
: gsl::details::throw_exception(gsl::fail_fast( \
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
#define GSL_CONTRACT_CHECK(type, cond) \ #define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate()) (GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
#define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond)
#endif // GSL_THROW_ON_CONTRACT_VIOLATION
#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond) #define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond) #define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)

View File

@ -21,7 +21,6 @@
#include <array> #include <array>
#include <cstddef> // for ptrdiff_t, size_t #include <cstddef> // for ptrdiff_t, size_t
#include <exception> // for exception
#include <initializer_list> // for initializer_list #include <initializer_list> // for initializer_list
#include <type_traits> // for is_signed, integral_constant #include <type_traits> // for is_signed, integral_constant
#include <utility> // for exchange, forward #include <utility> // for exchange, forward
@ -97,10 +96,6 @@ constexpr T narrow_cast(U&& u) noexcept
return static_cast<T>(std::forward<U>(u)); return static_cast<T>(std::forward<U>(u));
} }
struct narrowing_error : public std::exception
{
};
namespace details namespace details
{ {
template <class T, class U> template <class T, class U>
@ -120,9 +115,9 @@ constexpr
T narrow(U u) noexcept(false) T narrow(U u) noexcept(false)
{ {
T t = narrow_cast<T>(u); T t = narrow_cast<T>(u);
if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error()); if (static_cast<U>(t) != u) gsl::details::terminate();
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{}))) if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
gsl::details::throw_exception(narrowing_error()); gsl::details::terminate();
return t; return t;
} }

View File

@ -5,27 +5,33 @@ project(GSLTests CXX)
# will make visual studio generated project group files # will make visual studio generated project group files
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
list(APPEND CATCH_CMAKE_ARGS configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
"-DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external" execute_process(
"-DNO_SELFTEST=true" COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
) )
if(result)
if(GIT_FOUND) message(FATAL_ERROR "CMake step for googletest failed: ${result}")
# add catch
ExternalProject_Add(
catch
PREFIX ${CMAKE_BINARY_DIR}/catch
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.0.1
CMAKE_ARGS ${CATCH_CMAKE_ARGS}
LOG_DOWNLOAD 1
UPDATE_DISCONNECTED 1
)
else()
# assume catch is installed in a system directory
add_custom_target(catch)
endif() endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download
)
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL
)
if (MSVC AND (GSL_CXX_STANDARD EQUAL 17)) if (MSVC AND (GSL_CXX_STANDARD EQUAL 17))
set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-) set(GSL_CPLUSPLUS_OPT -Zc:__cplusplus -permissive-)
endif() endif()
@ -78,37 +84,23 @@ else()
) )
endif(MSVC) endif(MSVC)
# for tests to find the catch header # for tests to find the gtest header
target_include_directories(gsl_tests_config INTERFACE target_include_directories(gsl_tests_config SYSTEM INTERFACE
${CMAKE_BINARY_DIR}/external/include googletest/googletest/include
) )
# set definitions for tests set_property(TARGET PROPERTY FOLDER "GSL_tests")
target_compile_definitions(gsl_tests_config INTERFACE
GSL_THROW_ON_CONTRACT_VIOLATION
)
# create the main executable for each test. this reduces the compile time
# of each test by pre-compiling catch.
add_library(test_catch STATIC test.cpp)
target_link_libraries(test_catch
GSL
gsl_tests_config
)
add_dependencies(test_catch catch)
set_property(TARGET test_catch PROPERTY FOLDER "GSL_tests")
function(add_gsl_test name) function(add_gsl_test name)
add_executable(${name} ${name}.cpp) add_executable(${name} ${name}.cpp)
target_link_libraries(${name} target_link_libraries(${name}
GSL GSL
test_catch
gsl_tests_config gsl_tests_config
gtest_main
) )
add_dependencies(${name} catch)
add_test( add_test(
${name} ${name}
${name} ${name}
) )
# group all tests under GSL_tests # group all tests under GSL_tests
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests") set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests")
@ -141,11 +133,9 @@ endforeach(flag_var)
# please try to keep entries ordered =) # please try to keep entries ordered =)
add_library(gsl_tests_config_noexcept INTERFACE) add_library(gsl_tests_config_noexcept INTERFACE)
if(MSVC) # MSVC or simulating MSVC if(MSVC) # MSVC or simulating MSVC
target_compile_definitions(gsl_tests_config_noexcept INTERFACE
_HAS_EXCEPTIONS=0
)
target_compile_options(gsl_tests_config_noexcept INTERFACE target_compile_options(gsl_tests_config_noexcept INTERFACE
${GSL_CPLUSPLUS_OPT} ${GSL_CPLUSPLUS_OPT}
/EHsc
/W4 /W4
/WX /WX
$<$<CXX_COMPILER_ID:MSVC>: $<$<CXX_COMPILER_ID:MSVC>:
@ -184,16 +174,12 @@ else()
) )
endif(MSVC) endif(MSVC)
# set definitions for tests
target_compile_definitions(gsl_tests_config_noexcept INTERFACE
GSL_TERMINATE_ON_CONTRACT_VIOLATION
)
function(add_gsl_test_noexcept name) function(add_gsl_test_noexcept name)
add_executable(${name} ${name}.cpp) add_executable(${name} ${name}.cpp)
target_link_libraries(${name} target_link_libraries(${name}
GSL GSL
gsl_tests_config_noexcept gsl_tests_config_noexcept
gtest_main
) )
add_test( add_test(
${name} ${name}

14
tests/CMakeLists.txt.in Normal file
View File

@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.0.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@ -20,24 +20,38 @@
#pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 26440 26426) // from catch
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, CHE... #if __clang__ || __GNUC__
// disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_algorithm> // for copy #include <gsl/gsl_algorithm> // for copy
#include <gsl/span> // for span #include <gsl/span> // for span
#include <array> // for array #include <array> // for array
#include <cstddef> // for size_t #include <cstddef> // for size_t
namespace gsl { namespace
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl
{
struct fail_fast; struct fail_fast;
} // namespace gsl } // namespace gsl
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST(algorithm_tests, same_type)
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("same_type")
{ {
// dynamic source and destination span // dynamic source and destination span
{ {
@ -50,9 +64,10 @@ TEST_CASE("same_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -67,9 +82,10 @@ TEST_CASE("same_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -84,9 +100,10 @@ TEST_CASE("same_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -101,17 +118,15 @@ TEST_CASE("same_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
} }
TEST(algorithm_tests, compatible_type)
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("compatible_type")
{ {
// dynamic source and destination span // dynamic source and destination span
{ {
@ -124,9 +139,10 @@ TEST_CASE("compatible_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -141,9 +157,10 @@ TEST_CASE("compatible_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -158,9 +175,10 @@ TEST_CASE("compatible_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
@ -175,15 +193,16 @@ TEST_CASE("compatible_type")
copy(src_span, dst_span); copy(src_span, dst_span);
copy(src_span, dst_span.subspan(src_span.size())); copy(src_span, dst_span.subspan(src_span.size()));
for (std::size_t i = 0; i < src.size(); ++i) { for (std::size_t i = 0; i < src.size(); ++i)
CHECK(dst[i] == src[i]); {
CHECK(dst[i + src.size()] == src[i]); EXPECT_TRUE(dst[i] == src[i]);
EXPECT_TRUE(dst[i + src.size()] == src[i]);
} }
} }
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
TEST_CASE("incompatible_type") TEST(algorithm_tests, incompatible_type)
{ {
std::array<int, 4> src{1, 2, 3, 4}; std::array<int, 4> src{1, 2, 3, 4};
std::array<int*, 12> dst{}; std::array<int*, 12> dst{};
@ -201,8 +220,13 @@ TEST_CASE("incompatible_type")
} }
#endif #endif
TEST_CASE("small_destination_span") TEST(algorithm_tests, small_destination_span)
{ {
std::set_terminate([] {
std::cerr << "Expected Death. small_destination_span";
std::abort();
});
std::array<int, 12> src{1, 2, 3, 4}; std::array<int, 12> src{1, 2, 3, 4};
std::array<int, 4> dst{}; std::array<int, 4> dst{};
@ -211,11 +235,15 @@ TEST_CASE("small_destination_span")
const span<int> dst_span_dyn(dst); const span<int> dst_span_dyn(dst);
const span<int, 4> dst_span_static(dst); const span<int, 4> dst_span_static(dst);
CHECK_THROWS_AS(copy(src_span_dyn, dst_span_dyn), fail_fast); EXPECT_DEATH(copy(src_span_dyn, dst_span_dyn), deathstring);
CHECK_THROWS_AS(copy(src_span_dyn, dst_span_static), fail_fast); EXPECT_DEATH(copy(src_span_dyn, dst_span_static), deathstring);
CHECK_THROWS_AS(copy(src_span_static, dst_span_dyn), fail_fast); EXPECT_DEATH(copy(src_span_static, dst_span_dyn), deathstring);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);
#endif #endif
} }
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

View File

@ -20,33 +20,64 @@
#pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 26440 26426) // from catch
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, CHECK... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_assert> // for fail_fast (ptr only), Ensures, Expects #include <gsl/gsl_assert> // for fail_fast (ptr only), Ensures, Expects
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
int f(int i) int f(int i)
{ {
Expects(i > 0 && i < 10); Expects(i > 0 && i < 10);
return i; return i;
} }
TEST_CASE("expects")
{
CHECK(f(2) == 2);
CHECK_THROWS_AS(f(10), fail_fast);
}
int g(int i) int g(int i)
{ {
i++; i++;
Ensures(i > 0 && i < 10); Ensures(i > 0 && i < 10);
return i; return i;
} }
} // namespace
TEST_CASE("ensures") TEST(assertion_tests, expects)
{ {
CHECK(g(2) == 3); std::set_terminate([] {
CHECK_THROWS_AS(g(9), fail_fast); std::cerr << "Expected Death. expects";
std::abort();
});
EXPECT_TRUE(f(2) == 2);
EXPECT_DEATH(f(10), deathstring);
} }
TEST(assertion_tests, ensures)
{
std::set_terminate([] {
std::cerr << "Expected Death. ensures";
std::abort();
});
EXPECT_TRUE(g(2) == 3);
EXPECT_DEATH(g(9), deathstring);
}
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

View File

@ -20,7 +20,19 @@
#pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 26440 26426) // from catch
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK_THROW... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_util> // for at #include <gsl/gsl_util> // for at
@ -29,88 +41,95 @@
#include <initializer_list> // for initializer_list #include <initializer_list> // for initializer_list
#include <vector> // for vector #include <vector> // for vector
namespace
{
static constexpr char deathstring[] = "Expected Death";
}
namespace gsl { TEST(at_tests, static_array)
struct fail_fast;
} // namespace gsl
using gsl::fail_fast;
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("static_array")
{ {
int a[4] = {1, 2, 3, 4}; int a[4] = {1, 2, 3, 4};
const int(&c_a)[4] = a; const int(&c_a)[4] = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
CHECK(&gsl::at(a, i) == &a[i]); EXPECT_TRUE(&gsl::at(a, i) == &a[i]);
CHECK(&gsl::at(c_a, i) == &a[i]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[i]);
} }
CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); std::set_terminate([] {
CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); std::cerr << "Expected Death. static_array";
CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); std::abort();
CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); });
EXPECT_DEATH(gsl::at(a, -1), deathstring);
EXPECT_DEATH(gsl::at(a, 4), deathstring);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
} }
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST(at_tests, std_array)
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("std_array")
{ {
std::array<int, 4> a = {1, 2, 3, 4}; std::array<int, 4> a = {1, 2, 3, 4};
const std::array<int, 4>& c_a = a; const std::array<int, 4>& c_a = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
CHECK(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
CHECK(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); std::set_terminate([] {
CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); std::cerr << "Expected Death. std_array";
CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); std::abort();
CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); });
EXPECT_DEATH(gsl::at(a, -1), deathstring);
EXPECT_DEATH(gsl::at(a, 4), deathstring);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
} }
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST(at_tests, std_vector)
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("StdVector")
{ {
std::vector<int> a = {1, 2, 3, 4}; std::vector<int> a = {1, 2, 3, 4};
const std::vector<int>& c_a = a; const std::vector<int>& c_a = a;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
CHECK(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(a, i) == &a[static_cast<std::size_t>(i)]);
CHECK(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]); EXPECT_TRUE(&gsl::at(c_a, i) == &a[static_cast<std::size_t>(i)]);
} }
CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); std::set_terminate([] {
CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); std::cerr << "Expected Death. std_vector";
CHECK_THROWS_AS(gsl::at(c_a, -1), fail_fast); std::abort();
CHECK_THROWS_AS(gsl::at(c_a, 4), fail_fast); });
EXPECT_DEATH(gsl::at(a, -1), deathstring);
EXPECT_DEATH(gsl::at(a, 4), deathstring);
EXPECT_DEATH(gsl::at(c_a, -1), deathstring);
EXPECT_DEATH(gsl::at(c_a, 4), deathstring);
} }
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute TEST(at_tests, InitializerList)
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("InitializerList")
{ {
const std::initializer_list<int> a = {1, 2, 3, 4}; const std::initializer_list<int> a = {1, 2, 3, 4};
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
CHECK(gsl::at(a, i) == i + 1); EXPECT_TRUE(gsl::at(a, i) == i + 1);
CHECK(gsl::at({1, 2, 3, 4}, i) == i + 1); EXPECT_TRUE(gsl::at({1, 2, 3, 4}, i) == i + 1);
} }
CHECK_THROWS_AS(gsl::at(a, -1), fail_fast); std::set_terminate([] {
CHECK_THROWS_AS(gsl::at(a, 4), fail_fast); std::cerr << "Expected Death. InitializerList";
CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, -1), fail_fast); std::abort();
CHECK_THROWS_AS(gsl::at({1, 2, 3, 4}, 4), fail_fast); });
EXPECT_DEATH(gsl::at(a, -1), deathstring);
EXPECT_DEATH(gsl::at(a, 4), deathstring);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, -1), deathstring);
EXPECT_DEATH(gsl::at({1, 2, 3, 4}, 4), deathstring);
} }
#if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910 #if !defined(_MSC_VER) || defined(__clang__) || _MSC_VER >= 1910
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
static constexpr bool test_constexpr() static constexpr bool test_constexpr()
{ {
int a1[4] = {1, 2, 3, 4}; int a1[4] = {1, 2, 3, 4};
@ -133,3 +152,6 @@ static constexpr bool test_constexpr()
static_assert(test_constexpr(), "FAIL"); static_assert(test_constexpr(), "FAIL");
#endif #endif
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

View File

@ -24,18 +24,23 @@
#if __clang__ || __GNUC__ #if __clang__ || __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, TEST_CASE //disable warnings from gtest
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/multi_span> // for static_bounds, static_bounds_dynamic_range_t #include <gsl/multi_span> // for static_bounds, static_bounds_dynamic_range_t
#include <cstddef> // for ptrdiff_t, size_t #include <cstddef> // for ptrdiff_t, size_t
namespace gsl {
struct fail_fast;
} // namespace gsl
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
@ -44,8 +49,7 @@ namespace
void use(std::ptrdiff_t&) {} void use(std::ptrdiff_t&) {}
} }
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute TEST(bounds_tests, basic_bounds)
TEST_CASE("basic_bounds")
{ {
for (auto point : static_bounds<dynamic_range, 3, 4>{2}) { for (auto point : static_bounds<dynamic_range, 3, 4>{2}) {
for (decltype(point)::size_type j = 0; for (decltype(point)::size_type j = 0;
@ -57,9 +61,7 @@ TEST_CASE("basic_bounds")
} }
} }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute TEST(bounds_tests, bounds_basic)
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("bounds_basic")
{ {
static_bounds<3, 4, 5> b; static_bounds<3, 4, 5> b;
const auto a = b.slice(); const auto a = b.slice();
@ -68,9 +70,7 @@ TEST_CASE("bounds_basic")
x.slice().slice(); x.slice().slice();
} }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute TEST(bounds_tests, arrayview_iterator)
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("arrayview_iterator")
{ {
static_bounds<4, dynamic_range, 2> bounds{3}; static_bounds<4, dynamic_range, 2> bounds{3};
@ -88,8 +88,7 @@ TEST_CASE("arrayview_iterator")
#endif #endif
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(bounds_tests, bounds_convertible)
TEST_CASE("bounds_convertible")
{ {
static_bounds<7, 4, 2> b1; static_bounds<7, 4, 2> b1;
static_bounds<7, dynamic_range, 2> b2 = b1; static_bounds<7, dynamic_range, 2> b2 = b1;
@ -102,18 +101,21 @@ TEST_CASE("bounds_convertible")
static_bounds<7, 4, 2> b4 = b3; static_bounds<7, 4, 2> b4 = b3;
(void) b4; (void) b4;
static_bounds<dynamic_range> b11;
static_bounds<dynamic_range> b5; static_bounds<dynamic_range> b5;
static_bounds<34> b6; static_bounds<34> b6;
std::set_terminate([] {
std::cerr << "Expected Death. bounds_convertible";
std::abort();
});
b5 = static_bounds<20>(); b5 = static_bounds<20>();
CHECK_THROWS_AS(b6 = b5, fail_fast); EXPECT_DEATH(b6 = b5, ".*");
b5 = static_bounds<34>(); b5 = static_bounds<34>();
b6 = b5; b6 = b5;
CHECK(b5 == b6); EXPECT_TRUE(b5 == b6);
CHECK(b5.size() == b6.size()); EXPECT_TRUE(b5.size() == b6.size());
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -122,4 +124,4 @@ copy(src_span_static, dst_span_static);
#if __clang__ || __GNUC__ #if __clang__ || __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif // __clang__ || __GNUC__

View File

@ -17,10 +17,22 @@
#ifdef _MSC_VER #ifdef _MSC_VER
// blanket turn off warnings from CppCoreCheck from catch // blanket turn off warnings from CppCoreCheck from catch
// so people aren't annoyed by them when running the tool. // so people aren't annoyed by them when running the tool.
#pragma warning(disable : 26440 26426) // from catch #pragma warning(disable : 26440 26426)
#endif #endif // _MSC_VER
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_byte> // for to_byte, to_integer, byte, operator&, ope... #include <gsl/gsl_byte> // for to_byte, to_integer, byte, operator&, ope...
@ -29,104 +41,103 @@ using namespace gsl;
namespace namespace
{ {
TEST_CASE("construction") int modify_both(gsl::byte& b, int& i)
{
{
const byte b = static_cast<byte>(4);
CHECK(static_cast<unsigned char>(b) == 4);
}
GSL_SUPPRESS(es.49)
{
const byte b = byte(12);
CHECK(static_cast<unsigned char>(b) == 12);
}
{
const byte b = to_byte<12>();
CHECK(static_cast<unsigned char>(b) == 12);
}
{
const unsigned char uc = 12;
const byte b = to_byte(uc);
CHECK(static_cast<unsigned char>(b) == 12);
}
#if defined(__cplusplus) && (__cplusplus >= 201703L)
{
const byte b { 14 };
CHECK(static_cast<unsigned char>(b) == 14);
}
#endif
}
TEST_CASE("bitwise_operations")
{
const byte b = to_byte<0xFF>();
byte a = to_byte<0x00>();
CHECK((b | a) == to_byte<0xFF>());
CHECK(a == to_byte<0x00>());
a |= b;
CHECK(a == to_byte<0xFF>());
a = to_byte<0x01>();
CHECK((b & a) == to_byte<0x01>());
a &= b;
CHECK(a == to_byte<0x01>());
CHECK((b ^ a) == to_byte<0xFE>());
CHECK(a == to_byte<0x01>());
a ^= b;
CHECK(a == to_byte<0xFE>());
a = to_byte<0x01>();
CHECK(~a == to_byte<0xFE>());
a = to_byte<0xFF>();
CHECK((a << 4) == to_byte<0xF0>());
CHECK((a >> 4) == to_byte<0x0F>());
a <<= 4;
CHECK(a == to_byte<0xF0>());
a >>= 4;
CHECK(a == to_byte<0x0F>());
}
TEST_CASE("to_integer")
{
const byte b = to_byte<0x12>();
CHECK(0x12 == gsl::to_integer<char>(b));
CHECK(0x12 == gsl::to_integer<short>(b));
CHECK(0x12 == gsl::to_integer<long>(b));
CHECK(0x12 == gsl::to_integer<long long>(b));
CHECK(0x12 == gsl::to_integer<unsigned char>(b));
CHECK(0x12 == gsl::to_integer<unsigned short>(b));
CHECK(0x12 == gsl::to_integer<unsigned long>(b));
CHECK(0x12 == gsl::to_integer<unsigned long long>(b));
// CHECK(0x12 == gsl::to_integer<float>(b)); // expect compile-time error
// CHECK(0x12 == gsl::to_integer<double>(b)); // expect compile-time error
}
int modify_both(gsl::byte & b, int& i)
{ {
i = 10; i = 10;
b = to_byte<5>(); b = to_byte<5>();
return i; return i;
} }
GSL_SUPPRESS(type.1) TEST(byte_tests, construction)
TEST_CASE("aliasing") {
{
const byte b = static_cast<byte>(4);
EXPECT_TRUE(static_cast<unsigned char>(b) == 4);
}
GSL_SUPPRESS(es.49)
{
const byte b = byte(12);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
{
const byte b = to_byte<12>();
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
{
const unsigned char uc = 12;
const byte b = to_byte(uc);
EXPECT_TRUE(static_cast<unsigned char>(b) == 12);
}
#if defined(__cplusplus) && (__cplusplus >= 201703L)
{
const byte b { 14 };
EXPECT_TRUE(static_cast<unsigned char>(b) == 14);
}
#endif
}
TEST(byte_tests, bitwise_operations)
{
const byte b = to_byte<0xFF>();
byte a = to_byte<0x00>();
EXPECT_TRUE((b | a) == to_byte<0xFF>());
EXPECT_TRUE(a == to_byte<0x00>());
a |= b;
EXPECT_TRUE(a == to_byte<0xFF>());
a = to_byte<0x01>();
EXPECT_TRUE((b & a) == to_byte<0x01>());
a &= b;
EXPECT_TRUE(a == to_byte<0x01>());
EXPECT_TRUE((b ^ a) == to_byte<0xFE>());
EXPECT_TRUE(a == to_byte<0x01>());
a ^= b;
EXPECT_TRUE(a == to_byte<0xFE>());
a = to_byte<0x01>();
EXPECT_TRUE(~a == to_byte<0xFE>());
a = to_byte<0xFF>();
EXPECT_TRUE((a << 4) == to_byte<0xF0>());
EXPECT_TRUE((a >> 4) == to_byte<0x0F>());
a <<= 4;
EXPECT_TRUE(a == to_byte<0xF0>());
a >>= 4;
EXPECT_TRUE(a == to_byte<0x0F>());
}
TEST(byte_tests, to_integer)
{
const byte b = to_byte<0x12>();
EXPECT_TRUE(0x12 == gsl::to_integer<char>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<short>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<long>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<long long>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned char>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned short>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned long>(b));
EXPECT_TRUE(0x12 == gsl::to_integer<unsigned long long>(b));
// EXPECT_TRUE(0x12 == gsl::to_integer<float>(b)); // expect compile-time error
// EXPECT_TRUE(0x12 == gsl::to_integer<double>(b)); // expect compile-time error
}
TEST(byte_tests, aliasing)
{ {
int i{0}; int i{0};
const int res = modify_both(reinterpret_cast<byte&>(i), i); const int res = modify_both(reinterpret_cast<byte&>(i), i);
CHECK(res == i); EXPECT_TRUE(res == i);
} }
} }
@ -134,3 +145,7 @@ TEST_CASE("aliasing")
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
copy(src_span_static, dst_span_static); copy(src_span_static, dst_span_static);
#endif #endif
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,19 @@
#pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4702) // unreachable code
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gsl/pointers> // for not_null, operator<, operator<=, operator>
@ -34,13 +46,13 @@
#include <string> // for basic_string, operator==, string, operator<< #include <string> // for basic_string, operator==, string, operator<<
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
namespace gsl
{
struct fail_fast;
} // namespace gsl
using namespace gsl; using namespace gsl;
namespace
{
static constexpr char deathstring[] = "Expected Death";
} //namespace
struct MyBase struct MyBase
{ {
}; };
@ -133,10 +145,8 @@ GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
const int* return_pointer_const() { return nullptr; }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(notnull_tests, TestNotNullConstructors)
TEST_CASE("TestNotNullConstructors")
{ {
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -153,18 +163,22 @@ TEST_CASE("TestNotNullConstructors")
#endif #endif
} }
std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructors";
std::abort();
});
{ {
// from shared pointer // from shared pointer
int i = 12; int i = 12;
auto rp = RefCounted<int>(&i); auto rp = RefCounted<int>(&i);
not_null<int*> p(rp); not_null<int*> p(rp);
CHECK(p.get() == &i); EXPECT_TRUE(p.get() == &i);
not_null<std::shared_ptr<int>> x( not_null<std::shared_ptr<int>> x(
std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
int* pi = nullptr; int* pi = nullptr;
CHECK_THROWS_AS(not_null<decltype(pi)>(pi), fail_fast); EXPECT_DEATH((not_null<decltype(pi)>(pi)), deathstring);
} }
{ {
@ -175,7 +189,7 @@ TEST_CASE("TestNotNullConstructors")
helper(&t); helper(&t);
helper_const(&t); helper_const(&t);
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -191,7 +205,7 @@ TEST_CASE("TestNotNullConstructors")
helper(x); helper(x);
helper_const(x); helper_const(x);
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -205,7 +219,7 @@ TEST_CASE("TestNotNullConstructors")
helper_const(cp); helper_const(cp);
helper_const(x); helper_const(x);
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -215,19 +229,18 @@ TEST_CASE("TestNotNullConstructors")
auto x = not_null<const int*>{cp}; auto x = not_null<const int*>{cp};
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
// from returned pointer // from returned pointer
CHECK_THROWS_AS(helper(return_pointer()), fail_fast); EXPECT_DEATH(helper(return_pointer()), deathstring);
CHECK_THROWS_AS(helper_const(return_pointer()), fail_fast); EXPECT_DEATH(helper_const(return_pointer()), deathstring);
} }
} }
template <typename T> template <typename T>
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
void ostream_helper(T v) void ostream_helper(T v)
{ {
not_null<T*> p(&v); not_null<T*> p(&v);
@ -236,18 +249,18 @@ void ostream_helper(T v)
std::ostringstream ref; std::ostringstream ref;
os << static_cast<void*>(p); os << static_cast<void*>(p);
ref << static_cast<void*>(&v); ref << static_cast<void*>(&v);
CHECK(os.str() == ref.str()); EXPECT_TRUE(os.str() == ref.str());
} }
{ {
std::ostringstream os; std::ostringstream os;
std::ostringstream ref; std::ostringstream ref;
os << *p; os << *p;
ref << v; ref << v;
CHECK(os.str() == ref.str()); EXPECT_TRUE(os.str() == ref.str());
} }
} }
TEST_CASE("TestNotNullostream") TEST(notnull_tests, TestNotNullostream)
{ {
ostream_helper<int>(17); ostream_helper<int>(17);
ostream_helper<float>(21.5f); ostream_helper<float>(21.5f);
@ -258,9 +271,7 @@ TEST_CASE("TestNotNullostream")
ostream_helper<std::string>("string"); ostream_helper<std::string>("string");
} }
GSL_SUPPRESS(type.1) // NO-FORMAT: attribute TEST(notnull_tests, TestNotNullCasting)
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("TestNotNullCasting")
{ {
MyBase base; MyBase base;
MyDerived derived; MyDerived derived;
@ -270,7 +281,7 @@ TEST_CASE("TestNotNullCasting")
not_null<MyDerived*> p{&derived}; not_null<MyDerived*> p{&derived};
not_null<MyBase*> q(&base); not_null<MyBase*> q(&base);
q = p; // allowed with heterogeneous copy ctor q = p; // allowed with heterogeneous copy ctor
CHECK(q == p); EXPECT_TRUE(q == p);
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
q = u; // no viable conversion possible between MyBase* and Unrelated* q = u; // no viable conversion possible between MyBase* and Unrelated*
@ -280,20 +291,25 @@ TEST_CASE("TestNotNullCasting")
not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p); not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
#endif #endif
not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get())); not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get())); EXPECT_TRUE(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
} }
TEST_CASE("TestNotNullAssignment") TEST(notnull_tests, TestNotNullAssignment)
{ {
std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullAssignmentd";
std::abort();
});
int i = 12; int i = 12;
not_null<int*> p(&i); not_null<int*> p(&i);
CHECK(helper(p)); EXPECT_TRUE(helper(p));
int* q = nullptr; int* q = nullptr;
CHECK_THROWS_AS(p = not_null<int*>(q), fail_fast); EXPECT_DEATH(p = not_null<int*>(q), deathstring);
} }
TEST_CASE("TestNotNullRawPointerComparison") TEST(notnull_tests, TestNotNullRawPointerComparison)
{ {
int ints[2] = {42, 43}; int ints[2] = {42, 43};
int* p1 = &ints[0]; int* p1 = &ints[0];
@ -302,34 +318,33 @@ TEST_CASE("TestNotNullRawPointerComparison")
using NotNull1 = not_null<decltype(p1)>; using NotNull1 = not_null<decltype(p1)>;
using NotNull2 = not_null<decltype(p2)>; using NotNull2 = not_null<decltype(p2)>;
CHECK((NotNull1(p1) == NotNull1(p1)) == true); EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == true);
CHECK((NotNull1(p1) == NotNull2(p2)) == false); EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == false);
CHECK((NotNull1(p1) != NotNull1(p1)) == false); EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == false);
CHECK((NotNull1(p1) != NotNull2(p2)) == true); EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == true);
CHECK((NotNull1(p1) < NotNull1(p1)) == false); EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == false);
CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
CHECK((NotNull1(p1) > NotNull1(p1)) == false); EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == false);
CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
CHECK((NotNull1(p1) <= NotNull1(p1)) == true); EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == true);
CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(notnull_tests, TestNotNullDereferenceOperator)
TEST_CASE("TestNotNullDereferenceOperator")
{ {
{ {
auto sp1 = std::make_shared<NonCopyableNonMovable>(); auto sp1 = std::make_shared<NonCopyableNonMovable>();
using NotNullSp1 = not_null<decltype(sp1)>; using NotNullSp1 = not_null<decltype(sp1)>;
CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); EXPECT_TRUE(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); EXPECT_TRUE(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
} }
{ {
@ -337,22 +352,22 @@ TEST_CASE("TestNotNullDereferenceOperator")
CustomPtr<int> p1(&ints[0]); CustomPtr<int> p1(&ints[0]);
using NotNull1 = not_null<decltype(p1)>; using NotNull1 = not_null<decltype(p1)>;
CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); EXPECT_TRUE(typeid(*NotNull1(p1)) == typeid(*p1));
CHECK(*NotNull1(p1) == 42); EXPECT_TRUE(*NotNull1(p1) == 42);
*NotNull1(p1) = 43; *NotNull1(p1) = 43;
CHECK(ints[0] == 43); EXPECT_TRUE(ints[0] == 43);
} }
{ {
int v = 42; int v = 42;
gsl::not_null<int*> p(&v); gsl::not_null<int*> p(&v);
CHECK(typeid(*p) == typeid(*(&v))); EXPECT_TRUE(typeid(*p) == typeid(*(&v)));
*p = 43; *p = 43;
CHECK(v == 43); EXPECT_TRUE(v == 43);
} }
} }
TEST_CASE("TestNotNullSharedPtrComparison") TEST(notnull_tests, TestNotNullSharedPtrComparison)
{ {
auto sp1 = std::make_shared<int>(42); auto sp1 = std::make_shared<int>(42);
auto sp2 = std::make_shared<const int>(43); auto sp2 = std::make_shared<const int>(43);
@ -360,31 +375,30 @@ TEST_CASE("TestNotNullSharedPtrComparison")
using NotNullSp1 = not_null<decltype(sp1)>; using NotNullSp1 = not_null<decltype(sp1)>;
using NotNullSp2 = not_null<decltype(sp2)>; using NotNullSp2 = not_null<decltype(sp2)>;
CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); EXPECT_TRUE((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); EXPECT_TRUE((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); EXPECT_TRUE((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); EXPECT_TRUE((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); EXPECT_TRUE((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); EXPECT_TRUE((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); EXPECT_TRUE((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); EXPECT_TRUE((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); EXPECT_TRUE((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); EXPECT_TRUE((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(notnull_tests, TestNotNullCustomPtrComparison)
TEST_CASE("TestNotNullCustomPtrComparison")
{ {
int ints[2] = {42, 43}; int ints[2] = {42, 43};
CustomPtr<int> p1(&ints[0]); CustomPtr<int> p1(&ints[0]);
@ -393,33 +407,32 @@ TEST_CASE("TestNotNullCustomPtrComparison")
using NotNull1 = not_null<decltype(p1)>; using NotNull1 = not_null<decltype(p1)>;
using NotNull2 = not_null<decltype(p2)>; using NotNull2 = not_null<decltype(p2)>;
CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); EXPECT_TRUE((NotNull1(p1) == NotNull1(p1)) == "true");
CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); EXPECT_TRUE((NotNull1(p1) == NotNull2(p2)) == "false");
CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); EXPECT_TRUE((NotNull1(p1) != NotNull1(p1)) == "false");
CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); EXPECT_TRUE((NotNull1(p1) != NotNull2(p2)) == "true");
CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); EXPECT_TRUE((NotNull1(p1) < NotNull1(p1)) == "false");
CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); EXPECT_TRUE((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); EXPECT_TRUE((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); EXPECT_TRUE((NotNull1(p1) > NotNull1(p1)) == "false");
CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); EXPECT_TRUE((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); EXPECT_TRUE((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); EXPECT_TRUE((NotNull1(p1) <= NotNull1(p1)) == "true");
CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); EXPECT_TRUE((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); EXPECT_TRUE((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); EXPECT_TRUE((NotNull1(p1) >= NotNull1(p1)) == "true");
CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); EXPECT_TRUE((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); EXPECT_TRUE((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(notnull_tests, TestNotNullConstructorTypeDeduction)
TEST_CASE("TestNotNullConstructorTypeDeduction")
{ {
{ {
int i = 42; int i = 42;
@ -428,7 +441,7 @@ TEST_CASE("TestNotNullConstructorTypeDeduction")
helper(not_null{&i}); helper(not_null{&i});
helper_const(not_null{&i}); helper_const(not_null{&i});
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -439,15 +452,20 @@ TEST_CASE("TestNotNullConstructorTypeDeduction")
helper(not_null{p}); helper(not_null{p});
helper_const(not_null{p}); helper_const(not_null{p});
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] {
std::cerr << "Expected Death. TestNotNullConstructorTypeDeduction";
std::abort();
});
{ {
auto workaround_macro = []() { auto workaround_macro = []() {
int* p1 = nullptr; int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
@ -455,14 +473,14 @@ TEST_CASE("TestNotNullConstructorTypeDeduction")
const int* p1 = nullptr; const int* p1 = nullptr;
const not_null x{p1}; const not_null x{p1};
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
int* p = nullptr; int* p = nullptr;
CHECK_THROWS_AS(helper(not_null{p}), fail_fast); EXPECT_DEATH(helper(not_null{p}), deathstring);
CHECK_THROWS_AS(helper_const(not_null{p}), fail_fast); EXPECT_DEATH(helper_const(not_null{p}), deathstring);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -475,7 +493,7 @@ TEST_CASE("TestNotNullConstructorTypeDeduction")
} }
#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L) #endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
TEST_CASE("TestMakeNotNull") TEST(notnull_tests, TestMakeNotNull)
{ {
{ {
int i = 42; int i = 42;
@ -484,7 +502,7 @@ TEST_CASE("TestMakeNotNull")
helper(make_not_null(&i)); helper(make_not_null(&i));
helper_const(make_not_null(&i)); helper_const(make_not_null(&i));
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -495,42 +513,51 @@ TEST_CASE("TestMakeNotNull")
helper(make_not_null(p)); helper(make_not_null(p));
helper_const(make_not_null(p)); helper_const(make_not_null(p));
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
std::set_terminate([] {
std::cerr << "Expected Death. TestMakeNotNull";
std::abort();
});
{ {
const auto workaround_macro = []() { const auto workaround_macro = []() {
int* p1 = nullptr; int* p1 = nullptr;
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
const auto workaround_macro = []() { const auto workaround_macro = []() {
const int* p1 = nullptr; const int* p1 = nullptr;
const auto x = make_not_null(p1); const auto x = make_not_null(p1);
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
int* p = nullptr; int* p = nullptr;
CHECK_THROWS_AS(helper(make_not_null(p)), fail_fast); EXPECT_DEATH(helper(make_not_null(p)), deathstring);
CHECK_THROWS_AS(helper_const(make_not_null(p)), fail_fast); EXPECT_DEATH(helper_const(make_not_null(p)), deathstring);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
CHECK_THROWS_AS(make_not_null(nullptr), fail_fast); EXPECT_DEATH(make_not_null(nullptr), deathstring);
CHECK_THROWS_AS(helper(make_not_null(nullptr)), fail_fast); EXPECT_DEATH(helper(make_not_null(nullptr)), deathstring);
CHECK_THROWS_AS(helper_const(make_not_null(nullptr)), fail_fast); EXPECT_DEATH(helper_const(make_not_null(nullptr)), deathstring);
} }
#endif #endif
} }
static_assert(std::is_nothrow_move_constructible<not_null<void*>>::value, static_assert(std::is_nothrow_move_constructible<not_null<void*>>::value,
"not_null must be no-throw move constructible"); "not_null must be no-throw move constructible");
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

View File

@ -21,7 +21,19 @@
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/pointers> // for owner #include <gsl/pointers> // for owner
@ -30,19 +42,16 @@ using namespace gsl;
GSL_SUPPRESS(f.23) // NO-FORMAT: attribute GSL_SUPPRESS(f.23) // NO-FORMAT: attribute
void f(int* i) { *i += 1; } void f(int* i) { *i += 1; }
GSL_SUPPRESS(r.11) // NO-FORMAT: attribute TEST(owner_tests, basic_test)
GSL_SUPPRESS(r.3) // NO-FORMAT: attribute // TODO: false positive
GSL_SUPPRESS(r.5) // NO-FORMAT: attribute
TEST_CASE("basic_test")
{ {
owner<int*> p = new int(120); owner<int*> p = new int(120);
CHECK(*p == 120); EXPECT_TRUE(*p == 120);
f(p); f(p);
CHECK(*p == 121); EXPECT_TRUE(*p == 121);
delete p; delete p;
} }
TEST_CASE("check_pointer_constraint") TEST(owner_tests, check_pointer_constraint)
{ {
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{ {
@ -51,3 +60,7 @@ TEST_CASE("check_pointer_constraint")
} }
#endif #endif
} }
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,19 @@
#pragma warning(disable : 4702) // unreachable code #pragma warning(disable : 4702) // unreachable code
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/pointers> // for not_null, operator<, operator<=, operator> #include <gsl/pointers> // for not_null, operator<, operator<=, operator>
namespace gsl namespace gsl
@ -35,19 +47,20 @@ using namespace gsl;
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper(not_null<int*> p) { return *p == 12; } bool helper(not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool helper_const(not_null<const int*> p) { return *p == 12; } bool helper_const(not_null<const int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool strict_helper(strict_not_null<int*> p) { return *p == 12; } bool strict_helper(strict_not_null<int*> p) { return *p == 12; }
GSL_SUPPRESS(f.4) // NO-FORMAT: attribute GSL_SUPPRESS(f.4) // NO-FORMAT: attribute
bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; } bool strict_helper_const(strict_not_null<const int*> p) { return *p == 12; }
int* return_pointer() { return nullptr; } int* return_pointer() { return nullptr; }
const int* return_pointer_const() { return nullptr; } const int* return_pointer_const() { return nullptr; }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strict_notnull_tests, TestStrictNotNull)
TEST_CASE("TestStrictNotNull")
{ {
{ {
// raw ptr <-> strict_not_null // raw ptr <-> strict_not_null
@ -66,7 +79,7 @@ TEST_CASE("TestStrictNotNull")
helper(snn1); helper(snn1);
helper_const(snn1); helper_const(snn1);
CHECK(*snn1 == 42); EXPECT_TRUE(*snn1 == 42);
} }
{ {
@ -80,7 +93,7 @@ TEST_CASE("TestStrictNotNull")
strict_helper_const(snn1); strict_helper_const(snn1);
strict_helper_const(snn2); strict_helper_const(snn2);
CHECK(snn1 == snn2); EXPECT_TRUE(snn1 == snn2);
} }
{ {
@ -95,8 +108,8 @@ TEST_CASE("TestStrictNotNull")
helper(snn); helper(snn);
helper_const(snn); helper_const(snn);
CHECK(snn == nn1); EXPECT_TRUE(snn == nn1);
CHECK(snn == nn2); EXPECT_TRUE(snn == nn2);
} }
{ {
@ -111,16 +124,16 @@ TEST_CASE("TestStrictNotNull")
strict_helper(nn); strict_helper(nn);
strict_helper_const(nn); strict_helper_const(nn);
CHECK(snn1 == nn); EXPECT_TRUE(snn1 == nn);
CHECK(snn2 == nn); EXPECT_TRUE(snn2 == nn);
std::hash<strict_not_null<int*>> hash_snn; std::hash<strict_not_null<int*>> hash_snn;
std::hash<not_null<int*>> hash_nn; std::hash<not_null<int*>> hash_nn;
CHECK(hash_nn(snn1) == hash_nn(nn)); EXPECT_TRUE(hash_nn(snn1) == hash_nn(nn));
CHECK(hash_snn(snn1) == hash_nn(nn)); EXPECT_TRUE(hash_snn(snn1) == hash_nn(nn));
CHECK(hash_nn(snn1) == hash_nn(snn2)); EXPECT_TRUE(hash_nn(snn1) == hash_nn(snn2));
CHECK(hash_snn(snn1) == hash_snn(nn)); EXPECT_TRUE(hash_snn(snn1) == hash_snn(nn));
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -131,10 +144,18 @@ TEST_CASE("TestStrictNotNull")
} }
#if defined(__cplusplus) && (__cplusplus >= 201703L) #if defined(__cplusplus) && (__cplusplus >= 201703L)
namespace
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
{ {
static constexpr char deathstring[] = "Expected Death";
}
TEST(strict_notnull_tests, TestStrictNotNullConstructorTypeDeduction)
{
std::set_terminate([] {
std::cerr << "Expected Death. TestStrictNotNullConstructorTypeDeduction";
std::abort();
});
{ {
int i = 42; int i = 42;
@ -142,7 +163,7 @@ TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
helper(strict_not_null{&i}); helper(strict_not_null{&i});
helper_const(strict_not_null{&i}); helper_const(strict_not_null{&i});
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -153,7 +174,7 @@ TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
helper(strict_not_null{p}); helper(strict_not_null{p});
helper_const(strict_not_null{p}); helper_const(strict_not_null{p});
CHECK(*x == 42); EXPECT_TRUE(*x == 42);
} }
{ {
@ -161,7 +182,7 @@ TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
int* p1 = nullptr; int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
@ -169,14 +190,14 @@ TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
const int* p1 = nullptr; const int* p1 = nullptr;
const strict_not_null x{p1}; const strict_not_null x{p1};
}; };
CHECK_THROWS_AS(workaround_macro(), fail_fast); EXPECT_DEATH(workaround_macro(), deathstring);
} }
{ {
int* p = nullptr; int* p = nullptr;
CHECK_THROWS_AS(helper(strict_not_null{p}), fail_fast); EXPECT_DEATH(helper(strict_not_null{p}), deathstring);
CHECK_THROWS_AS(helper_const(strict_not_null{p}), fail_fast); EXPECT_DEATH(helper_const(strict_not_null{p}), deathstring);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -191,3 +212,7 @@ TEST_CASE("TestStrictNotNullConstructorTypeDeduction")
static_assert(std::is_nothrow_move_constructible<strict_not_null<void*>>::value, static_assert(std::is_nothrow_move_constructible<strict_not_null<void*>>::value,
"strict_not_null must be no-throw move constructible"); "strict_not_null must be no-throw move constructible");
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__

View File

@ -25,10 +25,17 @@
#if __clang__ || __GNUC__ #if __clang__ || __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif //disable warnings from gtest
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, CHECK... #if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_byte> // for byte #include <gsl/gsl_byte> // for byte
#include <gsl/gsl_util> // for narrow_cast #include <gsl/gsl_util> // for narrow_cast
#include <gsl/multi_span> // for strided_span, index, multi_span, strided_... #include <gsl/multi_span> // for strided_span, index, multi_span, strided_...
@ -39,24 +46,80 @@
#include <type_traits> // for integral_constant<>::value, is_convertible #include <type_traits> // for integral_constant<>::value, is_convertible
#include <vector> // for vector #include <vector> // for vector
namespace gsl {
struct fail_fast;
} // namespace gsl
using namespace std; using namespace std;
using namespace gsl; using namespace gsl;
namespace namespace
{ {
static constexpr char deathstring[] = "Expected Death";
struct BaseClass struct BaseClass
{ {
}; };
struct DerivedClass : BaseClass struct DerivedClass : BaseClass
{ {
}; };
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
void iterate_every_other_element(multi_span<int, dynamic_range> av)
{
// pick every other element
auto length = av.size() / 2;
#if defined(_MSC_VER) && _MSC_VER > 1800
auto bounds = strided_bounds<1>({length}, {2});
#else
auto bounds = strided_bounds<1>(multi_span_index<1>{length}, multi_span_index<1>{2});
#endif
strided_span<int, 1> strided(&av.data()[1], av.size() - 1, bounds);
EXPECT_TRUE(strided.size() == length);
EXPECT_TRUE(strided.bounds().index_bounds()[0] == length);
for (auto i = 0; i < strided.size(); ++i) {
EXPECT_TRUE(strided[i] == av[2 * i + 1]);
}
int idx = 0;
for (auto num : strided) {
EXPECT_TRUE(num == av[2 * idx + 1]);
idx++;
}
} }
TEST_CASE("span_section_test") GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute // TODO: does not work
void iterate_second_slice(multi_span<int, dynamic_range, dynamic_range, dynamic_range> av)
{
const int expected[6] = {2, 3, 10, 11, 18, 19};
auto section = av.section({0, 1, 0}, {3, 1, 2});
for (auto i = 0; i < section.extent<0>(); ++i) {
for (auto j = 0; j < section.extent<1>(); ++j)
for (auto k = 0; k < section.extent<2>(); ++k) {
auto idx = multi_span_index<3>{i, j, k}; // avoid braces in the EXPECT_TRUE macro
EXPECT_TRUE(section[idx] == expected[2 * i + 2 * j + k]);
}
}
for (auto i = 0; i < section.extent<0>(); ++i) {
for (auto j = 0; j < section.extent<1>(); ++j)
for (auto k = 0; k < section.extent<2>(); ++k)
EXPECT_TRUE(section[i][j][k] == expected[2 * i + 2 * j + k]);
}
int i = 0;
for (const auto num : section) {
EXPECT_TRUE(num == expected[i]);
i++;
}
}
}
TEST(strided_span_tests, span_section_test)
{ {
int a[30][4][5]; int a[30][4][5];
@ -66,51 +129,54 @@ TEST_CASE("span_section_test")
(void) subsub; (void) subsub;
} }
TEST_CASE("span_section") TEST(strided_span_tests, span_section)
{ {
std::vector<int> data(5 * 10); std::vector<int> data(5 * 10);
std::iota(begin(data), end(data), 0); std::iota(begin(data), end(data), 0);
const multi_span<int, 5, 10> av = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>()); const multi_span<int, 5, 10> av = as_multi_span(multi_span<int>{data}, dim<5>(), dim<10>());
const strided_span<int, 2> av_section_1 = av.section({1, 2}, {3, 4}); const strided_span<int, 2> av_section_1 = av.section({1, 2}, {3, 4});
CHECK(!av_section_1.empty()); EXPECT_TRUE(!av_section_1.empty());
CHECK((av_section_1[{0, 0}] == 12)); EXPECT_TRUE((av_section_1[{0, 0}] == 12));
CHECK((av_section_1[{0, 1}] == 13)); EXPECT_TRUE((av_section_1[{0, 1}] == 13));
CHECK((av_section_1[{1, 0}] == 22)); EXPECT_TRUE((av_section_1[{1, 0}] == 22));
CHECK((av_section_1[{2, 3}] == 35)); EXPECT_TRUE((av_section_1[{2, 3}] == 35));
const strided_span<int, 2> av_section_2 = av_section_1.section({1, 2}, {2, 2}); const strided_span<int, 2> av_section_2 = av_section_1.section({1, 2}, {2, 2});
CHECK(!av_section_2.empty()); EXPECT_TRUE(!av_section_2.empty());
CHECK((av_section_2[{0, 0}] == 24)); EXPECT_TRUE((av_section_2[{0, 0}] == 24));
CHECK((av_section_2[{0, 1}] == 25)); EXPECT_TRUE((av_section_2[{0, 1}] == 25));
CHECK((av_section_2[{1, 0}] == 34)); EXPECT_TRUE((av_section_2[{1, 0}] == 34));
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_constructors)
TEST_CASE("strided_span_constructors")
{ {
// Check stride constructor // EXPECT_TRUE stride constructor
{ {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; const int carr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
strided_span<int, 1> sav1{arr, {{9}, {1}}}; // T -> T strided_span<int, 1> sav1{arr, {{9}, {1}}}; // T -> T
CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{9}); EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{9});
CHECK(sav1.bounds().stride() == 1); EXPECT_TRUE(sav1.bounds().stride() == 1);
CHECK((sav1[0] == 1 && sav1[8] == 9)); EXPECT_TRUE(sav1[0] == 1);
EXPECT_TRUE(sav1[8] == 9);
strided_span<const int, 1> sav2{carr, {{4}, {2}}}; // const T -> const T strided_span<const int, 1> sav2{carr, {{4}, {2}}}; // const T -> const T
CHECK(sav2.bounds().index_bounds() == multi_span_index<1>{4}); EXPECT_TRUE(sav2.bounds().index_bounds() == multi_span_index<1>{4});
CHECK(sav2.bounds().strides() == multi_span_index<1>{2}); EXPECT_TRUE(sav2.bounds().strides() == multi_span_index<1>{2});
CHECK((sav2[0] == 1 && sav2[3] == 7)); EXPECT_TRUE(sav2[0] == 1);
EXPECT_TRUE(sav2[3] == 7);
strided_span<int, 2> sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T strided_span<int, 2> sav3{arr, {{2, 2}, {6, 2}}}; // T -> const T
CHECK((sav3.bounds().index_bounds() == multi_span_index<2>{2, 2})); EXPECT_TRUE((sav3.bounds().index_bounds() == multi_span_index<2>{2, 2}));
CHECK((sav3.bounds().strides() == multi_span_index<2>{6, 2})); EXPECT_TRUE((sav3.bounds().strides() == multi_span_index<2>{6, 2}));
CHECK((sav3[{0, 0}] == 1 && sav3[{0, 1}] == 3 && sav3[{1, 0}] == 7)); EXPECT_TRUE((sav3[{0, 0}]) == 1);
EXPECT_TRUE((sav3[{0, 1}]) == 3);
EXPECT_TRUE((sav3[{1, 0}]) == 7);
} }
// Check multi_span constructor // EXPECT_TRUE multi_span constructor
{ {
int arr[] = {1, 2}; int arr[] = {1, 2};
@ -119,9 +185,9 @@ TEST_CASE("strided_span_constructors")
const multi_span<int> src = arr; const multi_span<int> src = arr;
strided_span<int, 1> sav{src, {2, 1}}; strided_span<int, 1> sav{src, {2, 1}};
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav.bounds().strides() == multi_span_index<1>{1});
CHECK(sav[1] == 2); EXPECT_TRUE(sav[1] == 2);
#if defined(_MSC_VER) && _MSC_VER > 1800 #if defined(_MSC_VER) && _MSC_VER > 1800
// strided_span<const int, 1> sav_c{ {src}, {2, 1} }; // strided_span<const int, 1> sav_c{ {src}, {2, 1} };
@ -131,9 +197,9 @@ TEST_CASE("strided_span_constructors")
strided_span<const int, 1> sav_c{multi_span<const int>{src}, strided_span<const int, 1> sav_c{multi_span<const int>{src},
strided_bounds<1>{2, 1}}; strided_bounds<1>{2, 1}};
#endif #endif
CHECK(sav_c.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_c.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_c.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_c.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_c[1] == 2); EXPECT_TRUE(sav_c[1] == 2);
#if defined(_MSC_VER) && _MSC_VER > 1800 #if defined(_MSC_VER) && _MSC_VER > 1800
strided_span<volatile int, 1> sav_v{src, {2, 1}}; strided_span<volatile int, 1> sav_v{src, {2, 1}};
@ -141,9 +207,9 @@ TEST_CASE("strided_span_constructors")
strided_span<volatile int, 1> sav_v{multi_span<volatile int>{src}, strided_span<volatile int, 1> sav_v{multi_span<volatile int>{src},
strided_bounds<1>{2, 1}}; strided_bounds<1>{2, 1}};
#endif #endif
CHECK(sav_v.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_v.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_v.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_v.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_v[1] == 2); EXPECT_TRUE(sav_v[1] == 2);
#if defined(_MSC_VER) && _MSC_VER > 1800 #if defined(_MSC_VER) && _MSC_VER > 1800
strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
@ -151,9 +217,9 @@ TEST_CASE("strided_span_constructors")
strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src}, strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src},
strided_bounds<1>{2, 1}}; strided_bounds<1>{2, 1}};
#endif #endif
CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_cv[1] == 2); EXPECT_TRUE(sav_cv[1] == 2);
} }
// From const-qualified source // From const-qualified source
@ -161,9 +227,9 @@ TEST_CASE("strided_span_constructors")
const multi_span<const int> src{arr}; const multi_span<const int> src{arr};
strided_span<const int, 1> sav_c{src, {2, 1}}; strided_span<const int, 1> sav_c{src, {2, 1}};
CHECK(sav_c.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_c.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_c.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_c.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_c[1] == 2); EXPECT_TRUE(sav_c[1] == 2);
#if defined(_MSC_VER) && _MSC_VER > 1800 #if defined(_MSC_VER) && _MSC_VER > 1800
strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
@ -172,9 +238,9 @@ TEST_CASE("strided_span_constructors")
strided_bounds<1>{2, 1}}; strided_bounds<1>{2, 1}};
#endif #endif
CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_cv[1] == 2); EXPECT_TRUE(sav_cv[1] == 2);
} }
// From volatile-qualified source // From volatile-qualified source
@ -182,9 +248,9 @@ TEST_CASE("strided_span_constructors")
const multi_span<volatile int> src{arr}; const multi_span<volatile int> src{arr};
strided_span<volatile int, 1> sav_v{src, {2, 1}}; strided_span<volatile int, 1> sav_v{src, {2, 1}};
CHECK(sav_v.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_v.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_v.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_v.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_v[1] == 2); EXPECT_TRUE(sav_v[1] == 2);
#if defined(_MSC_VER) && _MSC_VER > 1800 #if defined(_MSC_VER) && _MSC_VER > 1800
strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
@ -192,9 +258,9 @@ TEST_CASE("strided_span_constructors")
strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src}, strided_span<const volatile int, 1> sav_cv{multi_span<const volatile int>{src},
strided_bounds<1>{2, 1}}; strided_bounds<1>{2, 1}};
#endif #endif
CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_cv[1] == 2); EXPECT_TRUE(sav_cv[1] == 2);
} }
// From cv-qualified source // From cv-qualified source
@ -202,19 +268,19 @@ TEST_CASE("strided_span_constructors")
const multi_span<const volatile int> src{arr}; const multi_span<const volatile int> src{arr};
strided_span<const volatile int, 1> sav_cv{src, {2, 1}}; strided_span<const volatile int, 1> sav_cv{src, {2, 1}};
CHECK(sav_cv.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav_cv.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav_cv.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav_cv.bounds().strides() == multi_span_index<1>{1});
CHECK(sav_cv[1] == 2); EXPECT_TRUE(sav_cv[1] == 2);
} }
} }
// Check const-casting constructor // EXPECT_TRUE const-casting constructor
{ {
int arr[2] = {4, 5}; int arr[2] = {4, 5};
const multi_span<int, 2> av(arr, 2); const multi_span<int, 2> av(arr, 2);
multi_span<const int, 2> av2{av}; multi_span<const int, 2> av2{av};
CHECK(av2[1] == 5); EXPECT_TRUE(av2[1] == 5);
static_assert( static_assert(
std::is_convertible<const multi_span<int, 2>, multi_span<const int, 2>>::value, std::is_convertible<const multi_span<int, 2>, multi_span<const int, 2>>::value,
@ -222,34 +288,35 @@ TEST_CASE("strided_span_constructors")
const strided_span<int, 1> src{arr, {2, 1}}; const strided_span<int, 1> src{arr, {2, 1}};
strided_span<const int, 1> sav{src}; strided_span<const int, 1> sav{src};
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav.bounds().stride() == 1); EXPECT_TRUE(sav.bounds().stride() == 1);
CHECK(sav[1] == 5); EXPECT_TRUE(sav[1] == 5);
static_assert( static_assert(
std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value, std::is_convertible<const strided_span<int, 1>, strided_span<const int, 1>>::value,
"ctor is not implicit!"); "ctor is not implicit!");
} }
// Check copy constructor // EXPECT_TRUE copy constructor
{ {
int arr1[2] = {3, 4}; int arr1[2] = {3, 4};
const strided_span<int, 1> src1{arr1, {2, 1}}; const strided_span<int, 1> src1{arr1, {2, 1}};
strided_span<int, 1> sav1{src1}; strided_span<int, 1> sav1{src1};
CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav1.bounds().stride() == 1); EXPECT_TRUE(sav1.bounds().stride() == 1);
CHECK(sav1[0] == 3); EXPECT_TRUE(sav1[0] == 3);
int arr2[6] = {1, 2, 3, 4, 5, 6}; int arr2[6] = {1, 2, 3, 4, 5, 6};
const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}}; const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}};
strided_span<const int, 2> sav2{src2}; strided_span<const int, 2> sav2{src2};
CHECK((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2})); EXPECT_TRUE((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2}));
CHECK((sav2.bounds().strides() == multi_span_index<2>{2, 1})); EXPECT_TRUE((sav2.bounds().strides() == multi_span_index<2>{2, 1}));
CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); EXPECT_TRUE((sav2[{0, 0}]) == 1);
EXPECT_TRUE((sav2[{2, 0}]) == 5);
} }
// Check const-casting assignment operator // EXPECT_TRUE const-casting assignment operator
{ {
int arr1[2] = {1, 2}; int arr1[2] = {1, 2};
int arr2[6] = {3, 4, 5, 6, 7, 8}; int arr2[6] = {3, 4, 5, 6, 7, 8};
@ -257,38 +324,38 @@ TEST_CASE("strided_span_constructors")
const strided_span<int, 1> src{arr1, {{2}, {1}}}; const strided_span<int, 1> src{arr1, {{2}, {1}}};
strided_span<const int, 1> sav{arr2, {{3}, {2}}}; strided_span<const int, 1> sav{arr2, {{3}, {2}}};
strided_span<const int, 1>& sav_ref = (sav = src); strided_span<const int, 1>& sav_ref = (sav = src);
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav.bounds().strides() == multi_span_index<1>{1});
CHECK(sav[0] == 1); EXPECT_TRUE(sav[0] == 1);
CHECK(&sav_ref == &sav); EXPECT_TRUE(&sav_ref == &sav);
} }
// Check copy assignment operator // EXPECT_TRUE copy assignment operator
{ {
int arr1[2] = {3, 4}; int arr1[2] = {3, 4};
int arr1b[1] = {0}; int arr1b[1] = {0};
const strided_span<int, 1> src1{arr1, {2, 1}}; const strided_span<int, 1> src1{arr1, {2, 1}};
strided_span<int, 1> sav1{arr1b, {1, 1}}; strided_span<int, 1> sav1{arr1b, {1, 1}};
strided_span<int, 1>& sav1_ref = (sav1 = src1); strided_span<int, 1>& sav1_ref = (sav1 = src1);
CHECK(sav1.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav1.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav1.bounds().strides() == multi_span_index<1>{1}); EXPECT_TRUE(sav1.bounds().strides() == multi_span_index<1>{1});
CHECK(sav1[0] == 3); EXPECT_TRUE(sav1[0] == 3);
CHECK(&sav1_ref == &sav1); EXPECT_TRUE(&sav1_ref == &sav1);
const int arr2[6] = {1, 2, 3, 4, 5, 6}; const int arr2[6] = {1, 2, 3, 4, 5, 6};
const int arr2b[1] = {0}; const int arr2b[1] = {0};
const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}}; const strided_span<const int, 2> src2{arr2, {{3, 2}, {2, 1}}};
strided_span<const int, 2> sav2{arr2b, {{1, 1}, {1, 1}}}; strided_span<const int, 2> sav2{arr2b, {{1, 1}, {1, 1}}};
strided_span<const int, 2>& sav2_ref = (sav2 = src2); strided_span<const int, 2>& sav2_ref = (sav2 = src2);
CHECK((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2})); EXPECT_TRUE((sav2.bounds().index_bounds() == multi_span_index<2>{3, 2}));
CHECK((sav2.bounds().strides() == multi_span_index<2>{2, 1})); EXPECT_TRUE((sav2.bounds().strides() == multi_span_index<2>{2, 1}));
CHECK((sav2[{0, 0}] == 1 && sav2[{2, 0}] == 5)); EXPECT_TRUE((sav2[{0, 0}] == 1));
CHECK(&sav2_ref == &sav2); EXPECT_TRUE((sav2[{2, 0}] == 5));
EXPECT_TRUE(&sav2_ref == &sav2);
} }
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_slice)
TEST_CASE("strided_span_slice")
{ {
std::vector<int> data(5 * 10); std::vector<int> data(5 * 10);
std::iota(begin(data), end(data), 0); std::iota(begin(data), end(data), 0);
@ -303,19 +370,18 @@ TEST_CASE("strided_span_slice")
{{5, 10}, {10, 1}}}; {{5, 10}, {10, 1}}};
strided_span<int, 1> sav_sl = sav[2]; strided_span<int, 1> sav_sl = sav[2];
CHECK(sav_sl[0] == 20); EXPECT_TRUE(sav_sl[0] == 20);
CHECK(sav_sl[9] == 29); EXPECT_TRUE(sav_sl[9] == 29);
strided_span<const int, 1> csav_sl = sav[3]; strided_span<const int, 1> csav_sl = sav[3];
CHECK(csav_sl[0] == 30); EXPECT_TRUE(csav_sl[0] == 30);
CHECK(csav_sl[9] == 39); EXPECT_TRUE(csav_sl[9] == 39);
CHECK(sav[4][0] == 40); EXPECT_TRUE(sav[4][0] == 40);
CHECK(sav[4][9] == 49); EXPECT_TRUE(sav[4][9] == 49);
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_column_major)
TEST_CASE("strided_span_column_major")
{ {
// strided_span may be used to accommodate more peculiar // strided_span may be used to accommodate more peculiar
// use cases, such as column-major multidimensional array // use cases, such as column-major multidimensional array
@ -325,119 +391,123 @@ TEST_CASE("strided_span_column_major")
strided_span<int, 2> cm_sav{cm_array, {{5, 3}, {1, 5}}}; strided_span<int, 2> cm_sav{cm_array, {{5, 3}, {1, 5}}};
// Accessing elements // Accessing elements
CHECK((cm_sav[{0, 0}] == 1)); EXPECT_TRUE((cm_sav[{0, 0}] == 1));
CHECK((cm_sav[{0, 1}] == 2)); EXPECT_TRUE((cm_sav[{0, 1}] == 2));
CHECK((cm_sav[{1, 0}] == 4)); EXPECT_TRUE((cm_sav[{1, 0}] == 4));
CHECK((cm_sav[{4, 2}] == 15)); EXPECT_TRUE((cm_sav[{4, 2}] == 15));
// Slice // Slice
strided_span<int, 1> cm_sl = cm_sav[3]; strided_span<int, 1> cm_sl = cm_sav[3];
CHECK(cm_sl[0] == 10); EXPECT_TRUE(cm_sl[0] == 10);
CHECK(cm_sl[1] == 11); EXPECT_TRUE(cm_sl[1] == 11);
CHECK(cm_sl[2] == 12); EXPECT_TRUE(cm_sl[2] == 12);
// Section // Section
strided_span<int, 2> cm_sec = cm_sav.section({2, 1}, {3, 2}); strided_span<int, 2> cm_sec = cm_sav.section({2, 1}, {3, 2});
CHECK((cm_sec.bounds().index_bounds() == multi_span_index<2>{3, 2})); EXPECT_TRUE((cm_sec.bounds().index_bounds() == multi_span_index<2>{3, 2}));
CHECK((cm_sec[{0, 0}] == 8)); EXPECT_TRUE((cm_sec[{0, 0}] == 8));
CHECK((cm_sec[{0, 1}] == 9)); EXPECT_TRUE((cm_sec[{0, 1}] == 9));
CHECK((cm_sec[{1, 0}] == 11)); EXPECT_TRUE((cm_sec[{1, 0}] == 11));
CHECK((cm_sec[{2, 1}] == 15)); EXPECT_TRUE((cm_sec[{2, 1}] == 15));
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_bounds)
TEST_CASE("strided_span_bounds")
{ {
int arr[] = {0, 1, 2, 3}; int arr[] = {0, 1, 2, 3};
multi_span<int> av(arr); multi_span<int> av(arr);
std::set_terminate([] {
std::cerr << "Expected Death. strided_span_bounds";
std::abort();
});
{ {
// incorrect sections // incorrect sections
CHECK_THROWS_AS(av.section(0, 0)[0], fail_fast); EXPECT_DEATH(av.section(0, 0)[0], deathstring);
CHECK_THROWS_AS(av.section(1, 0)[0], fail_fast); EXPECT_DEATH(av.section(1, 0)[0], deathstring);
CHECK_THROWS_AS(av.section(1, 1)[1], fail_fast); EXPECT_DEATH(av.section(1, 1)[1], deathstring);
CHECK_THROWS_AS(av.section(2, 5), fail_fast); EXPECT_DEATH(av.section(2, 5), deathstring);
CHECK_THROWS_AS(av.section(5, 2), fail_fast); EXPECT_DEATH(av.section(5, 2), deathstring);
CHECK_THROWS_AS(av.section(5, 0), fail_fast); EXPECT_DEATH(av.section(5, 0), deathstring);
CHECK_THROWS_AS(av.section(0, 5), fail_fast); EXPECT_DEATH(av.section(0, 5), deathstring);
CHECK_THROWS_AS(av.section(5, 5), fail_fast); EXPECT_DEATH(av.section(5, 5), deathstring);
} }
{ {
// zero stride // zero stride
strided_span<int, 1> sav{av, {{4}, {}}}; strided_span<int, 1> sav{av, {{4}, {}}};
CHECK(sav[0] == 0); EXPECT_TRUE(sav[0] == 0);
CHECK(sav[3] == 0); EXPECT_TRUE(sav[3] == 0);
CHECK_THROWS_AS(sav[4], fail_fast); EXPECT_DEATH(sav[4], deathstring);
} }
{ {
// zero extent // zero extent
strided_span<int, 1> sav{av, {{}, {1}}}; strided_span<int, 1> sav{av, {{}, {1}}};
CHECK_THROWS_AS(sav[0], fail_fast); EXPECT_DEATH(sav[0], deathstring);
} }
{ {
// zero extent and stride // zero extent and stride
strided_span<int, 1> sav{av, {{}, {}}}; strided_span<int, 1> sav{av, {{}, {}}};
CHECK_THROWS_AS(sav[0], fail_fast); EXPECT_DEATH(sav[0], deathstring);
} }
{ {
// strided array ctor with matching strided bounds // strided array ctor with matching strided bounds
strided_span<int, 1> sav{arr, {4, 1}}; strided_span<int, 1> sav{arr, {4, 1}};
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{4}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{4});
CHECK(sav[3] == 3); EXPECT_TRUE(sav[3] == 3);
CHECK_THROWS_AS(sav[4], fail_fast); EXPECT_DEATH(sav[4], deathstring);
} }
{ {
// strided array ctor with smaller strided bounds // strided array ctor with smaller strided bounds
strided_span<int, 1> sav{arr, {2, 1}}; strided_span<int, 1> sav{arr, {2, 1}};
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav[1] == 1); EXPECT_TRUE(sav[1] == 1);
CHECK_THROWS_AS(sav[2], fail_fast); EXPECT_DEATH(sav[2], deathstring);
} }
{ {
// strided array ctor with fitting irregular bounds // strided array ctor with fitting irregular bounds
strided_span<int, 1> sav{arr, {2, 3}}; strided_span<int, 1> sav{arr, {2, 3}};
CHECK(sav.bounds().index_bounds() == multi_span_index<1>{2}); EXPECT_TRUE(sav.bounds().index_bounds() == multi_span_index<1>{2});
CHECK(sav[0] == 0); EXPECT_TRUE(sav[0] == 0);
CHECK(sav[1] == 3); EXPECT_TRUE(sav[1] == 3);
CHECK_THROWS_AS(sav[2], fail_fast); EXPECT_DEATH(sav[2], deathstring);
} }
{ {
// bounds cross data boundaries - from static arrays // bounds cross data boundaries - from static arrays
CHECK_THROWS_AS((strided_span<int, 1>{arr, {3, 2}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{arr, {3, 2}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{arr, {3, 3}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{arr, {3, 3}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{arr, {4, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{arr, {4, 5}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{arr, {5, 1}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{arr, {5, 1}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{arr, {5, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{arr, {5, 5}}), deathstring);
} }
{ {
// bounds cross data boundaries - from array view // bounds cross data boundaries - from array view
CHECK_THROWS_AS((strided_span<int, 1>{av, {3, 2}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av, {3, 2}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av, {3, 3}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av, {3, 3}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av, {4, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av, {4, 5}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av, {5, 1}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av, {5, 1}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av, {5, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av, {5, 5}}), deathstring);
} }
{ {
// bounds cross data boundaries - from dynamic arrays // bounds cross data boundaries - from dynamic arrays
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {3, 2}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {3, 2}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {3, 3}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {3, 3}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {4, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {4, 5}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {5, 1}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {5, 1}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 4, {5, 5}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 4, {5, 5}}), deathstring);
CHECK_THROWS_AS((strided_span<int, 1>{av.data(), 2, {2, 2}}), fail_fast); EXPECT_DEATH((strided_span<int, 1>{av.data(), 2, {2, 2}}), deathstring);
} }
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -464,12 +534,16 @@ TEST_CASE("strided_span_bounds")
#endif #endif
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_type_conversion)
TEST_CASE("strided_span_type_conversion")
{ {
int arr[] = {0, 1, 2, 3}; int arr[] = {0, 1, 2, 3};
multi_span<int> av(arr); multi_span<int> av(arr);
std::set_terminate([] {
std::cerr << "Expected Death. strided_span_type_conversion";
std::abort();
});
{ {
strided_span<int, 1> sav{av.data(), av.size(), {av.size() / 2, 2}}; strided_span<int, 1> sav{av.data(), av.size(), {av.size() / 2, 2}};
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
@ -490,10 +564,10 @@ TEST_CASE("strided_span_type_conversion")
strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}}; strided_bounds<2> bounds{{2, bytes.size() / 4}, {bytes.size() / 2, 1}};
strided_span<const byte, 2> sav2{bytes.data(), bytes.size(), bounds}; strided_span<const byte, 2> sav2{bytes.data(), bytes.size(), bounds};
strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>(); strided_span<const int, 2> sav3 = sav2.as_strided_span<const int>();
CHECK(sav3[0][0] == 0); EXPECT_TRUE(sav3[0][0] == 0);
CHECK(sav3[1][0] == 2); EXPECT_TRUE(sav3[1][0] == 2);
CHECK_THROWS_AS(sav3[1][1], fail_fast); EXPECT_DEATH(sav3[1][1], deathstring);
CHECK_THROWS_AS(sav3[0][1], fail_fast); EXPECT_DEATH(sav3[0][1], deathstring);
} }
// retype strided array with regular strides - from multi_span // retype strided array with regular strides - from multi_span
@ -503,10 +577,10 @@ TEST_CASE("strided_span_type_conversion")
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
strided_span<const byte, 2> sav2{bytes2, bounds}; strided_span<const byte, 2> sav2{bytes2, bounds};
strided_span<int, 2> sav3 = sav2.as_strided_span<int>(); strided_span<int, 2> sav3 = sav2.as_strided_span<int>();
CHECK(sav3[0][0] == 0); EXPECT_TRUE(sav3[0][0] == 0);
CHECK(sav3[1][0] == 2); EXPECT_TRUE(sav3[1][0] == 2);
CHECK_THROWS_AS(sav3[1][1], fail_fast); EXPECT_DEATH(sav3[1][1], deathstring);
CHECK_THROWS_AS(sav3[0][1], fail_fast); EXPECT_DEATH(sav3[0][1], deathstring);
} }
// retype strided array with not enough elements - last dimension of the array is too small // retype strided array with not enough elements - last dimension of the array is too small
@ -515,7 +589,7 @@ TEST_CASE("strided_span_type_conversion")
multi_span<const byte, 2, dynamic_range> bytes2 = multi_span<const byte, 2, dynamic_range> bytes2 =
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
strided_span<const byte, 2> sav2{bytes2, bounds}; strided_span<const byte, 2> sav2{bytes2, bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
// retype strided array with not enough elements - strides are too small // retype strided array with not enough elements - strides are too small
@ -524,7 +598,7 @@ TEST_CASE("strided_span_type_conversion")
multi_span<const byte, 2, dynamic_range> bytes2 = multi_span<const byte, 2, dynamic_range> bytes2 =
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
strided_span<const byte, 2> sav2{bytes2, bounds}; strided_span<const byte, 2> sav2{bytes2, bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
// retype strided array with not enough elements - last dimension does not divide by the new // retype strided array with not enough elements - last dimension does not divide by the new
@ -534,7 +608,7 @@ TEST_CASE("strided_span_type_conversion")
multi_span<const byte, 2, dynamic_range> bytes2 = multi_span<const byte, 2, dynamic_range> bytes2 =
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
strided_span<const byte, 2> sav2{bytes2, bounds}; strided_span<const byte, 2> sav2{bytes2, bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
// retype strided array with not enough elements - strides does not divide by the new // retype strided array with not enough elements - strides does not divide by the new
@ -544,88 +618,63 @@ TEST_CASE("strided_span_type_conversion")
multi_span<const byte, 2, dynamic_range> bytes2 = multi_span<const byte, 2, dynamic_range> bytes2 =
as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2)); as_multi_span(bytes, dim<2>(), dim(bytes.size() / 2));
strided_span<const byte, 2> sav2{bytes2, bounds}; strided_span<const byte, 2> sav2{bytes2, bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
// retype strided array with irregular strides - from raw data // retype strided array with irregular strides - from raw data
{ {
strided_bounds<1> bounds{bytes.size() / 2, 2}; strided_bounds<1> bounds{bytes.size() / 2, 2};
strided_span<const byte, 1> sav2{bytes.data(), bytes.size(), bounds}; strided_span<const byte, 1> sav2{bytes.data(), bytes.size(), bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
// retype strided array with irregular strides - from multi_span // retype strided array with irregular strides - from multi_span
{ {
strided_bounds<1> bounds{bytes.size() / 2, 2}; strided_bounds<1> bounds{bytes.size() / 2, 2};
strided_span<const byte, 1> sav2{bytes, bounds}; strided_span<const byte, 1> sav2{bytes, bounds};
CHECK_THROWS_AS(sav2.as_strided_span<int>(), fail_fast); EXPECT_DEATH(sav2.as_strided_span<int>(), deathstring);
} }
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, empty_strided_spans)
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
TEST_CASE("empty_strided_spans")
{ {
std::set_terminate([] {
std::cerr << "Expected Death. empty_strided_spans";
std::abort();
});
{ {
multi_span<int, 0> empty_av(nullptr); multi_span<int, 0> empty_av(nullptr);
strided_span<int, 1> empty_sav{empty_av, {0, 1}}; strided_span<int, 1> empty_sav{empty_av, {0, 1}};
CHECK(empty_sav.bounds().index_bounds() == multi_span_index<1>{0}); EXPECT_TRUE(empty_sav.bounds().index_bounds() == multi_span_index<1>{0});
CHECK(empty_sav.empty()); EXPECT_TRUE(empty_sav.empty());
CHECK_THROWS_AS(empty_sav[0], fail_fast); EXPECT_DEATH(empty_sav[0], deathstring);
CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); EXPECT_DEATH(empty_sav.begin()[0], deathstring);
CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); EXPECT_DEATH(empty_sav.cbegin()[0], deathstring);
for (const auto& v : empty_sav) { for (const auto& v : empty_sav) {
(void) v; (void) v;
CHECK(false); EXPECT_TRUE(false);
} }
} }
{ {
strided_span<int, 1> empty_sav{nullptr, 0, {0, 1}}; strided_span<int, 1> empty_sav{nullptr, 0, {0, 1}};
CHECK(empty_sav.bounds().index_bounds() == multi_span_index<1>{0}); EXPECT_TRUE(empty_sav.bounds().index_bounds() == multi_span_index<1>{0});
CHECK_THROWS_AS(empty_sav[0], fail_fast); EXPECT_DEATH(empty_sav[0], deathstring);
CHECK_THROWS_AS(empty_sav.begin()[0], fail_fast); EXPECT_DEATH(empty_sav.begin()[0], deathstring);
CHECK_THROWS_AS(empty_sav.cbegin()[0], fail_fast); EXPECT_DEATH(empty_sav.cbegin()[0], deathstring);
for (const auto& v : empty_sav) { for (const auto& v : empty_sav) {
(void) v; (void) v;
CHECK(false); EXPECT_TRUE(false);
} }
} }
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_section_iteration)
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
void iterate_every_other_element(multi_span<int, dynamic_range> av)
{
// pick every other element
auto length = av.size() / 2;
#if defined(_MSC_VER) && _MSC_VER > 1800
auto bounds = strided_bounds<1>({length}, {2});
#else
auto bounds = strided_bounds<1>(multi_span_index<1>{length}, multi_span_index<1>{2});
#endif
strided_span<int, 1> strided(&av.data()[1], av.size() - 1, bounds);
CHECK(strided.size() == length);
CHECK(strided.bounds().index_bounds()[0] == length);
for (auto i = 0; i < strided.size(); ++i) {
CHECK(strided[i] == av[2 * i + 1]);
}
int idx = 0;
for (auto num : strided) {
CHECK(num == av[2 * idx + 1]);
idx++;
}
}
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
TEST_CASE("strided_span_section_iteration")
{ {
int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3}; int arr[8] = {4, 0, 5, 1, 6, 2, 7, 3};
@ -642,12 +691,7 @@ TEST_CASE("strided_span_section_iteration")
} }
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, dynamic_strided_span_section_iteration)
GSL_SUPPRESS(r.11) // NO-FORMAT: attribute
GSL_SUPPRESS(r.3) // NO-FORMAT: attribute
GSL_SUPPRESS(r.5) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
TEST_CASE("dynamic_strided_span_section_iteration")
{ {
auto arr = new int[8]; auto arr = new int[8];
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
@ -661,39 +705,7 @@ TEST_CASE("dynamic_strided_span_section_iteration")
delete[] arr; delete[] arr;
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_section_iteration_3d)
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute // TODO: does not work
void iterate_second_slice(multi_span<int, dynamic_range, dynamic_range, dynamic_range> av)
{
const int expected[6] = {2, 3, 10, 11, 18, 19};
auto section = av.section({0, 1, 0}, {3, 1, 2});
for (auto i = 0; i < section.extent<0>(); ++i) {
for (auto j = 0; j < section.extent<1>(); ++j)
for (auto k = 0; k < section.extent<2>(); ++k) {
auto idx = multi_span_index<3>{i, j, k}; // avoid braces in the CHECK macro
CHECK(section[idx] == expected[2 * i + 2 * j + k]);
}
}
for (auto i = 0; i < section.extent<0>(); ++i) {
for (auto j = 0; j < section.extent<1>(); ++j)
for (auto k = 0; k < section.extent<2>(); ++k)
CHECK(section[i][j][k] == expected[2 * i + 2 * j + k]);
}
int i = 0;
for (const auto num : section) {
CHECK(num == expected[i]);
i++;
}
}
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("strided_span_section_iteration_3d")
{ {
int arr[3][4][2]{}; int arr[3][4][2]{};
for (auto i = 0; i < 3; ++i) { for (auto i = 0; i < 3; ++i) {
@ -707,12 +719,7 @@ TEST_CASE("strided_span_section_iteration_3d")
} }
} }
GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute TEST(strided_span_tests, dynamic_strided_span_section_iteration_3d)
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute
GSL_SUPPRESS(r.3) // NO-FORMAT: attribute
GSL_SUPPRESS(r.5) // NO-FORMAT: attribute
GSL_SUPPRESS(r.11) // NO-FORMAT: attribute
TEST_CASE("dynamic_strided_span_section_iteration_3d")
{ {
const auto height = 12, width = 2; const auto height = 12, width = 2;
const auto size = height * width; const auto size = height * width;
@ -744,11 +751,13 @@ TEST_CASE("dynamic_strided_span_section_iteration_3d")
delete[] arr; delete[] arr;
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(strided_span_tests, strided_span_conversion)
GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute
GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute
TEST_CASE("strided_span_conversion")
{ {
std::set_terminate([] {
std::cerr << "Expected Death. strided_span_conversion";
std::abort();
});
// get an multi_span of 'c' values from the list of X's // get an multi_span of 'c' values from the list of X's
struct X struct X
@ -767,8 +776,8 @@ TEST_CASE("strided_span_conversion")
// convert to 4x12 array of bytes // convert to 4x12 array of bytes
auto av = as_multi_span(as_bytes(as_multi_span(&arr[0], 4)), dim(d1), dim(d2)); auto av = as_multi_span(as_bytes(as_multi_span(&arr[0], 4)), dim(d1), dim(d2));
CHECK(av.bounds().index_bounds()[0] == 4); EXPECT_TRUE(av.bounds().index_bounds()[0] == 4);
CHECK(av.bounds().index_bounds()[1] == 12); EXPECT_TRUE(av.bounds().index_bounds()[1] == 12);
// get the last 4 columns // get the last 4 columns
auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2], auto section = av.section({0, 2 * s}, {4, s}); // { { arr[0].c[0], arr[0].c[1], arr[0].c[2],
@ -778,8 +787,8 @@ TEST_CASE("strided_span_conversion")
// convert to array 4x1 array of integers // convert to array 4x1 array of integers
auto cs = section.as_strided_span<int>(); // { { arr[0].c }, {arr[1].c } , ... } auto cs = section.as_strided_span<int>(); // { { arr[0].c }, {arr[1].c } , ... }
CHECK(cs.bounds().index_bounds()[0] == 4); EXPECT_TRUE(cs.bounds().index_bounds()[0] == 4);
CHECK(cs.bounds().index_bounds()[1] == 1); EXPECT_TRUE(cs.bounds().index_bounds()[1] == 1);
// transpose to 1x4 array // transpose to 1x4 array
strided_bounds<2> reverse_bounds{ strided_bounds<2> reverse_bounds{
@ -791,16 +800,16 @@ TEST_CASE("strided_span_conversion")
// slice to get a one-dimensional array of c's // slice to get a one-dimensional array of c's
strided_span<int, 1> result = transposed[0]; strided_span<int, 1> result = transposed[0];
CHECK(result.bounds().index_bounds()[0] == 4); EXPECT_TRUE(result.bounds().index_bounds()[0] == 4);
CHECK_THROWS_AS(result.bounds().index_bounds()[1], fail_fast); EXPECT_DEATH(result.bounds().index_bounds()[1], deathstring);
int i = 0; int i = 0;
for (auto& num : result) { for (auto& num : result) {
CHECK(num == arr[i].c); EXPECT_TRUE(num == arr[i].c);
i++; i++;
} }
} }
#if __clang__ || __GNUC__ #if __clang__ || __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif // __clang__ || __GNUC__

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#define CATCH_CONFIG_MAIN
#ifdef _MSC_VER
// blanket turn off warnings from CppCoreCheck from catch
// so people aren't annoyed by them when running the tool.
#include <CodeAnalysis/Warnings.h>
#pragma warning(disable : ALL_CODE_ANALYSIS_WARNINGS) // from catch
#endif // _MSC_VER
#include <catch/catch.hpp>

View File

@ -21,7 +21,20 @@
#endif #endif
#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... #if __clang__ || __GNUC__
//disable warnings from gtest
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wundef"
#endif // __clang__ || __GNUC__
#if __clang__
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wused-but-marked-unused"
#pragma GCC diagnostic ignored "-Wcovered-switch-default"
#endif // __clang__
#include <gtest/gtest.h>
#include <gsl/gsl_util> // for narrow, finally, narrow_cast, narrowing_e... #include <gsl/gsl_util> // for narrow, finally, narrow_cast, narrowing_e...
@ -33,101 +46,114 @@
using namespace gsl; using namespace gsl;
TEST_CASE("sanity check for gsl::index typedef") namespace
{
static constexpr char deathstring[] = "Expected Death";
void f(int& i) { i += 1; }
static int j = 0;
void g() { j += 1; }
}
TEST(utils_tests, sanity_check_for_gsl_index_typedef)
{ {
static_assert(std::is_same<gsl::index, std::ptrdiff_t>::value, static_assert(std::is_same<gsl::index, std::ptrdiff_t>::value,
"gsl::index represents wrong arithmetic type"); "gsl::index represents wrong arithmetic type");
} }
void f(int& i) { i += 1; } TEST(utils_tests, finally_lambda)
TEST_CASE("finally_lambda")
{ {
int i = 0; int i = 0;
{ {
auto _ = finally([&]() { f(i); }); auto _ = finally([&]() { f(i); });
CHECK(i == 0); EXPECT_TRUE(i == 0);
} }
CHECK(i == 1); EXPECT_TRUE(i == 1);
} }
TEST_CASE("finally_lambda_move") TEST(utils_tests, finally_lambda_move)
{ {
int i = 0; int i = 0;
{ {
auto _1 = finally([&]() { f(i); }); auto _1 = finally([&]() { f(i); });
{ {
auto _2 = std::move(_1); auto _2 = std::move(_1);
CHECK(i == 0); EXPECT_TRUE(i == 0);
} }
CHECK(i == 1); EXPECT_TRUE(i == 1);
{ {
auto _2 = std::move(_1); auto _2 = std::move(_1);
CHECK(i == 1); EXPECT_TRUE(i == 1);
} }
CHECK(i == 1); EXPECT_TRUE(i == 1);
} }
CHECK(i == 1); EXPECT_TRUE(i == 1);
} }
TEST_CASE("finally_function_with_bind") TEST(utils_tests, finally_function_with_bind)
{ {
int i = 0; int i = 0;
{ {
auto _ = finally(std::bind(&f, std::ref(i))); auto _ = finally(std::bind(&f, std::ref(i)));
CHECK(i == 0); EXPECT_TRUE(i == 0);
} }
CHECK(i == 1); EXPECT_TRUE(i == 1);
} }
static int j = 0; TEST(utils_tests, finally_function_ptr)
void g() { j += 1; }
TEST_CASE("finally_function_ptr")
{ {
j = 0; j = 0;
{ {
auto _ = finally(&g); auto _ = finally(&g);
CHECK(j == 0); EXPECT_TRUE(j == 0);
} }
CHECK(j == 1); EXPECT_TRUE(j == 1);
} }
GSL_SUPPRESS(con.4) // NO-FORMAT: attribute TEST(utils_tests, narrow_cast)
TEST_CASE("narrow_cast")
{ {
int n = 120; int n = 120;
char c = narrow_cast<char>(n); char c = narrow_cast<char>(n);
CHECK(c == 120); EXPECT_TRUE(c == 120);
n = 300; n = 300;
unsigned char uc = narrow_cast<unsigned char>(n); unsigned char uc = narrow_cast<unsigned char>(n);
CHECK(uc == 44); EXPECT_TRUE(uc == 44);
} }
GSL_SUPPRESS(con.5) // NO-FORMAT: attribute TEST(utils_tests, narrow)
TEST_CASE("narrow")
{ {
std::set_terminate([] {
std::cerr << "Expected Death. narrow";
std::abort();
});
int n = 120; int n = 120;
const char c = narrow<char>(n); const char c = narrow<char>(n);
CHECK(c == 120); EXPECT_TRUE(c == 120);
n = 300; n = 300;
CHECK_THROWS_AS(narrow<char>(n), narrowing_error); EXPECT_DEATH(narrow<char>(n), deathstring);
const auto int32_max = std::numeric_limits<int32_t>::max(); const auto int32_max = std::numeric_limits<int32_t>::max();
const auto int32_min = std::numeric_limits<int32_t>::min(); const auto int32_min = std::numeric_limits<int32_t>::min();
CHECK(narrow<uint32_t>(int32_t(0)) == 0); EXPECT_TRUE(narrow<uint32_t>(int32_t(0)) == 0);
CHECK(narrow<uint32_t>(int32_t(1)) == 1); EXPECT_TRUE(narrow<uint32_t>(int32_t(1)) == 1);
CHECK(narrow<uint32_t>(int32_max) == static_cast<uint32_t>(int32_max)); EXPECT_TRUE(narrow<uint32_t>(int32_max) == static_cast<uint32_t>(int32_max));
CHECK_THROWS_AS(narrow<uint32_t>(int32_t(-1)), narrowing_error); EXPECT_DEATH(narrow<uint32_t>(int32_t(-1)), deathstring);
CHECK_THROWS_AS(narrow<uint32_t>(int32_min), narrowing_error); EXPECT_DEATH(narrow<uint32_t>(int32_min), deathstring);
n = -42; n = -42;
CHECK_THROWS_AS(narrow<unsigned>(n), narrowing_error); EXPECT_DEATH(narrow<unsigned>(n), deathstring);
#if GSL_CONSTEXPR_NARROW #if GSL_CONSTEXPR_NARROW
static_assert(narrow<char>(120) == 120, "Fix GSL_CONSTEXPR_NARROW"); static_assert(narrow<char>(120) == 120, "Fix GSL_CONSTEXPR_NARROW");
#endif #endif
} }
#if __clang__ || __GNUC__
#pragma GCC diagnostic pop
#endif // __clang__ || __GNUC__