#!
#! @ingroup group_sdk_cmake_camitk_test
#!
#! camitk_add_test is a macro to add a new test to the CTest infrastructure
#! It encapsulates CMake add_test and adds useful way of testing programs.
#! It cannot operate on its own, you need to call camitk_init_test first (and only once) before
#! calling camitk_add_test
#!
#! Details on the runned test can be found in ${CMAKE_BINARY_DIR}/Testing/Temporary/target#
#! where target is the executable name (see camitk_init_test() macro), and # is the test order number.
#!
#! Usage:
#! \code
#! camitk_add_test(EXECUTABLE_ARGS "arg1 arg2 arg3"
#!                 PASS_FILE_OUTPUT pristineOutput
#!                 PASS_REGULAR_EXPRESSION regexp
#!                 FAIL_REGULAR_EXPRESSION regexp
#!                 PROJECT_NAME name
#!                 TEST_SUFFIX name
#! )
#! \endcode
#!
#! \param EXECUTABLE_ARGS (optional)          The executable arguments (all in double quotes), typically each test will have different arguments. Can be empty
#! \param PASS_FILE_OUTPUT (optional)         If specified the test to perform is to compare the output of the command to this file. It the output is the same, then the test is passed, otherwise it is failed.
#! \param PASS_REGULAR_EXPRESSION (optional)  This is equivalent to "PASS_REGULAR_EXPRESSION regexp" property for the test, see http://www.cmake.org/Wiki/CTest:FAQ#My_test_does_not_return_non-zero_on_failure._What_can_I_do.3F
#! \param FAIL_REGULAR_EXPRESSION             This is equivalent to "FAIL_REGULAR_EXPRESSION regexp" property for the test, see http://www.cmake.org/Wiki/CTest:FAQ#My_test_does_not_return_non-zero_on_failure._What_can_I_do.3F
#! \param PROJECT_NAME                        Base name for the test, can be used for ctest -S
#! \param TEST_SUFFIX                         Suffix added to the test name, just after PROJECT_NAME and before the test index
#!
#! If no argument are given, it does the equivalent as add_test(name target)
#!
#! \note
#!   You can only choose one between nothing, PASS_FILE, PASS_REGULAR_EXPRESSION and FAIL_REGULAR_EXPRESSION
#!
#! Example invocation:
#!
#! \code
#!
#! add_executable(myprogram)
#!
#! ...
#! # Start the test series for myprogram
#! camitk_init_test(myprogram)
#! camitk_add_test(EXECUTABLE_ARGS "-a inputfile.xml -c" PASS_FILE pristineOuputToCompareTo.xml) # will be called myprogram1
#! ...
#! camitk_add_test(...) # myprogram2
#!
#! \endcode
#
#! @sa camitk_init_test
macro(camitk_add_test)
    set(options "")
    set(oneValueArgs EXECUTABLE_ARGS PASS_FILE PASS_REGULAR_EXPRESSION FAIL_REGULAR_EXPRESSION PASS_FILE_OUTPUT TEST_SUFFIX PROJECT_NAME)
    set(multiValueArgs "")
    cmake_parse_arguments(CAMITK_ADD_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
    
    if(NOT CAMITK_ADD_TEST_TEST_SUFFIX)
        set(CAMITK_ADD_TEST_TEST_SUFFIX "-")
    endif()
    
    math(EXPR CAMITK_TEST_ID "${CAMITK_TEST_ID} + 1")
    set(CAMITK_TEST_NAME "${CAMITK_ADD_TEST_PROJECT_NAME}${CAMITK_ADD_TEST_TEST_SUFFIX}${CAMITK_TEST_ID}")
    set(CAMITK_TEST_LIST ${CAMITK_TEST_LIST} ${CAMITK_TEST_NAME})

    # determine cmake macro path
    if (NOT EXISTS ${SDK_TOP_LEVEL_SOURCE_DIR})
        # this macro is called outside the sdk 
        set(CAMITK_CMAKE_MACRO_PATH ${CAMITK_CMAKE_DIR}/macros/camitk/test)
        if(NOT IS_DIRECTORY ${CAMITK_CMAKE_MACRO_PATH})
            # inside communityedition but not in sdk (modeling or imaging)
            set(CAMITK_CMAKE_MACRO_PATH ${CMAKE_SOURCE_DIR}/sdk/cmake/modules/macros/camitk/test)
        endif()
    else()
        # directly use the macro source dir
        set(CAMITK_CMAKE_MACRO_PATH ${SDK_TOP_LEVEL_SOURCE_DIR}/cmake/modules/macros/camitk/test)
    endif()   
    
    # create test output directory
    set(CAMITK_TEST_OUTPUT_DIR "${CMAKE_BINARY_DIR}/Testing/Temporary/${CAMITK_TEST_NAME}")
    execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CAMITK_TEST_OUTPUT_DIR})
    
    # check which test is to be performed
    if(CAMITK_ADD_TEST_PASS_FILE)
        add_test(NAME ${CAMITK_TEST_NAME}
                 COMMAND ${CMAKE_COMMAND}
                                -DCAMITK_TEST_COMMAND=${CAMITK_INIT_TEST_EXECUTABLE}
                                -DCAMITK_TEST_COMMAND_ARG=${CAMITK_ADD_TEST_EXECUTABLE_ARGS}
                                -DCAMITK_TEST_PASS_FILE=${CAMITK_ADD_TEST_PASS_FILE}
                                -DCAMITK_TEST_OUTPUT_DIR=${CAMITK_TEST_OUTPUT_DIR}
                                -DCAMITK_TEST_NAME=${CAMITK_TEST_NAME}
                                -P ${CAMITK_CMAKE_MACRO_PATH}/CamiTKTestPassFile.cmake
                 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} # needs to be at the top of the CamiTK module repository
        )
    elseif(CAMITK_ADD_TEST_PASS_FILE_OUTPUT)
        add_test(NAME ${CAMITK_TEST_NAME}
                 COMMAND ${CMAKE_COMMAND}
                                -DCAMITK_TEST_COMMAND=${CAMITK_INIT_TEST_EXECUTABLE}
                                -DCAMITK_TEST_COMMAND_ARG=${CAMITK_ADD_TEST_EXECUTABLE_ARGS}
                                -DCAMITK_TEST_PASS_FILE=${CAMITK_ADD_TEST_PASS_FILE_OUTPUT}
                                -DCAMITK_TEST_OUTPUT_DIR=${CAMITK_TEST_OUTPUT_DIR}
                                -DCAMITK_TEST_NAME=${CAMITK_TEST_NAME}
                                -P ${CAMITK_CMAKE_MACRO_PATH}/CamiTKTestCompareFile.cmake
                 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} # needs to be at the top of the CamiTK module repository
        )
    else()
        # set output files for more advanced checking/debugging
        set(CAMITK_TEST_COMMAND_FILE ${CAMITK_TEST_OUTPUT_DIR}/command) # which command is run to test the exectable
        
        execute_process(COMMAND ${CMAKE_COMMAND} -E remove -f ${CAMITK_TEST_COMMAND_FILE} )
        file(WRITE ${CAMITK_TEST_COMMAND_FILE} "Test command: ${CAMITK_INIT_TEST_EXECUTABLE} ${CAMITK_ADD_TEST_EXECUTABLE_ARGS}\nPASS_REGULAR_EXPRESSION: '${CAMITK_ADD_TEST_PASS_REGULAR_EXPRESSION}'")

        if(CAMITK_ADD_TEST_EXECUTABLE_ARGS)
            # expands all arguments
            string(REPLACE " " ";" CAMITK_TEST_COMMAND_ARG_LIST ${CAMITK_ADD_TEST_EXECUTABLE_ARGS})
        else()
            set(CAMITK_TEST_COMMAND_ARG_LIST)
        endif()
        
        # add the simple test command
        add_test(NAME ${CAMITK_TEST_NAME}
                 COMMAND ${CAMITK_INIT_TEST_EXECUTABLE} ${CAMITK_TEST_COMMAND_ARG_LIST}
                 WORKING_DIRECTORY ${CMAKE_BINARY_DIR} # needs to be at the top of the CamiTK module repository
        )

        # add properties if needed
        if(CAMITK_ADD_TEST_PASS_REGULAR_EXPRESSION)
            set_tests_properties( ${CAMITK_TEST_NAME} PROPERTIES PASS_REGULAR_EXPRESSION "${CAMITK_ADD_TEST_PASS_REGULAR_EXPRESSION}")
        else()
            if(CAMITK_ADD_TEST_FAIL_REGULAR_EXPRESSION)
                set_tests_properties( ${CAMITK_TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${CAMITK_ADD_TEST_FAIL_REGULAR_EXPRESSION}")
            endif()
        endif()
    endif()

    # set the label for tests
    if( CAMITK_ADD_TEST_PROJECT_NAME )
        set_tests_properties( ${CAMITK_TEST_NAME} PROPERTIES LABELS "${CAMITK_ADD_TEST_PROJECT_NAME}" )#associate tests to a project name in CDash 
    else()
        set_tests_properties( ${CAMITK_TEST_NAME} PROPERTIES LABELS "${CAMITK_TEST_BASENAME} ")
    endif()

    # On Windows, add ${CAMITK_BUILD_PRIVATE_LIB_DIR} and ${CAMITK_BUILD_BIN_DIR} to PATH in order
    # to find the required public and private library dll
    if (MSVC)
        # MSVC requires path to lib for the DLL
        string(REGEX REPLACE "/" "\\\\" PATH_TO_PRIVATE_DLL "${CAMITK_BUILD_PRIVATE_LIB_DIR}")
        # all ; needs to be escaped as well...
        # see https://developercommunity.visualstudio.com/t/cmake-tests-environment-variables-ignored/210188#T-N931342
        string(REPLACE ";" "\\;" ESCAPED_PATH "$ENV{PATH};${PATH_TO_PRIVATE_DLL}") 
        set_tests_properties(${CAMITK_TEST_NAME} PROPERTIES ENVIRONMENT "PATH=${ESCAPED_PATH}")
    endif()

endmacro()
