#include "tile/base/future/boxed.h"

#include "gtest/gtest.h"

namespace tile {
namespace future {
namespace detail {

TEST(Boxed, Construct)
{
    Boxed<> box1(box_values);
    static_assert(std::is_same<decltype(box1.Get()), void>::value, "");

    static_assert(std::is_void<decltype(std::declval<Boxed<>>().Get())>::value, "");

    Boxed<int> box2(box_values, 1);
    EXPECT_EQ(box2.Get(), 1);

    Boxed<int> box3(box2);
    EXPECT_EQ(box3.Get(), 1);
    EXPECT_EQ(box3.GetRaw(), std::make_tuple(1));

    Boxed<int, char> box4(box_values, 1, 'a');
    EXPECT_EQ(box4.Get(), std::make_tuple(1, 'a'));
}

TEST(Apply, All)
{
    auto f1 = []() { return 1; };
    auto f2 = [](int x) { return x + 1; };
    auto f3 = [](int x, int y) { return x + y; };
    auto t1 = std::make_tuple();
    auto t2 = std::make_tuple(1);
    auto t3 = std::make_tuple(1, 2);

    class ApplyTest {
    public:
        static void Test() {};
        static void Test(int) {};
        static void Test(int, int) {};
        void MTest() {};
        void MTest(int) {};
        void MTest(int, int) {};
    } at;

    // internal::apply(f1, t1);
    // internal::apply(f2, t2);
    // internal::apply(f3, t3);
    // internal::apply(&ApplyTest::Test, t1);
}

template<typename... Ts>
void
Consume(std::function<void(Boxed<Ts...> &&) noexcept> &&action, Boxed<Ts...> &&val)
{
    action(std::move(val));
}

TEST(Boxed, Consume)
{
    Boxed<int> box(box_values, 1);
    std::function<void(Boxed<int> &&) noexcept> l1 = [](Boxed<int> &&) noexcept {};
    auto l2                                        = [](Boxed<int> &&) noexcept {};
    Consume(std::move(l1), std::move(box));
}

}// namespace detail
}// namespace future
}// namespace tile
