# Custom cmake target for running nosetests on compiled libraries.
#
# This creates a custom target for running nosetests with the intent of
# verifying a compiled library using interpreted Python unit tests. It is
# meant to be used in addition to, not in lieu of, compiled unit test code.
# This can be particularly useful for math-heavy code where a compiled unit
# test could be quite cumbersome. The Python test code is responsible for
# importing the libraries (probably using ctypes).
#
# Usage: 
# 
#   add_python_test_target(TARGET_NAME LIBRARY_DEPENDENCY SOURCE_FILES)
#
# Released into the public domain. No warranty implied.

find_program(NOSETESTS_PATH nosetests)
if(NOT NOSETESTS_PATH)
    message(WARNING 
        "nosetests not found! Python library tests will not be available.")
endif()


function(add_python_test_target TARGET_NAME TARGET_LIB)
    # Try again to find nosetests here. We may have switched virtualenvs or
    # something since first running cmake.
    find_program(NOSETESTS_PATH nosetests)
    if(NOT NOSETESTS_PATH)
        message(FATAL_ERROR "nosetests not found! Aborting...")
    endif()

    set(COPY_DIR ${CMAKE_BINARY_DIR}/${TARGET_NAME}_files)

    add_custom_target(${TARGET_NAME}
        COMMAND ${NOSETESTS_PATH}
        WORKING_DIRECTORY ${COPY_DIR}
        COMMENT "Running Python tests.")

    # Copy Python files to the local binary directory so they can find the
    # dynamic library.
    set(COPY_TARGET ${TARGET_NAME}_copy)

    # We add a separate target for copying Python files. This way we can set
    # it as a dependency for the nosetests target.
    add_custom_target(${COPY_TARGET})

    # Make sure the directory exists before we copy the files.
    add_custom_command(TARGET ${COPY_TARGET}
        COMMAND ${CMAKE_COMMAND} -E make_directory ${COPY_DIR})

    # Add commands to copy each file in the list of sources.
    foreach(pysource ${ARGN})
        add_custom_command(TARGET ${COPY_TARGET}
            COMMAND ${CMAKE_COMMAND} -E copy 
            ${CMAKE_CURRENT_SOURCE_DIR}/${pysource} ${COPY_DIR})
    endforeach()

    get_target_property(TARGET_LIB_NAME ${TARGET_LIB} LOCATION)

    # Add a command to copy the target library into the same folder as the
    # python files.
    add_custom_command(TARGET ${COPY_TARGET}
        COMMAND ${CMAKE_COMMAND} -E copy ${TARGET_LIB_NAME} ${COPY_DIR}
        )

    # Make the copy target a dependency of the testing target to ensure it
    # gets done first.
    add_dependencies(${TARGET_NAME} ${COPY_TARGET})
    add_dependencies(${COPY_TARGET} ${TARGET_LIB})
endfunction()