# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
# file LICENSE.rst or https://cmake.org/licensing for details.

#[=======================================================================[.rst:
FindCxxTest
-----------

Finds `CxxTest`_, a C++ unit testing framework suite, and provides a helper
command to create test runners and integrate them with CTest:

.. code-block:: cmake

  find_package(CxxTest [...])

.. _`CxxTest`: https://github.com/CxxTest/cxxtest

Result Variables
^^^^^^^^^^^^^^^^

This module defines the following variables:

``CxxTest_FOUND``
  .. versionadded:: 4.2

  Boolean indicating whether the CxxTest framework was found.

``CXXTEST_INCLUDE_DIRS``
  Include directories containing headers needed to use CxxTest.

``CXXTEST_TESTGEN_EXECUTABLE``
  The path to the found CxxTest test generator script (Perl- or Python-based),
  selected based on the found interpreter or user-specified preference.

``CXXTEST_TESTGEN_INTERPRETER``
  The path to the found Perl or Python interpreter used to run the test
  generator script, if needed (e.g., on platforms where script shebang lines are
  not supported).

Cache Variables
^^^^^^^^^^^^^^^

The following cache variables may also be set:

``CXXTEST_PYTHON_TESTGEN_EXECUTABLE``
  The path to the Python-based CxxTest test generator script.

``CXXTEST_PERL_TESTGEN_EXECUTABLE``
  The path to the Perl-based CxxTest test generator script.

  .. note::
    Perl-based test generator script has been removed in CxxTest version
    4.0 in favor of Python-based script.

Hints
^^^^^

This module accepts the following variables before calling
``find_package(CxxTest)``:

``CXXTEST_TESTGEN_ARGS``
  This variable can be set to specify a semicolon-separated list of command-line
  options to pass to the CxxTest code generator.  If not set, the default value
  is ``--error-printer``.

Commands
^^^^^^^^

This module provides the following command if CxxTest is found:

.. command:: cxxtest_add_test

  Creates a CxxTest runner and adds it to the CTest testing suite:

  .. code-block:: cmake

    cxxtest_add_test(<test-name> <gen-source-file> <input-files-to-testgen>...)

  Parameters:

  ``<test-name>``
    The name of the test executable target to be created and registered as a
    test in the CTest suite.

  ``<gen-source-file>``
    The name of the source file to be generated by the CxxTest code generator.
    This must be a relative path.  It is interpreted relative to the
    current binary directory (:variable:`CMAKE_CURRENT_BINARY_DIR`).

  ``<input-files-to-testgen>...``
    A list of header files containing test suite classes derived from the C++
    class ``CxxTest::TestSuite``, to be included in the test runner.  These must
    be given as absolute paths.

Deprecated Variables
^^^^^^^^^^^^^^^^^^^^

The following variables are provided for backward compatibility:

``CXXTEST_FOUND``
  .. deprecated:: 4.2
    Use ``CxxTest_FOUND``, which has the same value.

  Boolean indicating whether the CxxTest framework was found.

``CXXTEST_USE_PYTHON``
  .. deprecated:: 2.8.3
    In earlier versions of CMake, this hint variable was used to force the use
    of the Python-based test generator instead of the Perl one, regardless of
    which scripting language was installed.  It is now only considered when both
    Perl and Python interpreters are found.

  A boolean hint variable that, when set to true, prefers the Python code
  generator over the Perl one if both interpreters are found.  This variable is
  only relevant when using CxxTest version 3.

Examples
^^^^^^^^

The following example demonstrates how CxxTest can be used in CMake with this
module.  If CxxTest is found:

* Additional interface :ref:`imported target <Imported Targets>` is created
  manually in the project to encapsulate the CxxTest usage requirements and
  link it to specified tests.  Such target is useful, for example, when dealing
  with multiple tests.

* Test generator is invoked to create ``foo_test.cc`` in the current binary
  directory from the input header ``foo_test.h`` located in the current source
  directory.

* An executable named ``unit_test_foo`` is built and registered as a test in
  CTest.

.. code-block:: cmake
  :caption: ``CMakeLists.txt``

  find_package(CxxTest)

  # Create interface imported target:
  if(CxxTest_FOUND AND NOT TARGET CxxTest::CxxTest)
    add_library(CxxTest::CxxTest INTERFACE IMPORTED)
    set_target_properties(
      CxxTest::CxxTest
      PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CXXTEST_INCLUDE_DIRS}"
    )
  endif()

  # Add test:
  if(CxxTest_FOUND)
    enable_testing()

    cxxtest_add_test(
      unit_test_foo
      foo_test.cc
      ${CMAKE_CURRENT_SOURCE_DIR}/foo_test.h
    )

    target_link_libraries(
      unit_test_foo
      PRIVATE
        CxxTest::CxxTest
        # Link any project targets as needed, if test depends on them:
        foo
    )
  endif()

.. code-block:: c++
  :caption: ``foo_test.h``

  #include <cxxtest/TestSuite.h>

  class MyTestSuite : public CxxTest::TestSuite
  {
  public:
    void testAddition(void)
    {
      TS_ASSERT(1 + 1 > 1);
      TS_ASSERT_EQUALS(1 + 1, 2);
    }
  };
#]=======================================================================]

