cmake_minimum_required(VERSION 3.20)
project(afterburner2-recomp C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type" FORCE)
endif()

option(AB2_ENABLE_IPO "Enable checked release interprocedural optimization (LTO)" ON)
option(AB2_REQUIRE_IPO "Fail configuration if requested LTO is unavailable" OFF)
if(AB2_ENABLE_IPO)
  include(CheckIPOSupported)
  check_ipo_supported(RESULT AB2_IPO_SUPPORTED OUTPUT AB2_IPO_ERROR LANGUAGES CXX)
  if(AB2_IPO_SUPPORTED)
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)
  else()
    if(AB2_REQUIRE_IPO)
      message(FATAL_ERROR "LTO unavailable. Use an LTO-capable compiler (e.g. LLVM-MinGW on Windows).\n${AB2_IPO_ERROR}")
    endif()
    message(WARNING "LTO unavailable: ${AB2_IPO_ERROR}")
  endif()
elseif(AB2_REQUIRE_IPO)
  message(FATAL_ERROR "AB2_REQUIRE_IPO requires AB2_ENABLE_IPO=ON")
endif()

# Match the optimized Make build without changing floating-point semantics or
# requiring the build machine's CPU instruction set on distribution machines.
if(MSVC)
  add_compile_options($<$<CONFIG:Release,RelWithDebInfo>:/O2>)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
  add_compile_options($<$<CONFIG:Release,RelWithDebInfo>:-O3>)
endif()

if(ANDROID)
  set(AB2_SDL_SOURCE "${CMAKE_SOURCE_DIR}/build/deps/SDL3-3.4.16" CACHE PATH "Pinned SDL3 source")
  set(SDL_SHARED ON CACHE BOOL "" FORCE)
  set(SDL_STATIC OFF CACHE BOOL "" FORCE)
  add_subdirectory("${AB2_SDL_SOURCE}" "${CMAKE_BINARY_DIR}/SDL3")
  set(CMAKE_POSITION_INDEPENDENT_CODE ON)
else()
  find_package(SDL3 3.4 REQUIRED CONFIG COMPONENTS SDL3)
endif()
find_package(Threads REQUIRED)

# The optional Slang runtime is dynamically loaded; no downloaded library is
# required to build or run the original frontend.
if(APPLE)
  enable_language(OBJCXX)
  add_library(ab2_slang STATIC src/main/frontend/native_slang.mm src/main/frontend/native_metal_sprite_filter.mm)
  set_target_properties(ab2_slang PROPERTIES OBJCXX_STANDARD 20 OBJCXX_STANDARD_REQUIRED ON)
  target_compile_options(ab2_slang PRIVATE -fobjc-arc)
  target_link_libraries(ab2_slang PRIVATE "-framework Foundation" "-framework Metal" "-framework QuartzCore" "-framework CoreVideo")
