1_generate_function_if_testing_is_disabled("catkin_add_nosetests")
2
3#
4# Add Python nose tests.
5#
6# Nose collects tests from the directory ``dir`` automatically.
7#
8# .. note:: The test can be executed by calling ``nosetests``
9#   directly or using:
10#   `` make run_tests_${PROJECT_NAME}_nosetests_${dir}``
11#   (where slashes in the ``dir`` are replaced with periods)
12#
13# :param path: a relative or absolute directory to search for
14#   nosetests in or a relative or absolute file containing tests
15# :type path: string
16# :param DEPENDENCIES: the targets which must be built before executing
17#   the test
18# :type DEPENDENCIES: list of strings
19# :param TIMEOUT: the timeout for individual tests in seconds
20#   (default: 60)
21# :type TIMEOUT: integer
22# :param WORKING_DIRECTORY: the working directory when executing the
23#   tests (this option can only be used when the ``path`` argument is a
24#   file  but not when it is a directory)
25# :type WORKING_DIRECTORY: string
26#
27# @public
28#
29function(catkin_add_nosetests path)
30  _warn_if_skip_testing("catkin_add_nosetests")
31
32  if(NOT NOSETESTS)
33    message(STATUS "skipping nosetests(${path}) in project '${PROJECT_NAME}'")
34    return()
35  endif()
36
37  cmake_parse_arguments(_nose "" "TIMEOUT;WORKING_DIRECTORY" "DEPENDENCIES" ${ARGN})
38  if(NOT _nose_TIMEOUT)
39    set(_nose_TIMEOUT 60)
40  endif()
41  if(NOT _nose_TIMEOUT GREATER 0)
42    message(FATAL_ERROR "nosetests() TIMEOUT argument must be a valid number of seconds greater than zero")
43  endif()
44
45  # check that the directory exists
46  set(_path_name _path_name-NOTFOUND)
47  if(IS_ABSOLUTE ${path})
48    set(_path_name ${path})
49  else()
50    find_file(_path_name ${path}
51      PATHS ${CMAKE_CURRENT_SOURCE_DIR}
52      NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
53    if(NOT _path_name)
54      message(FATAL_ERROR "Can't find nosetests path '${path}'")
55    endif()
56  endif()
57
58  # check if coverage reports are being requested
59  if("$ENV{CATKIN_TEST_COVERAGE}" STREQUAL "1")
60    set(_covarg " --with-coverage")
61  endif()
62
63  # strip PROJECT_SOURCE_DIR and PROJECT_BINARY_DIR prefix from output_file_name
64  set(output_file_name ${path})
65  _strip_path_prefix(output_file_name "${output_file_name}" "${PROJECT_SOURCE_DIR}")
66  _strip_path_prefix(output_file_name "${output_file_name}" "${PROJECT_BINARY_DIR}")
67  if("${output_file_name}" STREQUAL "")
68    set(output_file_name ".")
69  endif()
70  string(REPLACE "/" "." output_file_name ${output_file_name})
71  string(REPLACE ":" "." output_file_name ${output_file_name})
72
73  set(output_path ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME})
74  # make --xunit-file argument an absolute path (https://github.com/nose-devs/nose/issues/779)
75  get_filename_component(output_path "${output_path}" ABSOLUTE)
76  set(cmd "\"${CMAKE_COMMAND}\" -E make_directory ${output_path}")
77  if(IS_DIRECTORY ${_path_name})
78    set(tests "--where=${_path_name}")
79  else()
80    set(tests "${_path_name}")
81  endif()
82  set(cmd ${cmd} "${NOSETESTS} -P --process-timeout=${_nose_TIMEOUT} ${tests} --with-xunit --xunit-file=${output_path}/nosetests-${output_file_name}.xml${_covarg}")
83  catkin_run_tests_target("nosetests" ${output_file_name} "nosetests-${output_file_name}.xml" COMMAND ${cmd} DEPENDENCIES ${_nose_DEPENDENCIES} WORKING_DIRECTORY ${_nose_WORKING_DIRECTORY})
84endfunction()
85
86find_program(NOSETESTS NAMES
87  "nosetests${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}"
88  "nosetests-${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}"
89  "nosetests${PYTHON_VERSION_MAJOR}"
90  "nosetests-${PYTHON_VERSION_MAJOR}"
91  "nosetests")
92if(NOSETESTS)
93  message(STATUS "Using Python nosetests: ${NOSETESTS}")
94else()
95  if("${PYTHON_VERSION_MAJOR}" STREQUAL "3")
96    message(STATUS "nosetests not found, Python tests can not be run (try installing package 'python3-nose')")
97  else()
98    message(STATUS "nosetests not found, Python tests can not be run (try installing package 'python-nose')")
99  endif()
100endif()
101
102function(_strip_path_prefix var value prefix)
103  if("${value}" STREQUAL "${prefix}" OR "${value}" STREQUAL "${prefix}/")
104    set(${var} "" PARENT_SCOPE)
105  else()
106    set(result "${value}")
107    string(LENGTH "${prefix}/" prefix_length)
108    string(LENGTH "${value}" var_length)
109    if(${var_length} GREATER ${prefix_length})
110      string(SUBSTRING "${value}" 0 ${prefix_length} var_prefix)
111      if("${var_prefix}" STREQUAL "${prefix}/")
112        # passing length -1 does not work for CMake < 2.8.5
113        # http://public.kitware.com/Bug/view.php?id=10740
114        string(LENGTH "${value}" _rest)
115        math(EXPR _rest "${_rest} - ${prefix_length}")
116        string(SUBSTRING "${value}" ${prefix_length} ${_rest} result)
117      endif()
118    endif()
119    set(${var} "${result}" PARENT_SCOPE)
120  endif()
121endfunction()
122