mirror of https://github.com/oxen-io/lokinet
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
725 lines
22 KiB
C++
725 lines
22 KiB
C++
6 years ago
|
// Copyright 2017 The Abseil Authors.
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include "absl/types/any.h"
|
||
|
|
||
|
#include <initializer_list>
|
||
|
#include <type_traits>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "gtest/gtest.h"
|
||
|
#include "absl/base/config.h"
|
||
|
#include "absl/base/internal/exception_testing.h"
|
||
|
#include "absl/base/internal/raw_logging.h"
|
||
|
#include "absl/container/internal/test_instance_tracker.h"
|
||
|
|
||
|
namespace {
|
||
|
using absl::test_internal::CopyableOnlyInstance;
|
||
|
using absl::test_internal::InstanceTracker;
|
||
|
|
||
|
template <typename T>
|
||
|
const T& AsConst(const T& t) {
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
struct MoveOnly {
|
||
|
MoveOnly() = default;
|
||
|
explicit MoveOnly(int value) : value(value) {}
|
||
|
MoveOnly(MoveOnly&&) = default;
|
||
|
MoveOnly& operator=(MoveOnly&&) = default;
|
||
|
|
||
|
int value = 0;
|
||
|
};
|
||
|
|
||
|
struct CopyOnly {
|
||
|
CopyOnly() = default;
|
||
|
explicit CopyOnly(int value) : value(value) {}
|
||
|
CopyOnly(CopyOnly&&) = delete;
|
||
|
CopyOnly& operator=(CopyOnly&&) = delete;
|
||
|
CopyOnly(const CopyOnly&) = default;
|
||
|
CopyOnly& operator=(const CopyOnly&) = default;
|
||
|
|
||
|
int value = 0;
|
||
|
};
|
||
|
|
||
|
struct MoveOnlyWithListConstructor {
|
||
|
MoveOnlyWithListConstructor() = default;
|
||
|
explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
|
||
|
int value)
|
||
|
: value(value) {}
|
||
|
MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
|
||
|
MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
|
||
|
default;
|
||
|
|
||
|
int value = 0;
|
||
|
};
|
||
|
|
||
|
struct IntMoveOnlyCopyOnly {
|
||
|
IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/)
|
||
|
: value(value) {}
|
||
|
|
||
|
int value;
|
||
|
};
|
||
|
|
||
|
struct ListMoveOnlyCopyOnly {
|
||
|
ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/,
|
||
|
CopyOnly /*copy_only*/)
|
||
|
: values(ilist) {}
|
||
|
|
||
|
std::vector<int> values;
|
||
|
};
|
||
|
|
||
|
using FunctionType = void();
|
||
|
void FunctionToEmplace() {}
|
||
|
|
||
|
using ArrayType = int[2];
|
||
|
using DecayedArray = absl::decay_t<ArrayType>;
|
||
|
|
||
|
TEST(AnyTest, Noexcept) {
|
||
|
static_assert(std::is_nothrow_default_constructible<absl::any>(), "");
|
||
|
static_assert(std::is_nothrow_move_constructible<absl::any>(), "");
|
||
|
static_assert(std::is_nothrow_move_assignable<absl::any>(), "");
|
||
|
static_assert(noexcept(std::declval<absl::any&>().has_value()), "");
|
||
|
static_assert(noexcept(std::declval<absl::any&>().type()), "");
|
||
|
static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), "");
|
||
|
static_assert(
|
||
|
noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())),
|
||
|
"");
|
||
|
|
||
|
using std::swap;
|
||
|
static_assert(
|
||
|
noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())),
|
||
|
"");
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, HasValue) {
|
||
|
absl::any o;
|
||
|
EXPECT_FALSE(o.has_value());
|
||
|
o.emplace<int>();
|
||
|
EXPECT_TRUE(o.has_value());
|
||
|
o.reset();
|
||
|
EXPECT_FALSE(o.has_value());
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, Type) {
|
||
|
absl::any o;
|
||
|
EXPECT_EQ(typeid(void), o.type());
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(typeid(int), o.type());
|
||
|
o.emplace<float>(5.f);
|
||
|
EXPECT_EQ(typeid(float), o.type());
|
||
|
o.reset();
|
||
|
EXPECT_EQ(typeid(void), o.type());
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmptyPointerCast) {
|
||
|
// pointer-to-unqualified overload
|
||
|
{
|
||
|
absl::any o;
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
|
||
|
o.emplace<int>();
|
||
|
EXPECT_NE(nullptr, absl::any_cast<int>(&o));
|
||
|
o.reset();
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
|
||
|
}
|
||
|
|
||
|
// pointer-to-const overload
|
||
|
{
|
||
|
absl::any o;
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||
|
o.emplace<int>();
|
||
|
EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||
|
o.reset();
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstruction) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(),
|
||
|
copy_only);
|
||
|
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(5, v.value);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstructionWithCV) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5,
|
||
|
MoveOnly(), copy_only);
|
||
|
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(5, v.value);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstructionWithFunction) {
|
||
|
absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace);
|
||
|
FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o);
|
||
|
EXPECT_EQ(&FunctionToEmplace, construction_result);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstructionWithArray) {
|
||
|
ArrayType ar = {5, 42};
|
||
|
absl::any o(absl::in_place_type_t<ArrayType>(), ar);
|
||
|
DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o);
|
||
|
EXPECT_EQ(&ar[0], construction_result);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstructionIlist) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4},
|
||
|
MoveOnly(), copy_only);
|
||
|
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||
|
std::vector<int> expected_values = {1, 2, 3, 4};
|
||
|
EXPECT_EQ(expected_values, v.values);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceConstructionIlistWithCV) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(),
|
||
|
{1, 2, 3, 4}, MoveOnly(), copy_only);
|
||
|
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||
|
std::vector<int> expected_values = {1, 2, 3, 4};
|
||
|
EXPECT_EQ(expected_values, v.values);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, InPlaceNoArgs) {
|
||
|
absl::any o(absl::in_place_type_t<int>{});
|
||
|
EXPECT_EQ(0, absl::any_cast<int&>(o));
|
||
|
}
|
||
|
|
||
|
template <typename Enabler, typename T, typename... Args>
|
||
|
struct CanEmplaceAnyImpl : std::false_type {};
|
||
|
|
||
|
template <typename T, typename... Args>
|
||
|
struct CanEmplaceAnyImpl<
|
||
|
absl::void_t<decltype(
|
||
|
std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>,
|
||
|
T, Args...> : std::true_type {};
|
||
|
|
||
|
template <typename T, typename... Args>
|
||
|
using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>;
|
||
|
|
||
|
TEST(AnyTest, Emplace) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o;
|
||
|
EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>(
|
||
|
5, MoveOnly(), copy_only)),
|
||
|
IntMoveOnlyCopyOnly&>::value));
|
||
|
IntMoveOnlyCopyOnly& emplace_result =
|
||
|
o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||
|
EXPECT_EQ(5, emplace_result.value);
|
||
|
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(5, v.value);
|
||
|
EXPECT_EQ(&emplace_result, &v);
|
||
|
|
||
|
static_assert(!CanEmplaceAny<int, int, int>::value, "");
|
||
|
static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, "");
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceWithCV) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o;
|
||
|
EXPECT_TRUE(
|
||
|
(std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>(
|
||
|
5, MoveOnly(), copy_only)),
|
||
|
IntMoveOnlyCopyOnly&>::value));
|
||
|
IntMoveOnlyCopyOnly& emplace_result =
|
||
|
o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||
|
EXPECT_EQ(5, emplace_result.value);
|
||
|
IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(5, v.value);
|
||
|
EXPECT_EQ(&emplace_result, &v);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceWithFunction) {
|
||
|
absl::any o;
|
||
|
EXPECT_TRUE(
|
||
|
(std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)),
|
||
|
FunctionType*&>::value));
|
||
|
FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace);
|
||
|
EXPECT_EQ(&FunctionToEmplace, emplace_result);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceWithArray) {
|
||
|
absl::any o;
|
||
|
ArrayType ar = {5, 42};
|
||
|
EXPECT_TRUE(
|
||
|
(std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value));
|
||
|
DecayedArray& emplace_result = o.emplace<ArrayType>(ar);
|
||
|
EXPECT_EQ(&ar[0], emplace_result);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceIlist) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o;
|
||
|
EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>(
|
||
|
{1, 2, 3, 4}, MoveOnly(), copy_only)),
|
||
|
ListMoveOnlyCopyOnly&>::value));
|
||
|
ListMoveOnlyCopyOnly& emplace_result =
|
||
|
o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only);
|
||
|
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(&v, &emplace_result);
|
||
|
std::vector<int> expected_values = {1, 2, 3, 4};
|
||
|
EXPECT_EQ(expected_values, v.values);
|
||
|
|
||
|
static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, "");
|
||
|
static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor,
|
||
|
std::initializer_list<int>, int>::value,
|
||
|
"");
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceIlistWithCV) {
|
||
|
const CopyOnly copy_only{};
|
||
|
absl::any o;
|
||
|
EXPECT_TRUE(
|
||
|
(std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>(
|
||
|
{1, 2, 3, 4}, MoveOnly(), copy_only)),
|
||
|
ListMoveOnlyCopyOnly&>::value));
|
||
|
ListMoveOnlyCopyOnly& emplace_result =
|
||
|
o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(),
|
||
|
copy_only);
|
||
|
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||
|
EXPECT_EQ(&v, &emplace_result);
|
||
|
std::vector<int> expected_values = {1, 2, 3, 4};
|
||
|
EXPECT_EQ(expected_values, v.values);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, EmplaceNoArgs) {
|
||
|
absl::any o;
|
||
|
o.emplace<int>();
|
||
|
EXPECT_EQ(0, absl::any_cast<int>(o));
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, ConversionConstruction) {
|
||
|
{
|
||
|
absl::any o = 5;
|
||
|
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||
|
}
|
||
|
|
||
|
{
|
||
|
const CopyOnly copy_only(5);
|
||
|
absl::any o = copy_only;
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
|
||
|
}
|
||
|
|
||
|
static_assert(!std::is_convertible<MoveOnly, absl::any>::value, "");
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, ConversionAssignment) {
|
||
|
{
|
||
|
absl::any o;
|
||
|
o = 5;
|
||
|
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||
|
}
|
||
|
|
||
|
{
|
||
|
const CopyOnly copy_only(5);
|
||
|
absl::any o;
|
||
|
o = copy_only;
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
|
||
|
}
|
||
|
|
||
|
static_assert(!std::is_assignable<MoveOnly, absl::any>::value, "");
|
||
|
}
|
||
|
|
||
|
// Suppress MSVC warnings.
|
||
|
// 4521: multiple copy constructors specified
|
||
|
// We wrote multiple of them to test that the correct overloads are selected.
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma warning( push )
|
||
|
#pragma warning( disable : 4521)
|
||
|
#endif
|
||
|
|
||
|
// Weird type for testing, only used to make sure we "properly" perfect-forward
|
||
|
// when being placed into an absl::any (use the l-value constructor if given an
|
||
|
// l-value rather than use the copy constructor).
|
||
|
struct WeirdConstructor42 {
|
||
|
explicit WeirdConstructor42(int value) : value(value) {}
|
||
|
|
||
|
// Copy-constructor
|
||
|
WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {}
|
||
|
|
||
|
// L-value "weird" constructor (used when given an l-value)
|
||
|
WeirdConstructor42(
|
||
|
WeirdConstructor42& /*other*/) // NOLINT(runtime/references)
|
||
|
: value(42) {}
|
||
|
|
||
|
int value;
|
||
|
};
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma warning( pop )
|
||
|
#endif
|
||
|
|
||
|
TEST(AnyTest, WeirdConversionConstruction) {
|
||
|
{
|
||
|
const WeirdConstructor42 source(5);
|
||
|
absl::any o = source; // Actual copy
|
||
|
EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
WeirdConstructor42 source(5);
|
||
|
absl::any o = source; // Weird "conversion"
|
||
|
EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, WeirdConversionAssignment) {
|
||
|
{
|
||
|
const WeirdConstructor42 source(5);
|
||
|
absl::any o;
|
||
|
o = source; // Actual copy
|
||
|
EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
WeirdConstructor42 source(5);
|
||
|
absl::any o;
|
||
|
o = source; // Weird "conversion"
|
||
|
EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct Value {};
|
||
|
|
||
|
TEST(AnyTest, AnyCastValue) {
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<int>(o));
|
||
|
EXPECT_EQ(5, absl::any_cast<int>(AsConst(o)));
|
||
|
static_assert(
|
||
|
std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, "");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<const int>(o));
|
||
|
EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
|
||
|
static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)),
|
||
|
const Value>::value,
|
||
|
"");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, AnyCastReference) {
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<int&>(o));
|
||
|
EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o)));
|
||
|
static_assert(
|
||
|
std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, "");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<const int>(o));
|
||
|
EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
|
||
|
static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)),
|
||
|
const Value&>::value,
|
||
|
"");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o)));
|
||
|
static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))),
|
||
|
Value&&>::value,
|
||
|
"");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any o;
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(5, absl::any_cast<const int>(std::move(o)));
|
||
|
static_assert(
|
||
|
std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))),
|
||
|
const Value&&>::value,
|
||
|
"");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, AnyCastPointer) {
|
||
|
{
|
||
|
absl::any o;
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
|
||
|
o.emplace<char>('a');
|
||
|
EXPECT_EQ('a', *absl::any_cast<char>(&o));
|
||
|
static_assert(
|
||
|
std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, "");
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any o;
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
|
||
|
o.emplace<int>(5);
|
||
|
EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
|
||
|
o.emplace<char>('a');
|
||
|
EXPECT_EQ('a', *absl::any_cast<const char>(&o));
|
||
|
static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)),
|
||
|
const Value*>::value,
|
||
|
"");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, MakeAny) {
|
||
|
const CopyOnly copy_only{};
|
||
|
auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
|
||
|
static_assert(std::is_same<decltype(o), absl::any>::value, "");
|
||
|
EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value);
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, MakeAnyIList) {
|
||
|
const CopyOnly copy_only{};
|
||
|
auto o =
|
||
|
absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only);
|
||
|
static_assert(std::is_same<decltype(o), absl::any>::value, "");
|
||
|
ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
|
||
|
std::vector<int> expected_values = {1, 2, 3};
|
||
|
EXPECT_EQ(expected_values, v.values);
|
||
|
}
|
||
|
|
||
|
// Test the use of copy constructor and operator=
|
||
|
TEST(AnyTest, Copy) {
|
||
|
InstanceTracker tracker_raii;
|
||
|
|
||
|
{
|
||
|
absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123);
|
||
|
CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
|
||
|
|
||
|
absl::any o2(o);
|
||
|
const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2);
|
||
|
EXPECT_EQ(123, f2->value());
|
||
|
EXPECT_NE(f1, f2);
|
||
|
|
||
|
absl::any o3;
|
||
|
o3 = o2;
|
||
|
const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3);
|
||
|
EXPECT_EQ(123, f3->value());
|
||
|
EXPECT_NE(f2, f3);
|
||
|
|
||
|
const absl::any o4(4);
|
||
|
// copy construct from const lvalue ref.
|
||
|
absl::any o5 = o4;
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o5));
|
||
|
|
||
|
// Copy construct from const rvalue ref.
|
||
|
absl::any o6 = std::move(o4); // NOLINT
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o6));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, Move) {
|
||
|
InstanceTracker tracker_raii;
|
||
|
|
||
|
absl::any any1;
|
||
|
any1.emplace<CopyableOnlyInstance>(5);
|
||
|
|
||
|
// This is a copy, so copy count increases to 1.
|
||
|
absl::any any2 = any1;
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value());
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value());
|
||
|
EXPECT_EQ(1, tracker_raii.copies());
|
||
|
|
||
|
// This isn't a copy, so copy count doesn't increase.
|
||
|
absl::any any3 = std::move(any2);
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value());
|
||
|
EXPECT_EQ(1, tracker_raii.copies());
|
||
|
|
||
|
absl::any any4;
|
||
|
any4 = std::move(any3);
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value());
|
||
|
EXPECT_EQ(1, tracker_raii.copies());
|
||
|
|
||
|
absl::any tmp4(4);
|
||
|
absl::any o4(std::move(tmp4)); // move construct
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||
|
o4 = *&o4; // self assign
|
||
|
EXPECT_EQ(4, absl::any_cast<int>(o4));
|
||
|
EXPECT_TRUE(o4.has_value());
|
||
|
|
||
|
absl::any o5;
|
||
|
absl::any tmp5(5);
|
||
|
o5 = std::move(tmp5); // move assign
|
||
|
EXPECT_EQ(5, absl::any_cast<int>(o5));
|
||
|
}
|
||
|
|
||
|
// Reset the ObjectOwner with an object of a different type
|
||
|
TEST(AnyTest, Reset) {
|
||
|
absl::any o;
|
||
|
o.emplace<int>();
|
||
|
|
||
|
o.reset();
|
||
|
EXPECT_FALSE(o.has_value());
|
||
|
|
||
|
o.emplace<char>();
|
||
|
EXPECT_TRUE(o.has_value());
|
||
|
}
|
||
|
|
||
|
TEST(AnyTest, ConversionConstructionCausesOneCopy) {
|
||
|
InstanceTracker tracker_raii;
|
||
|
CopyableOnlyInstance counter(5);
|
||
|
absl::any o(counter);
|
||
|
EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value());
|
||
|
EXPECT_EQ(1, tracker_raii.copies());
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////
|
||
|
// Tests for Exception Behavior //
|
||
|
//////////////////////////////////
|
||
|
|
||
|
#if defined(ABSL_HAVE_STD_ANY)
|
||
|
|
||
|
// If using a std `any` implementation, we can't check for a specific message.
|
||
|
#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
|
||
|
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
|
||
|
"")
|
||
|
|
||
|
#else
|
||
|
|
||
|
// If using the absl `any` implementation, we can rely on a specific message.
|
||
|
#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
|
||
|
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
|
||
|
"Bad any cast")
|
||
|
|
||
|
#endif // defined(ABSL_HAVE_STD_ANY)
|
||
|
|
||
|
TEST(AnyTest, ThrowBadAlloc) {
|
||
|
{
|
||
|
absl::any a;
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{}));
|
||
|
|
||
|
// const absl::any operand
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a)));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a)));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a)));
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any a(absl::in_place_type_t<int>{});
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(
|
||
|
absl::any_cast<const float&&>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{}));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{}));
|
||
|
|
||
|
// const absl::any operand
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a)));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a)));
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class BadCopy {};
|
||
|
|
||
|
struct BadCopyable {
|
||
|
BadCopyable() = default;
|
||
|
BadCopyable(BadCopyable&&) = default;
|
||
|
BadCopyable(const BadCopyable&) {
|
||
|
#ifdef ABSL_HAVE_EXCEPTIONS
|
||
|
throw BadCopy();
|
||
|
#else
|
||
|
ABSL_RAW_LOG(FATAL, "Bad copy");
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \
|
||
|
ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy")
|
||
|
|
||
|
// Test the guarantees regarding exceptions in copy/assign.
|
||
|
TEST(AnyTest, FailedCopy) {
|
||
|
{
|
||
|
const BadCopyable bad{};
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad});
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
|
||
|
}
|
||
|
|
||
|
{
|
||
|
BadCopyable bad;
|
||
|
absl::any target;
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
BadCopyable bad;
|
||
|
absl::any target(absl::in_place_type_t<BadCopyable>{});
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
|
||
|
EXPECT_TRUE(target.has_value());
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||
|
absl::any target;
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
|
||
|
EXPECT_FALSE(target.has_value());
|
||
|
}
|
||
|
|
||
|
{
|
||
|
absl::any src(absl::in_place_type_t<BadCopyable>{});
|
||
|
absl::any target(absl::in_place_type_t<BadCopyable>{});
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
|
||
|
EXPECT_TRUE(target.has_value());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Test the guarantees regarding exceptions in emplace.
|
||
|
TEST(AnyTest, FailedEmplace) {
|
||
|
{
|
||
|
BadCopyable bad;
|
||
|
absl::any target;
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
|
||
|
}
|
||
|
|
||
|
{
|
||
|
BadCopyable bad;
|
||
|
absl::any target(absl::in_place_type_t<int>{});
|
||
|
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
|
||
|
#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
|
||
|
// libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
|
||
|
// exception is thrown, *this contains a value.
|
||
|
#define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1
|
||
|
#endif
|
||
|
#if defined(ABSL_HAVE_EXCEPTIONS) && \
|
||
|
!defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG)
|
||
|
EXPECT_FALSE(target.has_value());
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace
|