# Copyright (C) Alexander Lamaison <alexander.lamaison@gmail.com>
# Copyright (C) Viktor Szakats
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
#    contributors may be used to endorse or promote products derived from this
#    software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# SPDX-License-Identifier: BSD-3-Clause

set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "LIBSSH2_TESTS")

list(APPEND LIBSSH2_LIBS ${LIBSSH2_LIBS_SOCKET})

libssh2_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
# Get CONTAINER_TESTS, CONTAINER_TESTS_STATIC, STANDALONE_TESTS, STANDALONE_TESTS_STATIC, SSHD_TESTS,
# librunner_la_SOURCES, EXTRA_DIST variables
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
list(APPEND CONTAINER_TESTS ${CONTAINER_TESTS_STATIC})
list(APPEND STANDALONE_TESTS ${STANDALONE_TESTS_STATIC})

if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
  find_program(GCOV_PATH "gcov")
  if(GCOV_PATH)
    set(_gcov_cflags "-g" "--coverage")
    if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0)
      list(APPEND _gcov_cflags "-fprofile-abs-path")
    endif()
  endif()
endif()

option(RUN_SSHD_TESTS "Run tests requiring sshd" ON)

find_program(SH_EXECUTABLE "sh")
mark_as_advanced(SH_EXECUTABLE)
if(SH_EXECUTABLE)
  if(RUN_SSHD_TESTS)
    find_program(SSHD_EXECUTABLE "sshd")
    mark_as_advanced(SSHD_EXECUTABLE)
  endif()
endif()

add_library(runner STATIC ${librunner_la_SOURCES})
target_compile_definitions(runner PRIVATE "${CRYPTO_BACKEND_DEFINE}")
target_include_directories(runner PRIVATE
  "${PROJECT_BINARY_DIR}/src"
  "${PROJECT_SOURCE_DIR}/src"
  "${PROJECT_SOURCE_DIR}/include")
set_property(TARGET runner APPEND PROPERTY COMPILE_OPTIONS "${LIBSSH2_PICKY_C_FLAGS}")
target_link_libraries(runner PRIVATE libssh2 ${LIBSSH2_LIBS})

foreach(_test IN LISTS CONTAINER_TESTS STANDALONE_TESTS SSHD_TESTS)
  if(NOT ";${CONTAINER_TESTS_STATIC};${STANDALONE_TESTS_STATIC};" MATCHES ";${_test};")
    set(_lib_for_tests ${LIB_SELECTED})
  elseif(TARGET ${LIB_STATIC})
    set(_lib_for_tests ${LIB_STATIC})
  else()
    set(_lib_for_tests "")
    message(STATUS "Skip test requiring static libssh2 lib: ${_test}")
  endif()

  # We support the same target as both container and SSHD test. Build those only once.
  # Skip building tests that require the static lib when the static lib is not built.
  if(NOT TARGET ${_test} AND _lib_for_tests)
    add_executable(${_test} "${_test}.c")
    target_compile_definitions(${_test} PRIVATE "${CRYPTO_BACKEND_DEFINE}")
    target_include_directories(${_test} PRIVATE
      "${PROJECT_BINARY_DIR}/src"
      "${PROJECT_SOURCE_DIR}/src"
      "${PROJECT_SOURCE_DIR}/include")
    set_property(TARGET ${_test} APPEND PROPERTY COMPILE_OPTIONS "${LIBSSH2_PICKY_C_FLAGS}")
    set_target_properties(${_test} PROPERTIES UNITY_BUILD OFF)
    target_link_libraries(${_test} PRIVATE runner ${_lib_for_tests} ${LIBSSH2_LIBS})

    # build a single test with gcov
    if(GCOV_PATH AND _test STREQUAL "test_auth_keyboard_info_request" AND TARGET ${LIB_STATIC})
      target_compile_options(${_test} BEFORE PRIVATE ${_gcov_cflags})
      target_link_libraries(${_test} PRIVATE "gcov")
    endif()

    list(APPEND _test_targets ${_test})
  endif()
endforeach()

option(RUN_DOCKER_TESTS "Run tests requiring container" ON)

if(RUN_DOCKER_TESTS)
  foreach(_test IN LISTS CONTAINER_TESTS)
    if(TARGET ${_test})
      add_test(NAME ${_test} COMMAND "$<TARGET_FILE:${_test}>")
      set_property(TEST ${_test} APPEND PROPERTY ENVIRONMENT "srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
    endif()
  endforeach()
endif()

foreach(_test IN LISTS STANDALONE_TESTS)
  if(TARGET ${_test})
    add_test(NAME ${_test} COMMAND "$<TARGET_FILE:${_test}>")
    set_property(TEST ${_test} APPEND PROPERTY ENVIRONMENT "srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
  endif()
endforeach()

if(RUN_SSHD_TESTS AND SSHD_EXECUTABLE)
  set(_sshd_test_targets "")
  foreach(_test IN LISTS SSHD_TESTS)
    if(TARGET ${_test})
      string(APPEND _sshd_test_targets " $<TARGET_FILE:${_test}>")
    endif()
  endforeach()

  if(_sshd_test_targets)
    add_test(NAME test_sshd COMMAND "${SH_EXECUTABLE}" -c "${CMAKE_CURRENT_SOURCE_DIR}/test_sshd.test ${_sshd_test_targets}")
    set_property(TEST test_sshd APPEND PROPERTY ENVIRONMENT "srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
    set_property(TEST test_sshd APPEND PROPERTY ENVIRONMENT "SSHD=${SSHD_EXECUTABLE}")
  endif()
endif()

if(RUN_DOCKER_TESTS)
  # CRYPT/MAC algo tests
  file(READ "test_read_algos.txt" _algo_tests)
  string(REGEX REPLACE "\\\n" ";" _algo_tests ${_algo_tests})
  foreach(_test IN LISTS _algo_tests)
    if(_test)
      set(_testname "test_read-${_test}")
      add_test(NAME ${_testname} COMMAND "$<TARGET_FILE:test_read>")
      set_property(TEST ${_testname} APPEND PROPERTY ENVIRONMENT "srcdir=${CMAKE_CURRENT_SOURCE_DIR}")
      if(_test MATCHES "mac-")
        set_property(TEST ${_testname} APPEND PROPERTY ENVIRONMENT "FIXTURE_TEST_MAC=${_test}")
      elseif(_test MATCHES "-cert-")
        set_property(TEST ${_testname} APPEND PROPERTY ENVIRONMENT "FIXTURE_TEST_HOSTKEY=${_test}")
      else()
        set_property(TEST ${_testname} APPEND PROPERTY ENVIRONMENT "FIXTURE_TEST_CRYPT=${_test}")
      endif()
    endif()
  endforeach()
endif()

add_custom_target(coverage
  COMMAND gcovr --root "${PROJECT_SOURCE_DIR}" --exclude tests/*
  COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/coverage"
  COMMAND gcovr --root "${PROJECT_SOURCE_DIR}" --exclude tests/* --html-details
    --output "${CMAKE_CURRENT_BINARY_DIR}/coverage/index.html")

add_custom_target(clean-coverage COMMAND ${CMAKE_COMMAND} -E rm -rf --
  "${CMAKE_CURRENT_BINARY_DIR}/coverage")

if(BUILD_OSSFUZZ)
  add_subdirectory(ossfuzz)
endif()
