
function(Octopus_add_fortuno_test name)
    #[===[.md
    # Octopus_add_fortuno_test

     TODO: Use `fortuno_discover_tests` when it is implemented upstream

    Internal helper for registering Fortuno unit-tests

    ## Synopsis
    ```cmake
    Octopus_add_fortuno_test(TARGET <target>
            TEST_NAME <test_name>
            [TESTSUITES <test_suite1> ...]
            [LABELS <label1> ...])
    ```

    ## Options

    `TARGET`
      Target containing the Fortuno app

    `TEST_NAME`
      Name for the test to be used as the ctest name. Must correspond to the test_case name

    `TESTSUITES`
      Nested test-suites to prepend to `TEST_NAME`. Must mirror the test-suite module definition. Note order matters.

    `LABELS`
      Additional labels to be added. This is in addition to the labels that are defined in the `.test` file

    ]===]

    list(APPEND CMAKE_MESSAGE_CONTEXT Octopus_add_test)

    set(ARGS_Options)
    set(ARGS_OneValue
            TARGET
            TEST_NAME
    )
    set(ARGS_MultiValue
            TESTSUITES
            LABELS
    )
    cmake_parse_arguments(PARSE_ARGV 0 ARGS "${ARGS_Options}" "${ARGS_OneValue}" "${ARGS_MultiValue}")
    if (NOT DEFINED ARGS_TARGET)
        message(FATAL_ERROR "Missing TARGET in Octopus_add_fortuno_test call")
    endif ()
    if (NOT DEFINED ARGS_TEST_NAME)
        message(FATAL_ERROR "Missing TEST_NAME in Octopus_add_fortuno_test call")
    endif ()

    set(full_namespace ${ARGS_TESTSUITES} ${ARGS_TEST_NAME})
    list(JOIN full_namespace "/" full_testname)

    # Note, the cleanest way to suppress stderr when running --verbose is to use:
    # COMMAND sh -c "$<TARGET_FILE:${ARGS_TARGET}> ${full_testname} 2>/dev/null"
    add_test(NAME ${full_testname}
            COMMAND $<TARGET_FILE:${ARGS_TARGET}> ${full_testname}
    )
    # Ensure Octopus picks up correct path to variables file when running unit tests
    set_tests_properties(${full_testname} PROPERTIES
        ENVIRONMENT "OCTOPUS_SHARE=${PROJECT_BINARY_DIR}/share"
        )
    if (ARGS_LABELS)
        set_property(TEST ${full_testname} APPEND PROPERTY
                LABELS "${ARGS_LABELS}"
        )
    endif ()
endfunction()

# TODO(Alex) Issue #1040. Remove compiler version guard when Octopus drops foss2022 toolchain
if (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 12)
    message(WARNING "Unit testing support with Fortuno disabled. Requires gfortran >= 12.0.0")
    return()
endif ()

if(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel")
  message(WARNING "Unit testing support with Fortuno disabled. Not tested with Intel")
  return()
endif()

set(FORTUNO_GIT_TAG f83e52c75e41ecb8f3c7ae210e5989a220889376) # latest main as of 2024-11-11
if (OCTOPUS_MPI)
    option(FORTUNO_WITH_MPI "Fortuno: whether to build the MPI interface" ON)
    FetchContent_Declare(
            FortunoMPI
            GIT_REPOSITORY https://github.com/fortuno-repos/fortuno
            GIT_TAG ${FORTUNO_GIT_TAG}
    )
    FetchContent_MakeAvailable(FortunoMPI)
    set(fortuno_libs Fortuno::fortuno_mpi)
else ()
    option(FORTUNO_WITH_MPI "Fortuno: whether to build the MPI interface" OFF)
    FetchContent_Declare(Fortuno
            GIT_REPOSITORY https://github.com/fortuno-repos/fortuno
            GIT_TAG ${FORTUNO_GIT_TAG}
            FIND_PACKAGE_ARGS CONFIG
    )
    FetchContent_MakeAvailable(Fortuno)
    set(fortuno_libs Fortuno::fortuno_serial)
endif ()

# Main driver
add_executable(Octopus_test_suite
        fortuno_app.f90
        fortuno_interface.F90
        setup_teardown.f90
)

target_link_libraries(Octopus_test_suite PRIVATE
        Octopus_base
        Octopus_lib
        ${fortuno_libs}
        $<$<BOOL:${MPI}>:MPI::MPI_Fortran>
)

set_target_properties(Octopus_test_suite PROPERTIES
        OUTPUT_NAME test_suite
        LINKER_LANGUAGE Fortran
)

# All fortuno unit tests to be labelled with `unit_tests` in ctest
set_property(DIRECTORY APPEND
        PROPERTY LABELS unit_tests
)

# Unit test subdirectories
# These mirror the src/ top-level subdirectories, although one is not
# restricted to that convention
add_subdirectory(basic)
add_subdirectory(basis_set)
add_subdirectory(boxes)
add_subdirectory(classical)
add_subdirectory(communication)
add_subdirectory(electrons)
add_subdirectory(grid)
add_subdirectory(hamiltonian)
add_subdirectory(interactions)
add_subdirectory(ions)
add_subdirectory(math)
add_subdirectory(maxwell)
add_subdirectory(mesh)
add_subdirectory(multisystem)
add_subdirectory(opt_control)
add_subdirectory(output)
add_subdirectory(photons)
add_subdirectory(poisson)
add_subdirectory(scf)
add_subdirectory(species)
add_subdirectory(states)
add_subdirectory(sternheimer)
add_subdirectory(td)

add_subdirectory(mock)

# Excluded subdirectories:
# * dftbplus:     No unit testing of external library API
# * include:      Contains definitions
# * utils:        Utilities should be app-tested
