#include <gtest/gtest.h>
#include "core/command/Functor.h"

namespace orxonox
{
    namespace
    {
        class Testclass : public Destroyable
        {
            public:
                void testMember() {}
                static void testStatic() {}
        };

        class Subclass : public Testclass
        {
        };

        // Fixture
        class FunctorPtrTest : public ::testing::Test
        {
            public:
                virtual void SetUp() override
                {
                }

                virtual void TearDown() override
                {
                }
        };
    }

    TEST_F(FunctorPtrTest, emptyPtr)
    {
        FunctorMemberPtr<Testclass> ptr1;
        FunctorStaticPtr ptr2;
        FunctorPtr ptr3;

        ASSERT_FALSE(static_cast<bool>(ptr1));
        ASSERT_FALSE(static_cast<bool>(ptr2));
        ASSERT_FALSE(static_cast<bool>(ptr3));
    }

    TEST_F(FunctorPtrTest, canAssignToFunctorMemberPtr)
    {
        FunctorMemberPtr<Testclass> ptr = createFunctor(&Testclass::testMember);
        ASSERT_TRUE(static_cast<bool>(ptr));
    }

    TEST_F(FunctorPtrTest, canAssignToFunctorStaticPtr)
    {
        FunctorStaticPtr ptr = createFunctor(&Testclass::testStatic);
        ASSERT_TRUE(static_cast<bool>(ptr));
    }

    TEST_F(FunctorPtrTest, canAssignToFunctorPtr)
    {
        FunctorPtr ptr1 = createFunctor(&Testclass::testMember);
        ASSERT_TRUE(static_cast<bool>(ptr1));
        FunctorPtr ptr2 = createFunctor(&Testclass::testStatic);
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(FunctorPtrTest, canCastFromFunctorMemberPtr)
    {
        FunctorMemberPtr<Testclass> ptr1 = createFunctor(&Testclass::testMember);
        FunctorPtr ptr2 = ptr1;
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(FunctorPtrTest, canCastFromFunctorStaticPtr)
    {
        FunctorStaticPtr ptr1 = createFunctor(&Testclass::testStatic);
        FunctorPtr ptr2 = ptr1;
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(FunctorPtrTest, canCastToFunctorMemberOfSubclass)
    {
        FunctorPtr ptr1 = createFunctor(&Subclass::testMember);
        FunctorMemberPtr<Subclass> ptr2 = std::static_pointer_cast<FunctorMember<Subclass>>(ptr1);
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }
}
