//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        iutest_util_tests.hpp
 * @brief       iris unit test テスト情報 utility ファイル
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2012-2018, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================
#ifndef INCG_IRIS_IUTEST_UTIL_TESTS_HPP_4095FF9B_D6B8_4CD3_BF86_43DFED1760EA_
#define INCG_IRIS_IUTEST_UTIL_TESTS_HPP_4095FF9B_D6B8_4CD3_BF86_43DFED1760EA_

//======================================================================
// include
namespace iuutil
{

//======================================================================
// function

/**
 * @brief   テスト名を取得
*/
inline ::std::string TestFullName(const ::iutest::TestInfo* test_info)
{
    ::std::string fullname = test_info->test_case_name();
    fullname += ".";
    fullname += test_info->name();
    return fullname;
}

/**
 * @brief   インデックスを除いたテスト名を取得
*/
inline ::std::string TestNameRemoveIndexName(const char* name)
{
    const char* const p = strrchr(name, '/');
    if( p == NULL )
    {
        return name;
    }
    return ::std::string(name, p);
}

/**
 * @brief   インデックスを除いたテストケース名を取得
*/
inline ::std::string TestCaseNameRemoveIndexName(const char* name)
{
    return TestNameRemoveIndexName(name);
}

/**
 * @brief   インスタンス名とインデックスを除いたテストケース名を取得
*/
inline ::std::string TestCaseNameRemoveInstantiateAndIndexName(const char* name)
{
    // パッケージ名があれば取得
    const char* const pkg = strrchr(name, '.');
    // 先頭にインスタンス名がある
    const char* const p1 = strchr(name, '/');
    if( p1 == NULL )
    {
        return name;
    }
    if( pkg == NULL )
    {
        return TestCaseNameRemoveIndexName(p1 + 1);
    }
    else
    {
        return ::std::string(name, pkg + 1) + TestCaseNameRemoveIndexName(p1 + 1);
    }
}

/**
 * @brief   TestCase の検索
*/
inline const ::iutest::TestCase* FindTestCase(const char* testcase_name)
{
    if( testcase_name == NULL )
    {
        return NULL;
    }
    const int testcase_count = ::iutest::UnitTest::GetInstance()->total_test_case_count();
    for( int i=0; i < testcase_count; ++i )
    {
        const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
        if( strcmp(testcase->name(), testcase_name) == 0 )
        {
            return testcase;
        }
    }
    return NULL;
}

/**
 * @brief   TestCase の検索
*/
inline const ::iutest::TestCase* FindParamTestCase(const char* testcase_name, const ::iutest::TestCase* begin=NULL)
{
    if( testcase_name == NULL )
    {
        return NULL;
    }
    const int testcase_count = ::iutest::UnitTest::GetInstance()->total_test_case_count();
    int i=0;
    if( begin != NULL )
    {
        for( ; i < testcase_count; ++i )
        {
            const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
            if( testcase == begin )
            {
                break;
            }
        }
        ++i;
    }
    for( ; i < testcase_count; ++i )
    {
        const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
        const char* testcase_origin_name = strchr(testcase->name(), '/');
        if( testcase_origin_name != NULL )
        {
            if( strcmp(testcase_origin_name+1, testcase_name) == 0 )
            {
                return testcase;
            }
        }
    }
    return NULL;
}

/**
 * @brief   Typed Test の TestCase の検索
*/
inline const ::iutest::TestCase* FindTypedTestCase(const char* testcase_name, const ::iutest::TestCase* begin=NULL)
{
    if( testcase_name == NULL )
    {
        return NULL;
    }
    const int testcase_count = ::iutest::UnitTest::GetInstance()->total_test_case_count();
    int i=0;
    if( begin != NULL )
    {
        for( ; i < testcase_count; ++i )
        {
            const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
            if( testcase == begin )
            {
                break;
            }
        }
        ++i;
    }
    for( ; i < testcase_count; ++i )
    {
        const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
        if( testcase != NULL )
        {
            const char* name = testcase->name();
            if( name != NULL
                && strstr(name, testcase_name) == name
                && name[strlen(testcase_name)] == '/' )
            {
                return testcase;
            }
        }
    }
    return NULL;
}

/**
 * @brief   Type Parameter Test の TestCase の検索
*/
inline const ::iutest::TestCase* FindParamTypedTestCase(const char* testcase_name, const ::iutest::TestCase* begin=NULL)
{
    if( testcase_name == NULL )
    {
        return NULL;
    }
    const int testcase_count = ::iutest::UnitTest::GetInstance()->total_test_case_count();
    int i=0;
    if( begin != NULL )
    {
        for( ; i < testcase_count; ++i )
        {
            const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
            if( testcase == begin )
            {
                break;
            }
        }
        ++i;
    }
    for( ; i < testcase_count; ++i )
    {
        const ::iutest::TestCase* testcase = ::iutest::UnitTest::GetInstance()->GetTestCase(i);
        const char* name = strchr(testcase->name(), '/');
        if( name != NULL )
        {
            ++name;
            if( strstr(name, testcase_name) == name
                && name[strlen(testcase_name)] == '/' )
            {
                return testcase;
            }
        }
    }
    return NULL;
}

/**
 * @brief   TestInfo の検索
*/
inline const ::iutest::TestInfo* FindTestInfo(const ::iutest::TestCase* testcase, const char* testinfo_name)
{
    if( testcase == NULL || testinfo_name == NULL )
    {
        return NULL;
    }

    const int testinfo_count = testcase->total_test_count();
    for( int i=0; i < testinfo_count; ++i )
    {
        const ::iutest::TestInfo* testinfo = testcase->GetTestInfo(i);
        if( strcmp(testinfo->name(), testinfo_name) == 0 )
        {
            return testinfo;
        }
    }
    return NULL;
}

/**
 * @brief   TestInfo の検索
*/
inline const ::iutest::TestInfo* FindTestInfo(const char* testcase_name, const char* testinfo_name)
{
    if( testcase_name == NULL || testinfo_name == NULL )
    {
        return NULL;
    }
    const ::iutest::TestCase* testcase = FindTestCase(testcase_name);
    return FindTestInfo(testcase, testinfo_name);
}

/**
 * @brief   TestInfo の検索
*/
inline const ::iutest::TestInfo* FindParamTestInfo(const ::iutest::TestCase* testcase, const char* testinfo_name
                                                    , const ::iutest::TestInfo* begin=NULL)
{
    if( testcase == NULL || testinfo_name == NULL )
    {
        return NULL;
    }

    const int testinfo_count = testcase->total_test_count();
    int i=0;
    if( begin != NULL )
    {
        for( ; i < testinfo_count; ++i )
        {
            const ::iutest::TestInfo* testinfo = testcase->GetTestInfo(i);
            if( testinfo == begin )
            {
                break;
            }
        }
        ++i;
    }

    for( ; i < testinfo_count; ++i )
    {
        const ::iutest::TestInfo* testinfo = testcase->GetTestInfo(i);
        if( testinfo != NULL )
        {
            const char* name = testinfo->name();
            if( name != NULL
                && strstr(name, testinfo_name) == name
                && name[strlen(testinfo_name)] == '/' )
            {
                return testinfo;
            }
        }
    }
    return NULL;
}

/** 
 * @private
*/
inline const ::iutest::TestResult* TestResultPointer(const ::iutest::TestResult* result)
{
    return result;
}
/** 
 * @private
*/
inline const ::iutest::TestResult* TestResultPointer(const ::iutest::TestResult& result)
{
    return &result;
}

/**
 * @brief   ad_hoc_test_result の取得
*/
inline const ::iutest::TestResult* GetAdHocTestResult()
{
#if !defined(IUTEST_NO_UNITEST_AD_HOC_TEST_RESULT_ACCESSOR)
    return TestResultPointer(::iutest::UnitTest::GetInstance()->ad_hoc_test_result());
#else
    return NULL;
#endif
}

/**
 * @brief   TestCase の ad_hoc_test_result の取得
*/
inline const ::iutest::TestResult* GetTestCaseAdHocResult(const ::iutest::TestCase* test_case)
{
#if !defined(IUTEST_NO_TESTCASE_AD_HOC_TEST_RESULT_ACCESSOR)
    return TestResultPointer(test_case->ad_hoc_test_result());
#else
    IUTEST_UNUSED_VAR(test_case);
    return GetAdHocTestResult();
#endif
}

/**
 * @brief   TestCase の ad_hoc_test_result の取得
*/
inline const ::iutest::TestResult* GetCurrentTestCaseAdHocResult()
{
    return GetTestCaseAdHocResult(::iutest::UnitTest::GetInstance()->current_test_case());
}

/**
 * @brief   get test result
*/
inline const ::iutest::TestResult* GetTestResult(const ::iutest::TestInfo* test_info)
{
    return TestResultPointer(test_info->result());
}

/**
 * @brief   get test result
*/
inline const ::iutest::TestResult* GetCurrentTestResult()
{
    return GetTestResult(::iutest::UnitTest::GetInstance()->current_test_info());
}

}   // end of namespace iuutil

#endif // INCG_IRIS_IUTEST_UTIL_TESTS_HPP_4095FF9B_D6B8_4CD3_BF86_43DFED1760EA_
