blob: 79810222da5f82ce8e822bea6529c1cae3d07e73 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/containers/to_array.h"
#include <memory>
#include <ranges>
#include <string>
#include <string_view>
#include <vector>
#include "base/containers/adapters.h"
#include "base/containers/span.h"
#include "base/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base::test {
namespace {
using ::testing::ElementsAre;
using ::testing::IsNull;
using ::testing::Pointee;
TEST(ToArrayTest, IdentityFixedExtent) {
const int kRawArray[] = {1, 2, 3};
// From fixed-extent base::span
base::span<const int, 3> fixed_span(kRawArray);
auto arr1 = base::ToArray(fixed_span);
static_assert(std::same_as<decltype(arr1), std::array<int, 3>>);
EXPECT_THAT(arr1, ElementsAre(1, 2, 3));
// From C-style array
auto arr2 = base::ToArray(kRawArray);
static_assert(std::same_as<decltype(arr2), std::array<int, 3>>);
EXPECT_THAT(arr2, ElementsAre(1, 2, 3));
// From std::array
const std::array<int, 3> std_arr = {1, 2, 3};
auto arr3 = base::ToArray(std_arr);
static_assert(std::same_as<decltype(arr3), std::array<int, 3>>);
EXPECT_THAT(arr3, ElementsAre(1, 2, 3));
// From std::initializer_list
auto arr4 = base::ToArray({1, 2, 3});
static_assert(std::same_as<decltype(arr4), std::array<int, 3>>);
EXPECT_THAT(arr4, ElementsAre(1, 2, 3));
}
TEST(ToArrayTest, IdentityDynamicExtent) {
const int kRawArray[] = {1, 2, 3};
// From dynamic-extent base::span
base::span<const int> dynamic_span(kRawArray);
auto arr1 = base::ToArray<3>(dynamic_span);
static_assert(std::same_as<decltype(arr1), std::array<int, 3>>);
EXPECT_THAT(arr1, ElementsAre(1, 2, 3));
// From std::vector
std::vector<int> vec = {1, 2, 3};
auto arr2 = base::ToArray<3>(vec);
static_assert(std::same_as<decltype(arr2), std::array<int, 3>>);
EXPECT_THAT(arr2, ElementsAre(1, 2, 3));
}
TEST(ToArrayTest, CustomType) {
const int kRawArray[] = {1, 2, 3};
// Fixed-extent base::span with custom type
base::span<const int, 3> fixed_span(kRawArray);
auto arr1 = base::ToArray<int64_t>(fixed_span);
static_assert(std::same_as<decltype(arr1), std::array<int64_t, 3>>);
EXPECT_THAT(arr1, ElementsAre(1L, 2L, 3L));
// Dynamic-extent base::span with custom type
base::span<const int> dynamic_span(kRawArray);
auto arr2 = base::ToArray<3, int64_t>(dynamic_span);
static_assert(std::same_as<decltype(arr2), std::array<int64_t, 3>>);
EXPECT_THAT(arr2, ElementsAre(1L, 2L, 3L));
// Rvalue array with custom type
auto arr3 = base::ToArray<std::string_view>({"foo", "bar", "baz"});
static_assert(std::same_as<decltype(arr3), std::array<std::string_view, 3>>);
EXPECT_THAT(arr3, ElementsAre("foo", "bar", "baz"));
}
TEST(ToArrayTest, Projection) {
const int kRawArray[] = {1, 2, 3};
// Fixed-extent base::span with projection
base::span<const int, 3> fixed_span(kRawArray);
auto arr1 = base::ToArray(fixed_span, [](int x) { return x * 2; });
static_assert(std::same_as<decltype(arr1), std::array<int, 3>>);
EXPECT_THAT(arr1, ElementsAre(2, 4, 6));
// Dynamic-extent base::span with projection
base::span<const int> dynamic_span(kRawArray);
auto arr2 = base::ToArray<3>(dynamic_span, [](int x) { return x * 2; });
static_assert(std::same_as<decltype(arr2), std::array<int, 3>>);
EXPECT_THAT(arr2, ElementsAre(2, 4, 6));
}
TEST(ToArrayTest, MoveOnlyRvalueArray) {
auto arr = base::ToArray({
std::make_unique<int>(10),
std::make_unique<int>(20),
std::make_unique<int>(30),
});
static_assert(
std::same_as<decltype(arr), std::array<std::unique_ptr<int>, 3>>);
EXPECT_THAT(arr, ElementsAre(Pointee(10), Pointee(20), Pointee(30)));
}
TEST(ToArrayTest, MoveOnlyRange) {
std::vector<std::unique_ptr<int>> vec;
vec.push_back(std::make_unique<int>(1));
vec.push_back(std::make_unique<int>(2));
auto arr = base::ToArray<2>(std::views::as_rvalue(vec));
static_assert(
std::same_as<decltype(arr), std::array<std::unique_ptr<int>, 2>>);
EXPECT_THAT(arr, ElementsAre(Pointee(1), Pointee(2)));
// NOLINTNEXTLINE(bugprone-use-after-move)
EXPECT_THAT(vec, ElementsAre(IsNull(), IsNull()));
}
TEST(ToArrayTest, ConstexprTest) {
static constexpr int kArray[] = {1, 2, 3};
static constexpr base::span<const int, 3> kFixedSpan(kArray);
static constexpr base::span<const int> kDynamicSpan(kArray);
static_assert(base::ToArray(kFixedSpan) == std::array{1, 2, 3});
static_assert(base::ToArray<3>(kDynamicSpan) == std::array{1, 2, 3});
static_assert(base::ToArray(kArray) == std::array{1, 2, 3});
static_assert(base::ToArray({1, 2, 3}) == std::array{1, 2, 3});
static_assert(base::ToArray(kFixedSpan, [](int x) { return x + 1; }) ==
std::array{2, 3, 4});
static_assert(base::ToArray<3>(kDynamicSpan, [](int x) { return x + 1; }) ==
std::array{2, 3, 4});
}
TEST(ToArrayDeathTest, DynamicExtentSizeMismatch) {
const int kArray[] = {1, 2, 3};
base::span<const int> dynamic_span(kArray);
EXPECT_CHECK_DEATH((base::ToArray<2>(dynamic_span)));
EXPECT_CHECK_DEATH((base::ToArray<4>(dynamic_span)));
}
class ConstArrayMemberTestClass {
public:
explicit ConstArrayMemberTestClass(base::span<const int, 3> span_data)
: data_(base::ToArray(span_data)) {}
explicit ConstArrayMemberTestClass(base::span<const int> span_data)
: data_(base::ToArray<3>(span_data)) {}
const std::array<int, 3>& data() const { return data_; }
private:
const std::array<int, 3> data_;
};
TEST(ToArrayTest, ConstClassMemberInitialization) {
const int kData[] = {10, 20, 30};
ConstArrayMemberTestClass obj1{base::span<const int, 3>(kData)};
EXPECT_THAT(obj1.data(), ElementsAre(10, 20, 30));
ConstArrayMemberTestClass obj2{base::span<const int>(kData)};
EXPECT_THAT(obj2.data(), ElementsAre(10, 20, 30));
}
} // namespace
} // namespace base::test