# CMake 4.2
#     Module now consistently defines the CxxTest_FOUND result variable.
#
# Version 1.4 (11/18/10) (CMake 2.8.4)
#     Issue 11384: Added support to the cxxtest_add_test() macro so header
#                  files (containing the tests themselves) show up in
#                  Visual Studio and other IDEs.
#
# Version 1.3 (8/19/10) (CMake 2.8.3)
#     Included patch by Simone Rossetto to check if either Python or Perl
#     are present in the system.  Whichever interpreter that is detected
#     is now used to run the test generator program.  If both interpreters
#     are detected, the CXXTEST_USE_PYTHON variable is obeyed.
#
#     Also added support for CXXTEST_TESTGEN_ARGS, for manually specifying
#     options to the CxxTest code generator.
#
# Version 1.2 (3/2/08) (CMake 2.8.0)
#     Included patch from Tyler Roscoe to have the perl & python binaries
#     detected based on CXXTEST_INCLUDE_DIR.
#
# Version 1.1 (2/9/08) (CMake 2.8.0)
#     Clarified example to illustrate need to call target_link_libraries().
#     Changed commands to lowercase.
#     Added licensing info.
#
# Version 1.0 (1/8/08) (CMake 2.6.3)
#     Module added to CMake.
#     Fixed CXXTEST_INCLUDE_DIRS so it will work properly.
#     Eliminated superfluous CXXTEST_FOUND assignment.
#     Cleaned up and added more documentation.

#=============================================================
# cxxtest_add_test (public macro)
#=============================================================
macro(CXXTEST_ADD_TEST _cxxtest_testname _cxxtest_outfname)
    set(_cxxtest_real_outfname ${CMAKE_CURRENT_BINARY_DIR}/${_cxxtest_outfname})

    add_custom_command(
        OUTPUT  ${_cxxtest_real_outfname}
        DEPENDS ${ARGN}
        COMMAND ${CXXTEST_TESTGEN_INTERPRETER}
        ${CXXTEST_TESTGEN_EXECUTABLE} ${CXXTEST_TESTGEN_ARGS} -o ${_cxxtest_real_outfname} ${ARGN}
    )

    set_source_files_properties(${_cxxtest_real_outfname} PROPERTIES GENERATED true)
    add_executable(${_cxxtest_testname} ${_cxxtest_real_outfname} ${ARGN})

    # There's no target used for these commands, so we don't need to do
    # anything here for CMP0178.
    if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
        add_test(${_cxxtest_testname} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_cxxtest_testname})
    elseif(EXECUTABLE_OUTPUT_PATH)
        add_test(${_cxxtest_testname} ${EXECUTABLE_OUTPUT_PATH}/${_cxxtest_testname})
    else()
        add_test(${_cxxtest_testname} ${CMAKE_CURRENT_BINARY_DIR}/${_cxxtest_testname})
    endif()
endmacro()

#=============================================================
# main()
#=============================================================
if(NOT DEFINED CXXTEST_TESTGEN_ARGS)
  set(CXXTEST_TESTGEN_ARGS --error-printer)
endif()

find_package(Python QUIET)
find_package(Perl QUIET)

find_path(CXXTEST_INCLUDE_DIR cxxtest/TestSuite.h)
find_program(CXXTEST_PYTHON_TESTGEN_EXECUTABLE
         NAMES cxxtestgen cxxtestgen.py
         PATHS ${CXXTEST_INCLUDE_DIR})
find_program(CXXTEST_PERL_TESTGEN_EXECUTABLE cxxtestgen.pl
         PATHS ${CXXTEST_INCLUDE_DIR})

if(Python_FOUND OR Perl_FOUND)
  include(FindPackageHandleStandardArgs)

  if(Python_FOUND AND (CXXTEST_USE_PYTHON OR NOT Perl_FOUND OR NOT DEFINED CXXTEST_USE_PYTHON))
    set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE})
    execute_process(COMMAND ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE} --version
      OUTPUT_VARIABLE _CXXTEST_OUT ERROR_VARIABLE _CXXTEST_OUT RESULT_VARIABLE _CXXTEST_RESULT)
    if(_CXXTEST_RESULT EQUAL 0)
      set(CXXTEST_TESTGEN_INTERPRETER "")
    else()
      set(CXXTEST_TESTGEN_INTERPRETER ${Python_EXECUTABLE})
    endif()
    find_package_handle_standard_args(CxxTest DEFAULT_MSG
        CXXTEST_INCLUDE_DIR CXXTEST_PYTHON_TESTGEN_EXECUTABLE)

  elseif(Perl_FOUND)
    set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PERL_TESTGEN_EXECUTABLE})
    set(CXXTEST_TESTGEN_INTERPRETER ${PERL_EXECUTABLE})
    find_package_handle_standard_args(CxxTest DEFAULT_MSG
        CXXTEST_INCLUDE_DIR CXXTEST_PERL_TESTGEN_EXECUTABLE)
  endif()

  if(CxxTest_FOUND)
    set(CXXTEST_INCLUDE_DIRS ${CXXTEST_INCLUDE_DIR})
  endif()

else()
  set(CxxTest_FOUND FALSE)
  set(CXXTEST_FOUND ${CxxTest_FOUND})

  if(NOT CxxTest_FIND_QUIETLY)
    if(CxxTest_FIND_REQUIRED)
      message(FATAL_ERROR "Neither Python nor Perl found, cannot use CxxTest, aborting!")
    else()
      message(STATUS "Neither Python nor Perl found, CxxTest will not be used.")
    endif()
  endif()

endif()
