diff options
Diffstat (limited to 'third_party/abseil_cpp/absl/types/variant_test.cc')
-rw-r--r-- | third_party/abseil_cpp/absl/types/variant_test.cc | 2718 |
1 files changed, 0 insertions, 2718 deletions
diff --git a/third_party/abseil_cpp/absl/types/variant_test.cc b/third_party/abseil_cpp/absl/types/variant_test.cc deleted file mode 100644 index cf237334da02..000000000000 --- a/third_party/abseil_cpp/absl/types/variant_test.cc +++ /dev/null @@ -1,2718 +0,0 @@ -// 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 -// -// https://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. - -// Unit tests for the variant template. The 'is' and 'IsEmpty' methods -// of variant are not explicitly tested because they are used repeatedly -// in building other tests. All other public variant methods should have -// explicit tests. - -#include "absl/types/variant.h" - -// This test is a no-op when absl::variant is an alias for std::variant. -#if !defined(ABSL_USES_STD_VARIANT) - -#include <algorithm> -#include <cstddef> -#include <functional> -#include <initializer_list> -#include <memory> -#include <ostream> -#include <queue> -#include <type_traits> -#include <unordered_set> -#include <utility> -#include <vector> - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/base/config.h" -#include "absl/base/port.h" -#include "absl/memory/memory.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/string_view.h" - -#ifdef ABSL_HAVE_EXCEPTIONS - -#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_THROW(expr, exception_t) - -#else - -#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_DEATH_IF_SUPPORTED(expr, text) - -#endif // ABSL_HAVE_EXCEPTIONS - -#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \ - ABSL_VARIANT_TEST_EXPECT_FAIL((void)(__VA_ARGS__), absl::bad_variant_access, \ - "Bad variant access") - -struct Hashable {}; - -namespace std { -template <> -struct hash<Hashable> { - size_t operator()(const Hashable&); -}; -} // namespace std - -struct NonHashable {}; - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace { - -using ::testing::DoubleEq; -using ::testing::Pointee; -using ::testing::VariantWith; - -struct MoveCanThrow { - MoveCanThrow() : v(0) {} - MoveCanThrow(int v) : v(v) {} // NOLINT(runtime/explicit) - MoveCanThrow(const MoveCanThrow& other) : v(other.v) {} - MoveCanThrow& operator=(const MoveCanThrow& /*other*/) { return *this; } - int v; -}; - -bool operator==(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v == rhs.v; } -bool operator!=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v != rhs.v; } -bool operator<(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v < rhs.v; } -bool operator<=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v <= rhs.v; } -bool operator>=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v >= rhs.v; } -bool operator>(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v > rhs.v; } - -// This helper class allows us to determine if it was swapped with std::swap() -// or with its friend swap() function. -struct SpecialSwap { - explicit SpecialSwap(int i) : i(i) {} - friend void swap(SpecialSwap& a, SpecialSwap& b) { - a.special_swap = b.special_swap = true; - std::swap(a.i, b.i); - } - bool operator==(SpecialSwap other) const { return i == other.i; } - int i; - bool special_swap = false; -}; - -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; -}; - -#ifdef ABSL_HAVE_EXCEPTIONS - -struct ConversionException {}; - -template <class T> -struct ExceptionOnConversion { - operator T() const { // NOLINT(runtime/explicit) - throw ConversionException(); - } -}; - -// Forces a variant into the valueless by exception state. -template <class H, class... T> -void ToValuelessByException(absl::variant<H, T...>& v) { // NOLINT - try { - v.template emplace<0>(ExceptionOnConversion<H>()); - } catch (ConversionException& /*e*/) { - // This space intentionally left blank. - } -} - -#endif // ABSL_HAVE_EXCEPTIONS - -// An indexed sequence of distinct structures holding a single -// value of type T -template<typename T, size_t N> -struct ValueHolder { - explicit ValueHolder(const T& x) : value(x) {} - typedef T value_type; - value_type value; - static const size_t kIndex = N; -}; -template<typename T, size_t N> -const size_t ValueHolder<T, N>::kIndex; - -// The following three functions make ValueHolder compatible with -// EXPECT_EQ and EXPECT_NE -template<typename T, size_t N> -inline bool operator==(const ValueHolder<T, N>& left, - const ValueHolder<T, N>& right) { - return left.value == right.value; -} - -template<typename T, size_t N> -inline bool operator!=(const ValueHolder<T, N>& left, - const ValueHolder<T, N>& right) { - return left.value != right.value; -} - -template<typename T, size_t N> -inline std::ostream& operator<<( - std::ostream& stream, const ValueHolder<T, N>& object) { - return stream << object.value; -} - -// Makes a variant holding twelve uniquely typed T wrappers. -template<typename T> -struct VariantFactory { - typedef variant<ValueHolder<T, 1>, ValueHolder<T, 2>, ValueHolder<T, 3>, - ValueHolder<T, 4>> - Type; -}; - -// A typelist in 1:1 with VariantFactory, to use type driven unit tests. -typedef ::testing::Types<ValueHolder<size_t, 1>, ValueHolder<size_t, 2>, - ValueHolder<size_t, 3>, - ValueHolder<size_t, 4>> VariantTypes; - -// Increments the provided counter pointer in the destructor -struct IncrementInDtor { - explicit IncrementInDtor(int* counter) : counter(counter) {} - ~IncrementInDtor() { *counter += 1; } - int* counter; -}; - -struct IncrementInDtorCopyCanThrow { - explicit IncrementInDtorCopyCanThrow(int* counter) : counter(counter) {} - IncrementInDtorCopyCanThrow(IncrementInDtorCopyCanThrow&& other) noexcept = - default; - IncrementInDtorCopyCanThrow(const IncrementInDtorCopyCanThrow& other) - : counter(other.counter) {} - IncrementInDtorCopyCanThrow& operator=( - IncrementInDtorCopyCanThrow&&) noexcept = default; - IncrementInDtorCopyCanThrow& operator=( - IncrementInDtorCopyCanThrow const& other) { - counter = other.counter; - return *this; - } - ~IncrementInDtorCopyCanThrow() { *counter += 1; } - int* counter; -}; - -// This is defined so operator== for ValueHolder<IncrementInDtor> will -// return true if two IncrementInDtor objects increment the same -// counter -inline bool operator==(const IncrementInDtor& left, - const IncrementInDtor& right) { - return left.counter == right.counter; -} - -// This is defined so EXPECT_EQ can work with IncrementInDtor -inline std::ostream& operator<<( - std::ostream& stream, const IncrementInDtor& object) { - return stream << object.counter; -} - -// A class that can be copied, but not assigned. -class CopyNoAssign { - public: - explicit CopyNoAssign(int value) : foo(value) {} - CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {} - int foo; - private: - const CopyNoAssign& operator=(const CopyNoAssign&); -}; - -// A class that can neither be copied nor assigned. We provide -// overloads for the constructor with up to four parameters so we can -// test the overloads of variant::emplace. -class NonCopyable { - public: - NonCopyable() - : value(0) {} - explicit NonCopyable(int value1) - : value(value1) {} - - NonCopyable(int value1, int value2) - : value(value1 + value2) {} - - NonCopyable(int value1, int value2, int value3) - : value(value1 + value2 + value3) {} - - NonCopyable(int value1, int value2, int value3, int value4) - : value(value1 + value2 + value3 + value4) {} - NonCopyable(const NonCopyable&) = delete; - NonCopyable& operator=(const NonCopyable&) = delete; - int value; -}; - -// A typed test and typed test case over the VariantTypes typelist, -// from which we derive a number of tests that will execute for one of -// each type. -template <typename T> -class VariantTypesTest : public ::testing::Test {}; -TYPED_TEST_SUITE(VariantTypesTest, VariantTypes); - -//////////////////// -// [variant.ctor] // -//////////////////// - -struct NonNoexceptDefaultConstructible { - NonNoexceptDefaultConstructible() {} - int value = 5; -}; - -struct NonDefaultConstructible { - NonDefaultConstructible() = delete; -}; - -TEST(VariantTest, TestDefaultConstructor) { - { - using X = variant<int>; - constexpr variant<int> x{}; - ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); - EXPECT_EQ(0, absl::get<0>(x)); - EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); - } - - { - using X = variant<NonNoexceptDefaultConstructible>; - X x{}; - ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); - EXPECT_EQ(5, absl::get<0>(x).value); - EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); - } - - { - using X = variant<int, NonNoexceptDefaultConstructible>; - X x{}; - ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); - EXPECT_EQ(0, absl::get<0>(x)); - EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); - } - - { - using X = variant<NonNoexceptDefaultConstructible, int>; - X x{}; - ASSERT_FALSE(x.valueless_by_exception()); - ASSERT_EQ(0, x.index()); - EXPECT_EQ(5, absl::get<0>(x).value); - EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); - } - EXPECT_FALSE( - std::is_default_constructible<variant<NonDefaultConstructible>>::value); - EXPECT_FALSE((std::is_default_constructible< - variant<NonDefaultConstructible, int>>::value)); - EXPECT_TRUE((std::is_default_constructible< - variant<int, NonDefaultConstructible>>::value)); -} - -// Test that for each slot, copy constructing a variant with that type -// produces a sensible object that correctly reports its type, and -// that copies the provided value. -TYPED_TEST(VariantTypesTest, TestCopyCtor) { - typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - using value_type2 = absl::variant_alternative_t<1, Variant>; - using value_type3 = absl::variant_alternative_t<2, Variant>; - using value_type4 = absl::variant_alternative_t<3, Variant>; - const TypeParam value(TypeParam::kIndex); - Variant original(value); - Variant copied(original); - EXPECT_TRUE(absl::holds_alternative<value_type1>(copied) || - TypeParam::kIndex != 1); - EXPECT_TRUE(absl::holds_alternative<value_type2>(copied) || - TypeParam::kIndex != 2); - EXPECT_TRUE(absl::holds_alternative<value_type3>(copied) || - TypeParam::kIndex != 3); - EXPECT_TRUE(absl::holds_alternative<value_type4>(copied) || - TypeParam::kIndex != 4); - EXPECT_TRUE((absl::get_if<value_type1>(&original) == - absl::get_if<value_type1>(&copied)) || - TypeParam::kIndex == 1); - EXPECT_TRUE((absl::get_if<value_type2>(&original) == - absl::get_if<value_type2>(&copied)) || - TypeParam::kIndex == 2); - EXPECT_TRUE((absl::get_if<value_type3>(&original) == - absl::get_if<value_type3>(&copied)) || - TypeParam::kIndex == 3); - EXPECT_TRUE((absl::get_if<value_type4>(&original) == - absl::get_if<value_type4>(&copied)) || - TypeParam::kIndex == 4); - EXPECT_TRUE((absl::get_if<value_type1>(&original) == - absl::get_if<value_type1>(&copied)) || - TypeParam::kIndex == 1); - EXPECT_TRUE((absl::get_if<value_type2>(&original) == - absl::get_if<value_type2>(&copied)) || - TypeParam::kIndex == 2); - EXPECT_TRUE((absl::get_if<value_type3>(&original) == - absl::get_if<value_type3>(&copied)) || - TypeParam::kIndex == 3); - EXPECT_TRUE((absl::get_if<value_type4>(&original) == - absl::get_if<value_type4>(&copied)) || - TypeParam::kIndex == 4); - const TypeParam* ovalptr = absl::get_if<TypeParam>(&original); - const TypeParam* cvalptr = absl::get_if<TypeParam>(&copied); - ASSERT_TRUE(ovalptr != nullptr); - ASSERT_TRUE(cvalptr != nullptr); - EXPECT_EQ(*ovalptr, *cvalptr); - TypeParam* mutable_ovalptr = absl::get_if<TypeParam>(&original); - TypeParam* mutable_cvalptr = absl::get_if<TypeParam>(&copied); - ASSERT_TRUE(mutable_ovalptr != nullptr); - ASSERT_TRUE(mutable_cvalptr != nullptr); - EXPECT_EQ(*mutable_ovalptr, *mutable_cvalptr); -} - -template <class> -struct MoveOnly { - MoveOnly() = default; - explicit MoveOnly(int value) : value(value) {} - MoveOnly(MoveOnly&&) = default; - MoveOnly& operator=(MoveOnly&&) = default; - int value = 5; -}; - -TEST(VariantTest, TestMoveConstruct) { - using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>; - - V v(in_place_index<1>, 10); - V v2 = absl::move(v); - EXPECT_EQ(10, absl::get<1>(v2).value); -} - -// Used internally to emulate missing triviality traits for tests. -template <class T> -union SingleUnion { - T member; -}; - -// NOTE: These don't work with types that can't be union members. -// They are just for testing. -template <class T> -struct is_trivially_move_constructible - : std::is_move_constructible<SingleUnion<T>>::type {}; - -template <class T> -struct is_trivially_move_assignable - : absl::is_move_assignable<SingleUnion<T>>::type {}; - -TEST(VariantTest, NothrowMoveConstructible) { - // Verify that variant is nothrow move constructible iff its template - // arguments are. - using U = std::unique_ptr<int>; - struct E { - E(E&&) {} - }; - static_assert(std::is_nothrow_move_constructible<variant<U>>::value, ""); - static_assert(std::is_nothrow_move_constructible<variant<U, int>>::value, ""); - static_assert(!std::is_nothrow_move_constructible<variant<U, E>>::value, ""); -} - -// Test that for each slot, constructing a variant with that type -// produces a sensible object that correctly reports its type, and -// that copies the provided value. -TYPED_TEST(VariantTypesTest, TestValueCtor) { - typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - using value_type2 = absl::variant_alternative_t<1, Variant>; - using value_type3 = absl::variant_alternative_t<2, Variant>; - using value_type4 = absl::variant_alternative_t<3, Variant>; - const TypeParam value(TypeParam::kIndex); - Variant v(value); - EXPECT_TRUE(absl::holds_alternative<value_type1>(v) || - TypeParam::kIndex != 1); - EXPECT_TRUE(absl::holds_alternative<value_type2>(v) || - TypeParam::kIndex != 2); - EXPECT_TRUE(absl::holds_alternative<value_type3>(v) || - TypeParam::kIndex != 3); - EXPECT_TRUE(absl::holds_alternative<value_type4>(v) || - TypeParam::kIndex != 4); - EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) || - TypeParam::kIndex != 1); - EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) || - TypeParam::kIndex != 2); - EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) || - TypeParam::kIndex != 3); - EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) || - TypeParam::kIndex != 4); - EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) || - TypeParam::kIndex != 1); - EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) || - TypeParam::kIndex != 2); - EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) || - TypeParam::kIndex != 3); - EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) || - TypeParam::kIndex != 4); - const TypeParam* valptr = absl::get_if<TypeParam>(&v); - ASSERT_TRUE(nullptr != valptr); - EXPECT_EQ(value.value, valptr->value); - const TypeParam* mutable_valptr = absl::get_if<TypeParam>(&v); - ASSERT_TRUE(nullptr != mutable_valptr); - EXPECT_EQ(value.value, mutable_valptr->value); -} - -TEST(VariantTest, AmbiguousValueConstructor) { - EXPECT_FALSE((std::is_convertible<int, absl::variant<int, int>>::value)); - EXPECT_FALSE((std::is_constructible<absl::variant<int, int>, int>::value)); -} - -TEST(VariantTest, InPlaceType) { - using Var = variant<int, std::string, NonCopyable, std::vector<int>>; - - Var v1(in_place_type_t<int>(), 7); - ASSERT_TRUE(absl::holds_alternative<int>(v1)); - EXPECT_EQ(7, absl::get<int>(v1)); - - Var v2(in_place_type_t<std::string>(), "ABC"); - ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); - EXPECT_EQ("ABC", absl::get<std::string>(v2)); - - Var v3(in_place_type_t<std::string>(), "ABC", 2); - ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); - EXPECT_EQ("AB", absl::get<std::string>(v3)); - - Var v4(in_place_type_t<NonCopyable>{}); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4)); - - Var v5(in_place_type_t<std::vector<int>>(), {1, 2, 3}); - ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); - EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); -} - -TEST(VariantTest, InPlaceTypeVariableTemplate) { - using Var = variant<int, std::string, NonCopyable, std::vector<int>>; - - Var v1(in_place_type<int>, 7); - ASSERT_TRUE(absl::holds_alternative<int>(v1)); - EXPECT_EQ(7, absl::get<int>(v1)); - - Var v2(in_place_type<std::string>, "ABC"); - ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); - EXPECT_EQ("ABC", absl::get<std::string>(v2)); - - Var v3(in_place_type<std::string>, "ABC", 2); - ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); - EXPECT_EQ("AB", absl::get<std::string>(v3)); - - Var v4(in_place_type<NonCopyable>); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4)); - - Var v5(in_place_type<std::vector<int>>, {1, 2, 3}); - ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); - EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); -} - -TEST(VariantTest, InPlaceTypeInitializerList) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); -} - -TEST(VariantTest, InPlaceTypeInitializerListVariabletemplate) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(in_place_type<MoveOnlyWithListConstructor>, {1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); -} - -TEST(VariantTest, InPlaceIndex) { - using Var = variant<int, std::string, NonCopyable, std::vector<int>>; - - Var v1(in_place_index_t<0>(), 7); - ASSERT_TRUE(absl::holds_alternative<int>(v1)); - EXPECT_EQ(7, absl::get<int>(v1)); - - Var v2(in_place_index_t<1>(), "ABC"); - ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); - EXPECT_EQ("ABC", absl::get<std::string>(v2)); - - Var v3(in_place_index_t<1>(), "ABC", 2); - ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); - EXPECT_EQ("AB", absl::get<std::string>(v3)); - - Var v4(in_place_index_t<2>{}); - EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4)); - - // Verify that a variant with only non-copyables can still be constructed. - EXPECT_TRUE(absl::holds_alternative<NonCopyable>( - variant<NonCopyable>(in_place_index_t<0>{}))); - - Var v5(in_place_index_t<3>(), {1, 2, 3}); - ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); - EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); -} - -TEST(VariantTest, InPlaceIndexVariableTemplate) { - using Var = variant<int, std::string, NonCopyable, std::vector<int>>; - - Var v1(in_place_index<0>, 7); - ASSERT_TRUE(absl::holds_alternative<int>(v1)); - EXPECT_EQ(7, absl::get<int>(v1)); - - Var v2(in_place_index<1>, "ABC"); - ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); - EXPECT_EQ("ABC", absl::get<std::string>(v2)); - - Var v3(in_place_index<1>, "ABC", 2); - ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); - EXPECT_EQ("AB", absl::get<std::string>(v3)); - - Var v4(in_place_index<2>); - EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4)); - - // Verify that a variant with only non-copyables can still be constructed. - EXPECT_TRUE(absl::holds_alternative<NonCopyable>( - variant<NonCopyable>(in_place_index<0>))); - - Var v5(in_place_index<3>, {1, 2, 3}); - ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); - EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); -} - -TEST(VariantTest, InPlaceIndexInitializerList) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); -} - -TEST(VariantTest, InPlaceIndexInitializerListVariableTemplate) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(in_place_index<3>, {1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); -} - -//////////////////// -// [variant.dtor] // -//////////////////// - -// Make sure that the destructor destroys the contained value -TEST(VariantTest, TestDtor) { - typedef VariantFactory<IncrementInDtor>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - using value_type2 = absl::variant_alternative_t<1, Variant>; - using value_type3 = absl::variant_alternative_t<2, Variant>; - using value_type4 = absl::variant_alternative_t<3, Variant>; - int counter = 0; - IncrementInDtor counter_adjuster(&counter); - EXPECT_EQ(0, counter); - - value_type1 value1(counter_adjuster); - { Variant object(value1); } - EXPECT_EQ(1, counter); - - value_type2 value2(counter_adjuster); - { Variant object(value2); } - EXPECT_EQ(2, counter); - - value_type3 value3(counter_adjuster); - { Variant object(value3); } - EXPECT_EQ(3, counter); - - value_type4 value4(counter_adjuster); - { Variant object(value4); } - EXPECT_EQ(4, counter); -} - -#ifdef ABSL_HAVE_EXCEPTIONS - -// See comment in absl/base/config.h -#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE) -TEST(VariantTest, DISABLED_TestDtorValuelessByException) -#else -// Test destruction when in the valueless_by_exception state. -TEST(VariantTest, TestDtorValuelessByException) -#endif -{ - int counter = 0; - IncrementInDtor counter_adjuster(&counter); - - { - using Variant = VariantFactory<IncrementInDtor>::Type; - - Variant v(in_place_index<0>, counter_adjuster); - EXPECT_EQ(0, counter); - - ToValuelessByException(v); - ASSERT_TRUE(v.valueless_by_exception()); - EXPECT_EQ(1, counter); - } - EXPECT_EQ(1, counter); -} - -#endif // ABSL_HAVE_EXCEPTIONS - -////////////////////// -// [variant.assign] // -////////////////////// - -// Test that self-assignment doesn't destroy the current value -TEST(VariantTest, TestSelfAssignment) { - typedef VariantFactory<IncrementInDtor>::Type Variant; - int counter = 0; - IncrementInDtor counter_adjuster(&counter); - absl::variant_alternative_t<0, Variant> value(counter_adjuster); - Variant object(value); - object.operator=(object); - EXPECT_EQ(0, counter); - - // A string long enough that it's likely to defeat any inline representation - // optimization. - const std::string long_str(128, 'a'); - - std::string foo = long_str; - foo = *&foo; - EXPECT_EQ(long_str, foo); - - variant<int, std::string> so = long_str; - ASSERT_EQ(1, so.index()); - EXPECT_EQ(long_str, absl::get<1>(so)); - so = *&so; - - ASSERT_EQ(1, so.index()); - EXPECT_EQ(long_str, absl::get<1>(so)); -} - -// Test that assigning a variant<..., T, ...> to a variant<..., T, ...> produces -// a variant<..., T, ...> with the correct value. -TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValueSameTypes) { - typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; - const TypeParam value(TypeParam::kIndex); - const Variant source(value); - Variant target(TypeParam(value.value + 1)); - ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); - ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); - ASSERT_NE(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); - target = source; - ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); - ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); - EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); -} - -// Test that assisnging a variant<..., T, ...> to a variant<1, ...> -// produces a variant<..., T, ...> with the correct value. -TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingSourceType) { - typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - const TypeParam value(TypeParam::kIndex); - const Variant source(value); - ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); - Variant target(value_type1(1)); - ASSERT_TRUE(absl::holds_alternative<value_type1>(target)); - target = source; - EXPECT_TRUE(absl::holds_alternative<TypeParam>(source)); - EXPECT_TRUE(absl::holds_alternative<TypeParam>(target)); - EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); -} - -// Test that assigning a variant<1, ...> to a variant<..., T, ...> -// produces a variant<1, ...> with the correct value. -TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingTargetType) { - typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - const Variant source(value_type1(1)); - ASSERT_TRUE(absl::holds_alternative<value_type1>(source)); - const TypeParam value(TypeParam::kIndex); - Variant target(value); - ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); - target = source; - EXPECT_TRUE(absl::holds_alternative<value_type1>(target)); - EXPECT_TRUE(absl::holds_alternative<value_type1>(source)); - EXPECT_EQ(absl::get<value_type1>(source), absl::get<value_type1>(target)); -} - -// Test that operator=<T> works, that assigning a new value destroys -// the old and that assigning the new value again does not redestroy -// the old -TEST(VariantTest, TestAssign) { - typedef VariantFactory<IncrementInDtor>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - using value_type2 = absl::variant_alternative_t<1, Variant>; - using value_type3 = absl::variant_alternative_t<2, Variant>; - using value_type4 = absl::variant_alternative_t<3, Variant>; - - const int kSize = 4; - int counter[kSize]; - std::unique_ptr<IncrementInDtor> counter_adjustor[kSize]; - for (int i = 0; i != kSize; i++) { - counter[i] = 0; - counter_adjustor[i] = absl::make_unique<IncrementInDtor>(&counter[i]); - } - - value_type1 v1(*counter_adjustor[0]); - value_type2 v2(*counter_adjustor[1]); - value_type3 v3(*counter_adjustor[2]); - value_type4 v4(*counter_adjustor[3]); - - // Test that reassignment causes destruction of old value - { - Variant object(v1); - object = v2; - object = v3; - object = v4; - object = v1; - } - - EXPECT_EQ(2, counter[0]); - EXPECT_EQ(1, counter[1]); - EXPECT_EQ(1, counter[2]); - EXPECT_EQ(1, counter[3]); - - std::fill(std::begin(counter), std::end(counter), 0); - - // Test that self-assignment does not cause destruction of old value - { - Variant object(v1); - object.operator=(object); - EXPECT_EQ(0, counter[0]); - } - { - Variant object(v2); - object.operator=(object); - EXPECT_EQ(0, counter[1]); - } - { - Variant object(v3); - object.operator=(object); - EXPECT_EQ(0, counter[2]); - } - { - Variant object(v4); - object.operator=(object); - EXPECT_EQ(0, counter[3]); - } - - EXPECT_EQ(1, counter[0]); - EXPECT_EQ(1, counter[1]); - EXPECT_EQ(1, counter[2]); - EXPECT_EQ(1, counter[3]); -} - -// This tests that we perform a backup if the copy-assign can throw but the move -// cannot throw. -TEST(VariantTest, TestBackupAssign) { - typedef VariantFactory<IncrementInDtorCopyCanThrow>::Type Variant; - using value_type1 = absl::variant_alternative_t<0, Variant>; - using value_type2 = absl::variant_alternative_t<1, Variant>; - using value_type3 = absl::variant_alternative_t<2, Variant>; - using value_type4 = absl::variant_alternative_t<3, Variant>; - - const int kSize = 4; - int counter[kSize]; - std::unique_ptr<IncrementInDtorCopyCanThrow> counter_adjustor[kSize]; - for (int i = 0; i != kSize; i++) { - counter[i] = 0; - counter_adjustor[i].reset(new IncrementInDtorCopyCanThrow(&counter[i])); - } - - value_type1 v1(*counter_adjustor[0]); - value_type2 v2(*counter_adjustor[1]); - value_type3 v3(*counter_adjustor[2]); - value_type4 v4(*counter_adjustor[3]); - - // Test that reassignment causes destruction of old value - { - Variant object(v1); - object = v2; - object = v3; - object = v4; - object = v1; - } - - // libstdc++ doesn't pass this test -#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__)) - EXPECT_EQ(3, counter[0]); - EXPECT_EQ(2, counter[1]); - EXPECT_EQ(2, counter[2]); - EXPECT_EQ(2, counter[3]); -#endif - - std::fill(std::begin(counter), std::end(counter), 0); - - // Test that self-assignment does not cause destruction of old value - { - Variant object(v1); - object.operator=(object); - EXPECT_EQ(0, counter[0]); - } - { - Variant object(v2); - object.operator=(object); - EXPECT_EQ(0, counter[1]); - } - { - Variant object(v3); - object.operator=(object); - EXPECT_EQ(0, counter[2]); - } - { - Variant object(v4); - object.operator=(object); - EXPECT_EQ(0, counter[3]); - } - - EXPECT_EQ(1, counter[0]); - EXPECT_EQ(1, counter[1]); - EXPECT_EQ(1, counter[2]); - EXPECT_EQ(1, counter[3]); -} - -/////////////////// -// [variant.mod] // -/////////////////// - -TEST(VariantTest, TestEmplaceBasic) { - using Variant = variant<int, char>; - - Variant v(absl::in_place_index<0>, 0); - - { - char& emplace_result = v.emplace<char>(); - ASSERT_TRUE(absl::holds_alternative<char>(v)); - EXPECT_EQ(absl::get<char>(v), 0); - EXPECT_EQ(&emplace_result, &absl::get<char>(v)); - } - - // Make sure that another emplace does zero-initialization - absl::get<char>(v) = 'a'; - v.emplace<char>('b'); - ASSERT_TRUE(absl::holds_alternative<char>(v)); - EXPECT_EQ(absl::get<char>(v), 'b'); - - { - int& emplace_result = v.emplace<int>(); - EXPECT_TRUE(absl::holds_alternative<int>(v)); - EXPECT_EQ(absl::get<int>(v), 0); - EXPECT_EQ(&emplace_result, &absl::get<int>(v)); - } -} - -TEST(VariantTest, TestEmplaceInitializerList) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(absl::in_place_index<0>, 555); - MoveOnlyWithListConstructor& emplace_result = - v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); - EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1)); -} - -TEST(VariantTest, TestEmplaceIndex) { - using Variant = variant<int, char>; - - Variant v(absl::in_place_index<0>, 555); - - { - char& emplace_result = v.emplace<1>(); - ASSERT_TRUE(absl::holds_alternative<char>(v)); - EXPECT_EQ(absl::get<char>(v), 0); - EXPECT_EQ(&emplace_result, &absl::get<char>(v)); - } - - // Make sure that another emplace does zero-initialization - absl::get<char>(v) = 'a'; - v.emplace<1>('b'); - ASSERT_TRUE(absl::holds_alternative<char>(v)); - EXPECT_EQ(absl::get<char>(v), 'b'); - - { - int& emplace_result = v.emplace<0>(); - EXPECT_TRUE(absl::holds_alternative<int>(v)); - EXPECT_EQ(absl::get<int>(v), 0); - EXPECT_EQ(&emplace_result, &absl::get<int>(v)); - } -} - -TEST(VariantTest, TestEmplaceIndexInitializerList) { - using Var = - variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; - - Var v1(absl::in_place_index<0>, 555); - MoveOnlyWithListConstructor& emplace_result = - v1.emplace<3>({1, 2, 3, 4, 5}, 6); - ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); - EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); - EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1)); -} - -////////////////////// -// [variant.status] // -////////////////////// - -TEST(VariantTest, Index) { - using Var = variant<int, std::string, double>; - - Var v = 1; - EXPECT_EQ(0, v.index()); - v = "str"; - EXPECT_EQ(1, v.index()); - v = 0.; - EXPECT_EQ(2, v.index()); - - Var v2 = v; - EXPECT_EQ(2, v2.index()); - v2.emplace<int>(3); - EXPECT_EQ(0, v2.index()); -} - -TEST(VariantTest, NotValuelessByException) { - using Var = variant<int, std::string, double>; - - Var v = 1; - EXPECT_FALSE(v.valueless_by_exception()); - v = "str"; - EXPECT_FALSE(v.valueless_by_exception()); - v = 0.; - EXPECT_FALSE(v.valueless_by_exception()); - - Var v2 = v; - EXPECT_FALSE(v.valueless_by_exception()); - v2.emplace<int>(3); - EXPECT_FALSE(v.valueless_by_exception()); -} - -#ifdef ABSL_HAVE_EXCEPTIONS - -TEST(VariantTest, IndexValuelessByException) { - using Var = variant<MoveCanThrow, std::string, double>; - - Var v(absl::in_place_index<0>); - EXPECT_EQ(0, v.index()); - ToValuelessByException(v); - EXPECT_EQ(absl::variant_npos, v.index()); - v = "str"; - EXPECT_EQ(1, v.index()); -} - -TEST(VariantTest, ValuelessByException) { - using Var = variant<MoveCanThrow, std::string, double>; - - Var v(absl::in_place_index<0>); - EXPECT_FALSE(v.valueless_by_exception()); - ToValuelessByException(v); - EXPECT_TRUE(v.valueless_by_exception()); - v = "str"; - EXPECT_FALSE(v.valueless_by_exception()); -} - -#endif // ABSL_HAVE_EXCEPTIONS - -//////////////////// -// [variant.swap] // -//////////////////// - -TEST(VariantTest, MemberSwap) { - SpecialSwap v1(3); - SpecialSwap v2(7); - - variant<SpecialSwap> a = v1, b = v2; - - EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); - EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); - - a.swap(b); - EXPECT_THAT(a, VariantWith<SpecialSwap>(v2)); - EXPECT_THAT(b, VariantWith<SpecialSwap>(v1)); - EXPECT_TRUE(absl::get<SpecialSwap>(a).special_swap); - - using V = variant<MoveCanThrow, std::string, int>; - int i = 33; - std::string s = "abc"; - { - // lhs and rhs holds different alternative - V lhs(i), rhs(s); - lhs.swap(rhs); - EXPECT_THAT(lhs, VariantWith<std::string>(s)); - EXPECT_THAT(rhs, VariantWith<int>(i)); - } -#ifdef ABSL_HAVE_EXCEPTIONS - V valueless(in_place_index<0>); - ToValuelessByException(valueless); - { - // lhs is valueless - V lhs(valueless), rhs(i); - lhs.swap(rhs); - EXPECT_THAT(lhs, VariantWith<int>(i)); - EXPECT_TRUE(rhs.valueless_by_exception()); - } - { - // rhs is valueless - V lhs(s), rhs(valueless); - lhs.swap(rhs); - EXPECT_THAT(rhs, VariantWith<std::string>(s)); - EXPECT_TRUE(lhs.valueless_by_exception()); - } - { - // both are valueless - V lhs(valueless), rhs(valueless); - lhs.swap(rhs); - EXPECT_TRUE(lhs.valueless_by_exception()); - EXPECT_TRUE(rhs.valueless_by_exception()); - } -#endif // ABSL_HAVE_EXCEPTIONS -} - -////////////////////// -// [variant.helper] // -////////////////////// - -TEST(VariantTest, VariantSize) { - { - using Size1Variant = absl::variant<int>; - EXPECT_EQ(1, absl::variant_size<Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<const Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<volatile Size1Variant>::value); - EXPECT_EQ(1, absl::variant_size<const volatile Size1Variant>::value); - } - - { - using Size3Variant = absl::variant<int, float, int>; - EXPECT_EQ(3, absl::variant_size<Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<const Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<volatile Size3Variant>::value); - EXPECT_EQ(3, absl::variant_size<const volatile Size3Variant>::value); - } -} - -TEST(VariantTest, VariantAlternative) { - { - using V = absl::variant<float, int, const char*>; - EXPECT_TRUE( - (std::is_same<float, absl::variant_alternative_t<0, V>>::value)); - EXPECT_TRUE((std::is_same<const float, - absl::variant_alternative_t<0, const V>>::value)); - EXPECT_TRUE( - (std::is_same<volatile float, - absl::variant_alternative_t<0, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const volatile float, - absl::variant_alternative_t<0, const volatile V>>::value)); - - EXPECT_TRUE((std::is_same<int, absl::variant_alternative_t<1, V>>::value)); - EXPECT_TRUE((std::is_same<const int, - absl::variant_alternative_t<1, const V>>::value)); - EXPECT_TRUE( - (std::is_same<volatile int, - absl::variant_alternative_t<1, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const volatile int, - absl::variant_alternative_t<1, const volatile V>>::value)); - - EXPECT_TRUE( - (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value)); - EXPECT_TRUE((std::is_same<const char* const, - absl::variant_alternative_t<2, const V>>::value)); - EXPECT_TRUE( - (std::is_same<const char* volatile, - absl::variant_alternative_t<2, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const char* const volatile, - absl::variant_alternative_t<2, const volatile V>>::value)); - } - - { - using V = absl::variant<float, volatile int, const char*>; - EXPECT_TRUE( - (std::is_same<float, absl::variant_alternative_t<0, V>>::value)); - EXPECT_TRUE((std::is_same<const float, - absl::variant_alternative_t<0, const V>>::value)); - EXPECT_TRUE( - (std::is_same<volatile float, - absl::variant_alternative_t<0, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const volatile float, - absl::variant_alternative_t<0, const volatile V>>::value)); - - EXPECT_TRUE( - (std::is_same<volatile int, absl::variant_alternative_t<1, V>>::value)); - EXPECT_TRUE((std::is_same<const volatile int, - absl::variant_alternative_t<1, const V>>::value)); - EXPECT_TRUE( - (std::is_same<volatile int, - absl::variant_alternative_t<1, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const volatile int, - absl::variant_alternative_t<1, const volatile V>>::value)); - - EXPECT_TRUE( - (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value)); - EXPECT_TRUE((std::is_same<const char* const, - absl::variant_alternative_t<2, const V>>::value)); - EXPECT_TRUE( - (std::is_same<const char* volatile, - absl::variant_alternative_t<2, volatile V>>::value)); - EXPECT_TRUE(( - std::is_same<const char* const volatile, - absl::variant_alternative_t<2, const volatile V>>::value)); - } -} - -/////////////////// -// [variant.get] // -/////////////////// - -TEST(VariantTest, HoldsAlternative) { - using Var = variant<int, std::string, double>; - - Var v = 1; - EXPECT_TRUE(absl::holds_alternative<int>(v)); - EXPECT_FALSE(absl::holds_alternative<std::string>(v)); - EXPECT_FALSE(absl::holds_alternative<double>(v)); - v = "str"; - EXPECT_FALSE(absl::holds_alternative<int>(v)); - EXPECT_TRUE(absl::holds_alternative<std::string>(v)); - EXPECT_FALSE(absl::holds_alternative<double>(v)); - v = 0.; - EXPECT_FALSE(absl::holds_alternative<int>(v)); - EXPECT_FALSE(absl::holds_alternative<std::string>(v)); - EXPECT_TRUE(absl::holds_alternative<double>(v)); - - Var v2 = v; - EXPECT_FALSE(absl::holds_alternative<int>(v2)); - EXPECT_FALSE(absl::holds_alternative<std::string>(v2)); - EXPECT_TRUE(absl::holds_alternative<double>(v2)); - v2.emplace<int>(3); - EXPECT_TRUE(absl::holds_alternative<int>(v2)); - EXPECT_FALSE(absl::holds_alternative<std::string>(v2)); - EXPECT_FALSE(absl::holds_alternative<double>(v2)); -} - -TEST(VariantTest, GetIndex) { - using Var = variant<int, std::string, double, int>; - - { - Var v(absl::in_place_index<0>, 0); - - using LValueGetType = decltype(absl::get<0>(v)); - using RValueGetType = decltype(absl::get<0>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); - EXPECT_EQ(absl::get<0>(v), 0); - EXPECT_EQ(absl::get<0>(absl::move(v)), 0); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<0>(const_v)); - using ConstRValueGetType = decltype(absl::get<0>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); - EXPECT_EQ(absl::get<0>(const_v), 0); - EXPECT_EQ(absl::get<0>(absl::move(const_v)), 0); - } - - { - Var v = std::string("Hello"); - - using LValueGetType = decltype(absl::get<1>(v)); - using RValueGetType = decltype(absl::get<1>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value)); - EXPECT_EQ(absl::get<1>(v), "Hello"); - EXPECT_EQ(absl::get<1>(absl::move(v)), "Hello"); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<1>(const_v)); - using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value)); - EXPECT_EQ(absl::get<1>(const_v), "Hello"); - EXPECT_EQ(absl::get<1>(absl::move(const_v)), "Hello"); - } - - { - Var v = 2.0; - - using LValueGetType = decltype(absl::get<2>(v)); - using RValueGetType = decltype(absl::get<2>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, double&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value)); - EXPECT_EQ(absl::get<2>(v), 2.); - EXPECT_EQ(absl::get<2>(absl::move(v)), 2.); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<2>(const_v)); - using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value)); - EXPECT_EQ(absl::get<2>(const_v), 2.); - EXPECT_EQ(absl::get<2>(absl::move(const_v)), 2.); - } - - { - Var v(absl::in_place_index<0>, 0); - v.emplace<3>(1); - - using LValueGetType = decltype(absl::get<3>(v)); - using RValueGetType = decltype(absl::get<3>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); - EXPECT_EQ(absl::get<3>(v), 1); - EXPECT_EQ(absl::get<3>(absl::move(v)), 1); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<3>(const_v)); - using ConstRValueGetType = decltype(absl::get<3>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); - EXPECT_EQ(absl::get<3>(const_v), 1); - EXPECT_EQ(absl::get<3>(absl::move(const_v)), 1); // NOLINT - } -} - -TEST(VariantTest, BadGetIndex) { - using Var = variant<int, std::string, double>; - - { - Var v = 1; - - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(std::move(v))); - - const Var& const_v = v; - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(const_v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<1>(std::move(const_v))); // NOLINT - } - - { - Var v = std::string("Hello"); - - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(std::move(v))); - - const Var& const_v = v; - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(const_v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<0>(std::move(const_v))); // NOLINT - } -} - -TEST(VariantTest, GetType) { - using Var = variant<int, std::string, double>; - - { - Var v = 1; - - using LValueGetType = decltype(absl::get<int>(v)); - using RValueGetType = decltype(absl::get<int>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); - EXPECT_EQ(absl::get<int>(v), 1); - EXPECT_EQ(absl::get<int>(absl::move(v)), 1); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<int>(const_v)); - using ConstRValueGetType = decltype(absl::get<int>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); - EXPECT_EQ(absl::get<int>(const_v), 1); - EXPECT_EQ(absl::get<int>(absl::move(const_v)), 1); - } - - { - Var v = std::string("Hello"); - - using LValueGetType = decltype(absl::get<1>(v)); - using RValueGetType = decltype(absl::get<1>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value)); - EXPECT_EQ(absl::get<std::string>(v), "Hello"); - EXPECT_EQ(absl::get<std::string>(absl::move(v)), "Hello"); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<1>(const_v)); - using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value)); - EXPECT_EQ(absl::get<std::string>(const_v), "Hello"); - EXPECT_EQ(absl::get<std::string>(absl::move(const_v)), "Hello"); - } - - { - Var v = 2.0; - - using LValueGetType = decltype(absl::get<2>(v)); - using RValueGetType = decltype(absl::get<2>(absl::move(v))); - - EXPECT_TRUE((std::is_same<LValueGetType, double&>::value)); - EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value)); - EXPECT_EQ(absl::get<double>(v), 2.); - EXPECT_EQ(absl::get<double>(absl::move(v)), 2.); - - const Var& const_v = v; - using ConstLValueGetType = decltype(absl::get<2>(const_v)); - using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v))); - EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value)); - EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value)); - EXPECT_EQ(absl::get<double>(const_v), 2.); - EXPECT_EQ(absl::get<double>(absl::move(const_v)), 2.); - } -} - -TEST(VariantTest, BadGetType) { - using Var = variant<int, std::string, double>; - - { - Var v = 1; - - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<std::string>(std::move(v))); - - const Var& const_v = v; - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<std::string>(const_v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<std::string>(std::move(const_v))); // NOLINT - } - - { - Var v = std::string("Hello"); - - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(std::move(v))); - - const Var& const_v = v; - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(const_v)); - ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( - absl::get<int>(std::move(const_v))); // NOLINT - } -} - -TEST(VariantTest, GetIfIndex) { - using Var = variant<int, std::string, double, int>; - - { - Var v(absl::in_place_index<0>, 0); - EXPECT_TRUE(noexcept(absl::get_if<0>(&v))); - - { - auto* elem = absl::get_if<0>(&v); - EXPECT_TRUE((std::is_same<decltype(elem), int*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 0); - { - auto* bad_elem = absl::get_if<1>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - } - - const Var& const_v = v; - EXPECT_TRUE(noexcept(absl::get_if<0>(&const_v))); - - { - auto* elem = absl::get_if<0>(&const_v); - EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 0); - { - auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE( - (std::is_same<decltype(bad_elem), const std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&const_v); - EXPECT_EQ(bad_elem, nullptr); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - } - } - } - - { - Var v = std::string("Hello"); - EXPECT_TRUE(noexcept(absl::get_if<1>(&v))); - - { - auto* elem = absl::get_if<1>(&v); - EXPECT_TRUE((std::is_same<decltype(elem), std::string*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, "Hello"); - { - auto* bad_elem = absl::get_if<0>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - } - - const Var& const_v = v; - EXPECT_TRUE(noexcept(absl::get_if<1>(&const_v))); - - { - auto* elem = absl::get_if<1>(&const_v); - EXPECT_TRUE((std::is_same<decltype(elem), const std::string*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, "Hello"); - { - auto* bad_elem = absl::get_if<0>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&const_v); - EXPECT_EQ(bad_elem, nullptr); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - } - } - } - - { - Var v = 2.0; - EXPECT_TRUE(noexcept(absl::get_if<2>(&v))); - - { - auto* elem = absl::get_if<2>(&v); - EXPECT_TRUE((std::is_same<decltype(elem), double*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 2.0); - { - auto* bad_elem = absl::get_if<0>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<1>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - } - - const Var& const_v = v; - EXPECT_TRUE(noexcept(absl::get_if<2>(&const_v))); - - { - auto* elem = absl::get_if<2>(&const_v); - EXPECT_TRUE((std::is_same<decltype(elem), const double*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 2.0); - { - auto* bad_elem = absl::get_if<0>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE( - (std::is_same<decltype(bad_elem), const std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<3>(&const_v); - EXPECT_EQ(bad_elem, nullptr); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - } - } - } - - { - Var v(absl::in_place_index<0>, 0); - v.emplace<3>(1); - EXPECT_TRUE(noexcept(absl::get_if<3>(&v))); - - { - auto* elem = absl::get_if<3>(&v); - EXPECT_TRUE((std::is_same<decltype(elem), int*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 1); - { - auto* bad_elem = absl::get_if<0>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<1>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - } - - const Var& const_v = v; - EXPECT_TRUE(noexcept(absl::get_if<3>(&const_v))); - - { - auto* elem = absl::get_if<3>(&const_v); - EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value)); - ASSERT_NE(elem, nullptr); - EXPECT_EQ(*elem, 1); - { - auto* bad_elem = absl::get_if<0>(&const_v); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<1>(&const_v); - EXPECT_TRUE( - (std::is_same<decltype(bad_elem), const std::string*>::value)); - EXPECT_EQ(bad_elem, nullptr); - } - { - auto* bad_elem = absl::get_if<2>(&const_v); - EXPECT_EQ(bad_elem, nullptr); - EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); - } - } - } -} - -////////////////////// -// [variant.relops] // -////////////////////// - -TEST(VariantTest, OperatorEquals) { - variant<int, std::string> a(1), b(1); - EXPECT_TRUE(a == b); - EXPECT_TRUE(b == a); - EXPECT_FALSE(a != b); - EXPECT_FALSE(b != a); - - b = "str"; - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); - EXPECT_TRUE(a != b); - EXPECT_TRUE(b != a); - - b = 0; - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); - EXPECT_TRUE(a != b); - EXPECT_TRUE(b != a); - - a = b = "foo"; - EXPECT_TRUE(a == b); - EXPECT_TRUE(b == a); - EXPECT_FALSE(a != b); - EXPECT_FALSE(b != a); - - a = "bar"; - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); - EXPECT_TRUE(a != b); - EXPECT_TRUE(b != a); -} - -TEST(VariantTest, OperatorRelational) { - variant<int, std::string> a(1), b(1); - EXPECT_FALSE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_FALSE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_TRUE(b <= a); - EXPECT_TRUE(a >= b); - EXPECT_TRUE(b >= a); - - b = "str"; - EXPECT_TRUE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_TRUE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_FALSE(b <= a); - EXPECT_FALSE(a >= b); - EXPECT_TRUE(b >= a); - - b = 0; - EXPECT_FALSE(a < b); - EXPECT_TRUE(b < a); - EXPECT_TRUE(a > b); - EXPECT_FALSE(b > a); - EXPECT_FALSE(a <= b); - EXPECT_TRUE(b <= a); - EXPECT_TRUE(a >= b); - EXPECT_FALSE(b >= a); - - a = b = "foo"; - EXPECT_FALSE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_FALSE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_TRUE(b <= a); - EXPECT_TRUE(a >= b); - EXPECT_TRUE(b >= a); - - a = "bar"; - EXPECT_TRUE(a < b); - EXPECT_FALSE(b < a); - EXPECT_FALSE(a > b); - EXPECT_TRUE(b > a); - EXPECT_TRUE(a <= b); - EXPECT_FALSE(b <= a); - EXPECT_FALSE(a >= b); - EXPECT_TRUE(b >= a); -} - -#ifdef ABSL_HAVE_EXCEPTIONS - -TEST(VariantTest, ValuelessOperatorEquals) { - variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), - valueless(absl::in_place_index<0>), - other_valueless(absl::in_place_index<0>); - ToValuelessByException(valueless); - ToValuelessByException(other_valueless); - - EXPECT_TRUE(valueless == other_valueless); - EXPECT_TRUE(other_valueless == valueless); - EXPECT_FALSE(valueless == int_v); - EXPECT_FALSE(valueless == string_v); - EXPECT_FALSE(int_v == valueless); - EXPECT_FALSE(string_v == valueless); - - EXPECT_FALSE(valueless != other_valueless); - EXPECT_FALSE(other_valueless != valueless); - EXPECT_TRUE(valueless != int_v); - EXPECT_TRUE(valueless != string_v); - EXPECT_TRUE(int_v != valueless); - EXPECT_TRUE(string_v != valueless); -} - -TEST(VariantTest, ValuelessOperatorRelational) { - variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), - valueless(absl::in_place_index<0>), - other_valueless(absl::in_place_index<0>); - ToValuelessByException(valueless); - ToValuelessByException(other_valueless); - - EXPECT_FALSE(valueless < other_valueless); - EXPECT_FALSE(other_valueless < valueless); - EXPECT_TRUE(valueless < int_v); - EXPECT_TRUE(valueless < string_v); - EXPECT_FALSE(int_v < valueless); - EXPECT_FALSE(string_v < valueless); - - EXPECT_TRUE(valueless <= other_valueless); - EXPECT_TRUE(other_valueless <= valueless); - EXPECT_TRUE(valueless <= int_v); - EXPECT_TRUE(valueless <= string_v); - EXPECT_FALSE(int_v <= valueless); - EXPECT_FALSE(string_v <= valueless); - - EXPECT_TRUE(valueless >= other_valueless); - EXPECT_TRUE(other_valueless >= valueless); - EXPECT_FALSE(valueless >= int_v); - EXPECT_FALSE(valueless >= string_v); - EXPECT_TRUE(int_v >= valueless); - EXPECT_TRUE(string_v >= valueless); - - EXPECT_FALSE(valueless > other_valueless); - EXPECT_FALSE(other_valueless > valueless); - EXPECT_FALSE(valueless > int_v); - EXPECT_FALSE(valueless > string_v); - EXPECT_TRUE(int_v > valueless); - EXPECT_TRUE(string_v > valueless); -} - -#endif - -///////////////////// -// [variant.visit] // -///////////////////// - -template <typename T> -struct ConvertTo { - template <typename U> - T operator()(const U& u) const { - return u; - } -}; - -TEST(VariantTest, VisitSimple) { - variant<std::string, const char*> v = "A"; - - std::string str = absl::visit(ConvertTo<std::string>{}, v); - EXPECT_EQ("A", str); - - v = std::string("B"); - - absl::string_view piece = absl::visit(ConvertTo<absl::string_view>{}, v); - EXPECT_EQ("B", piece); - - struct StrLen { - int operator()(const char* s) const { return strlen(s); } - int operator()(const std::string& s) const { return s.size(); } - }; - - v = "SomeStr"; - EXPECT_EQ(7, absl::visit(StrLen{}, v)); - v = std::string("VeryLargeThisTime"); - EXPECT_EQ(17, absl::visit(StrLen{}, v)); -} - -TEST(VariantTest, VisitRValue) { - variant<std::string> v = std::string("X"); - struct Visitor { - bool operator()(const std::string&) const { return false; } - bool operator()(std::string&&) const { return true; } // NOLINT - - int operator()(const std::string&, const std::string&) const { return 0; } - int operator()(const std::string&, std::string&&) const { - return 1; - } // NOLINT - int operator()(std::string&&, const std::string&) const { - return 2; - } // NOLINT - int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT - }; - EXPECT_FALSE(absl::visit(Visitor{}, v)); - EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v))); - - // Also test the variadic overload. - EXPECT_EQ(0, absl::visit(Visitor{}, v, v)); - EXPECT_EQ(1, absl::visit(Visitor{}, v, absl::move(v))); - EXPECT_EQ(2, absl::visit(Visitor{}, absl::move(v), v)); - EXPECT_EQ(3, absl::visit(Visitor{}, absl::move(v), absl::move(v))); -} - -TEST(VariantTest, VisitRValueVisitor) { - variant<std::string> v = std::string("X"); - struct Visitor { - bool operator()(const std::string&) const& { return false; } - bool operator()(const std::string&) && { return true; } - }; - Visitor visitor; - EXPECT_FALSE(absl::visit(visitor, v)); - EXPECT_TRUE(absl::visit(Visitor{}, v)); -} - -TEST(VariantTest, VisitResultTypeDifferent) { - variant<std::string> v = std::string("X"); - struct LValue_LValue {}; - struct RValue_LValue {}; - struct LValue_RValue {}; - struct RValue_RValue {}; - struct Visitor { - LValue_LValue operator()(const std::string&) const& { return {}; } - RValue_LValue operator()(std::string&&) const& { return {}; } // NOLINT - LValue_RValue operator()(const std::string&) && { return {}; } - RValue_RValue operator()(std::string&&) && { return {}; } // NOLINT - } visitor; - - EXPECT_TRUE( - (std::is_same<LValue_LValue, decltype(absl::visit(visitor, v))>::value)); - EXPECT_TRUE( - (std::is_same<RValue_LValue, - decltype(absl::visit(visitor, absl::move(v)))>::value)); - EXPECT_TRUE(( - std::is_same<LValue_RValue, decltype(absl::visit(Visitor{}, v))>::value)); - EXPECT_TRUE( - (std::is_same<RValue_RValue, - decltype(absl::visit(Visitor{}, absl::move(v)))>::value)); -} - -TEST(VariantTest, VisitVariadic) { - using A = variant<int, std::string>; - using B = variant<std::unique_ptr<int>, absl::string_view>; - - struct Visitor { - std::pair<int, int> operator()(int a, std::unique_ptr<int> b) const { - return {a, *b}; - } - std::pair<int, int> operator()(absl::string_view a, - std::unique_ptr<int> b) const { - return {static_cast<int>(a.size()), static_cast<int>(*b)}; - } - std::pair<int, int> operator()(int a, absl::string_view b) const { - return {a, static_cast<int>(b.size())}; - } - std::pair<int, int> operator()(absl::string_view a, - absl::string_view b) const { - return {static_cast<int>(a.size()), static_cast<int>(b.size())}; - } - }; - - EXPECT_THAT(absl::visit(Visitor(), A(1), B(std::unique_ptr<int>(new int(7)))), - ::testing::Pair(1, 7)); - EXPECT_THAT(absl::visit(Visitor(), A(1), B(absl::string_view("ABC"))), - ::testing::Pair(1, 3)); - EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")), - B(std::unique_ptr<int>(new int(7)))), - ::testing::Pair(5, 7)); - EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")), - B(absl::string_view("ABC"))), - ::testing::Pair(5, 3)); -} - -TEST(VariantTest, VisitNoArgs) { - EXPECT_EQ(5, absl::visit([] { return 5; })); -} - -struct ConstFunctor { - int operator()(int a, int b) const { return a - b; } -}; - -struct MutableFunctor { - int operator()(int a, int b) { return a - b; } -}; - -struct Class { - int Method(int a, int b) { return a - b; } - int ConstMethod(int a, int b) const { return a - b; } - - int member; -}; - -TEST(VariantTest, VisitReferenceWrapper) { - ConstFunctor cf; - MutableFunctor mf; - absl::variant<int> three = 3; - absl::variant<int> two = 2; - - EXPECT_EQ(1, absl::visit(std::cref(cf), three, two)); - EXPECT_EQ(1, absl::visit(std::ref(cf), three, two)); - EXPECT_EQ(1, absl::visit(std::ref(mf), three, two)); -} - -// libstdc++ std::variant doesn't support the INVOKE semantics. -#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__)) -TEST(VariantTest, VisitMemberFunction) { - absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>()); - absl::variant<std::unique_ptr<const Class>> cp( - absl::make_unique<const Class>()); - absl::variant<int> three = 3; - absl::variant<int> two = 2; - - EXPECT_EQ(1, absl::visit(&Class::Method, p, three, two)); - EXPECT_EQ(1, absl::visit(&Class::ConstMethod, p, three, two)); - EXPECT_EQ(1, absl::visit(&Class::ConstMethod, cp, three, two)); -} - -TEST(VariantTest, VisitDataMember) { - absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>(Class{42})); - absl::variant<std::unique_ptr<const Class>> cp( - absl::make_unique<const Class>(Class{42})); - EXPECT_EQ(42, absl::visit(&Class::member, p)); - - absl::visit(&Class::member, p) = 5; - EXPECT_EQ(5, absl::visit(&Class::member, p)); - - EXPECT_EQ(42, absl::visit(&Class::member, cp)); -} -#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__)) - -///////////////////////// -// [variant.monostate] // -///////////////////////// - -TEST(VariantTest, MonostateBasic) { - absl::monostate mono; - (void)mono; - - // TODO(mattcalabrese) Expose move triviality metafunctions in absl. - EXPECT_TRUE(absl::is_trivially_default_constructible<absl::monostate>::value); - EXPECT_TRUE(is_trivially_move_constructible<absl::monostate>::value); - EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::monostate>::value); - EXPECT_TRUE(is_trivially_move_assignable<absl::monostate>::value); - EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::monostate>::value); - EXPECT_TRUE(absl::is_trivially_destructible<absl::monostate>::value); -} - -TEST(VariantTest, VariantMonostateDefaultConstruction) { - absl::variant<absl::monostate, NonDefaultConstructible> var; - EXPECT_EQ(var.index(), 0); -} - -//////////////////////////////// -// [variant.monostate.relops] // -//////////////////////////////// - -TEST(VariantTest, MonostateComparisons) { - absl::monostate lhs, rhs; - - EXPECT_EQ(lhs, lhs); - EXPECT_EQ(lhs, rhs); - - EXPECT_FALSE(lhs != lhs); - EXPECT_FALSE(lhs != rhs); - EXPECT_FALSE(lhs < lhs); - EXPECT_FALSE(lhs < rhs); - EXPECT_FALSE(lhs > lhs); - EXPECT_FALSE(lhs > rhs); - - EXPECT_LE(lhs, lhs); - EXPECT_LE(lhs, rhs); - EXPECT_GE(lhs, lhs); - EXPECT_GE(lhs, rhs); - - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() == - std::declval<absl::monostate>())); - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() != - std::declval<absl::monostate>())); - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() < - std::declval<absl::monostate>())); - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() > - std::declval<absl::monostate>())); - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <= - std::declval<absl::monostate>())); - EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >= - std::declval<absl::monostate>())); -} - -/////////////////////// -// [variant.specalg] // -/////////////////////// - -TEST(VariantTest, NonmemberSwap) { - using std::swap; - - SpecialSwap v1(3); - SpecialSwap v2(7); - - variant<SpecialSwap> a = v1, b = v2; - - EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); - EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); - - std::swap(a, b); - EXPECT_THAT(a, VariantWith<SpecialSwap>(v2)); - EXPECT_THAT(b, VariantWith<SpecialSwap>(v1)); -#ifndef ABSL_USES_STD_VARIANT - EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap); -#endif - - swap(a, b); - EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); - EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); - EXPECT_TRUE(absl::get<SpecialSwap>(b).special_swap); -} - -////////////////////////// -// [variant.bad.access] // -////////////////////////// - -TEST(VariantTest, BadAccess) { - EXPECT_TRUE(noexcept(absl::bad_variant_access())); - absl::bad_variant_access exception_obj; - std::exception* base = &exception_obj; - (void)base; -} - -//////////////////// -// [variant.hash] // -//////////////////// - -TEST(VariantTest, MonostateHash) { - absl::monostate mono, other_mono; - std::hash<absl::monostate> const hasher{}; - static_assert(std::is_same<decltype(hasher(mono)), std::size_t>::value, ""); - EXPECT_EQ(hasher(mono), hasher(other_mono)); -} - -TEST(VariantTest, Hash) { - static_assert(type_traits_internal::IsHashable<variant<int>>::value, ""); - static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, ""); - static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value, - ""); - -#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ - static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value, - ""); - static_assert( - !type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value, - ""); -#endif - -// MSVC std::hash<std::variant> does not use the index, thus produce the same -// result on the same value as different alternative. -#if !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT)) - { - // same value as different alternative - variant<int, int> v0(in_place_index<0>, 42); - variant<int, int> v1(in_place_index<1>, 42); - std::hash<variant<int, int>> hash; - EXPECT_NE(hash(v0), hash(v1)); - } -#endif // !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT)) - - { - std::hash<variant<int>> hash; - std::set<size_t> hashcodes; - for (int i = 0; i < 100; ++i) { - hashcodes.insert(hash(i)); - } - EXPECT_GT(hashcodes.size(), 90); - - // test const-qualified - static_assert(type_traits_internal::IsHashable<variant<const int>>::value, - ""); - static_assert( - type_traits_internal::IsHashable<variant<const Hashable>>::value, ""); - std::hash<absl::variant<const int>> c_hash; - for (int i = 0; i < 100; ++i) { - EXPECT_EQ(hash(i), c_hash(i)); - } - } -} - -//////////////////////////////////////// -// Miscellaneous and deprecated tests // -//////////////////////////////////////// - -// Test that a set requiring a basic type conversion works correctly -#if !defined(ABSL_USES_STD_VARIANT) -TEST(VariantTest, TestConvertingSet) { - typedef variant<double> Variant; - Variant v(1.0); - const int two = 2; - v = two; - EXPECT_TRUE(absl::holds_alternative<double>(v)); - ASSERT_TRUE(nullptr != absl::get_if<double>(&v)); - EXPECT_DOUBLE_EQ(2, absl::get<double>(v)); -} -#endif // ABSL_USES_STD_VARIANT - -// Test that a vector of variants behaves reasonably. -TEST(VariantTest, Container) { - typedef variant<int, float> Variant; - - // Creation of vector should work - std::vector<Variant> vec; - vec.push_back(Variant(10)); - vec.push_back(Variant(20.0f)); - - // Vector resizing should work if we supply a value for new slots - vec.resize(10, Variant(0)); -} - -// Test that a variant with a non-copyable type can be constructed and -// manipulated to some degree. -TEST(VariantTest, TestVariantWithNonCopyableType) { - typedef variant<int, NonCopyable> Variant; - const int kValue = 1; - Variant v(kValue); - ASSERT_TRUE(absl::holds_alternative<int>(v)); - EXPECT_EQ(kValue, absl::get<int>(v)); -} - -// Test that a variant with a non-copyable type can be transformed to -// the non-copyable type with a call to `emplace` for different numbers -// of arguments. We do not need to test this for each of T1 ... T8 -// because `emplace` does not overload on T1 ... to T8, so if this -// works for any one of T1 ... T8, then it works for all of them. We -// do need to test that it works with varying numbers of parameters -// though. -TEST(VariantTest, TestEmplace) { - typedef variant<int, NonCopyable> Variant; - const int kValue = 1; - Variant v(kValue); - ASSERT_TRUE(absl::holds_alternative<int>(v)); - EXPECT_EQ(kValue, absl::get<int>(v)); - - // emplace with zero arguments, then back to 'int' - v.emplace<NonCopyable>(); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(0, absl::get<NonCopyable>(v).value); - v = kValue; - ASSERT_TRUE(absl::holds_alternative<int>(v)); - - // emplace with one argument: - v.emplace<NonCopyable>(1); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(1, absl::get<NonCopyable>(v).value); - v = kValue; - ASSERT_TRUE(absl::holds_alternative<int>(v)); - - // emplace with two arguments: - v.emplace<NonCopyable>(1, 2); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(3, absl::get<NonCopyable>(v).value); - v = kValue; - ASSERT_TRUE(absl::holds_alternative<int>(v)); - - // emplace with three arguments - v.emplace<NonCopyable>(1, 2, 3); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(6, absl::get<NonCopyable>(v).value); - v = kValue; - ASSERT_TRUE(absl::holds_alternative<int>(v)); - - // emplace with four arguments - v.emplace<NonCopyable>(1, 2, 3, 4); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(10, absl::get<NonCopyable>(v).value); - v = kValue; - ASSERT_TRUE(absl::holds_alternative<int>(v)); -} - -TEST(VariantTest, TestEmplaceDestroysCurrentValue) { - typedef variant<int, IncrementInDtor, NonCopyable> Variant; - int counter = 0; - Variant v(0); - ASSERT_TRUE(absl::holds_alternative<int>(v)); - v.emplace<IncrementInDtor>(&counter); - ASSERT_TRUE(absl::holds_alternative<IncrementInDtor>(v)); - ASSERT_EQ(0, counter); - v.emplace<NonCopyable>(); - ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); - EXPECT_EQ(1, counter); -} - -TEST(VariantTest, TestMoveSemantics) { - typedef variant<std::unique_ptr<int>, std::unique_ptr<std::string>> Variant; - - // Construct a variant by moving from an element value. - Variant v(absl::WrapUnique(new int(10))); - EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v)); - - // Construct a variant by moving from another variant. - Variant v2(absl::move(v)); - ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v2)); - ASSERT_NE(nullptr, absl::get<std::unique_ptr<int>>(v2)); - EXPECT_EQ(10, *absl::get<std::unique_ptr<int>>(v2)); - - // Moving from a variant object leaves it holding moved-from value of the - // same element type. - EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v)); - ASSERT_NE(nullptr, absl::get_if<std::unique_ptr<int>>(&v)); - EXPECT_EQ(nullptr, absl::get<std::unique_ptr<int>>(v)); - - // Assign a variant from an element value by move. - v = absl::make_unique<std::string>("foo"); - ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v)); - EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v)); - - // Move-assign a variant. - v2 = absl::move(v); - ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v2)); - EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v2)); - EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v)); -} - -variant<int, std::string> PassThrough(const variant<int, std::string>& arg) { - return arg; -} - -TEST(VariantTest, TestImplicitConversion) { - EXPECT_TRUE(absl::holds_alternative<int>(PassThrough(0))); - - // We still need the explicit cast for std::string, because C++ won't apply - // two user-defined implicit conversions in a row. - EXPECT_TRUE( - absl::holds_alternative<std::string>(PassThrough(std::string("foo")))); -} - -struct Convertible2; -struct Convertible1 { - Convertible1() {} - Convertible1(const Convertible1&) {} - Convertible1& operator=(const Convertible1&) { return *this; } - - // implicit conversion from Convertible2 - Convertible1(const Convertible2&) {} // NOLINT(runtime/explicit) -}; - -struct Convertible2 { - Convertible2() {} - Convertible2(const Convertible2&) {} - Convertible2& operator=(const Convertible2&) { return *this; } - - // implicit conversion from Convertible1 - Convertible2(const Convertible1&) {} // NOLINT(runtime/explicit) -}; - -TEST(VariantTest, TestRvalueConversion) { -#if !defined(ABSL_USES_STD_VARIANT) - variant<double, std::string> var( - ConvertVariantTo<variant<double, std::string>>( - variant<std::string, int>(0))); - ASSERT_TRUE(absl::holds_alternative<double>(var)); - EXPECT_EQ(0.0, absl::get<double>(var)); - - var = ConvertVariantTo<variant<double, std::string>>( - variant<const char*, float>("foo")); - ASSERT_TRUE(absl::holds_alternative<std::string>(var)); - EXPECT_EQ("foo", absl::get<std::string>(var)); - - variant<double> singleton( - ConvertVariantTo<variant<double>>(variant<int, float>(42))); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_EQ(42.0, absl::get<double>(singleton)); - - singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f)); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); - - singleton = ConvertVariantTo<variant<double>>(variant<int>(0)); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_EQ(0.0, absl::get<double>(singleton)); - - variant<int32_t, uint32_t> variant2( - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); - ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); - EXPECT_EQ(42, absl::get<int32_t>(variant2)); - - variant2 = - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); - ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); - EXPECT_EQ(42, absl::get<uint32_t>(variant2)); -#endif // !ABSL_USES_STD_VARIANT - - variant<Convertible1, Convertible2> variant3( - ConvertVariantTo<variant<Convertible1, Convertible2>>( - (variant<Convertible2, Convertible1>(Convertible1())))); - ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); - - variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>( - variant<Convertible2, Convertible1>(Convertible2())); - ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); -} - -TEST(VariantTest, TestLvalueConversion) { -#if !defined(ABSL_USES_STD_VARIANT) - variant<std::string, int> source1 = 0; - variant<double, std::string> destination( - ConvertVariantTo<variant<double, std::string>>(source1)); - ASSERT_TRUE(absl::holds_alternative<double>(destination)); - EXPECT_EQ(0.0, absl::get<double>(destination)); - - variant<const char*, float> source2 = "foo"; - destination = ConvertVariantTo<variant<double, std::string>>(source2); - ASSERT_TRUE(absl::holds_alternative<std::string>(destination)); - EXPECT_EQ("foo", absl::get<std::string>(destination)); - - variant<int, float> source3(42); - variant<double> singleton(ConvertVariantTo<variant<double>>(source3)); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_EQ(42.0, absl::get<double>(singleton)); - - source3 = 3.14f; - singleton = ConvertVariantTo<variant<double>>(source3); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); - - variant<int> source4(0); - singleton = ConvertVariantTo<variant<double>>(source4); - ASSERT_TRUE(absl::holds_alternative<double>(singleton)); - EXPECT_EQ(0.0, absl::get<double>(singleton)); - - variant<int32_t> source5(42); - variant<int32_t, uint32_t> variant2( - ConvertVariantTo<variant<int32_t, uint32_t>>(source5)); - ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); - EXPECT_EQ(42, absl::get<int32_t>(variant2)); - - variant<uint32_t> source6(42); - variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); - ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); - EXPECT_EQ(42, absl::get<uint32_t>(variant2)); -#endif - - variant<Convertible2, Convertible1> source7((Convertible1())); - variant<Convertible1, Convertible2> variant3( - ConvertVariantTo<variant<Convertible1, Convertible2>>(source7)); - ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); - - source7 = Convertible2(); - variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7); - ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); -} - -TEST(VariantTest, TestMoveConversion) { - using Variant = - variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; - using OtherVariant = - variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; - - Variant var( - ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)})); - ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const int>>(var)); - ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr); - EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var)); - - var = ConvertVariantTo<Variant>( - OtherVariant(absl::make_unique<std::string>("foo"))); - ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var)); - EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var)); -} - -TEST(VariantTest, DoesNotMoveFromLvalues) { - // We use shared_ptr here because it's both copyable and movable, and - // a moved-from shared_ptr is guaranteed to be null, so we can detect - // whether moving or copying has occurred. - using Variant = - variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>; - using OtherVariant = - variant<std::shared_ptr<int>, std::shared_ptr<std::string>>; - - Variant v1(std::make_shared<const int>(0)); - - // Test copy constructor - Variant v2(v1); - EXPECT_EQ(absl::get<std::shared_ptr<const int>>(v1), - absl::get<std::shared_ptr<const int>>(v2)); - - // Test copy-assignment operator - v1 = std::make_shared<const std::string>("foo"); - v2 = v1; - EXPECT_EQ(absl::get<std::shared_ptr<const std::string>>(v1), - absl::get<std::shared_ptr<const std::string>>(v2)); - - // Test converting copy constructor - OtherVariant other(std::make_shared<int>(0)); - Variant v3(ConvertVariantTo<Variant>(other)); - EXPECT_EQ(absl::get<std::shared_ptr<int>>(other), - absl::get<std::shared_ptr<const int>>(v3)); - - other = std::make_shared<std::string>("foo"); - v3 = ConvertVariantTo<Variant>(other); - EXPECT_EQ(absl::get<std::shared_ptr<std::string>>(other), - absl::get<std::shared_ptr<const std::string>>(v3)); -} - -TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { -#if !defined(ABSL_USES_STD_VARIANT) - variant<double, std::string> var( - ConvertVariantTo<variant<double, std::string>>( - variant<std::string, int>(3))); - EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0)); - - var = ConvertVariantTo<variant<double, std::string>>( - variant<const char*, float>("foo")); - EXPECT_THAT(absl::get_if<std::string>(&var), Pointee(std::string("foo"))); - - variant<double> singleton( - ConvertVariantTo<variant<double>>(variant<int, float>(42))); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0)); - - singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f)); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f))); - - singleton = ConvertVariantTo<variant<double>>(variant<int>(3)); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0)); - - variant<int32_t, uint32_t> variant2( - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); - EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); - - variant2 = - ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); - EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); -#endif - - variant<Convertible1, Convertible2> variant3( - ConvertVariantTo<variant<Convertible1, Convertible2>>( - (variant<Convertible2, Convertible1>(Convertible1())))); - ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); - - variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>( - variant<Convertible2, Convertible1>(Convertible2())); - ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); -} - -TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) { -#if !defined(ABSL_USES_STD_VARIANT) - variant<std::string, int> source1 = 3; - variant<double, std::string> destination( - ConvertVariantTo<variant<double, std::string>>(source1)); - EXPECT_THAT(absl::get_if<double>(&destination), Pointee(3.0)); - - variant<const char*, float> source2 = "foo"; - destination = ConvertVariantTo<variant<double, std::string>>(source2); - EXPECT_THAT(absl::get_if<std::string>(&destination), - Pointee(std::string("foo"))); - - variant<int, float> source3(42); - variant<double> singleton(ConvertVariantTo<variant<double>>(source3)); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0)); - - source3 = 3.14f; - singleton = ConvertVariantTo<variant<double>>(source3); - EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f))); - - variant<int> source4(3); - singleton = ConvertVariantTo<variant<double>>(source4); - EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0)); - - variant<int32_t> source5(42); - variant<int32_t, uint32_t> variant2( - ConvertVariantTo<variant<int32_t, uint32_t>>(source5)); - EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); - - variant<uint32_t> source6(42); - variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); - EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); -#endif // !ABSL_USES_STD_VARIANT - - variant<Convertible2, Convertible1> source7((Convertible1())); - variant<Convertible1, Convertible2> variant3( - ConvertVariantTo<variant<Convertible1, Convertible2>>(source7)); - ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); - - source7 = Convertible2(); - variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7); - ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); -} - -TEST(VariantTest, TestMoveConversionViaConvertVariantTo) { - using Variant = - variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; - using OtherVariant = - variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; - - Variant var( - ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)})); - EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var), - Pointee(Pointee(3))); - - var = ConvertVariantTo<Variant>( - OtherVariant(absl::make_unique<std::string>("foo"))); - EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var), - Pointee(Pointee(std::string("foo")))); -} - -// If all alternatives are trivially copy/move constructible, variant should -// also be trivially copy/move constructible. This is not required by the -// standard and we know that libstdc++ variant doesn't have this feature. -// For more details see the paper: -// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html -#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__)) -#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1 -#endif - -TEST(VariantTest, TestCopyAndMoveTypeTraits) { - EXPECT_TRUE(std::is_copy_constructible<variant<std::string>>::value); - EXPECT_TRUE(absl::is_copy_assignable<variant<std::string>>::value); - EXPECT_TRUE(std::is_move_constructible<variant<std::string>>::value); - EXPECT_TRUE(absl::is_move_assignable<variant<std::string>>::value); - EXPECT_TRUE(std::is_move_constructible<variant<std::unique_ptr<int>>>::value); - EXPECT_TRUE(absl::is_move_assignable<variant<std::unique_ptr<int>>>::value); - EXPECT_FALSE( - std::is_copy_constructible<variant<std::unique_ptr<int>>>::value); - EXPECT_FALSE(absl::is_copy_assignable<variant<std::unique_ptr<int>>>::value); - - EXPECT_FALSE( - absl::is_trivially_copy_constructible<variant<std::string>>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<variant<std::string>>::value); -#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY - EXPECT_TRUE(absl::is_trivially_copy_constructible<variant<int>>::value); - EXPECT_TRUE(absl::is_trivially_copy_assignable<variant<int>>::value); - EXPECT_TRUE(is_trivially_move_constructible<variant<int>>::value); - EXPECT_TRUE(is_trivially_move_assignable<variant<int>>::value); -#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY -} - -TEST(VariantTest, TestVectorOfMoveonlyVariant) { - // Verify that variant<MoveonlyType> works correctly as a std::vector element. - std::vector<variant<std::unique_ptr<int>, std::string>> vec; - vec.push_back(absl::make_unique<int>(42)); - vec.emplace_back("Hello"); - vec.reserve(3); - auto another_vec = absl::move(vec); - // As a sanity check, verify vector contents. - ASSERT_EQ(2, another_vec.size()); - EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0])); - EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1])); -} - -TEST(VariantTest, NestedVariant) { -#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY - static_assert(absl::is_trivially_copy_constructible<variant<int>>(), ""); - static_assert(absl::is_trivially_copy_assignable<variant<int>>(), ""); - static_assert(is_trivially_move_constructible<variant<int>>(), ""); - static_assert(is_trivially_move_assignable<variant<int>>(), ""); - - static_assert(absl::is_trivially_copy_constructible<variant<variant<int>>>(), - ""); - static_assert(absl::is_trivially_copy_assignable<variant<variant<int>>>(), - ""); - static_assert(is_trivially_move_constructible<variant<variant<int>>>(), ""); - static_assert(is_trivially_move_assignable<variant<variant<int>>>(), ""); -#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY - - variant<int> x(42); - variant<variant<int>> y(x); - variant<variant<int>> z(y); - EXPECT_TRUE(absl::holds_alternative<variant<int>>(z)); - EXPECT_EQ(x, absl::get<variant<int>>(z)); -} - -struct TriviallyDestructible { - TriviallyDestructible(TriviallyDestructible&&) {} - TriviallyDestructible(const TriviallyDestructible&) {} - TriviallyDestructible& operator=(TriviallyDestructible&&) { return *this; } - TriviallyDestructible& operator=(const TriviallyDestructible&) { - return *this; - } -}; - -struct TriviallyMovable { - TriviallyMovable(TriviallyMovable&&) = default; - TriviallyMovable(TriviallyMovable const&) {} - TriviallyMovable& operator=(const TriviallyMovable&) { return *this; } -}; - -struct TriviallyCopyable { - TriviallyCopyable(const TriviallyCopyable&) = default; - TriviallyCopyable& operator=(const TriviallyCopyable&) { return *this; } -}; - -struct TriviallyMoveAssignable { - TriviallyMoveAssignable(TriviallyMoveAssignable&&) = default; - TriviallyMoveAssignable(const TriviallyMoveAssignable&) {} - TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default; - TriviallyMoveAssignable& operator=(const TriviallyMoveAssignable&) { - return *this; - } -}; - -struct TriviallyCopyAssignable {}; - -#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY -TEST(VariantTest, TestTriviality) { - { - using TrivDestVar = absl::variant<TriviallyDestructible>; - - EXPECT_FALSE(is_trivially_move_constructible<TrivDestVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivDestVar>::value); - EXPECT_FALSE(is_trivially_move_assignable<TrivDestVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivDestVar>::value); - EXPECT_TRUE(absl::is_trivially_destructible<TrivDestVar>::value); - } - - { - using TrivMoveVar = absl::variant<TriviallyMovable>; - - EXPECT_TRUE(is_trivially_move_constructible<TrivMoveVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivMoveVar>::value); - EXPECT_FALSE(is_trivially_move_assignable<TrivMoveVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveVar>::value); - EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveVar>::value); - } - - { - using TrivCopyVar = absl::variant<TriviallyCopyable>; - - EXPECT_TRUE(is_trivially_move_constructible<TrivCopyVar>::value); - EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivCopyVar>::value); - EXPECT_FALSE(is_trivially_move_assignable<TrivCopyVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivCopyVar>::value); - EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyVar>::value); - } - - { - using TrivMoveAssignVar = absl::variant<TriviallyMoveAssignable>; - - EXPECT_TRUE(is_trivially_move_constructible<TrivMoveAssignVar>::value); - EXPECT_FALSE( - absl::is_trivially_copy_constructible<TrivMoveAssignVar>::value); - EXPECT_TRUE(is_trivially_move_assignable<TrivMoveAssignVar>::value); - EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveAssignVar>::value); - EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveAssignVar>::value); - } - - { - using TrivCopyAssignVar = absl::variant<TriviallyCopyAssignable>; - - EXPECT_TRUE(is_trivially_move_constructible<TrivCopyAssignVar>::value); - EXPECT_TRUE( - absl::is_trivially_copy_constructible<TrivCopyAssignVar>::value); - EXPECT_TRUE(is_trivially_move_assignable<TrivCopyAssignVar>::value); - EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivCopyAssignVar>::value); - EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyAssignVar>::value); - } -} -#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY - -// To verify that absl::variant correctly use the nontrivial move ctor of its -// member rather than use the trivial copy constructor. -TEST(VariantTest, MoveCtorBug) { - // To simulate std::tuple in libstdc++. - struct TrivialCopyNontrivialMove { - TrivialCopyNontrivialMove() = default; - TrivialCopyNontrivialMove(const TrivialCopyNontrivialMove&) = default; - TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) { called = true; } - bool called = false; - }; - { - using V = absl::variant<TrivialCopyNontrivialMove, int>; - V v1(absl::in_place_index<0>); - // this should invoke the move ctor, rather than the trivial copy ctor. - V v2(std::move(v1)); - EXPECT_TRUE(absl::get<0>(v2).called); - } - { - // this case failed to compile before our fix due to a GCC bug. - using V = absl::variant<int, TrivialCopyNontrivialMove>; - V v1(absl::in_place_index<1>); - // this should invoke the move ctor, rather than the trivial copy ctor. - V v2(std::move(v1)); - EXPECT_TRUE(absl::get<1>(v2).called); - } -} - -} // namespace -ABSL_NAMESPACE_END -} // namespace absl - -#endif // #if !defined(ABSL_USES_STD_VARIANT) |