find_package(Boost 1.68 QUIET COMPONENTS unit_test_framework)
if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
    option(OMPL_BUILD_TESTS "Build OMPL tests" ON)
else()
    option(OMPL_BUILD_TESTS "Build OMPL tests" OFF)
endif()
add_feature_info(OMPL_BUILD_TESTS "${OMPL_BUILD_TESTS}" "Whether to build the unit tests.")

if (OMPL_BUILD_TESTS)

    file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/resources" TEST_RESOURCES_DIR)
    string(REPLACE "\\" "\\\\" TEST_RESOURCES_DIR "${TEST_RESOURCES_DIR}")
    add_definitions(-DTEST_RESOURCES_DIR=\"${TEST_RESOURCES_DIR}\")

    # Test datastructures implementation
    add_ompl_test(test_adjacency_list datastructures/adjacency_list.cpp)
    add_ompl_test(test_heap datastructures/heap.cpp)

    if(NOT MSVC)
      add_ompl_test(test_grid datastructures/grid.cpp)
      add_ompl_test(test_gridb datastructures/gridb.cpp)
      add_ompl_test(test_nearestneighbors datastructures/nearestneighbors.cpp)
    endif()

    if(OMPL_HAVE_FLANN)
        # FLANN uses std::random_shuffle in a header file which is removed in C++17
        # https://github.com/flann-lib/flann/issues/387
        set_target_properties(test_nearestneighbors PROPERTIES CXX_STANDARD 14)
    endif()
    add_ompl_test(test_pdf datastructures/pdf.cpp)

    # Test utilities
    add_ompl_test(test_random util/random/random.cpp)
    # optimization flags make this test fail
    if (CMAKE_BUILD_TYPE STREQUAL "Debug")
        add_ompl_test(test_machine_specs benchmark/machine_specs.cpp)
    endif()

    # Test base code
    add_ompl_test(test_halton_sampling base/halton_deterministic_sampling.cpp)
    add_ompl_test(test_state_operations base/state_operations.cpp)
    add_ompl_test(test_state_spaces base/state_spaces.cpp)
    add_ompl_test(test_state_storage base/state_storage.cpp)
    add_ompl_test(test_planner_data base/planner_data.cpp)

    if(NOT MSVC)
      add_ompl_test(test_ptc base/ptc.cpp)
    endif()

    # Test kinematic motion planners in 2D environments
    # add_ompl_test(test_2denvs_geometric geometric/2d/2denvs.cpp) # Test is brittle for github runners
    add_ompl_test(test_2dmap_geometric_simple geometric/2d/2dmap_simple.cpp)
    add_ompl_test(test_2dmap_ik geometric/2d/2dmap_ik.cpp)
    add_ompl_test(test_2dcircles_opt_geometric geometric/2d/2dcircles_optimize.cpp)
    add_ompl_test(test_2dpath_simplifying geometric/2d/2dpath_simplifying.cpp)

    # Test constrained planning
    add_ompl_test(test_constraint_sphere geometric/constraint/test_sphere.cpp)

    # Test space-time planning
    add_ompl_test(test_spacetime_STRRTstar geometric/spacetime/STRRTstar_test.cpp)

    # Test planning with controls on a 2D map
    add_ompl_test(test_2dmap_control control/2dmap/2dmap.cpp)
    add_ompl_test(test_planner_data_control control/planner_data.cpp)

    # Test experience based planning
    add_ompl_test(test_experience_planning tools/test_experience_planning.cpp)

    # Test VAMP integration
    if(OMPL_HAVE_VAMP)
        add_ompl_test(test_vamp_integration util/test_vamp_integration.cpp)
        if(TARGET vamp_cpp)
            target_link_libraries(test_vamp_integration vamp_cpp)
            
            # Apply VAMP SIMD flags to the test to ensure SIMD functionality works
            if(DEFINED VAMP_SIMD_FLAGS)
                target_compile_options(test_vamp_integration PRIVATE ${VAMP_SIMD_FLAGS})
                message(STATUS "Applied VAMP SIMD flags to test_vamp_integration: ${VAMP_SIMD_FLAGS}")
            endif()
            
            message(STATUS "VAMP integration test configured with vamp_cpp target and SIMD flags")
        else()
            message(WARNING "OMPL_HAVE_VAMP is TRUE but vamp_cpp target not found")
        endif()
    endif()

    # Python unit tests
    if(PYTHON_FOUND AND OMPL_BUILD_PYTESTS)
        if (EXISTS "${CMAKE_CURRENT_BINARY_DIR}/../py-bindings/bindings")
            add_ompl_python_test(util/test_util.py)
            add_ompl_python_test(base/test_base.py)
            add_ompl_python_test(geometric/test_geometric.py)
            add_ompl_python_test(geometric/test_geometric_compoundstate.py)
            add_ompl_python_test(control/test_control.py)
        endif()

        # test the python function to std::function conversion utility functions
        include_directories(${PYTHON_INCLUDE_DIRS})
        add_library(py_std_function MODULE util/test_py_std_function.cpp)
        target_link_libraries(py_std_function ompl ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARIES})
        if(WIN32)
            set_target_properties(py_std_function PROPERTIES OUTPUT_NAME py_std_function SUFFIX .pyd)
        endif(WIN32)
        add_custom_command(TARGET py_std_function POST_BUILD
            COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_FILE:py_std_function>"
            "${CMAKE_CURRENT_SOURCE_DIR}/util")
        add_ompl_python_test(util/test_py_std_function.py)
    endif()

    add_subdirectory(regression_tests)
endif()
