# Taken from amazon-freertos repository

# function to create the test executable
function(create_test test_name test_src link_list dep_list include_list)
  set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
  include(CTest)
  get_filename_component(test_src_absolute ${test_src} ABSOLUTE)
  add_custom_command(
    OUTPUT ${test_name}_runner.c
    COMMAND
      ruby ${cmock_SOURCE_DIR}/vendor/unity/auto/generate_test_runner.rb
      ${MODULE_ROOT_DIR}/tools/cmock/project.yml ${test_src_absolute}
      ${test_name}_runner.c
    DEPENDS ${test_src})
  add_executable(${test_name} ${test_src} ${test_name}_runner.c)
  set_target_properties(
    ${test_name}
    PROPERTIES COMPILE_FLAG "-O0 -ggdb"
               RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests"
               INSTALL_RPATH_USE_LINK_PATH TRUE
               LINK_FLAGS " \
                -Wl,-rpath,${CMAKE_BINARY_DIR}/lib \
                -Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib")
  target_include_directories(${test_name} PUBLIC ${mocks_dir} ${include_list})

  target_link_directories(${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})

  # link all libraries sent through parameters
  foreach(link IN LISTS link_list)
    target_link_libraries(${test_name} ${link})
  endforeach()

  # add dependency to all the dep_list parameter
  foreach(dependency IN LISTS dep_list)
    add_dependencies(${test_name} ${dependency})
    target_link_libraries(${test_name} ${dependency})
  endforeach()
  target_link_libraries(${test_name} -lgcov unity)
  target_link_directories(${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/lib)
  add_test(
    NAME ${test_name}
    COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name}
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endfunction()

# Run the C preprocessor on target files. Takes a CMAKE list of arguments to
# pass to the C compiler
function(preprocess_mock_list mock_name file_list compiler_args)
  set_property(GLOBAL PROPERTY ${mock_name}_processed TRUE)
  foreach(target_file IN LISTS file_list)
    # Has to be TARGET ALL so the file is pre-processed before CMOCK is executed
    # on the file.
    add_custom_command(
      OUTPUT ${target_file}.backup
      COMMAND scp ${target_file} ${target_file}.backup
      VERBATIM
      COMMAND ${CMAKE_C_COMPILER} -E ${compiler_args} ${target_file} >
              ${target_file}.out)
    add_custom_target(
      pre_${mock_name}
      COMMAND mv ${target_file}.out ${target_file}
      DEPENDS ${target_file}.backup)
  endforeach()

  # Clean up temporary files that were created. First we test to see if the
  # backup file still exists. If it does we revert the change made to the
  # original file.
  foreach(target_file IN LISTS file_list)
    add_custom_command(
      TARGET ${mock_name}
      POST_BUILD
      COMMAND test ! -e ${target_file}.backup || mv ${target_file}.backup
              ${target_file})
  endforeach()
endfunction()

# Generates a mock library based on a module's header file places the generated
# source file in the build directory @param mock_name: name of the target name
# @param mock_list list of header files to mock @param cmock_config
# configuration file of the cmock framework @param mock_include_list include
# list for the target @param mock_define_list special definitions to control
# compilation
function(create_mock_list mock_name mock_list cmock_config mock_include_list
         mock_define_list)
  set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
  add_library(${mock_name} SHARED)
  foreach(mock_file IN LISTS mock_list)
    get_filename_component(mock_file_abs ${mock_file} ABSOLUTE)
    get_filename_component(mock_file_name ${mock_file} NAME_WLE)
    get_filename_component(mock_file_dir ${mock_file} DIRECTORY)
    add_custom_command(
      OUTPUT ${mocks_dir}/mock_${mock_file_name}.c
      COMMAND ruby ${cmock_SOURCE_DIR}/lib/cmock.rb -o${cmock_config} ${mock_file_abs}
      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
    target_sources(${mock_name} PUBLIC ${mocks_dir}/mock_${mock_file_name}.c)

    target_include_directories(${mock_name} PUBLIC ${mock_file_dir})
  endforeach()
  target_include_directories(${mock_name} PUBLIC ${mocks_dir}
                                                 ${mock_include_list})
  set_target_properties(
    ${mock_name}
    PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
               POSITION_INDEPENDENT_CODE ON)
  target_compile_definitions(${mock_name} PUBLIC ${mock_define_list})
  target_link_libraries(${mock_name} cmock unity)
endfunction()

function(create_real_library target src_file real_include_list mock_name)
  add_library(${target} STATIC ${src_file})
  target_include_directories(${target} PUBLIC ${real_include_list})
  set_target_properties(
    ${target}
    PROPERTIES COMPILE_FLAGS "-Wextra -Wpedantic \
                    -fprofile-arcs -ftest-coverage -fprofile-generate \
                    -Wno-unused-but-set-variable"
               LINK_FLAGS "-fprofile-arcs -ftest-coverage \
                    -fprofile-generate "
               ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
  if(NOT (mock_name STREQUAL ""))
    add_dependencies(${target} ${mock_name})
    target_link_libraries(${target} -l${mock_name} -lgcov)
  endif()
endfunction()
