text: // -*- 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);
    }
  }
  