mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-08 15:38:19 +01:00
commit
b372dc6157
272 changed files with 22238 additions and 7949 deletions
|
|
@ -9,200 +9,21 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_container_properties.hpp>
|
||||
#include <catch2/matchers/catch_matchers_contains.hpp>
|
||||
#include <catch2/matchers/catch_matchers_range_equals.hpp>
|
||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||
#include <catch2/matchers/catch_matchers_quantifiers.hpp>
|
||||
#include <catch2/matchers/catch_matchers_predicate.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <helpers/range_test_helpers.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <initializer_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
|
||||
namespace unrelated {
|
||||
template <typename T>
|
||||
class needs_ADL_begin {
|
||||
std::vector<T> m_elements;
|
||||
public:
|
||||
using iterator = typename std::vector<T>::iterator;
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
needs_ADL_begin(std::initializer_list<T> init) : m_elements(init) {}
|
||||
|
||||
const_iterator Begin() const { return m_elements.begin(); }
|
||||
const_iterator End() const { return m_elements.end(); }
|
||||
|
||||
friend const_iterator begin(needs_ADL_begin const& lhs) {
|
||||
return lhs.Begin();
|
||||
}
|
||||
friend const_iterator end(needs_ADL_begin const& rhs) {
|
||||
return rhs.End();
|
||||
}
|
||||
};
|
||||
} // end unrelated namespace
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class has_different_begin_end_types {
|
||||
// Using std::vector<T> leads to annoying issues when T is bool
|
||||
// so we just use list because the perf is not critical and ugh.
|
||||
std::list<T> m_elements;
|
||||
|
||||
// Different type for the "end" iterator
|
||||
struct iterator_end {};
|
||||
// Fake-ish forward iterator that only compares to a different type
|
||||
class iterator {
|
||||
using underlying_iter = typename std::list<T>::const_iterator;
|
||||
underlying_iter m_start;
|
||||
underlying_iter m_end;
|
||||
|
||||
public:
|
||||
iterator( underlying_iter start, underlying_iter end ):
|
||||
m_start( start ), m_end( end ) {}
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = T;
|
||||
using const_reference = T const&;
|
||||
using pointer = T const*;
|
||||
|
||||
|
||||
friend bool operator==( iterator iter, iterator_end ) {
|
||||
return iter.m_start == iter.m_end;
|
||||
}
|
||||
friend bool operator!=( iterator iter, iterator_end ) {
|
||||
return iter.m_start != iter.m_end;
|
||||
}
|
||||
iterator& operator++() {
|
||||
++m_start;
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int) {
|
||||
auto tmp(*this);
|
||||
++m_start;
|
||||
return tmp;
|
||||
}
|
||||
const_reference operator*() const {
|
||||
return *m_start;
|
||||
}
|
||||
pointer operator->() const {
|
||||
return m_start;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
explicit has_different_begin_end_types( std::initializer_list<T> init ):
|
||||
m_elements( init ) {}
|
||||
|
||||
iterator begin() const {
|
||||
return { m_elements.begin(), m_elements.end() };
|
||||
}
|
||||
|
||||
iterator_end end() const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
template <typename T> struct with_mocked_iterator_access {
|
||||
std::vector<T> m_elements;
|
||||
|
||||
// use plain arrays to have nicer printouts with CHECK(...)
|
||||
mutable std::unique_ptr<bool[]> m_derefed;
|
||||
|
||||
// We want to check which elements were dereferenced when iterating, so
|
||||
// we can check whether iterator-using code traverses range correctly
|
||||
template <bool is_const> class basic_iterator {
|
||||
template <typename U>
|
||||
using constify_t = std::conditional_t<is_const, std::add_const_t<U>, U>;
|
||||
|
||||
constify_t<with_mocked_iterator_access>* m_origin;
|
||||
size_t m_origin_idx;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = constify_t<T>;
|
||||
using const_reference = typename std::vector<T>::const_reference;
|
||||
using reference = typename std::vector<T>::reference;
|
||||
using pointer = typename std::vector<T>::pointer;
|
||||
|
||||
basic_iterator( constify_t<with_mocked_iterator_access>* origin,
|
||||
std::size_t origin_idx ):
|
||||
m_origin{ origin }, m_origin_idx{ origin_idx } {}
|
||||
|
||||
friend bool operator==( basic_iterator lhs, basic_iterator rhs ) {
|
||||
return lhs.m_origin == rhs.m_origin &&
|
||||
lhs.m_origin_idx == rhs.m_origin_idx;
|
||||
}
|
||||
friend bool operator!=( basic_iterator lhs, basic_iterator rhs ) {
|
||||
return !( lhs == rhs );
|
||||
}
|
||||
basic_iterator& operator++() {
|
||||
++m_origin_idx;
|
||||
return *this;
|
||||
}
|
||||
basic_iterator operator++( int ) {
|
||||
auto tmp( *this );
|
||||
++( *this );
|
||||
return tmp;
|
||||
}
|
||||
const_reference operator*() const {
|
||||
assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" );
|
||||
m_origin->m_derefed[m_origin_idx] = true;
|
||||
return m_origin->m_elements[m_origin_idx];
|
||||
}
|
||||
pointer operator->() const {
|
||||
assert( m_origin_idx < m_origin->m_elements.size() && "Attempted to deref invalid position" );
|
||||
return &m_origin->m_elements[m_origin_idx];
|
||||
}
|
||||
};
|
||||
|
||||
using iterator = basic_iterator<false>;
|
||||
using const_iterator = basic_iterator<true>;
|
||||
|
||||
with_mocked_iterator_access( std::initializer_list<T> init ):
|
||||
m_elements( init ),
|
||||
m_derefed( std::make_unique<bool[]>( m_elements.size() ) ) {}
|
||||
|
||||
const_iterator begin() const { return { this, 0 }; }
|
||||
const_iterator end() const { return { this, m_elements.size() }; }
|
||||
iterator begin() { return { this, 0 }; }
|
||||
iterator end() { return { this, m_elements.size() }; }
|
||||
};
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
namespace Catch {
|
||||
// make sure with_mocked_iterator_access is not considered a range by Catch,
|
||||
// so that below StringMaker is used instead of the default one for ranges
|
||||
template <typename T>
|
||||
struct is_range<with_mocked_iterator_access<T>> : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct StringMaker<with_mocked_iterator_access<T>> {
|
||||
static std::string
|
||||
convert( with_mocked_iterator_access<T> const& access ) {
|
||||
// We have to avoid the type's iterators, because we check
|
||||
// their use in tests
|
||||
return ::Catch::Detail::stringify( access.m_elements );
|
||||
}
|
||||
};
|
||||
} // namespace Catch
|
||||
|
||||
struct MoveOnlyTestElement {
|
||||
int num = 0;
|
||||
MoveOnlyTestElement(int n) :num(n) {}
|
||||
|
|
@ -286,16 +107,6 @@ namespace {
|
|||
bool empty() const { return false; }
|
||||
};
|
||||
|
||||
namespace unrelated {
|
||||
struct ADL_empty {
|
||||
bool Empty() const { return true; }
|
||||
|
||||
friend bool empty(ADL_empty e) {
|
||||
return e.Empty();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace unrelated
|
||||
} // end unnamed namespace
|
||||
|
||||
TEST_CASE("Basic use of the Empty range matcher", "[matchers][templated][empty]") {
|
||||
|
|
@ -345,17 +156,6 @@ namespace {
|
|||
return LessThanMatcher{ sz };
|
||||
}
|
||||
|
||||
namespace unrelated {
|
||||
struct ADL_size {
|
||||
size_t sz() const {
|
||||
return 12;
|
||||
}
|
||||
friend size_t size(ADL_size s) {
|
||||
return s.sz();
|
||||
}
|
||||
};
|
||||
} // end namespace unrelated
|
||||
|
||||
struct has_size {
|
||||
size_t size() const {
|
||||
return 13;
|
||||
|
|
@ -581,7 +381,7 @@ TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]"
|
|||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evalutes to false" ) {
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<bool, 5> const data{ { true, true, false, true, true } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
}
|
||||
|
|
@ -598,7 +398,7 @@ TEST_CASE("Usage of AllTrue range matcher", "[matchers][templated][quantifiers]"
|
|||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AllTrue() );
|
||||
}
|
||||
SECTION( "One false evalutes to false" ) {
|
||||
SECTION( "One false evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { true }, { true }, { false }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !AllTrue() );
|
||||
|
|
@ -646,7 +446,7 @@ TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers
|
|||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evalutes to false" ) {
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
|
|
@ -664,7 +464,7 @@ TEST_CASE( "Usage of NoneTrue range matcher", "[matchers][templated][quantifiers
|
|||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
}
|
||||
SECTION( "One true evalutes to false" ) {
|
||||
SECTION( "One true evaluates to false" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, !NoneTrue() );
|
||||
|
|
@ -712,7 +512,7 @@ TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers]
|
|||
std::array<bool, 0> const data{};
|
||||
REQUIRE_THAT( data, !AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evalutes to true" ) {
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<bool, 5> const data{
|
||||
{ false, false, true, false, false } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
|
|
@ -730,7 +530,7 @@ TEST_CASE( "Usage of AnyTrue range matcher", "[matchers][templated][quantifiers]
|
|||
{ { true }, { true }, { true }, { true }, { true } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
}
|
||||
SECTION( "One true evalutes to true" ) {
|
||||
SECTION( "One true evaluates to true" ) {
|
||||
std::array<ConvertibleToBool, 5> const data{
|
||||
{ { false }, { false }, { true }, { false }, { false } } };
|
||||
REQUIRE_THAT( data, AnyTrue() );
|
||||
|
|
@ -831,4 +631,287 @@ TEST_CASE( "The quantifier range matchers support types with different types ret
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "RangeEquals supports ranges with different types returned from begin and end",
|
||||
"[matchers][templated][range][approvals] ") {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
has_different_begin_end_types<int> diff_types{ 1, 2, 3, 4, 5 };
|
||||
std::array<int, 5> arr1{ { 1, 2, 3, 4, 5 } }, arr2{ { 2, 3, 4, 5, 6 } };
|
||||
|
||||
REQUIRE_THAT( diff_types, RangeEquals( arr1 ) );
|
||||
REQUIRE_THAT( diff_types, RangeEquals( arr2, []( int l, int r ) {
|
||||
return l + 1 == r;
|
||||
} ) );
|
||||
REQUIRE_THAT( diff_types, UnorderedRangeEquals( diff_types ) );
|
||||
}
|
||||
|
||||
TEST_CASE( "RangeContains supports ranges with different types returned from "
|
||||
"begin and end",
|
||||
"[matchers][templated][range][approvals]" ) {
|
||||
using Catch::Matchers::Contains;
|
||||
|
||||
has_different_begin_end_types<size_t> diff_types{ 1, 2, 3, 4, 5 };
|
||||
REQUIRE_THAT( diff_types, Contains( size_t( 3 ) ) );
|
||||
REQUIRE_THAT( diff_types, Contains( LessThanMatcher( size_t( 4 ) ) ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE( "Usage of RangeEquals range matcher", "[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
|
||||
// In these tests, the types are always the same - type conversion is in the next section
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "Empty container matches empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, RangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> non_empty_vector{ 1 };
|
||||
CHECK_THAT( empty_vector, !RangeEquals( non_empty_vector ) );
|
||||
// ...and in reverse
|
||||
CHECK_THAT( non_empty_vector, !RangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Two equal 1-length non-empty containers" ) {
|
||||
const std::array<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array, RangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, RangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
const std::array<int, 3> array_c{ { 1, 2, 2 } };
|
||||
CHECK_THAT( array_a, !RangeEquals( array_b ) );
|
||||
CHECK_THAT( array_a, !RangeEquals( array_c ) );
|
||||
}
|
||||
SECTION( "Two non-equal-sized, non-empty containers (with same first "
|
||||
"elements)" ) {
|
||||
const std::vector<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> vector_b{ 1, 2, 3, 4 };
|
||||
CHECK_THAT( vector_a, !RangeEquals( vector_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_a_plus_1{ { 2, 3, 4 } };
|
||||
CHECK_THAT( vector_a, RangeEquals( vector_a_plus_1, close_enough ) );
|
||||
}
|
||||
SECTION( "Two non-equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_b{ { 3, 3, 4 } };
|
||||
CHECK_THAT( vector_a, !RangeEquals( vector_b, close_enough ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Ranges that need ADL begin/end" ) {
|
||||
unrelated::needs_ADL_begin<int> const
|
||||
needs_adl1{ 1, 2, 3, 4, 5 },
|
||||
needs_adl2{ 1, 2, 3, 4, 5 },
|
||||
needs_adl3{ 2, 3, 4, 5, 6 };
|
||||
|
||||
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl2 ) );
|
||||
REQUIRE_THAT( needs_adl1, RangeEquals( needs_adl3, []( int l, int r ) {
|
||||
return l + 1 == r;
|
||||
} ) );
|
||||
}
|
||||
|
||||
SECTION("Check short-circuiting behaviour") {
|
||||
with_mocked_iterator_access<int> const mocked1{ 1, 2, 3, 4 };
|
||||
|
||||
SECTION( "Check short-circuits on failure" ) {
|
||||
std::array<int, 4> arr{ { 1, 2, 4, 4 } };
|
||||
|
||||
REQUIRE_THAT( mocked1, !RangeEquals( arr ) );
|
||||
REQUIRE( mocked1.m_derefed[0] );
|
||||
REQUIRE( mocked1.m_derefed[1] );
|
||||
REQUIRE( mocked1.m_derefed[2] );
|
||||
REQUIRE_FALSE( mocked1.m_derefed[3] );
|
||||
}
|
||||
SECTION("All elements are checked on success") {
|
||||
std::array<int, 4> arr{ { 1, 2, 3, 4 } };
|
||||
|
||||
REQUIRE_THAT( mocked1, RangeEquals( arr ) );
|
||||
REQUIRE( mocked1.m_derefed[0] );
|
||||
REQUIRE( mocked1.m_derefed[1] );
|
||||
REQUIRE( mocked1.m_derefed[2] );
|
||||
REQUIRE( mocked1.m_derefed[3] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "Usage of UnorderedRangeEquals range matcher",
|
||||
"[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
// In these tests, the types are always the same - type conversion is in the
|
||||
// next section
|
||||
SECTION( "Basic usage" ) {
|
||||
SECTION( "Empty container matches empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
CHECK_THAT( empty_vector, UnorderedRangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Empty container does not match non-empty container" ) {
|
||||
const std::vector<int> empty_vector;
|
||||
const std::vector<int> non_empty_vector{ 1 };
|
||||
CHECK_THAT( empty_vector,
|
||||
!UnorderedRangeEquals( non_empty_vector ) );
|
||||
// ...and in reverse
|
||||
CHECK_THAT( non_empty_vector,
|
||||
!UnorderedRangeEquals( empty_vector ) );
|
||||
}
|
||||
SECTION( "Two equal 1-length non-empty containers" ) {
|
||||
const std::array<int, 1> non_empty_array{ { 1 } };
|
||||
CHECK_THAT( non_empty_array,
|
||||
UnorderedRangeEquals( non_empty_array ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
CHECK_THAT( array_a, UnorderedRangeEquals( array_a ) );
|
||||
}
|
||||
SECTION( "Two equal-sized, non-equal, non-empty containers" ) {
|
||||
const std::array<int, 3> array_a{ { 1, 2, 3 } };
|
||||
const std::array<int, 3> array_b{ { 2, 2, 3 } };
|
||||
CHECK_THAT( array_a, !UnorderedRangeEquals( array_b ) );
|
||||
}
|
||||
SECTION( "Two non-equal-sized, non-empty containers" ) {
|
||||
const std::vector<int> vector_a{ 1, 2, 3 };
|
||||
const std::vector<int> vector_b{ 1, 2, 3, 4 };
|
||||
CHECK_THAT( vector_a, !UnorderedRangeEquals( vector_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 10, 20 } };
|
||||
const std::vector<int> vector_a_plus_1{ { 11, 21, 2 } };
|
||||
CHECK_THAT( vector_a,
|
||||
UnorderedRangeEquals( vector_a_plus_1, close_enough ) );
|
||||
}
|
||||
SECTION( "Two non-equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 10, 21 } };
|
||||
const std::vector<int> vector_b{ { 11, 21, 3 } };
|
||||
CHECK_THAT( vector_a,
|
||||
!UnorderedRangeEquals( vector_b, close_enough ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION( "Ranges that need ADL begin/end" ) {
|
||||
unrelated::needs_ADL_begin<int> const
|
||||
needs_adl1{ 1, 2, 3, 4, 5 },
|
||||
needs_adl2{ 1, 2, 3, 4, 5 };
|
||||
|
||||
REQUIRE_THAT( needs_adl1, UnorderedRangeEquals( needs_adl2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the type given has a random access iterator type.
|
||||
*/
|
||||
template <typename Container>
|
||||
static constexpr bool ContainerIsRandomAccess( const Container& ) {
|
||||
using array_iter_category = typename std::iterator_traits<
|
||||
typename Container::iterator>::iterator_category;
|
||||
|
||||
return std::is_base_of<std::random_access_iterator_tag,
|
||||
array_iter_category>::value;
|
||||
}
|
||||
|
||||
TEST_CASE( "Type conversions of RangeEquals and similar",
|
||||
"[matchers][templated][quantifiers]" ) {
|
||||
using Catch::Matchers::RangeEquals;
|
||||
using Catch::Matchers::UnorderedRangeEquals;
|
||||
|
||||
// In these test, we can always test RangeEquals and
|
||||
// UnorderedRangeEquals in the same way, since we're mostly
|
||||
// testing the template type deductions (and RangeEquals
|
||||
// implies UnorderedRangeEquals)
|
||||
|
||||
SECTION( "Container conversions" ) {
|
||||
SECTION( "Two equal containers of different container types" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const int c_array[3] = { 1, 2, 3 };
|
||||
CHECK_THAT( array_int_a, RangeEquals( c_array ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( c_array ) );
|
||||
}
|
||||
SECTION( "Two equal containers of different container types "
|
||||
"(differ in array N)" ) {
|
||||
const std::array<int, 3> array_int_3{ { 1, 2, 3 } };
|
||||
const std::array<int, 4> array_int_4{ { 1, 2, 3, 4 } };
|
||||
CHECK_THAT( array_int_3, !RangeEquals( array_int_4 ) );
|
||||
CHECK_THAT( array_int_3, !UnorderedRangeEquals( array_int_4 ) );
|
||||
}
|
||||
SECTION( "Two equal containers of different container types and value "
|
||||
"types" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::vector<int> vector_char_a{ 1, 2, 3 };
|
||||
CHECK_THAT( array_int_a, RangeEquals( vector_char_a ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( vector_char_a ) );
|
||||
}
|
||||
SECTION( "Two equal containers, one random access, one not" ) {
|
||||
const std::array<int, 3> array_int_a{ { 1, 2, 3 } };
|
||||
const std::list<int> list_char_a{ 1, 2, 3 };
|
||||
|
||||
// Verify these types really are different in random access nature
|
||||
STATIC_REQUIRE( ContainerIsRandomAccess( array_int_a ) !=
|
||||
ContainerIsRandomAccess( list_char_a ) );
|
||||
|
||||
CHECK_THAT( array_int_a, RangeEquals( list_char_a ) );
|
||||
CHECK_THAT( array_int_a, UnorderedRangeEquals( list_char_a ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Value type" ) {
|
||||
SECTION( "Two equal containers of different value types" ) {
|
||||
const std::vector<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> vector_char_a{ 1, 2, 3 };
|
||||
CHECK_THAT( vector_int_a, RangeEquals( vector_char_a ) );
|
||||
CHECK_THAT( vector_int_a, UnorderedRangeEquals( vector_char_a ) );
|
||||
}
|
||||
SECTION( "Two non-equal containers of different value types" ) {
|
||||
const std::vector<int> vector_int_a{ 1, 2, 3 };
|
||||
const std::vector<char> vector_char_b{ 1, 2, 2 };
|
||||
CHECK_THAT( vector_int_a, !RangeEquals( vector_char_b ) );
|
||||
CHECK_THAT( vector_int_a, !UnorderedRangeEquals( vector_char_b ) );
|
||||
}
|
||||
}
|
||||
|
||||
SECTION( "Ranges with begin that needs ADL" ) {
|
||||
unrelated::needs_ADL_begin<int> a{ 1, 2, 3 }, b{ 3, 2, 1 };
|
||||
REQUIRE_THAT( a, !RangeEquals( b ) );
|
||||
REQUIRE_THAT( a, UnorderedRangeEquals( b ) );
|
||||
}
|
||||
|
||||
SECTION( "Custom predicate" ) {
|
||||
|
||||
auto close_enough = []( int lhs, int rhs ) {
|
||||
return std::abs( lhs - rhs ) <= 1;
|
||||
};
|
||||
|
||||
SECTION( "Two equal non-empty containers (close enough)" ) {
|
||||
const std::vector<int> vector_a{ { 1, 2, 3 } };
|
||||
const std::array<char, 3> array_a_plus_1{ { 2, 3, 4 } };
|
||||
CHECK_THAT( vector_a,
|
||||
RangeEquals( array_a_plus_1, close_enough ) );
|
||||
CHECK_THAT( vector_a,
|
||||
UnorderedRangeEquals( array_a_plus_1, close_enough ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue