diff options
author | Vincent Ambo <tazjin@google.com> | 2020-05-20T01·32+0100 |
---|---|---|
committer | Vincent Ambo <tazjin@google.com> | 2020-05-20T01·32+0100 |
commit | fc8dc48020ac5b52731d0828a96ea4d2526c77ba (patch) | |
tree | 353204eea3268095a9ad3f5345720f32c2615c69 /third_party/abseil_cpp/absl/types/variant_test.cc | |
parent | ffb2ae54beb5796cd408fbe15d2d2da09ff37adf (diff) | |
parent | 768eb2ca2857342673fcd462792ce04b8bac3fa3 (diff) |
Add 'third_party/abseil_cpp/' from commit '768eb2ca2857342673fcd462792ce04b8bac3fa3' r/781
git-subtree-dir: third_party/abseil_cpp git-subtree-mainline: ffb2ae54beb5796cd408fbe15d2d2da09ff37adf git-subtree-split: 768eb2ca2857342673fcd462792ce04b8bac3fa3
Diffstat (limited to 'third_party/abseil_cpp/absl/types/variant_test.cc')
-rw-r--r-- | third_party/abseil_cpp/absl/types/variant_test.cc | 2716 |
1 files changed, 2716 insertions, 0 deletions
diff --git a/third_party/abseil_cpp/absl/types/variant_test.cc b/third_party/abseil_cpp/absl/types/variant_test.cc new file mode 100644 index 000000000000..cf8f7f337403 --- /dev/null +++ b/third_party/abseil_cpp/absl/types/variant_test.cc @@ -0,0 +1,2716 @@ +// 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) |