elseif(WIN32 OR (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
  set(AB2_NATIVE_VULKAN ON)
  find_path(AB2_VULKAN_INCLUDE_DIR vulkan/vulkan.h
    HINTS "$ENV{VULKAN_SDK}/Include" "${CMAKE_SOURCE_DIR}/build/deps/Vulkan-Headers-1.4.341/include"
    REQUIRED)
  add_library(ab2_slang STATIC src/main/frontend/native_slang_vulkan.cpp src/main/frontend/native_vulkan_sprite_filter.cpp)
  # Native Windows/Linux CMake entrypoints use this compositor. Make builds
  # retain their existing stub host and do not link the Vulkan implementation.
  set_property(SOURCE src/main/main.cpp tests/native_shader_main_integration.cpp
    APPEND PROPERTY COMPILE_DEFINITIONS AB2_NATIVE_VULKAN_SPRITES)
  target_include_directories(ab2_slang PRIVATE "${AB2_VULKAN_INCLUDE_DIR}")
else()
  add_library(ab2_slang STATIC src/main/frontend/native_slang_stub.cpp)
endif()
target_include_directories(ab2_slang PUBLIC src/main)
target_link_libraries(ab2_slang PUBLIC SDL3::SDL3)
option(AB2_ENABLE_OPENAL "Enable optional OpenAL Soft spatial audio" ON)
if(AB2_ENABLE_OPENAL)
  find_package(OpenAL QUIET CONFIG HINTS "${CMAKE_SOURCE_DIR}/build/deps/openal")
  if(TARGET OpenAL::OpenAL)
    set(AB2_OPENAL_TARGET OpenAL::OpenAL)
  else()
    find_package(PkgConfig QUIET)
    if(PkgConfig_FOUND)
      pkg_check_modules(OPENAL QUIET IMPORTED_TARGET openal)
      if(TARGET PkgConfig::OPENAL)
        set(AB2_OPENAL_TARGET PkgConfig::OPENAL)
      endif()
    endif()
  endif()
endif()


set(AB2_APP_SOURCES
    src/main/main.cpp
    src/main/frontend/music_decoder.cpp
    src/main/romloader.cpp
    src/main/roms.cpp
    src/main/hwvideo/hwroad.cpp
    src/main/hwvideo/hwsprites.cpp
    src/main/hwvideo/hwtiles.cpp
    src/main/hwvideo/hwpalette.cpp
    src/main/hwvideo/screen.cpp
    src/main/hwaudio/arcade_audio.cpp
    src/third_party/ymfm/ymfm_opm.cpp
    src/main/hwaudio/xboard_sound_cpu.cpp
    src/main/hwaudio/soundchip.cpp
    src/main/hwaudio/segapcm.cpp
    src/main/hwaudio/ym2151.cpp
    src/main/engine/ohud.cpp
    src/main/engine/osprites.cpp
    src/main/engine/omaininput.cpp
    src/main/engine/omainplayer.cpp
    src/main/engine/omaindamage.cpp src/main/engine/omainsequence.cpp
    src/main/engine/omainworld.cpp src/main/engine/omainweapons.cpp
    src/main/engine/omainobjects.cpp
    src/main/engine/omainhost.cpp
    src/main/engine/omainsound.cpp
    src/main/engine/omainpalette.cpp
    src/main/engine/omainframe.cpp
    src/main/engine/omainsprites.cpp
    src/main/engine/osubsprites.cpp
    src/main/engine/olevelobjs.cpp
    src/main/engine/oengine.cpp
    src/main/engine/subbus.cpp
    src/main/engine/mainbus.cpp
    src/main/engine/omainadc.cpp
    src/main/engine/omainirqservice.cpp src/main/engine/omainirqcallee.cpp
    src/main/engine/oscenery.cpp
    src/main/engine/ostagesetup.cpp
    src/main/engine/osubroad.cpp
    src/main/engine/osubirq.cpp src/main/engine/osubprogress.cpp src/main/engine/osubpublication.cpp
)
if(ANDROID)
  add_library(afterburner2 SHARED ${AB2_APP_SOURCES})
  set_target_properties(afterburner2 PROPERTIES OUTPUT_NAME main)
  option(AB2_ANDROID_WORKER_CONTINUATION "Use worker CPU continuations for Android comparison" OFF)
  if(AB2_ANDROID_WORKER_CONTINUATION)
    target_compile_definitions(afterburner2 PRIVATE AB2_FORCE_THREAD_CONTINUATION)
  endif()
  # Explicit device-side ABI/lifecycle checks; never included in the APK.
  foreach(backend stack worker)
    add_executable(android_continuation_${backend} EXCLUDE_FROM_ALL tests/cpu_continuation_regression.cpp)
    target_include_directories(android_continuation_${backend} PRIVATE src/main)
    target_link_libraries(android_continuation_${backend} PRIVATE Threads::Threads)
  endforeach()
  target_compile_definitions(android_continuation_worker PRIVATE AB2_FORCE_THREAD_CONTINUATION)
  add_executable(android_whole_host EXCLUDE_FROM_ALL tests/oracle_whole_host.cpp)
  target_include_directories(android_whole_host PRIVATE src/main)
  target_link_libraries(android_whole_host PRIVATE afterburner2 Threads::Threads)
  if(AB2_ANDROID_WORKER_CONTINUATION)
    target_compile_definitions(android_whole_host PRIVATE AB2_FORCE_THREAD_CONTINUATION)
  endif()
else()
  add_executable(afterburner2 ${AB2_APP_SOURCES})
endif()

if(AB2_OPENAL_TARGET)
  target_compile_definitions(afterburner2 PRIVATE AB2_OPENAL=1)
  target_link_libraries(afterburner2 PRIVATE ${AB2_OPENAL_TARGET})
  if(WIN32 AND TARGET OpenAL::OpenAL)
    add_custom_command(TARGET afterburner2 POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:OpenAL::OpenAL> $<TARGET_FILE_DIR:afterburner2>)
  endif()
endif()
target_include_directories(afterburner2 PRIVATE src/main)
target_link_libraries(afterburner2 PRIVATE SDL3::SDL3 Threads::Threads ab2_slang)
if(WIN32)
  add_custom_command(TARGET afterburner2 POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:SDL3::SDL3> $<TARGET_FILE_DIR:afterburner2>)
  if(MINGW)
    get_filename_component(AB2_COMPILER_BIN "${CMAKE_CXX_COMPILER}" DIRECTORY)
    foreach(runtime libc++.dll libunwind.dll libwinpthread-1.dll)
      if(EXISTS "${AB2_COMPILER_BIN}/${runtime}")
        add_custom_command(TARGET afterburner2 POST_BUILD
          COMMAND ${CMAKE_COMMAND} -E copy_if_different "${AB2_COMPILER_BIN}/${runtime}" $<TARGET_FILE_DIR:afterburner2>)
      endif()
    endforeach()
  endif()
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
  target_compile_options(afterburner2 PRIVATE -Wall -Wextra)
endif()

include(CTest)
if(BUILD_TESTING)
    find_package(Python3 REQUIRED COMPONENTS Interpreter)
    add_test(NAME android_benchmark_regression COMMAND ${Python3_EXECUTABLE}
      ${CMAKE_SOURCE_DIR}/tests/android_benchmark_regression.py)
    add_executable(native_touch_regression tests/native_touch_regression.cpp)
    target_include_directories(native_touch_regression PRIVATE src/main)
    target_link_libraries(native_touch_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_touch_regression COMMAND native_touch_regression)
    set_tests_properties(native_touch_regression PROPERTIES ENVIRONMENT "SDL_VIDEODRIVER=dummy")
    add_executable(frame_pacing_regression tests/frame_pacing_regression.cpp)
    target_include_directories(frame_pacing_regression PRIVATE src/main)
    add_test(NAME frame_pacing_regression COMMAND frame_pacing_regression)
    add_executable(native_rom_picker_regression tests/native_rom_picker_regression.cpp)
    target_include_directories(native_rom_picker_regression PRIVATE src/main)
    target_link_libraries(native_rom_picker_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_rom_picker COMMAND native_rom_picker_regression)
    add_executable(romloader_regression tests/romloader_regression.cpp src/main/romloader.cpp)
    target_include_directories(romloader_regression PRIVATE src/main)
    if(WIN32)
      target_link_libraries(romloader_regression PRIVATE shell32)
    endif()
    add_test(NAME romloader_zip COMMAND ${Python3_EXECUTABLE}
        ${CMAKE_SOURCE_DIR}/tests/test_romloader_zip.py $<TARGET_FILE:romloader_regression>)
    add_executable(video_clip_regression tests/video_clip_regression.cpp src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp)
    target_include_directories(video_clip_regression PRIVATE src/main)
    add_test(NAME video_clips COMMAND video_clip_regression)
    add_executable(integrated_renderer_regression tests/integrated_renderer_regression.cpp
        src/main/hwvideo/screen.cpp src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp
        src/main/hwvideo/hwsprites.cpp src/main/hwvideo/hwpalette.cpp)
    target_include_directories(integrated_renderer_regression PRIVATE src/main)
    add_test(NAME integrated_renderer_regression COMMAND integrated_renderer_regression)
    add_test(NAME integrated_renderer_mutations COMMAND ${Python3_EXECUTABLE}
        ${CMAKE_SOURCE_DIR}/tools/video/check_integrated_renderer_mutations.py
        --compiler ${CMAKE_CXX_COMPILER} --runtime-dir ${CMAKE_BINARY_DIR})
    add_test(NAME video_clip_mutations COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/oracle/check_video_clip_mutations.py)
    find_package(Threads REQUIRED)


    add_executable(game_controls_regression tests/game_controls_regression.cpp)
    target_include_directories(game_controls_regression PRIVATE src/main)
    add_test(NAME game_controls_regression COMMAND game_controls_regression)
    add_executable(shuffle_rom_regression tests/shuffle_rom_regression.cpp src/main/roms.cpp src/main/romloader.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(shuffle_rom_regression PRIVATE src/main)
    add_test(NAME shuffle_rom_regression COMMAND shuffle_rom_regression)
    set_tests_properties(shuffle_rom_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(sprite_filter_regression tests/sprite_filter_regression.cpp)
    target_include_directories(sprite_filter_regression PRIVATE src/main tests/scalers_reference)
    add_test(NAME sprite_filter_regression COMMAND sprite_filter_regression)
    add_test(NAME fragment_mutations COMMAND ${CMAKE_COMMAND} -E env
        "CXX=${CMAKE_CXX_COMPILER}" ${Python3_EXECUTABLE}
        ${CMAKE_SOURCE_DIR}/tools/scalers/check_fragment_mutations.py)
    add_executable(native_music_regression tests/native_music_regression.cpp src/main/frontend/music_decoder.cpp src/third_party/ymfm/ymfm_opm.cpp)
    target_include_directories(native_music_regression PRIVATE src/main)
    target_link_libraries(native_music_regression PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME native_music_fixtures COMMAND ${Python3_EXECUTABLE} tools/audio/generate_test_audio.py)
    set_tests_properties(native_music_fixtures PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} FIXTURES_SETUP music_tones)
    add_test(NAME native_music_regression COMMAND native_music_regression)
    set_tests_properties(native_music_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ENVIRONMENT "SDL_AUDIODRIVER=dummy" FIXTURES_REQUIRED music_tones)
    add_executable(native_haptics_regression tests/native_haptics_regression.cpp)
    target_include_directories(native_haptics_regression PRIVATE src/main)
    target_link_libraries(native_haptics_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_haptics_regression COMMAND native_haptics_regression)
    add_executable(native_input_regression tests/native_input_regression.cpp)
    target_include_directories(native_input_regression PRIVATE src/main)
    target_link_libraries(native_input_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_input_regression COMMAND native_input_regression)
    add_executable(native_settings_regression tests/native_settings_regression.cpp)
    target_include_directories(native_settings_regression PRIVATE src/main)
    add_test(NAME native_settings_regression COMMAND native_settings_regression)
    set_tests_properties(native_settings_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(hud_scene_regression tests/hud_scene_regression.cpp src/main/romloader.cpp src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp src/main/hwvideo/hwpalette.cpp)
    target_include_directories(hud_scene_regression PRIVATE src/main)
    add_test(NAME hud_scene_regression COMMAND hud_scene_regression)
    add_executable(native_hud_regression tests/native_hud_regression.cpp src/main/romloader.cpp)
    target_include_directories(native_hud_regression PRIVATE src/main)
    target_link_libraries(native_hud_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_hud_regression COMMAND native_hud_regression)
    set_tests_properties(native_hud_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ENVIRONMENT "SDL_VIDEODRIVER=dummy")
    add_custom_target(verify-gpu-hud COMMAND native_hud_regression --gpu
        DEPENDS native_hud_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(native_player_aircraft_regression tests/native_player_aircraft_regression.cpp)
    target_include_directories(native_player_aircraft_regression PRIVATE src/main)
    target_link_libraries(native_player_aircraft_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_player_aircraft_regression COMMAND native_player_aircraft_regression)
    set_tests_properties(native_player_aircraft_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ENVIRONMENT "SDL_VIDEODRIVER=dummy")
    add_custom_target(verify-gpu-player-aircraft COMMAND native_player_aircraft_regression --gpu
        DEPENDS native_player_aircraft_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(native_crt_regression tests/native_crt_regression.cpp)
    target_include_directories(native_crt_regression PRIVATE src/main)
    target_link_libraries(native_crt_regression PRIVATE SDL3::SDL3)
    add_test(NAME native_crt_regression COMMAND native_crt_regression)
    set_tests_properties(native_crt_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ENVIRONMENT "SDL_VIDEODRIVER=dummy")
    add_custom_target(verify-gpu-crt COMMAND native_crt_regression --gpu
        DEPENDS native_crt_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_test(NAME librashader_fetch_regression COMMAND ${Python3_EXECUTABLE} tests/test_fetch_librashader.py)
    set_tests_properties(librashader_fetch_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    if(APPLE OR AB2_NATIVE_VULKAN)
      add_executable(native_slang_integration tests/native_slang_integration.mm)
      if(APPLE)
        set_target_properties(native_slang_integration PROPERTIES OBJCXX_STANDARD 20 OBJCXX_STANDARD_REQUIRED ON)
      else()
        set_source_files_properties(tests/native_slang_integration.mm PROPERTIES LANGUAGE CXX)
      endif()
      target_link_libraries(native_slang_integration PRIVATE ab2_slang)
      add_custom_target(verify-native-slang COMMAND native_slang_integration
          DEPENDS native_slang_integration WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
      if(APPLE)
        add_executable(native_metal_sprite_filter_regression tests/gpu_sprite_filter_regression.cpp)
        target_compile_definitions(native_metal_sprite_filter_regression PRIVATE AB2_NATIVE_METAL_SPRITES)
        target_link_libraries(native_metal_sprite_filter_regression PRIVATE ab2_slang)
        add_custom_target(verify-native-metal-sprite-filters COMMAND native_metal_sprite_filter_regression
            DEPENDS native_metal_sprite_filter_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        add_custom_target(verify-native-metal-sprite-mutations
            COMMAND ${Python3_EXECUTABLE} tools/scalers/check_native_metal_mutations.py
            DEPENDS verify-native-metal-sprite-filters WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        add_custom_target(verify-native-slang-mutations
          COMMAND ${Python3_EXECUTABLE} tools/video/check_native_slang_mutations.py
          DEPENDS verify-native-slang WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
      elseif(AB2_NATIVE_VULKAN)
        add_executable(native_vulkan_sprite_filter_regression tests/gpu_sprite_filter_regression.cpp)
        target_compile_definitions(native_vulkan_sprite_filter_regression PRIVATE AB2_NATIVE_VULKAN_SPRITES)
        target_link_libraries(native_vulkan_sprite_filter_regression PRIVATE ab2_slang)
        add_custom_target(verify-native-vulkan-sprite-filters COMMAND native_vulkan_sprite_filter_regression
            DEPENDS native_vulkan_sprite_filter_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        add_custom_target(verify-native-vulkan-sprite-mutations
            COMMAND ${Python3_EXECUTABLE} tools/scalers/check_native_vulkan_mutations.py --build-dir ${CMAKE_BINARY_DIR}
            DEPENDS verify-native-vulkan-sprite-filters WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        add_custom_target(verify-native-slang-mutations
          COMMAND ${Python3_EXECUTABLE} tools/video/check_native_slang_vulkan_mutations.py --build-dir ${CMAKE_BINARY_DIR}
          DEPENDS verify-native-slang WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
      endif()
    endif()
    add_executable(gpu_sprite_filter_regression tests/gpu_sprite_filter_regression.cpp)
    target_include_directories(gpu_sprite_filter_regression PRIVATE src/main)
    target_link_libraries(gpu_sprite_filter_regression PRIVATE SDL3::SDL3)
    # GPU validation is explicit; ordinary headless CTest retains CPU references.
    add_custom_target(verify-gpu-sprite-filters
        COMMAND gpu_sprite_filter_regression DEPENDS gpu_sprite_filter_regression
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(cpu_continuation_regression tests/cpu_continuation_regression.cpp)
    target_include_directories(cpu_continuation_regression PRIVATE src/main)
    target_link_libraries(cpu_continuation_regression PRIVATE Threads::Threads)
    add_test(NAME cpu_continuation_regression COMMAND cpu_continuation_regression)
    add_executable(cpu_continuation_thread_regression tests/cpu_continuation_regression.cpp)
    target_include_directories(cpu_continuation_thread_regression PRIVATE src/main)
    target_compile_definitions(cpu_continuation_thread_regression PRIVATE AB2_FORCE_THREAD_CONTINUATION)
    target_link_libraries(cpu_continuation_thread_regression PRIVATE Threads::Threads)
    add_test(NAME cpu_continuation_thread_regression COMMAND cpu_continuation_thread_regression)
    add_executable(audio_deadline_regression tests/audio_deadline_regression.cpp src/third_party/ymfm/ymfm_opm.cpp)
    target_include_directories(audio_deadline_regression PRIVATE src/main)
    add_test(NAME audio_deadline_regression COMMAND audio_deadline_regression)
    add_executable(sound_cpu_regression tests/sound_cpu_regression.cpp src/main/hwaudio/xboard_sound_cpu.cpp)
    target_include_directories(sound_cpu_regression PRIVATE src/main)
    add_test(NAME sound_cpu_regression COMMAND sound_cpu_regression)
    add_executable(oracle_sound_boot tests/oracle_sound_boot.cpp src/main/hwaudio/xboard_sound_cpu.cpp)
    target_include_directories(oracle_sound_boot PRIVATE src/main)
    add_test(NAME oracle_sound_boot COMMAND oracle_sound_boot build/oracle/sound_boot.bin)
    set_tests_properties(oracle_sound_boot PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_sound_execution tests/oracle_sound_execution.cpp src/main/hwaudio/xboard_sound_cpu.cpp src/third_party/ymfm/ymfm_opm.cpp)
    target_include_directories(oracle_sound_execution PRIVATE src/main)
    add_test(NAME oracle_sound_execution COMMAND oracle_sound_execution build/oracle/sound_execution.bin build/oracle/sound_execution.txt)
    add_test(NAME oracle_sound_irq COMMAND oracle_sound_execution build/oracle/sound_irq.bin build/oracle/sound_irq.txt)
    set_tests_properties(oracle_sound_execution oracle_sound_irq PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_sound_audio_irq COMMAND oracle_sound_execution build/oracle/sound_audio_irq.bin build/oracle/sound_audio_irq.txt --native-audio)
    add_test(NAME oracle_sound_audio_timer_b COMMAND oracle_sound_execution build/oracle/sound_audio_timer_b.bin build/oracle/sound_audio_timer_b.txt --native-audio)
    set_tests_properties(oracle_sound_audio_irq oracle_sound_audio_timer_b PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_pcm tests/oracle_pcm.cpp src/main/romloader.cpp)
    target_include_directories(oracle_pcm PRIVATE src/main)
    add_test(NAME oracle_pcm COMMAND oracle_pcm build/oracle/pcm.bin)
    add_test(NAME oracle_pcm_directed COMMAND oracle_pcm build/oracle/pcm_directed.bin --require-directed)
    add_test(NAME oracle_pcm_synthetic COMMAND oracle_pcm build/oracle/pcm_synthetic.bin --require-directed)
    set_tests_properties(oracle_pcm oracle_pcm_directed oracle_pcm_synthetic PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(xboard_timeline_regression tests/xboard_timeline_regression.cpp)
    target_include_directories(xboard_timeline_regression PRIVATE src/main)
    add_test(NAME xboard_timeline_regression COMMAND xboard_timeline_regression)
    add_executable(xboard_irq_lines_regression tests/xboard_irq_lines_regression.cpp)
    target_include_directories(xboard_irq_lines_regression PRIVATE src/main)
    add_test(NAME xboard_irq_lines_regression COMMAND xboard_irq_lines_regression)
    add_executable(mainbus_regression tests/mainbus_regression.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(mainbus_regression PRIVATE src/main)
    add_test(NAME mainbus_regression COMMAND mainbus_regression)
    add_executable(engine_regression
        tests/engine_regression.cpp
        src/main/engine/ohud.cpp
        src/main/engine/osprites.cpp
        src/main/engine/omaininput.cpp
    src/main/engine/omainplayer.cpp
    src/main/engine/omaindamage.cpp src/main/engine/omainsequence.cpp
    src/main/engine/omainworld.cpp src/main/engine/omainweapons.cpp
    src/main/engine/omainobjects.cpp
        src/main/engine/omainhost.cpp
        src/main/engine/omainsound.cpp
        src/main/engine/omainpalette.cpp
    src/main/engine/omainframe.cpp
    src/main/engine/omainsprites.cpp
    src/main/engine/osubsprites.cpp
        src/main/engine/olevelobjs.cpp
        src/main/engine/oengine.cpp
        src/main/engine/subbus.cpp
        src/main/engine/mainbus.cpp
        src/main/engine/oscenery.cpp
        src/main/engine/ostagesetup.cpp
        src/main/engine/osubroad.cpp
        src/main/hwvideo/hwroad.cpp
        src/main/hwvideo/hwsprites.cpp
        src/main/hwvideo/hwtiles.cpp
        src/main/hwvideo/hwpalette.cpp
        src/main/hwvideo/screen.cpp
    )
    target_include_directories(engine_regression PRIVATE src/main)
    add_test(NAME engine_regression COMMAND engine_regression)
endif()

option(ORACLE_TESTS "Enable tests against MAME captures in build/oracle (see make oracle-capture)" OFF)
if(BUILD_TESTING AND ORACLE_TESTS)
    add_executable(oracle_handlers tests/oracle_handlers.cpp src/main/engine/omainsprites.cpp
        src/main/engine/omaininput.cpp src/main/engine/omainplayer.cpp
        src/main/engine/omaindamage.cpp src/main/engine/omainsequence.cpp src/main/engine/omainworld.cpp src/main/engine/omainweapons.cpp
        src/main/engine/omainobjects.cpp src/main/engine/omainhost.cpp
        src/main/engine/omainsound.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_handlers PRIVATE src/main)
    add_test(NAME oracle_wide_explosions COMMAND oracle_handlers build/oracle/wide_explosions_directed.bin --explosion-coverage)
    set_tests_properties(oracle_wide_explosions PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_wide_hit_effects COMMAND oracle_handlers build/oracle/wide_hit_effects_directed.bin --hit-effect-coverage)
    set_tests_properties(oracle_wide_hit_effects PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_wide_trail_frontier COMMAND oracle_handlers build/oracle/wide_trail_effects_frontier.bin)
    set_tests_properties(oracle_wide_trail_frontier PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_wide_trail_effects COMMAND oracle_handlers build/oracle/wide_trail_effects_directed.bin --trail-effect-coverage)
    set_tests_properties(oracle_wide_trail_effects PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    foreach(CAPTURE host_entries_directed input input_gameplay input_directed input_endpoints buttons_endpoints player_init player player_directed player_parts player_parts_gameplay player_parts_directed reload reload_directed weapon_control weapon_control_directed world world_directed buttons buttons_directed projectiles projectiles_directed missiles missiles_directed effects_directed collision_directed enemy_weapons_directed enemy_parts_directed enemy_effects enemy_effects_gameplay damage_directed damage_gameplay companion_directed companion_gameplay sequence_directed sequence_gameplay enemy_tracking_directed enemy_tracking_gameplay world_graph_directed refuel_parts_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_handlers build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_executable(oracle_host_objects tests/oracle_host_objects.cpp src/main/engine/omainsprites.cpp
        src/main/engine/omainhost.cpp src/main/engine/omaininput.cpp
        src/main/engine/omainplayer.cpp src/main/engine/omaindamage.cpp
        src/main/engine/omainsequence.cpp src/main/engine/omainworld.cpp
        src/main/engine/omainweapons.cpp src/main/engine/omainobjects.cpp
        src/main/engine/omainsound.cpp src/main/engine/mainbus.cpp
        src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_host_objects PRIVATE src/main)
    foreach(CAPTURE host_objects host_objects_endpoints)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_host_objects build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    set(HOST_ACCEPTANCE_SOURCES
        src/main/engine/omainsprites.cpp src/main/engine/omainhost.cpp
        src/main/engine/omainobjects.cpp src/main/engine/omaininput.cpp
        src/main/engine/omainplayer.cpp src/main/engine/omaindamage.cpp
        src/main/engine/omainsequence.cpp src/main/engine/omainworld.cpp
        src/main/engine/omainweapons.cpp src/main/engine/omainsound.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp
        src/main/engine/omainadc.cpp src/main/engine/omainframe.cpp
        src/main/engine/omainpalette.cpp src/main/engine/oscenery.cpp
        src/main/roms.cpp src/main/romloader.cpp)
    add_executable(oracle_host_interleave tests/oracle_host_interleave.cpp ${HOST_ACCEPTANCE_SOURCES})
    add_executable(oracle_frame_host tests/oracle_frame_host.cpp ${HOST_ACCEPTANCE_SOURCES})
    add_executable(oracle_sound_stream tests/oracle_sound_stream.cpp
        src/main/engine/omainsound.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    foreach(TEST oracle_host_interleave oracle_frame_host oracle_sound_stream)
        target_include_directories(${TEST} PRIVATE src/main)
    endforeach()
    add_test(NAME oracle_host_prefix COMMAND oracle_host_interleave build/oracle/host_prefix.bin build/oracle/host_requests.bin)
    add_test(NAME oracle_host_publication COMMAND oracle_host_interleave build/oracle/host_publication.bin)
    add_test(NAME oracle_paired_objects COMMAND oracle_host_interleave build/oracle/paired_objects.bin build/oracle/paired_requests.bin)
    add_test(NAME oracle_paired_frame COMMAND oracle_frame_host build/oracle/paired_frame.bin)
    add_test(NAME oracle_paired_sound COMMAND oracle_sound_stream build/oracle/paired_sound.bin)
    set_tests_properties(oracle_host_prefix oracle_host_publication oracle_paired_objects oracle_paired_frame oracle_paired_sound PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_board tests/oracle_board.cpp)
    target_include_directories(oracle_board PRIVATE src/main)
    foreach(CAPTURE board board_endpoints board_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_board build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_executable(oracle_adc_timing tests/oracle_adc_timing.cpp)
    target_include_directories(oracle_adc_timing PRIVATE src/main)
    foreach(CAPTURE adc_timing adc_timing_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_adc_timing build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_executable(oracle_irq_service tests/oracle_irq_service.cpp
        src/main/engine/omainirqservice.cpp src/main/engine/omainirqcallee.cpp src/main/engine/mainbus.cpp
        src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_irq_service PRIVATE src/main)
    foreach(CAPTURE service service_endpoints service_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_irq_service build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_executable(oracle_mainirq tests/oracle_mainirq.cpp
        src/main/engine/omainadc.cpp src/main/engine/omainsound.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(oracle_mainirq PRIVATE src/main)
    foreach(CAPTURE mainirq mainirq_endpoints)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_mainirq build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_executable(oracle_objects tests/oracle_objects.cpp ${HOST_ACCEPTANCE_SOURCES})
    target_include_directories(oracle_objects PRIVATE src/main)
    foreach(CAPTURE objects objects_gameplay objects_directed object_leaves object_leaves_directed object_calls_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_objects build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    foreach(PORT palette mainsprites mainframe)
        set(PORT_SOURCE src/main/engine/omain${PORT}.cpp)
        if(PORT STREQUAL "mainframe")
            set(PORT_SOURCE src/main/engine/omainframe.cpp)
        elseif(PORT STREQUAL "mainsprites")
            set(PORT_SOURCE src/main/engine/omainsprites.cpp)
        endif()
        add_executable(oracle_${PORT} tests/oracle_${PORT}.cpp ${PORT_SOURCE}
            src/main/romloader.cpp src/main/roms.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
        if(PORT STREQUAL "palette")
            target_sources(oracle_${PORT} PRIVATE src/main/engine/omainframe.cpp)
        endif()
        target_include_directories(oracle_${PORT} PRIVATE src/main)
        add_test(NAME oracle_${PORT} COMMAND oracle_${PORT} build/oracle/${PORT}.bin)
        add_test(NAME oracle_${PORT}_directed COMMAND oracle_${PORT} build/oracle/${PORT}_directed.bin)
        set_tests_properties(oracle_${PORT} oracle_${PORT}_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_test(NAME oracle_spriteinit COMMAND oracle_mainsprites build/oracle/spriteinit.bin)
    set_tests_properties(oracle_spriteinit PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_stagesetup tests/oracle_stagesetup.cpp src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp src/main/engine/ostagesetup.cpp)
    target_include_directories(oracle_stagesetup PRIVATE src/main)
    add_test(NAME oracle_stagesetup COMMAND oracle_stagesetup build/oracle/stagesetup.bin)
    add_test(NAME oracle_stagesetup_control COMMAND oracle_stagesetup build/oracle/stagesetup_control.bin)
    add_test(NAME oracle_stagesetup_alternate COMMAND oracle_stagesetup build/oracle/stagesetup_alternate.bin)
    set_tests_properties(oracle_stagesetup oracle_stagesetup_alternate oracle_stagesetup_control PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_scenery tests/oracle_scenery.cpp src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp src/main/engine/oscenery.cpp)
    target_include_directories(oracle_scenery PRIVATE src/main)
    add_test(NAME oracle_scenery COMMAND oracle_scenery build/oracle/scenery.bin)
    add_test(NAME oracle_scenery_extended COMMAND oracle_scenery build/oracle/scenery_extended.bin)
    add_test(NAME oracle_scenery_gameplay COMMAND oracle_scenery build/oracle/scenery_gameplay.bin)
    set_tests_properties(oracle_scenery oracle_scenery_extended oracle_scenery_gameplay
        PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_main tests/oracle_main.cpp src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/mainbus.cpp src/main/engine/subbus.cpp src/main/engine/omainadc.cpp src/main/engine/omainsound.cpp)
    target_include_directories(oracle_main PRIVATE src/main)
    add_test(NAME oracle_main COMMAND oracle_main build/oracle/main.bin)
    add_test(NAME oracle_main_gameplay COMMAND oracle_main build/oracle/main_gameplay.bin)
    set_tests_properties(oracle_main oracle_main_gameplay PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_compare tests/oracle_compare.cpp)
    target_include_directories(oracle_compare PRIVATE src/main)
    add_test(NAME oracle_compare COMMAND oracle_compare)
    set_tests_properties(oracle_compare PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subsprites tests/oracle_subsprites.cpp
        src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/subbus.cpp src/main/engine/osubsprites.cpp)
    target_include_directories(oracle_subsprites PRIVATE src/main)
    add_test(NAME oracle_subsprites COMMAND oracle_subsprites)
    add_test(NAME oracle_subsprites_directed COMMAND oracle_subsprites build/oracle/subsprites_directed.bin)
    add_test(NAME oracle_subsprites_gameplay COMMAND oracle_subsprites build/oracle/subsprites_gameplay.bin)
    set_tests_properties(oracle_subsprites oracle_subsprites_directed oracle_subsprites_gameplay PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subpublication tests/oracle_subpublication.cpp
        src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/subbus.cpp src/main/engine/osubpublication.cpp)
    target_include_directories(oracle_subpublication PRIVATE src/main)
    add_test(NAME oracle_subpublication_short COMMAND oracle_subpublication build/oracle/subpublication_short.bin)
    add_test(NAME oracle_subpublication_directed COMMAND oracle_subpublication build/oracle/subpublication_directed.bin --require-endpoints)
    add_test(NAME oracle_subpublication COMMAND oracle_subpublication build/oracle/subpublication.bin)
    set_tests_properties(oracle_subpublication_short oracle_subpublication_directed oracle_subpublication PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subprogress tests/oracle_subprogress.cpp
        src/main/romloader.cpp src/main/roms.cpp src/main/engine/subbus.cpp
        src/main/engine/osubpublication.cpp src/main/engine/osubprogress.cpp)
    target_include_directories(oracle_subprogress PRIVATE src/main)
    add_test(NAME oracle_subprogress_short COMMAND oracle_subprogress build/oracle/subprogress_short.bin)
    add_test(NAME oracle_subprogress_directed COMMAND oracle_subprogress build/oracle/subprogress_directed.bin --require-endpoints)
    add_test(NAME oracle_subprogress_full COMMAND oracle_subprogress build/oracle/subprogress.bin)
    set_tests_properties(oracle_subprogress_short oracle_subprogress_directed oracle_subprogress_full PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subirq tests/oracle_subirq.cpp
        src/main/romloader.cpp src/main/roms.cpp src/main/engine/subbus.cpp
        src/main/engine/osubpublication.cpp src/main/engine/osubprogress.cpp src/main/engine/osubirq.cpp)
    target_include_directories(oracle_subirq PRIVATE src/main)
    add_test(NAME oracle_subirq_short COMMAND oracle_subirq build/oracle/subirq_short.bin)
    add_test(NAME oracle_subirq_directed COMMAND oracle_subirq build/oracle/subirq_directed.bin --require-endpoints)
    add_test(NAME oracle_subirq_full COMMAND oracle_subirq build/oracle/subirq.bin)
    set_tests_properties(oracle_subirq_short oracle_subirq_directed oracle_subirq_full PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subreset tests/oracle_subreset.cpp src/main/engine/osubirq.cpp
        src/main/engine/osubprogress.cpp src/main/engine/osubpublication.cpp
        src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_subreset PRIVATE src/main)
    add_test(NAME oracle_subreset COMMAND oracle_subreset build/oracle/subreset.bin)
    set_tests_properties(oracle_subreset PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_bus_arbiter tests/oracle_bus_arbiter.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(oracle_bus_arbiter PRIVATE src/main)
    add_executable(oracle_publication_schedule tests/oracle_publication_schedule.cpp src/main/hwaudio/xboard_sound_cpu.cpp src/third_party/ymfm/ymfm_opm.cpp
        src/main/hwvideo/hwsprites.cpp src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp src/main/hwvideo/hwpalette.cpp src/main/hwvideo/screen.cpp
        src/main/engine/omainirqservice.cpp src/main/engine/omainirqcallee.cpp src/main/engine/mainbus.cpp
        src/main/engine/osubpublication.cpp src/main/engine/osubprogress.cpp src/main/engine/osubirq.cpp src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_publication_schedule PRIVATE src/main)
    target_link_libraries(oracle_publication_schedule PRIVATE Threads::Threads)
    add_test(NAME oracle_publication_schedule COMMAND oracle_publication_schedule build/oracle/publication_schedule.bin build/oracle/publication_schedule.txt)
    add_test(NAME oracle_joint_main_progress COMMAND oracle_publication_schedule build/oracle/joint_main_progress.bin build/oracle/joint_main_progress.txt --require-main-closed --require-sub-continuity --require-video-frontiers --require-sound-handshake)
    add_test(NAME oracle_joint_reset_window COMMAND oracle_publication_schedule build/oracle/joint_reset_focused.bin build/oracle/joint_reset_focused.txt --reset-window --physical-main --require-sub-continuity --require-video-frontiers --require-sound-handshake)
    add_test(NAME oracle_joint_main_progress_full COMMAND oracle_publication_schedule build/oracle/joint_main_progress_full.bin build/oracle/joint_main_progress_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-frontiers --require-sound-handshake)
    add_test(NAME oracle_joint_sound_full COMMAND oracle_publication_schedule build/oracle/joint_sound_full.bin build/oracle/joint_sound_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-native-sound)
    set_tests_properties(oracle_joint_sound_full PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_joint_audio_full COMMAND oracle_publication_schedule build/oracle/joint_audio_full.bin build/oracle/joint_audio_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines)
    set_tests_properties(oracle_joint_audio_full PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_joint_video COMMAND oracle_publication_schedule build/oracle/joint_main_progress_full.bin build/oracle/joint_main_progress_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-sound-handshake)
    add_test(NAME oracle_joint_video_directed COMMAND oracle_publication_schedule build/oracle/joint_video_directed.bin build/oracle/joint_video_directed.txt --require-video-fixture --require-main-closed --require-sub-continuity --require-video-rgb --require-sound-handshake)
    set_tests_properties(oracle_joint_video oracle_joint_video_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    set_tests_properties(oracle_publication_schedule oracle_joint_main_progress oracle_joint_reset_window oracle_joint_main_progress_full PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_bus_arbiter COMMAND oracle_bus_arbiter build/oracle/bus_arbiter_short.bin build/oracle/arbiter_schedule.txt)
    set_tests_properties(oracle_bus_arbiter PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_bus_boot COMMAND oracle_bus_arbiter build/oracle/bus_arbiter_boot.bin build/oracle/arbiter_boot.txt --require-boot)
    set_tests_properties(oracle_bus_boot PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_subroad tests/oracle_subroad.cpp
        src/main/romloader.cpp src/main/roms.cpp
        src/main/engine/subbus.cpp src/main/engine/osubroad.cpp)
    target_include_directories(oracle_subroad PRIVATE src/main)
    add_test(NAME oracle_subroad COMMAND oracle_subroad)
    add_test(NAME oracle_roadrequests COMMAND oracle_subroad build/oracle/roadrequests.bin)
    add_test(NAME oracle_roadinit COMMAND oracle_subroad build/oracle/roadinit.bin)
    add_test(NAME oracle_subroad_special COMMAND oracle_subroad build/oracle/subroad_special.bin)
    add_test(NAME oracle_subroad_gameplay COMMAND oracle_subroad build/oracle/subroad_gameplay.bin)
    set_tests_properties(oracle_subroad oracle_subroad_gameplay oracle_roadrequests oracle_roadinit oracle_subroad_special PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_video tests/oracle_video.cpp
        src/main/romloader.cpp src/main/roms.cpp
        src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwsprites.cpp src/main/hwvideo/hwtiles.cpp
        src/main/hwvideo/hwpalette.cpp src/main/hwvideo/screen.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp src/main/engine/omainsprites.cpp src/main/engine/osubsprites.cpp src/main/engine/osubroad.cpp)
    target_include_directories(oracle_video PRIVATE src/main)
    get_target_property(INTEGRATED_ORACLE_SOURCES oracle_video SOURCES)
    list(REMOVE_ITEM INTEGRATED_ORACLE_SOURCES tests/oracle_video.cpp)
    add_executable(oracle_integrated_video tests/oracle_integrated_video.cpp ${INTEGRATED_ORACLE_SOURCES})
    target_include_directories(oracle_integrated_video PRIVATE src/main)
    add_test(NAME oracle_integrated_video_mutations COMMAND ${Python3_EXECUTABLE}
        ${CMAKE_SOURCE_DIR}/tools/video/check_integrated_mame_mutations.py
        --compiler ${CMAKE_CXX_COMPILER} --runtime-dir ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/build/oracle/frames.bin)
    foreach(width 320 358 398 522 640)
        add_test(NAME oracle_integrated_video_${width} COMMAND oracle_integrated_video ${width} build/oracle/frames.bin)
        set_tests_properties(oracle_integrated_video_${width} PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        foreach(corpus IN ITEMS frames_nosprites frames_gameplay frames_rolls)
            add_test(NAME oracle_integrated_video_${width}_${corpus} COMMAND oracle_integrated_video ${width} build/oracle/${corpus}.bin)
            set_tests_properties(oracle_integrated_video_${width}_${corpus} PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        endforeach()
    endforeach()
    add_test(NAME oracle_video COMMAND oracle_video build/oracle/frames.bin)
    add_test(NAME oracle_video_nosprites COMMAND oracle_video build/oracle/frames_nosprites.bin)
    add_test(NAME oracle_paired COMMAND oracle_video build/oracle/paired.bin 0 build/oracle/paired_requests.bin)
    set_tests_properties(oracle_paired PROPERTIES DEPENDS oracle_paired_objects WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_paired_road_objects COMMAND oracle_host_interleave build/oracle/paired_road_objects.bin build/oracle/paired_road_requests.bin)
    add_test(NAME oracle_paired_road_frame COMMAND oracle_frame_host build/oracle/paired_road_frame.bin)
    add_test(NAME oracle_paired_road_sound COMMAND oracle_sound_stream build/oracle/paired_road_sound.bin)
    add_test(NAME oracle_paired_road COMMAND oracle_video build/oracle/paired_road.bin 0 build/oracle/paired_road_requests.bin)
    set_tests_properties(oracle_paired_road_objects oracle_paired_road_frame oracle_paired_road_sound oracle_paired_road PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    set_tests_properties(oracle_paired_road PROPERTIES DEPENDS oracle_paired_road_objects)
    add_test(NAME oracle_pipeline COMMAND oracle_video build/oracle/pipeline.bin)
    add_test(NAME oracle_video_gameplay COMMAND oracle_video build/oracle/frames_gameplay.bin)
    set_tests_properties(oracle_video oracle_video_nosprites oracle_video_gameplay oracle_pipeline PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()

option(STAGE1_ROM_TESTS "Enable tests requiring the user's Stage 1 ROM set" OFF)
if(BUILD_TESTING AND STAGE1_ROM_TESTS)
    get_target_property(STAGE1_SOURCES afterburner2 SOURCES)
    list(REMOVE_ITEM STAGE1_SOURCES src/main/main.cpp src/main/frontend/music_decoder.cpp)
    add_executable(stage1_integration tests/stage1_integration.cpp ${STAGE1_SOURCES})
    target_include_directories(stage1_integration PRIVATE src/main)
    add_test(NAME stage1_integration COMMAND stage1_integration)
    set_tests_properties(stage1_integration PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
    foreach(PORT irq4_service logic_wait caller)
        add_executable(oracle_${PORT} tests/oracle_${PORT}.cpp
            src/main/engine/omainirqservice.cpp src/main/engine/omainirqcallee.cpp src/main/engine/mainbus.cpp
            src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
        target_include_directories(oracle_${PORT} PRIVATE src/main)
    endforeach()
    add_test(NAME oracle_irq4_service_gameflow_actions COMMAND oracle_irq4_service build/oracle/irq4_service_gameflow_actions.bin --require-actions)
    set_tests_properties(oracle_irq4_service_gameflow_actions PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_irq4_service_gameflow_endpoints COMMAND oracle_irq4_service build/oracle/irq4_service_gameflow_endpoints.bin --require-gameflow)
    set_tests_properties(oracle_irq4_service_gameflow_endpoints PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_irq4_service_rts_callees COMMAND oracle_irq4_service build/oracle/irq4_service_rts_callees.bin --require-rts)
    set_tests_properties(oracle_irq4_service_rts_callees PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    foreach(CAPTURE irq4_service irq4_service_directed irq4_service_edges irq4_service_road_endpoints irq4_service_cycle_endpoints irq4_service_callee_endpoints irq4_service_scenery_endpoints)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_irq4_service build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    foreach(CAPTURE irq4_return irq4_return_edges)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_irq4_service build/oracle/${CAPTURE}.bin build/oracle/${CAPTURE}.bin.returns)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    foreach(CAPTURE logic_wait logic_wait_directed)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_logic_wait build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    foreach(CAPTURE caller caller_directed caller_service caller_service_edges caller_return caller_return_edges caller_steps)
        add_test(NAME oracle_${CAPTURE} COMMAND oracle_caller build/oracle/${CAPTURE}.bin)
        set_tests_properties(oracle_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()

    add_test(NAME oracle_caller_words COMMAND oracle_caller build/oracle/caller_words.bin build/oracle/caller_steps.bin)
    set_tests_properties(oracle_caller_words PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_successors COMMAND oracle_caller build/oracle/caller_successors.bin build/oracle/caller_words.bin)
    add_test(NAME oracle_caller_successors_directed COMMAND oracle_caller build/oracle/caller_successors_directed.bin --require-taken)
    set_tests_properties(oracle_caller_successors oracle_caller_successors_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_cpu_visibility tests/oracle_cpu_visibility.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(oracle_cpu_visibility PRIVATE src/main)
    add_test(NAME oracle_caller_closure COMMAND oracle_caller build/oracle/caller_closure.bin build/oracle/caller_successors.bin --require-closed)
    add_test(NAME oracle_caller_closure_directed COMMAND oracle_caller build/oracle/caller_closure_directed.bin --require-taken --require-closed)
    set_tests_properties(oracle_caller_closure oracle_caller_closure_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")

    add_test(NAME oracle_caller_follower COMMAND oracle_caller build/oracle/caller_follower.bin --require-closed)
    add_test(NAME oracle_caller_follower_directed COMMAND oracle_caller build/oracle/caller_follower_directed.bin --require-follower --require-closed)
    set_tests_properties(oracle_caller_follower oracle_caller_follower_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")

    add_test(NAME oracle_caller_ready COMMAND oracle_caller build/oracle/caller_ready.bin --require-ready-path --require-worldinit --require-publication-init --require-closed)
    add_test(NAME oracle_caller_ready_directed COMMAND oracle_caller build/oracle/caller_ready_directed.bin --require-ready --require-closed)
    add_test(NAME oracle_caller_worldinit_directed COMMAND oracle_caller build/oracle/caller_worldinit_directed.bin --require-worldinit --require-closed)
    set_tests_properties(oracle_caller_ready oracle_caller_ready_directed oracle_caller_worldinit_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")

    add_test(NAME oracle_caller_allirq COMMAND oracle_caller build/oracle/caller_allirq_trail.bin --require-ready-path --require-worldinit --require-publication-init --require-clear --require-trail-path --require-allirq --require-closed)
    add_test(NAME oracle_caller_trail_directed COMMAND oracle_caller build/oracle/caller_trail_directed.bin --require-trail --require-closed)
    set_tests_properties(oracle_caller_allirq oracle_caller_trail_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")

    add_test(NAME oracle_caller_soundproducer COMMAND oracle_caller build/oracle/caller_soundproducer.bin --require-soundproducer-path --require-allirq --require-closed)
    add_test(NAME oracle_caller_soundproducer_directed COMMAND oracle_caller build/oracle/caller_soundproducer_directed.bin --require-soundproducer --require-closed)
    set_tests_properties(oracle_caller_soundproducer oracle_caller_soundproducer_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_input_short COMMAND oracle_caller build/oracle/caller_input_short.bin --require-input-path --require-closed)
    add_test(NAME oracle_caller_input_directed COMMAND oracle_caller build/oracle/caller_input_directed.bin --require-input --require-closed)
    add_test(NAME oracle_caller_input COMMAND oracle_caller build/oracle/caller_input.bin --require-input-path --require-allirq --require-closed)
    set_tests_properties(oracle_caller_input_short oracle_caller_input_directed oracle_caller_input PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_weapon_full COMMAND oracle_caller build/oracle/caller_weapon.bin --require-weapon-path --require-flight-path --require-input-path --require-allirq --require-closed)
    add_test(NAME oracle_caller_weapon_short COMMAND oracle_caller build/oracle/caller_weapon_short.bin --require-weapon-path --require-closed)
    add_test(NAME oracle_caller_weapon_directed COMMAND oracle_caller build/oracle/caller_weapon_directed.bin --require-weapon --require-closed)
    set_tests_properties(oracle_caller_weapon_full oracle_caller_weapon_short oracle_caller_weapon_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_host_short COMMAND oracle_caller build/oracle/caller_host_short.bin --require-closed)
    add_test(NAME oracle_caller_host_full COMMAND oracle_caller build/oracle/caller_host.bin --require-host-path --require-weapon-path --require-flight-path --require-input-path --require-allirq --require-closed)
    add_test(NAME oracle_caller_host_directed COMMAND oracle_caller build/oracle/caller_host_directed.bin --require-host --require-closed)
    set_tests_properties(oracle_caller_host_short oracle_caller_host_full oracle_caller_host_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_companion_short COMMAND oracle_caller build/oracle/caller_companion_short.bin --require-companion-path --require-closed)
    add_test(NAME oracle_caller_companion_directed COMMAND oracle_caller build/oracle/caller_companion_directed.bin --require-companion --require-closed)
    add_test(NAME oracle_caller_companion COMMAND oracle_caller build/oracle/caller_companion.bin --require-companion-path --require-flight-path --require-input-path --require-allirq --require-closed)
    set_tests_properties(oracle_caller_companion_short oracle_caller_companion_directed oracle_caller_companion PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_caller_flight_short COMMAND oracle_caller build/oracle/caller_flight_short.bin --require-flight-path --require-closed)
    add_test(NAME oracle_caller_flight_directed COMMAND oracle_caller build/oracle/caller_flight_directed.bin --require-flight --require-closed)
    add_test(NAME oracle_caller_flight COMMAND oracle_caller build/oracle/caller_flight.bin --require-flight-path --require-input-path --require-allirq --require-closed)
    set_tests_properties(oracle_caller_flight_short oracle_caller_flight_directed oracle_caller_flight PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    foreach(CAPTURE caller_host_short caller_host caller_host_directed caller_companion_short caller_companion_directed caller_companion caller_flight_short caller_flight_directed caller_flight caller_input_short caller_input_directed caller_input caller_soundproducer caller_soundproducer_directed caller_allirq_trail caller_trail_directed caller_ready caller_ready_directed caller_worldinit_directed caller_follower caller_follower_directed caller caller_directed caller_service caller_service_edges caller_return caller_return_edges caller_steps caller_words caller_successors caller_successors_directed caller_closure caller_closure_directed)
        add_test(NAME oracle_visibility_${CAPTURE} COMMAND oracle_cpu_visibility build/oracle/${CAPTURE}.bin.visibility)
        set_tests_properties(oracle_visibility_${CAPTURE} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()

endif()

if(BUILD_TESTING AND ORACLE_TESTS)
add_executable(oracle_speaker tests/oracle_speaker.cpp)
target_include_directories(oracle_speaker PRIVATE src/main)
add_custom_target(oracle-speaker
    COMMAND $<TARGET_FILE:oracle_speaker> build/oracle/joint_speaker_full.bin.audio
    COMMAND $<TARGET_FILE:oracle_speaker> build/oracle/speaker_edges
    DEPENDS oracle_speaker WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_target(oracle-joint-speaker-full
    COMMAND $<TARGET_FILE:oracle_publication_schedule> build/oracle/joint_speaker_full.bin build/oracle/joint_speaker_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines --require-speaker
    DEPENDS oracle_publication_schedule WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_custom_target(oracle-speaker-mutations
    COMMAND ${Python3_EXECUTABLE} tools/oracle/check_speaker_mutations.py
    DEPENDS oracle-speaker oracle-joint-speaker-full WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_test(NAME oracle_speaker COMMAND oracle_speaker build/oracle/joint_speaker_full.bin.audio)
add_test(NAME oracle_speaker_edges COMMAND oracle_speaker build/oracle/speaker_edges)
add_test(NAME oracle_joint_speaker_full COMMAND oracle_publication_schedule build/oracle/joint_speaker_full.bin build/oracle/joint_speaker_full.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines --require-speaker)
add_test(NAME oracle_speaker_mutations COMMAND ${Python3_EXECUTABLE} tools/oracle/check_speaker_mutations.py)
set_tests_properties(oracle_speaker oracle_speaker_edges oracle_joint_speaker_full oracle_speaker_mutations PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
add_test(NAME oracle_joint_video_owned_directed COMMAND oracle_publication_schedule build/oracle/joint_video_owned_directed.bin build/oracle/joint_video_owned_directed.txt --require-video-fixture --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines --require-speaker)
set_tests_properties(oracle_joint_video_owned_directed PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
    foreach(PORT cpu_coverage cpu_nested_irq)
        add_executable(oracle_${PORT} tests/oracle_${PORT}.cpp
            src/main/engine/omainirqservice.cpp src/main/engine/omainirqcallee.cpp src/main/engine/mainbus.cpp
            src/main/engine/osubirq.cpp src/main/engine/osubprogress.cpp src/main/engine/osubpublication.cpp
            src/main/engine/subbus.cpp src/main/roms.cpp src/main/romloader.cpp)
        target_include_directories(oracle_${PORT} PRIVATE src/main)
        target_link_libraries(oracle_${PORT} PRIVATE Threads::Threads)
    endforeach()
    add_test(NAME oracle_cpu_coverage COMMAND oracle_cpu_coverage build/oracle/cpu_coverage.bin)
    add_test(NAME oracle_recovery COMMAND oracle_cpu_coverage build/oracle/cpu_recovery.bin)
    add_test(NAME oracle_recovery_complete COMMAND oracle_cpu_coverage build/oracle/cpu_recovery_complete.bin)
    add_test(NAME oracle_recovery_coverage COMMAND ${Python3_EXECUTABLE} tools/oracle/check_recovery_coverage.py build/oracle/cpu_recovery.bin build/oracle/cpu_recovery_complete.bin)
    add_test(NAME oracle_recovery_mutations COMMAND ${Python3_EXECUTABLE} tools/oracle/check_cpu_coverage_mutations.py --recovery)
    set_tests_properties(oracle_recovery oracle_recovery_complete oracle_recovery_coverage oracle_recovery_mutations PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    set_tests_properties(oracle_recovery oracle_recovery_complete PROPERTIES FIXTURES_SETUP recovery_census)
    set_tests_properties(oracle_recovery_coverage oracle_recovery_mutations PROPERTIES FIXTURES_REQUIRED recovery_census)
    add_test(NAME oracle_cpu_coverage_legacy COMMAND oracle_cpu_coverage build/oracle/cpu_coverage_expanded.bin)
    add_test(NAME oracle_cpu_coverage_expanded COMMAND oracle_cpu_coverage build/oracle/cpu_coverage_expanded_full.bin)
    add_test(NAME oracle_cpu_nested_irq COMMAND oracle_cpu_nested_irq build/oracle/cpu_nested_irq.bin)
    add_test(NAME oracle_cpu_coverage_check COMMAND ${Python3_EXECUTABLE} tools/oracle/check_cpu_coverage.py build/oracle/cpu_coverage_plan.json build/oracle/cpu_coverage_expanded_full.bin.coverage.json)
    set_tests_properties(oracle_cpu_coverage_expanded PROPERTIES FIXTURES_SETUP cpu_coverage_census)
    set_tests_properties(oracle_cpu_coverage_check PROPERTIES FIXTURES_REQUIRED cpu_coverage_census)
    add_test(NAME oracle_joint_coverage_flight COMMAND oracle_publication_schedule build/oracle/joint_coverage_flight_expanded.bin build/oracle/joint_coverage_flight_expanded.txt --require-reset --require-main-closed --require-sub-continuity --require-video-rgb --require-sound-handshake)
    set_tests_properties(oracle_cpu_coverage oracle_cpu_coverage_legacy oracle_cpu_coverage_expanded oracle_cpu_nested_irq oracle_cpu_coverage_check oracle_joint_coverage_flight PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_custom_target(oracle_cpu_coverage_mutations
        COMMAND ${Python3_EXECUTABLE} tools/oracle/check_cpu_coverage_mutations.py
        DEPENDS oracle_cpu_coverage oracle_cpu_nested_irq WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
add_test(NAME oracle_joint_cold COMMAND oracle_publication_schedule build/oracle/joint_cold.bin build/oracle/joint_cold.txt --require-cold --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines --require-speaker)
add_test(NAME oracle_joint_cold_full COMMAND oracle_publication_schedule build/oracle/joint_cold_full.bin build/oracle/joint_cold_full.txt --require-reset --require-cold --require-main-closed --require-sub-continuity --require-video-rgb --require-native-deadlines --require-speaker)
add_test(NAME oracle_joint_cold_boundaries COMMAND ${Python3_EXECUTABLE} tools/oracle/check_joint_cold_boundaries.py build/oracle/joint_cold_full.bin build/oracle/joint_speaker_full.bin)
add_test(NAME oracle_joint_cold_mutations COMMAND ${Python3_EXECUTABLE} tools/oracle/check_joint_cold_mutations.py)
set_tests_properties(oracle_joint_cold PROPERTIES FIXTURES_SETUP cold_initial)
set_tests_properties(oracle_joint_cold_mutations PROPERTIES FIXTURES_REQUIRED cold_initial)
set_tests_properties(oracle_joint_cold_full PROPERTIES FIXTURES_SETUP cold_census)
set_tests_properties(oracle_joint_cold_boundaries PROPERTIES FIXTURES_REQUIRED cold_census)
set_tests_properties(oracle_joint_cold oracle_joint_cold_full oracle_joint_cold_boundaries oracle_joint_cold_mutations PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
    get_target_property(WHOLE_HOST_ORACLE_SOURCES oracle_publication_schedule SOURCES)
    list(REMOVE_ITEM WHOLE_HOST_ORACLE_SOURCES tests/oracle_publication_schedule.cpp)
    add_executable(oracle_whole_host tests/oracle_whole_host.cpp ${WHOLE_HOST_ORACLE_SOURCES})
    target_include_directories(oracle_whole_host PRIVATE src/main)
    target_link_libraries(oracle_whole_host PRIVATE Threads::Threads)
    foreach(corpus IN ITEMS cold cold_full)
        add_test(NAME oracle_whole_host_${corpus} COMMAND oracle_whole_host build/oracle/joint_${corpus}.bin build/oracle/joint_${corpus}.txt)
        set_tests_properties(oracle_whole_host_${corpus} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    add_test(NAME oracle_whole_host_expanded COMMAND oracle_whole_host build/oracle/whole_host_expanded.bin build/oracle/whole_host_expanded.txt)
    foreach(width IN ITEMS 358 398)
        foreach(corpus IN ITEMS joint_cold joint_cold_full whole_host_expanded)
            add_test(NAME oracle_integrated_host_${width}_${corpus} COMMAND oracle_whole_host
                build/oracle/${corpus}.bin build/oracle/${corpus}.txt ${width})
            set_tests_properties(oracle_integrated_host_${width}_${corpus} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
        endforeach()
    endforeach()
    add_test(NAME oracle_integrated_host_mutations COMMAND ${Python3_EXECUTABLE} tools/video/check_integrated_host_mutations.py)
    set_tests_properties(oracle_integrated_host_mutations PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_whole_host_mutations COMMAND ${Python3_EXECUTABLE} tools/oracle/check_whole_host_mutations.py)
    set_tests_properties(oracle_whole_host_expanded oracle_whole_host_mutations PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    set_tests_properties(oracle_whole_host_cold PROPERTIES FIXTURES_SETUP whole_host_initial)
    set_tests_properties(oracle_whole_host_mutations PROPERTIES FIXTURES_REQUIRED whole_host_initial)
endif()

if(BUILD_TESTING AND STAGE1_ROM_TESTS)
    get_target_property(WHOLE_HOST_GAME_SOURCES afterburner2 SOURCES)
    list(REMOVE_ITEM WHOLE_HOST_GAME_SOURCES src/main/main.cpp src/main/frontend/music_decoder.cpp)
    add_executable(music_presentation_integration tests/music_presentation_integration.cpp src/main/frontend/music_decoder.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(music_presentation_integration PRIVATE src/main)
    target_link_libraries(music_presentation_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME music_presentation_integration COMMAND music_presentation_integration)
    set_tests_properties(music_presentation_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} FIXTURES_REQUIRED music_tones)
    add_executable(oracle_spatial_routing tests/oracle_spatial_routing.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(oracle_spatial_routing PRIVATE src/main)
    target_link_libraries(oracle_spatial_routing PRIVATE Threads::Threads)
    add_test(NAME oracle_spatial_routing COMMAND oracle_spatial_routing build/oracle/spatial-audio/routing.bin)
    set_tests_properties(oracle_spatial_routing PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(oracle_music_routing tests/oracle_music_routing.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(oracle_music_routing PRIVATE src/main)
    target_link_libraries(oracle_music_routing PRIVATE Threads::Threads)
    add_executable(native_menu_integration tests/native_menu_integration.cpp src/main/frontend/music_decoder.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(native_menu_integration PRIVATE src/main)
    target_link_libraries(native_menu_integration PRIVATE SDL3::SDL3 Threads::Threads)
    if(APPLE OR AB2_NATIVE_VULKAN)
      add_executable(native_shader_main_integration tests/native_shader_main_integration.cpp src/main/frontend/music_decoder.cpp ${WHOLE_HOST_GAME_SOURCES})
      target_include_directories(native_shader_main_integration PRIVATE src/main)
      target_link_libraries(native_shader_main_integration PRIVATE SDL3::SDL3 Threads::Threads ab2_slang)
      add_custom_target(verify-native-shader-main
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp
          DEPENDS native_shader_main_integration WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
      add_custom_target(verify-integrated-shader-main
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" original
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" 16:9
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" 16:10
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" original scalefx
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" 16:9 scalefx
          COMMAND ${CMAKE_COMMAND} -E env SDL_AUDIODRIVER=dummy $<TARGET_FILE:native_shader_main_integration> tests/fixtures/native_slang/reference.slangp "" 16:10 scalefx
          DEPENDS native_shader_main_integration WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM)
    endif()
    add_test(NAME native_menu_integration COMMAND native_menu_integration)
    set_tests_properties(native_menu_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy" FIXTURES_REQUIRED music_tones)
    add_executable(natural_credit tools/natural_credit.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(natural_credit PRIVATE src/main)
    target_link_libraries(natural_credit PRIVATE SDL3::SDL3 Threads::Threads)
    add_executable(whole_host_integration tests/whole_host_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(whole_host_integration PRIVATE src/main)
    target_link_libraries(whole_host_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME whole_host_integration COMMAND whole_host_integration)
    set_tests_properties(whole_host_integration PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(game_session_integration tests/game_session_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(game_session_integration PRIVATE src/main)
    target_link_libraries(game_session_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME game_session_integration COMMAND game_session_integration)
    set_tests_properties(game_session_integration PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(practice_mode_integration tests/practice_mode_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(practice_mode_integration PRIVATE src/main)
    target_link_libraries(practice_mode_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME practice_mode_integration COMMAND practice_mode_integration)
    set_tests_properties(practice_mode_integration PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(shuffle_session_integration tests/shuffle_session_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(shuffle_session_integration PRIVATE src/main)
    target_link_libraries(shuffle_session_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME shuffle_session_integration COMMAND shuffle_session_integration)
    set_tests_properties(shuffle_session_integration PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(hud_presentation_integration tests/hud_presentation_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(hud_presentation_integration PRIVATE src/main)
    target_link_libraries(hud_presentation_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME hud_presentation_integration COMMAND hud_presentation_integration)
    set_tests_properties(hud_presentation_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(player_aircraft_presentation tests/player_aircraft_presentation.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(player_aircraft_presentation PRIVATE src/main)
    target_link_libraries(player_aircraft_presentation PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME player_aircraft_presentation COMMAND player_aircraft_presentation)
    set_tests_properties(player_aircraft_presentation PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_test(NAME whole_host_attract COMMAND afterburner2 --frames 2400)
    set_tests_properties(whole_host_attract PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ENVIRONMENT "SDL_VIDEO_DRIVER=dummy;SDL_AUDIO_DRIVER=dummy")
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
    add_executable(oracle_stage_catalog tests/oracle_stage_catalog.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(oracle_stage_catalog PRIVATE src/main)
    add_test(NAME oracle_stage_catalog COMMAND oracle_stage_catalog build/oracle/stage_catalog.bin)
    set_tests_properties(oracle_stage_catalog PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_executable(oracle_shuffle_palette tests/oracle_shuffle_palette.cpp src/main/roms.cpp src/main/romloader.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(oracle_shuffle_palette PRIVATE src/main)
    foreach(stage 5 8 13 17)
        add_test(NAME oracle_shuffle_palette_${stage} COMMAND oracle_shuffle_palette build/oracle/shuffle_palette_stage${stage}.bin)
        set_tests_properties(oracle_shuffle_palette_${stage} PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    endforeach()
    get_target_property(SHUFFLE_ORACLE_GAME_SOURCES afterburner2 SOURCES)
    list(REMOVE_ITEM SHUFFLE_ORACLE_GAME_SOURCES src/main/main.cpp src/main/frontend/music_decoder.cpp)
    add_executable(oracle_shuffle_run tests/oracle_shuffle_run.cpp ${SHUFFLE_ORACLE_GAME_SOURCES})
    target_include_directories(oracle_shuffle_run PRIVATE src/main)
    target_link_libraries(oracle_shuffle_run PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME oracle_shuffle_run COMMAND oracle_shuffle_run build/oracle/shuffle_run build/oracle/shuffle_run.csv)
    set_tests_properties(oracle_shuffle_run PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
    add_test(NAME oracle_shuffle_run_mutation COMMAND ${Python3_EXECUTABLE} tools/check_shuffle_run_mutation.py $<TARGET_FILE:oracle_shuffle_run>)
    set_tests_properties(oracle_shuffle_run_mutation PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" DEPENDS oracle_shuffle_run)
    add_test(NAME oracle_shuffle_ending_mutation COMMAND ${Python3_EXECUTABLE} tools/check_shuffle_ending_mutation.py $<TARGET_FILE:oracle_shuffle_run>)
    set_tests_properties(oracle_shuffle_ending_mutation PROPERTIES WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()


if(BUILD_TESTING)
    add_executable(ground_horizon_regression tests/ground_horizon_regression.cpp)
    add_executable(sprite_decode_regression tests/sprite_decode_regression.cpp)
    target_include_directories(sprite_decode_regression PRIVATE src/main)
    add_test(NAME sprite_decode_regression COMMAND sprite_decode_regression)
    target_include_directories(ground_horizon_regression PRIVATE src/main)
    add_test(NAME ground_horizon_regression COMMAND ground_horizon_regression)
endif()
if(BUILD_TESTING AND STAGE1_ROM_TESTS)
    add_executable(wide_ground_reference_regression tests/wide_ground_reference_regression.cpp)
    target_include_directories(wide_ground_reference_regression PRIVATE src/main)
    add_test(NAME wide_ground_reference_regression COMMAND wide_ground_reference_regression)
    add_executable(ground_horizon_integration tests/ground_horizon_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(ground_horizon_integration PRIVATE src/main)
    target_link_libraries(ground_horizon_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME ground_horizon_integration COMMAND ground_horizon_integration)
    set_tests_properties(ground_horizon_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()

if(BUILD_TESTING AND ORACLE_TESTS)
    add_executable(ground_horizon_fixture tests/ground_horizon_fixture.cpp
        src/main/roms.cpp src/main/romloader.cpp src/main/hwvideo/hwroad.cpp
        src/main/hwvideo/hwtiles.cpp src/main/hwvideo/hwpalette.cpp
        src/main/hwvideo/hwsprites.cpp src/main/hwvideo/screen.cpp)
    target_include_directories(ground_horizon_fixture PRIVATE src/main)
    add_test(NAME ground_horizon_fixture COMMAND ground_horizon_fixture)
    set_tests_properties(ground_horizon_fixture PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()

if(BUILD_TESTING AND STAGE1_ROM_TESTS)
    add_executable(feedback_integration tests/feedback_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(feedback_integration PRIVATE src/main)
    target_link_libraries(feedback_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME feedback_integration COMMAND feedback_integration)
    set_tests_properties(feedback_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()
if(BUILD_TESTING AND ORACLE_TESTS)
    add_executable(feedback_fixture tests/feedback_fixture.cpp src/main/engine/mainbus.cpp src/main/engine/subbus.cpp)
    target_include_directories(feedback_fixture PRIVATE src/main)
    add_test(NAME feedback_fixture COMMAND feedback_fixture ${CMAKE_SOURCE_DIR}/build/oracle/feedback.bin)
    add_test(NAME feedback_attract_fixture COMMAND feedback_fixture ${CMAKE_SOURCE_DIR}/build/oracle/whole_host_expanded.bin)
endif()

if(BUILD_TESTING AND STAGE1_ROM_TESTS)
    add_executable(wide_scene_geometry src/main/engine/subbus.cpp tests/wide_scene_geometry.cpp src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp src/main/hwvideo/hwpalette.cpp src/main/roms.cpp src/main/romloader.cpp)
    target_include_directories(wide_scene_geometry PRIVATE src/main)
    target_link_libraries(wide_scene_geometry PRIVATE SDL3::SDL3)
    add_test(NAME wide_scene_geometry COMMAND wide_scene_geometry)
    set_tests_properties(wide_scene_geometry PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(integrated_scene_clip_regression tests/integrated_scene_clip_regression.cpp
        src/main/roms.cpp src/main/romloader.cpp src/main/hwvideo/screen.cpp
        src/main/hwvideo/hwroad.cpp src/main/hwvideo/hwtiles.cpp src/main/hwvideo/hwsprites.cpp src/main/hwvideo/hwpalette.cpp)
    target_include_directories(integrated_scene_clip_regression PRIVATE src/main)
    add_test(NAME integrated_scene_clips COMMAND integrated_scene_clip_regression)
    set_tests_properties(integrated_scene_clips PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_test(NAME integrated_scene_mutations COMMAND ${Python3_EXECUTABLE}
        ${CMAKE_SOURCE_DIR}/tools/video/check_integrated_scene_mutations.py
        --compiler ${CMAKE_CXX_COMPILER} --runtime-dir ${CMAKE_BINARY_DIR})
    add_executable(integrated_scene_integration tests/integrated_scene_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(integrated_scene_integration PRIVATE src/main)
    target_link_libraries(integrated_scene_integration PRIVATE SDL3::SDL3 Threads::Threads)
    foreach(width 358 398 522)
        add_test(NAME integrated_scene_${width} COMMAND integrated_scene_integration ${width})
        set_tests_properties(integrated_scene_${width} PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    endforeach()
    add_executable(wide_scene_integration tests/wide_scene_integration.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(wide_scene_integration PRIVATE src/main)
    target_link_libraries(wide_scene_integration PRIVATE SDL3::SDL3 Threads::Threads)
    add_executable(wide_stage_visibility tests/wide_stage_visibility.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(wide_stage_visibility PRIVATE src/main)
    target_link_libraries(wide_stage_visibility PRIVATE SDL3::SDL3 Threads::Threads)
    add_test(NAME wide_stage_visibility COMMAND wide_stage_visibility)
    set_tests_properties(wide_stage_visibility PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    add_executable(wide_lifecycle_visibility tests/wide_lifecycle_visibility.cpp ${WHOLE_HOST_GAME_SOURCES})
    target_include_directories(wide_lifecycle_visibility PRIVATE src/main)
    target_link_libraries(wide_lifecycle_visibility PRIVATE SDL3::SDL3 Threads::Threads)
    foreach(recording ending neutral continue weapons)
        add_test(NAME wide_lifecycle_${recording} COMMAND wide_lifecycle_visibility ${recording})
        set_tests_properties(wide_lifecycle_${recording} PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    endforeach()
    foreach(width IN ITEMS 358 398)
        foreach(recording ending neutral continue weapons)
            add_test(NAME integrated_lifecycle_${width}_${recording} COMMAND wide_lifecycle_visibility ${recording} --integrated ${width})
            set_tests_properties(integrated_lifecycle_${width}_${recording} PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
        endforeach()
    endforeach()
    add_test(NAME wide_scene_integration COMMAND wide_scene_integration)
    set_tests_properties(wide_scene_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()
option(WIDE_GPU_TESTS "Enable real-GPU widescreen CTest checks" OFF)
if(BUILD_TESTING)
    add_executable(wide_gpu_regression tests/wide_gpu_regression.cpp)
    target_include_directories(wide_gpu_regression PRIVATE src/main)
    target_link_libraries(wide_gpu_regression PRIVATE SDL3::SDL3)
    add_custom_target(verify-wide-gpu COMMAND wide_gpu_regression
        DEPENDS wide_gpu_regression WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    if(WIDE_GPU_TESTS)
        add_test(NAME wide_gpu_regression COMMAND wide_gpu_regression)
        set_tests_properties(wide_gpu_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
    endif()
endif()

if(BUILD_TESTING)
  add_executable(spatial_audio_sdl_regression tests/spatial_audio_regression.cpp)
  target_include_directories(spatial_audio_sdl_regression PRIVATE src/main)
  target_link_libraries(spatial_audio_sdl_regression PRIVATE SDL3::SDL3 Threads::Threads)
  add_test(NAME spatial_audio_sdl_regression COMMAND spatial_audio_sdl_regression)
  set_tests_properties(spatial_audio_sdl_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endif()

if(BUILD_TESTING AND AB2_OPENAL_TARGET)
  add_executable(spatial_audio_regression tests/spatial_audio_regression.cpp)
  target_include_directories(spatial_audio_regression PRIVATE src/main)
  target_compile_definitions(spatial_audio_regression PRIVATE AB2_OPENAL=1)
  target_link_libraries(spatial_audio_regression PRIVATE SDL3::SDL3 ${AB2_OPENAL_TARGET} Threads::Threads)
  add_test(NAME spatial_audio_regression COMMAND spatial_audio_regression)
  set_tests_properties(spatial_audio_regression PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} FIXTURES_REQUIRED music_tones)
endif()

if(BUILD_TESTING AND STAGE1_ROM_TESTS AND AB2_OPENAL_TARGET)
  add_executable(spatial_audio_game_integration tests/spatial_audio_game_integration.cpp src/main/frontend/music_decoder.cpp ${WHOLE_HOST_GAME_SOURCES})
  target_include_directories(spatial_audio_game_integration PRIVATE src/main)
  target_compile_definitions(spatial_audio_game_integration PRIVATE AB2_OPENAL=1)
  target_link_libraries(spatial_audio_game_integration PRIVATE SDL3::SDL3 ${AB2_OPENAL_TARGET} Threads::Threads)
  add_test(NAME spatial_audio_game_integration COMMAND spatial_audio_game_integration)
  set_tests_properties(spatial_audio_game_integration PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} FIXTURES_REQUIRED music_tones)
endif()
