blob: f8040ea40ef9be487b8bcd308e85f308eac0b9ac [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/containers/checked_range.h"
#include <algorithm>
#include <array>
#include <initializer_list>
#include <type_traits>
#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(CheckedContiguousRange, Constructor_Vector) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
EXPECT_EQ(vector.data(), range.data());
EXPECT_EQ(vector.size(), range.size());
}
TEST(CheckedContiguousRange, Constructor_String) {
std::string str = "Hello World";
CheckedContiguousRange<std::string> range(str);
EXPECT_EQ(str.data(), range.data());
EXPECT_EQ(str.size(), range.size());
}
TEST(CheckedContiguousRange, Constructor_Array) {
static constexpr int array[] = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const int[5]> range(array);
static_assert(data(array) == range.data(), "");
static_assert(size(array) == range.size(), "");
}
TEST(CheckedContiguousRange, Constructor_StdArray) {
static constexpr std::array<int, 5> array = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const std::array<int, 5>> range(array);
static_assert(data(array) == range.data(), "");
static_assert(size(array) == range.size(), "");
}
TEST(CheckedContiguousRange, Constructor_StringPiece) {
static constexpr base::StringPiece str = "Hello World";
constexpr CheckedContiguousRange<const base::StringPiece> range(str);
static_assert(str.data() == range.data(), "");
static_assert(str.size() == range.size(), "");
}
TEST(CheckedContiguousRange, Constructor_InitializerList) {
static constexpr std::initializer_list<int> il = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const std::initializer_list<int>> range(il);
static_assert(data(il) == range.data(), "");
static_assert(size(il) == range.size(), "");
}
TEST(CheckedContiguousRange, Constructor_Copy) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
CheckedContiguousRange<std::vector<int>> copy(range);
EXPECT_EQ(vector.data(), copy.data());
EXPECT_EQ(vector.size(), copy.size());
}
TEST(CheckedContiguousRange, Constructor_Move) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
CheckedContiguousRange<std::vector<int>> move(std::move(range));
EXPECT_EQ(vector.data(), move.data());
EXPECT_EQ(vector.size(), move.size());
}
TEST(CheckedContiguousRange, Copy_Assign) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
CheckedContiguousRange<std::vector<int>> copy;
copy = range;
EXPECT_EQ(vector.data(), copy.data());
EXPECT_EQ(vector.size(), copy.size());
}
TEST(CheckedContiguousRange, Move_Assign) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
CheckedContiguousRange<std::vector<int>> move;
move = std::move(range);
EXPECT_EQ(vector.data(), move.data());
EXPECT_EQ(vector.size(), move.size());
}
TEST(CheckedContiguousRange, Iterators) {
std::vector<int> vector;
CheckedContiguousRange<const std::vector<int>> range(vector);
// Check that all ranges by the iterators compare equal, even when elements
// are added.
for (size_t i = 0; i < 5; ++i) {
vector.push_back(i);
EXPECT_TRUE(
std::equal(vector.begin(), vector.end(), range.begin(), range.end()));
EXPECT_TRUE(std::equal(vector.cbegin(), vector.cend(), range.cbegin(),
range.cend()));
EXPECT_TRUE(std::equal(vector.rbegin(), vector.rend(), range.rbegin(),
range.rend()));
EXPECT_TRUE(std::equal(vector.crbegin(), vector.crend(), range.crbegin(),
range.crend()));
}
}
TEST(CheckedContiguousRange, Front) {
static constexpr std::array<int, 5> array = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const std::array<int, 5>> range(array);
static_assert(array.front() == range.front(), "");
}
TEST(CheckedContiguousRange, Back) {
static constexpr std::array<int, 5> array = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const std::array<int, 5>> range(array);
static_assert(array.back() == range.back(), "");
}
TEST(CheckedContiguousRange, OperatorAt_Constexpr) {
static constexpr std::array<int, 5> array = {1, 2, 3, 4, 5};
constexpr CheckedContiguousRange<const std::array<int, 5>> range(array);
static_assert(array[0] == range[0], "");
static_assert(array[1] == range[1], "");
static_assert(array[2] == range[2], "");
static_assert(array[3] == range[3], "");
static_assert(array[4] == range[4], "");
}
TEST(CheckedContiguousRange, Mutable_OperatorAt) {
std::vector<int> vector = {1, 2, 3, 4, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
EXPECT_EQ(vector[0], range[0]);
range[0] = 2;
EXPECT_EQ(vector[0], 2);
}
TEST(CheckedContiguousRange, Mutable_Data) {
std::vector<int> vector = {3, 1, 4, 2, 5};
CheckedContiguousRange<std::vector<int>> range(vector);
EXPECT_FALSE(std::is_sorted(vector.begin(), vector.end()));
std::sort(range.data(), range.data() + range.size());
EXPECT_TRUE(std::is_sorted(vector.begin(), vector.end()));
}
TEST(CheckedContiguousRange, DataSizeEmpty_Constexpr) {
static constexpr std::array<int, 0> array = {};
constexpr CheckedContiguousRange<const std::array<int, 0>> range(array);
static_assert(data(array) == range.data(), "");
static_assert(data(array) == range.cdata(), "");
static_assert(size(array) == range.size(), "");
static_assert(range.empty(), "");
}
TEST(CheckedContiguousRange, MakeCheckedContiguousRange) {
using Vec = std::vector<int>;
static_assert(std::is_same<CheckedContiguousRange<Vec>,
decltype(MakeCheckedContiguousRange(
std::declval<Vec&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousRange(
std::declval<const Vec&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<Vec>,
decltype(MakeCheckedContiguousRange(
std::declval<Vec&&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousRange(
std::declval<const Vec&&>()))>::value,
"");
}
TEST(CheckedContiguousRange, MakeCheckedContiguousConstRange) {
using Vec = std::vector<int>;
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousConstRange(
std::declval<Vec&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousConstRange(
std::declval<const Vec&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousConstRange(
std::declval<Vec&&>()))>::value,
"");
static_assert(std::is_same<CheckedContiguousRange<const Vec>,
decltype(MakeCheckedContiguousConstRange(
std::declval<const Vec&&>()))>::value,
"");
}
TEST(CheckedContiguousRange, Conversions) {
using T = std::vector<int>;
// Check that adding const is allowed, but removing const is not.
static_assert(std::is_convertible<CheckedContiguousRange<T>,
CheckedContiguousRange<const T>>::value,
"");
static_assert(!std::is_constructible<CheckedContiguousRange<T>,
CheckedContiguousRange<const T>>::value,
"");
struct Base {};
struct Derived : Base {};
// Check that trying to assign arrays from a derived class fails.
static_assert(
!std::is_constructible<CheckedContiguousRange<Base[5]>,
CheckedContiguousRange<Derived[5]>>::value,
"");
}
TEST(CheckedContiguousRange, OutOfBoundsDeath) {
std::vector<int> empty_vector;
CheckedContiguousRange<std::vector<int>> empty_range(empty_vector);
ASSERT_DEATH_IF_SUPPORTED(empty_range[0], "");
ASSERT_DEATH_IF_SUPPORTED(empty_range.front(), "");
ASSERT_DEATH_IF_SUPPORTED(empty_range.back(), "");
static constexpr int array[] = {0, 1, 2};
constexpr CheckedContiguousRange<const int[3]> range(array);
ASSERT_DEATH_IF_SUPPORTED(range[3], "");
}
} // namespace base