cmake_minimum_required(VERSION 3.20)
project(MaxSpinWindowsRuntimeContracts C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
if(NOT WIN32)
  message(FATAL_ERROR "These contracts require real native Windows threads and synchronization")
endif()
if(NOT TOPSPIN_SDK_ROOT)
  message(FATAL_ERROR "TOPSPIN_SDK_ROOT must select the isolated SDK")
endif()
if(NOT TOPSPIN_FRONTEND_INCLUDE)
  get_filename_component(TOPSPIN_FRONTEND_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/../../../../native-linux/src" ABSOLUTE)
endif()
# Generated fixture headers always reflect the exact selected SDK sources.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
  "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_bridge.c"
  "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_thread.c"
  "${TOPSPIN_SDK_ROOT}/src/kernel/nv2a_executor_job.c"
  "${TOPSPIN_SDK_ROOT}/src/kernel/nv2a_pb_exec.c")
enable_testing()
foreach(pair "job;nv2a_executor_job.c;JOB_TLS" "decoder;nv2a_pb_exec.c;NV_TLS")
  list(GET pair 0 name)
  list(GET pair 1 source)
  list(GET pair 2 macro)
  file(STRINGS "${TOPSPIN_SDK_ROOT}/src/kernel/${source}" tls_line REGEX "^#define ${macro} ")
  list(GET tls_line 0 tls_line)
  string(REGEX REPLACE "^#define ${macro} " "" tls_qualifier "${tls_line}")
  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${name}")
  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${name}/tls_under_test.h" "#include \"platform/xbox_winnt.h\"\n#define TEST_TLS ${tls_qualifier}\n")
  add_executable(tls_${name} tls_contract.c)
  target_include_directories(tls_${name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${name}" "${TOPSPIN_SDK_ROOT}/src" ..)
  add_test(NAME tls_${name} COMMAND tls_${name})
endforeach()
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/../guest_turn_windows.c")
  add_executable(guest_turn_contract guest_turn_contract.c ../guest_turn_windows.c)
  target_include_directories(guest_turn_contract PRIVATE ..)
  add_test(NAME guest_turn_contract COMMAND guest_turn_contract)
endif()
set_tests_properties(tls_job tls_decoder PROPERTIES TIMEOUT 15)
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/../nv2a_progress_windows.c")
  add_executable(progress_contract progress_contract.c ../guest_turn_windows.c ../nv2a_progress_windows.c)
  target_include_directories(progress_contract PRIVATE ..)
  add_test(NAME progress_contract COMMAND progress_contract)
  set_tests_properties(progress_contract PROPERTIES TIMEOUT 15)
endif()
if(TARGET guest_turn_contract)
  set_tests_properties(guest_turn_contract PROPERTIES TIMEOUT 15)
endif()
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/../material_save_transaction_windows.c")
  # Compile the exact actual import bridge body too: generic NtClose tests
  # alone miss title dispatch paths that bypass kernel_file bookkeeping.
  file(READ "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_bridge.c" bridge_source)
  string(FIND "${bridge_source}" "static void bridge_NtClose(void)\n{" bridge_begin)
  if(bridge_begin LESS 0)
    message(FATAL_ERROR "Actual SDK NtClose bridge was not found")
  endif()
  string(SUBSTRING "${bridge_source}" ${bridge_begin} -1 bridge_tail)
  string(FIND "${bridge_tail}" "\n/* " bridge_end)
  if(bridge_end LESS 0)
    message(FATAL_ERROR "Actual SDK NtClose bridge boundary was not found")
  endif()
  string(SUBSTRING "${bridge_tail}" 0 ${bridge_end} bridge_body)
  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/actual_ntclose_bridge.h" "${bridge_body}\n")
  add_executable(save_contract save_contract.c ../material_save_transaction_windows.c ../guest_turn_windows.c "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_file.c")
  target_include_directories(save_contract PRIVATE "${CMAKE_CURRENT_BINARY_DIR}" .. "${TOPSPIN_SDK_ROOT}/src" "${TOPSPIN_FRONTEND_INCLUDE}")
  target_link_libraries(save_contract PRIVATE advapi32)
  foreach(mode RANGE 0 16)
    add_test(NAME save_${mode} COMMAND save_contract ${mode})
    set_tests_properties(save_${mode} PROPERTIES TIMEOUT 30)
  endforeach()
  set_tests_properties(save_13 PROPERTIES FIXTURES_SETUP crashed_save)
  set_tests_properties(save_14 PROPERTIES FIXTURES_REQUIRED crashed_save)
  add_test(NAME save_reload COMMAND save_contract 99)
  set_tests_properties(save_0 PROPERTIES FIXTURES_SETUP committed_save)
  set_tests_properties(save_reload PROPERTIES FIXTURES_REQUIRED committed_save TIMEOUT 15)
endif()
add_executable(executor_contract executor_contract.c ../guest_turn_windows.c "${TOPSPIN_SDK_ROOT}/src/kernel/nv2a_executor_job.c")
target_include_directories(executor_contract PRIVATE .. "${TOPSPIN_SDK_ROOT}/src")
add_test(NAME executor_contract COMMAND executor_contract)
set_tests_properties(executor_contract PROPERTIES TIMEOUT 15)
file(READ "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_thread.c" thread_source)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/actual_thread_suspend.h" "")
foreach(function xbox_NtSuspendThread xbox_NtResumeThread)
  string(FIND "${thread_source}" "NTSTATUS __stdcall ${function}(" begin)
  if(begin LESS 0)
    message(FATAL_ERROR "Actual SDK ${function} was not found")
  endif()
  string(SUBSTRING "${thread_source}" ${begin} -1 tail)
  string(FIND "${tail}" "\n}" end)
  math(EXPR length "${end}+2")
  string(SUBSTRING "${tail}" 0 ${length} body)
  file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/actual_thread_suspend.h" "${body}\n")
endforeach()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/actual_suspend_import.h" "")
foreach(function bridge_NtSuspendThread bridge_NtResumeThread)
  string(FIND "${bridge_source}" "static void ${function}(void)\n{" begin)
  if(begin LESS 0)
    message(FATAL_ERROR "Actual SDK ${function} import was not found")
  endif()
  string(SUBSTRING "${bridge_source}" ${begin} -1 tail)
  string(FIND "${tail}" "\n}" end)
  math(EXPR length "${end}+2")
  string(SUBSTRING "${tail}" 0 ${length} body)
  file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/actual_suspend_import.h" "${body}\n")
endforeach()
add_executable(suspend_contract suspend_contract.c ../guest_turn_windows.c)
target_include_directories(suspend_contract PRIVATE "${CMAKE_CURRENT_BINARY_DIR}" .. "${TOPSPIN_SDK_ROOT}/src")
add_test(NAME suspend_contract COMMAND suspend_contract)
set_tests_properties(suspend_contract PROPERTIES TIMEOUT 20)
string(FIND "${bridge_source}" "static void bridge_NtQueryVolumeInformationFile(void)\n{" volume_begin)
if(volume_begin LESS 0)
  message(FATAL_ERROR "Actual SDK volume-query bridge was not found")
endif()
string(SUBSTRING "${bridge_source}" ${volume_begin} -1 volume_tail)
string(FIND "${volume_tail}" "\n}" volume_end)
math(EXPR volume_length "${volume_end}+2")
string(SUBSTRING "${volume_tail}" 0 ${volume_length} volume_body)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/actual_volume_import.h" "${volume_body}\n")
add_executable(volume_contract volume_contract.c ../material_save_transaction_windows.c ../guest_turn_windows.c "${TOPSPIN_SDK_ROOT}/src/kernel/kernel_file.c")
target_include_directories(volume_contract PRIVATE "${CMAKE_CURRENT_BINARY_DIR}" .. "${TOPSPIN_SDK_ROOT}/src" "${TOPSPIN_FRONTEND_INCLUDE}")
target_link_libraries(volume_contract PRIVATE advapi32)
add_test(NAME volume_contract COMMAND volume_contract)
set_tests_properties(volume_contract PROPERTIES TIMEOUT 30)
