summaryrefslogtreecommitdiffstats
path: root/src/test/test_any.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/test_any.cc')
-rw-r--r--src/test/test_any.cc812
1 files changed, 812 insertions, 0 deletions
diff --git a/src/test/test_any.cc b/src/test/test_any.cc
new file mode 100644
index 000000000..82d4a43f1
--- /dev/null
+++ b/src/test/test_any.cc
@@ -0,0 +1,812 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2018 Adam C. Emerson <aemerson@redhat.com>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License version 2, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include <initializer_list>
+#include <optional>
+
+#include "gtest/gtest.h"
+
+#include "include/any.h"
+
+using std::optional;
+using std::bad_any_cast;
+
+using ceph::immobile_any;
+using ceph::unique_any;
+using ceph::shared_any;
+
+using ceph::make_immobile_any;
+using ceph::make_unique_any;
+using ceph::make_shared_any;
+
+using ceph::any_cast;
+using std::swap;
+
+template<typename A>
+static void test_empty() {
+ A a;
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+ a.reset();
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+
+}
+
+TEST(Empty, Immobile) {
+ static_assert(std::is_nothrow_default_constructible_v<immobile_any<1024>>);
+ test_empty<immobile_any<1024>>();
+}
+
+TEST(Empty, Unique) {
+ static_assert(std::is_nothrow_default_constructible_v<unique_any>);
+ test_empty<unique_any>();
+}
+
+TEST(Empty, Shared) {
+ static_assert(std::is_nothrow_default_constructible_v<shared_any>);
+ test_empty<shared_any>();
+}
+
+struct cmd_tattler {
+ static thread_local bool copied;
+ static thread_local bool moved;
+ static thread_local bool destructed;
+
+ static void reset() {
+ copied = false;
+ moved = false;
+ destructed = false;
+ }
+
+ cmd_tattler() noexcept = default;
+ ~cmd_tattler() noexcept {
+ if (destructed) {
+ std::terminate();
+ }
+ destructed = true;
+ }
+ cmd_tattler(const cmd_tattler&) noexcept {
+ if (copied) {
+ std::terminate();
+ }
+ copied = true;
+ }
+ cmd_tattler& operator =(const cmd_tattler&) noexcept {
+ if (copied) {
+ std::terminate();
+ }
+ copied = true;
+ return *this;
+ }
+
+ cmd_tattler(cmd_tattler&&) noexcept {
+ if (moved) {
+ std::terminate();
+ }
+ moved = true;
+ }
+ cmd_tattler& operator =(cmd_tattler&&) noexcept {
+ if (moved) {
+ std::terminate();
+ }
+ moved = true;
+ return *this;
+ }
+};
+
+thread_local bool cmd_tattler::copied = false;
+thread_local bool cmd_tattler::moved = false;
+thread_local bool cmd_tattler::destructed = false;
+
+struct not_noexcept {
+ not_noexcept() = default;
+
+ not_noexcept(const not_noexcept&) noexcept(false) {
+ }
+ not_noexcept& operator =(const not_noexcept&) noexcept(false) {
+ return *this;
+ }
+
+ not_noexcept(not_noexcept&&) noexcept(false) {
+ }
+ not_noexcept& operator =(not_noexcept&&) noexcept(false) {
+ return *this;
+ }
+
+ template<typename ...Args>
+ explicit not_noexcept(Args&& ...) noexcept(false) {
+ }
+
+ template<typename U, typename ...Args>
+ not_noexcept(std::initializer_list<U>, Args&& ...) noexcept(false) {
+ }
+};
+
+template<typename A>
+static void test_value_CMD() {
+ {
+ cmd_tattler::reset();
+ cmd_tattler c;
+ A a(c);
+ EXPECT_TRUE(cmd_tattler::copied);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+
+ cmd_tattler::reset();
+ a = c;
+ EXPECT_TRUE(cmd_tattler::copied);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+
+ cmd_tattler::reset();
+ a = c;
+ EXPECT_TRUE(cmd_tattler::copied);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+ cmd_tattler::reset();
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ cmd_tattler::reset();
+ }
+ {
+ cmd_tattler::reset();
+ cmd_tattler c;
+ A a(std::move(c));
+ EXPECT_TRUE(cmd_tattler::moved);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+
+ cmd_tattler::reset();
+ a = std::move(c);
+ EXPECT_TRUE(cmd_tattler::moved);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+
+ cmd_tattler::reset();
+ a = std::move(c);
+ EXPECT_TRUE(cmd_tattler::moved);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+ cmd_tattler::reset();
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ cmd_tattler::reset();
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+ EXPECT_TRUE(cmd_tattler::moved);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+
+ cmd_tattler::reset();
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+
+ cmd_tattler::reset();
+ a = cmd_tattler{};
+ EXPECT_TRUE(cmd_tattler::moved);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(cmd_tattler), a.type());
+ cmd_tattler::reset();
+ a.reset();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ cmd_tattler::reset();
+ }
+}
+
+
+
+TEST(Value_CMD, Immobile) {
+ static_assert(std::is_nothrow_constructible_v<
+ immobile_any<1024>, const cmd_tattler&>);
+ static_assert(std::is_nothrow_assignable_v<
+ immobile_any<1024>, const cmd_tattler&>);
+ static_assert(std::is_nothrow_constructible_v<
+ immobile_any<1024>, cmd_tattler&&>);
+ static_assert(std::is_nothrow_assignable_v<
+ immobile_any<1024>, cmd_tattler&&>);
+
+ static_assert(!std::is_nothrow_constructible_v<
+ immobile_any<1024>, const not_noexcept&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ immobile_any<1024>, const not_noexcept&>);
+ static_assert(!std::is_nothrow_constructible_v<
+ immobile_any<1024>, not_noexcept&&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ immobile_any<1024>, not_noexcept&&>);
+
+ test_value_CMD<immobile_any<1024>>();
+}
+
+TEST(Value_CMD, Unique) {
+ static_assert(!std::is_nothrow_constructible_v<
+ unique_any, const cmd_tattler&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ unique_any, const cmd_tattler&>);
+ static_assert(!std::is_nothrow_constructible_v<
+ unique_any, cmd_tattler&&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ unique_any, cmd_tattler&&>);
+
+ static_assert(!std::is_nothrow_constructible_v<
+ unique_any, const not_noexcept&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ unique_any, const not_noexcept&>);
+ static_assert(!std::is_nothrow_constructible_v<
+ unique_any, not_noexcept&&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ unique_any, not_noexcept&&>);
+
+ test_value_CMD<unique_any>();
+}
+
+TEST(Value_CMD, Shared) {
+ static_assert(!std::is_nothrow_constructible_v<
+ shared_any, const cmd_tattler&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ shared_any, const cmd_tattler&>);
+ static_assert(!std::is_nothrow_constructible_v<
+ shared_any, cmd_tattler&&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ shared_any, cmd_tattler&&>);
+
+ static_assert(!std::is_nothrow_constructible_v<
+ shared_any, const not_noexcept&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ shared_any, const not_noexcept&>);
+ static_assert(!std::is_nothrow_constructible_v<
+ shared_any, not_noexcept&&>);
+ static_assert(!std::is_nothrow_assignable_v<
+ shared_any, not_noexcept&&>);
+
+ test_value_CMD<shared_any>();
+}
+
+template<typename A>
+static void test_move() {
+ {
+ A a(5);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+
+ A b(std::move(a));
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+
+ EXPECT_FALSE(a.has_value());
+ EXPECT_EQ(typeid(void), a.type());
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ A b(5);
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+ cmd_tattler::reset();
+
+ a = std::move(b);
+ EXPECT_TRUE(cmd_tattler::destructed);
+
+ EXPECT_FALSE(b.has_value());
+ EXPECT_EQ(typeid(void), b.type());
+
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+ }
+}
+
+static_assert(!std::is_move_constructible_v<immobile_any<1024>>);
+static_assert(!std::is_move_assignable_v<immobile_any<1024>>);
+
+TEST(Move, Unique) {
+ static_assert(std::is_nothrow_move_constructible_v<unique_any>);
+ static_assert(std::is_nothrow_move_assignable_v<unique_any>);
+
+ test_move<unique_any>();
+}
+
+TEST(Move, Shared) {
+ static_assert(std::is_nothrow_move_constructible_v<shared_any>);
+ static_assert(std::is_nothrow_move_assignable_v<shared_any>);
+
+ test_move<shared_any>();
+}
+
+template<typename A>
+static void test_copy() {
+ {
+ const A a(5);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+
+ A b(a);
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+
+ EXPECT_EQ(any_cast<int>(a), any_cast<int>(b));
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ const A b(5);
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+ cmd_tattler::reset();
+
+ a = b;
+ EXPECT_TRUE(cmd_tattler::destructed);
+
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+
+ EXPECT_EQ(any_cast<int>(a), any_cast<int>(b));
+ }
+}
+
+static_assert(!std::is_copy_constructible_v<immobile_any<1024>>);
+static_assert(!std::is_copy_assignable_v<immobile_any<1024>>);
+
+static_assert(!std::is_copy_constructible_v<unique_any>);
+static_assert(!std::is_copy_assignable_v<unique_any>);
+
+TEST(Copy, Shared) {
+ static_assert(std::is_nothrow_copy_constructible_v<shared_any>);
+ test_copy<shared_any>();
+}
+
+struct unmoving {
+ optional<int> a;
+
+ unmoving() noexcept {}
+
+ template<typename... Args>
+ explicit unmoving(Args&& ...args) noexcept
+ : a(sizeof...(Args)) {}
+
+ template<typename U, typename... Args>
+ explicit unmoving(std::initializer_list<U> l) noexcept
+ : a(-l.size()) {}
+
+ template<typename U, typename... Args>
+ unmoving(std::initializer_list<U> l, Args&& ...args) noexcept
+ : a(-l.size() * sizeof...(Args)) {}
+
+ unmoving(const unmoving&) = delete;
+ unmoving& operator =(const unmoving&) = delete;
+
+ unmoving(unmoving&&) = delete;
+ unmoving& operator =(unmoving&&) = delete;
+};
+
+template<typename A>
+static void test_unmoving_pack_il() {
+ // Nothing!
+ {
+ const A a(std::in_place_type<unmoving>);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_FALSE(any_cast<const unmoving&>(a).a);
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ cmd_tattler::reset();
+ a.template emplace<unmoving>();
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_FALSE(any_cast<unmoving&>(a).a);
+ }
+
+ // Pack!
+ {
+ const A a(std::in_place_type<unmoving>, nullptr, 5, 3.1);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(3, *any_cast<const unmoving&>(a).a);
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ cmd_tattler::reset();
+ a.template emplace<unmoving>(nullptr, 5, 3.1);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_EQ(3, *any_cast<unmoving&>(a).a);
+ }
+
+ // List!
+ {
+ const A a(std::in_place_type<unmoving>, {true, true, true, true});
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-4, *any_cast<const unmoving&>(a).a);
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ cmd_tattler::reset();
+ a.template emplace<unmoving>({true, true, true, true});
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_EQ(-4, *any_cast<unmoving&>(a).a);
+ }
+
+ // List + pack!!
+ {
+ const A a(std::in_place_type<unmoving>, {true, true, true, true},
+ nullptr, 5, 3.1);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-12, *any_cast<const unmoving&>(a).a);
+ }
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+
+ cmd_tattler::reset();
+ a.template emplace<unmoving>({true, true, true, true}, nullptr, 5, 3.1);
+ EXPECT_TRUE(cmd_tattler::destructed);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_EQ(-12, *any_cast<unmoving&>(a).a);
+ }
+}
+
+TEST(UmovingPackIl, Immobile) {
+ static_assert(std::is_nothrow_constructible_v<immobile_any<1024>,
+ std::in_place_type_t<unmoving>>);
+ static_assert(noexcept(immobile_any<1024>{}.emplace<unmoving>()));
+
+ static_assert(std::is_nothrow_constructible_v<immobile_any<1024>,
+ std::in_place_type_t<unmoving>, std::nullptr_t, int, double>);
+ static_assert(noexcept(immobile_any<1024>{}.emplace<unmoving>(
+ nullptr, 5, 3.1)));
+
+ static_assert(std::is_nothrow_constructible_v<immobile_any<1024>,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>>);
+ static_assert(noexcept(immobile_any<1024>{}.emplace<unmoving>(
+ {true, true, true, true})));
+
+ static_assert(std::is_nothrow_constructible_v<immobile_any<1024>,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>,
+ std::nullptr_t, int, double>);
+ static_assert(noexcept(immobile_any<1024>{}.emplace<unmoving>(
+ {true, true, true, true}, nullptr, 5, 3.1)));
+
+ test_unmoving_pack_il<immobile_any<1024>>();
+}
+
+TEST(UmovingPackIl, Unique) {
+ static_assert(!std::is_nothrow_constructible_v<unique_any,
+ std::in_place_type_t<unmoving>>);
+ static_assert(!noexcept(unique_any{}.emplace<unmoving>()));
+
+ static_assert(!std::is_nothrow_constructible_v<unique_any,
+ std::in_place_type_t<unmoving>, std::nullptr_t, int, double>);
+ static_assert(!noexcept(unique_any{}.emplace<unmoving>(
+ nullptr, 5, 3.1)));
+
+ static_assert(!std::is_nothrow_constructible_v<unique_any,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>>);
+ static_assert(!noexcept(unique_any{}.emplace<unmoving>(
+ {true, true, true, true})));
+
+ static_assert(!std::is_nothrow_constructible_v<unique_any,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>,
+ std::nullptr_t, int, double>);
+ static_assert(!noexcept(unique_any{}.emplace<unmoving>(
+ {true, true, true, true}, nullptr, 5, 3.1)));
+
+ test_unmoving_pack_il<unique_any>();
+}
+
+TEST(UmovingPackIl, Shared) {
+ static_assert(!std::is_nothrow_constructible_v<shared_any,
+ std::in_place_type_t<unmoving>>);
+ static_assert(!noexcept(shared_any{}.emplace<unmoving>()));
+
+ static_assert(!std::is_nothrow_constructible_v<shared_any,
+ std::in_place_type_t<unmoving>, std::nullptr_t, int, double>);
+ static_assert(!noexcept(shared_any{}.emplace<unmoving>(
+ nullptr, 5, 3.1)));
+
+ static_assert(!std::is_nothrow_constructible_v<shared_any,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>>);
+ static_assert(!noexcept(shared_any{}.emplace<unmoving>(
+ {true, true, true, true})));
+
+ static_assert(!std::is_nothrow_constructible_v<shared_any,
+ std::in_place_type_t<unmoving>, std::initializer_list<int>,
+ std::nullptr_t, int, double>);
+ static_assert(!noexcept(shared_any{}.emplace<unmoving>(
+ {true, true, true, true}, nullptr, 5, 3.1)));
+
+ test_unmoving_pack_il<shared_any>();
+}
+
+template<typename A>
+static void test_swap() {
+ A a(true);
+ ASSERT_TRUE(a.has_value());
+ ASSERT_EQ(typeid(bool), a.type());
+ ASSERT_EQ(true, any_cast<bool>(a));
+
+ A b(5);
+ ASSERT_TRUE(b.has_value());
+ ASSERT_EQ(typeid(int), b.type());
+ ASSERT_EQ(5, any_cast<int>(b));
+
+ a.swap(b);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(int), a.type());
+ EXPECT_EQ(5, any_cast<int>(a));
+
+ EXPECT_TRUE(b.has_value());
+ ASSERT_EQ(typeid(bool), b.type());
+ ASSERT_EQ(true, any_cast<bool>(b));
+
+ swap(a,b);
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(bool), a.type());
+ EXPECT_EQ(true, any_cast<bool>(a));
+
+ EXPECT_TRUE(b.has_value());
+ EXPECT_EQ(typeid(int), b.type());
+ EXPECT_EQ(5, any_cast<int>(b));
+}
+
+static_assert(!std::is_swappable_v<immobile_any<1024>>);
+
+TEST(Swap, Unique) {
+ static_assert(std::is_nothrow_swappable_v<unique_any>);
+ test_swap<unique_any>();
+}
+
+TEST(Swap, Shared) {
+ static_assert(std::is_nothrow_swappable_v<shared_any>);
+ test_swap<shared_any>();
+}
+
+template<typename A>
+static void test_cast() {
+ // Empty
+ {
+ A a;
+ EXPECT_EQ(nullptr, any_cast<int>(&a));
+ EXPECT_THROW({any_cast<int>(a);}, bad_any_cast);
+ EXPECT_THROW({any_cast<int&>(a);}, bad_any_cast);
+ EXPECT_THROW({any_cast<int>(std::move(a));}, bad_any_cast);
+ EXPECT_THROW({any_cast<int&&>(std::move(a));}, bad_any_cast);
+ }
+
+ // Constant Empty
+ {
+ const A a{};
+ EXPECT_EQ(nullptr, any_cast<int>(const_cast<const A*>(&a)));
+ EXPECT_THROW({any_cast<int>(a);}, bad_any_cast);
+ EXPECT_THROW({any_cast<const int&>(a);}, bad_any_cast);
+ }
+
+ // Filled!
+ {
+ A a(true);
+ EXPECT_TRUE(*any_cast<bool>(&a));
+ EXPECT_EQ(nullptr, any_cast<int>(&a));
+
+ EXPECT_TRUE(any_cast<bool>(a));
+ EXPECT_THROW({any_cast<int>(a);}, bad_any_cast);
+
+ EXPECT_TRUE(any_cast<bool&>(a));
+ EXPECT_THROW({any_cast<int&>(a);}, bad_any_cast);
+
+ EXPECT_TRUE(any_cast<bool>(std::move(a)));
+ EXPECT_THROW({any_cast<int>(std::move(a));}, bad_any_cast);
+
+ EXPECT_TRUE(any_cast<bool&&>(std::move(a)));
+ EXPECT_THROW({any_cast<int&&>(std::move(a));}, bad_any_cast);
+ }
+
+ // Constant filled
+ {
+ const A a(true);
+ EXPECT_TRUE(*any_cast<const bool>(&a));
+ EXPECT_EQ(nullptr, any_cast<const int>(&a));
+
+ EXPECT_TRUE(any_cast<bool>(a));
+ EXPECT_THROW({any_cast<int>(a);}, bad_any_cast);
+
+ EXPECT_TRUE(any_cast<const bool&>(a));
+ EXPECT_THROW({any_cast<const int&>(a);}, bad_any_cast);
+ }
+
+ // Move!
+ {
+ cmd_tattler::reset();
+ A a(cmd_tattler{});
+ cmd_tattler::reset();
+
+ auto q = any_cast<cmd_tattler>(std::move(a));
+ EXPECT_TRUE(cmd_tattler::moved);
+ cmd_tattler::reset();
+ a.reset();
+ cmd_tattler::reset();
+ }
+
+ // Move! Again!
+ {
+ cmd_tattler::reset();
+ auto q = any_cast<cmd_tattler>(A(std::in_place_type<cmd_tattler>));
+ EXPECT_TRUE(cmd_tattler::moved);
+ cmd_tattler::reset();
+ }
+}
+
+TEST(Cast, Immobile) {
+ test_cast<immobile_any<1024>>();
+}
+
+TEST(Cast, Unique) {
+ test_cast<unique_any>();
+}
+
+TEST(Cast, Shared) {
+ test_cast<shared_any>();
+}
+
+TEST(Make, Immobile) {
+ // Nothing!
+ {
+ auto a{make_immobile_any<unmoving, 1024>()};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_FALSE(any_cast<const unmoving&>(a).a);
+ }
+
+ // Pack!
+ {
+ auto a(make_immobile_any<unmoving, 1024>(nullptr, 5, 3.1));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(3, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List!
+ {
+ auto a(make_immobile_any<unmoving, 1024>({true, true, true, true}));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-4, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List + pack!!
+ {
+ auto a{make_immobile_any<unmoving, 1024>({true, true, true, true},
+ nullptr, 5, 3.1)};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-12, *any_cast<const unmoving&>(a).a);
+ }
+}
+
+TEST(Make, Unique) {
+ // Nothing!
+ {
+ auto a{make_unique_any<unmoving>()};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_FALSE(any_cast<const unmoving&>(a).a);
+ }
+
+ // Pack!
+ {
+ auto a(make_unique_any<unmoving>(nullptr, 5, 3.1));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(3, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List!
+ {
+ auto a(make_unique_any<unmoving>({true, true, true, true}));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-4, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List + pack!!
+ {
+ auto a{make_unique_any<unmoving>({true, true, true, true},
+ nullptr, 5, 3.1)};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-12, *any_cast<const unmoving&>(a).a);
+ }
+}
+
+TEST(Make, Shared) {
+ // Nothing!
+ {
+ auto a{make_shared_any<unmoving>()};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_FALSE(any_cast<const unmoving&>(a).a);
+ }
+
+ // Pack!
+ {
+ auto a(make_shared_any<unmoving>(nullptr, 5, 3.1));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(3, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List!
+ {
+ auto a(make_shared_any<unmoving>({true, true, true, true}));
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-4, *any_cast<const unmoving&>(a).a);
+ }
+
+ // List + pack!!
+ {
+ auto a{make_shared_any<unmoving>({true, true, true, true},
+ nullptr, 5, 3.1)};
+ EXPECT_TRUE(a.has_value());
+ EXPECT_EQ(typeid(unmoving), a.type());
+ EXPECT_TRUE(any_cast<const unmoving&>(a).a);
+ EXPECT_EQ(-12, *any_cast<const unmoving&>(a).a);
+ }
+}