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

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

        class Subclass : public Testclass
        {
        };

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

                virtual void TearDown() override
                {
                }
        };
    }

    TEST_F(ExecutorPtrTest, emptyPtr)
    {
        ExecutorMemberPtr<Testclass> ptr1;
        ExecutorStaticPtr ptr2;
        ExecutorPtr ptr3;

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

    TEST_F(ExecutorPtrTest, canAssignToExecutorMemberPtr)
    {
        ExecutorMemberPtr<Testclass> ptr = createExecutor(createFunctor(&Testclass::testMember));
        ASSERT_TRUE(static_cast<bool>(ptr));
    }

    TEST_F(ExecutorPtrTest, canAssignToExecutorStaticPtr)
    {
        ExecutorStaticPtr ptr = createExecutor(createFunctor(&Testclass::testStatic));
        ASSERT_TRUE(static_cast<bool>(ptr));
    }

    TEST_F(ExecutorPtrTest, canAssignToExecutorPtr)
    {
        ExecutorPtr ptr1 = createExecutor(createFunctor(&Testclass::testMember));
        ASSERT_TRUE(static_cast<bool>(ptr1));
        ExecutorPtr ptr2 = createExecutor(createFunctor(&Testclass::testStatic));
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(ExecutorPtrTest, canCastFromExecutorMemberPtr)
    {
        ExecutorMemberPtr<Testclass> ptr1 = createExecutor(createFunctor(&Testclass::testMember));
        ExecutorPtr ptr2 = ptr1;
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(ExecutorPtrTest, canCastFromExecutorStaticPtr)
    {
        ExecutorStaticPtr ptr1 = createExecutor(createFunctor(&Testclass::testStatic));
        ExecutorPtr ptr2 = ptr1;
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }

    TEST_F(ExecutorPtrTest, canCastToExecutorMemberOfSubclass)
    {
        ExecutorPtr ptr1 = createExecutor(createFunctor(&Subclass::testMember));
        ExecutorMemberPtr<Subclass> ptr2 = std::static_pointer_cast<ExecutorMember<Subclass>>(ptr1);
        ASSERT_TRUE(static_cast<bool>(ptr2));
    }
}
