add_executable(neograph_tests
    test_graph_state.cpp
    test_graph_engine.cpp
    test_engine_config.cpp
    test_checkpoint.cpp
    test_store.cpp
    test_node.cpp
    test_node_header.cpp
    test_loader.cpp
    test_schema_export.cpp
    test_json_path.cpp
    test_pending_writes.cpp
    test_channel_write_mode.cpp
    test_usage_accounting.cpp
    test_subgraph_context.cpp
    test_subgraph_output_deltas.cpp
    test_plan_execute_graph.cpp
    test_signal_dispatch.cpp
    test_multi_node_resume.cpp
    test_resume_if_exists.cpp
    test_cancel_token_propagation.cpp
    test_live_llm_cancel_fanout_cpp.cpp
    test_scheduler.cpp
    test_node_execution.cpp
    test_tool_dispatch_parity.cpp
    test_tool_execution.cpp
    test_host_admission.cpp
    test_compiler.cpp
    test_compiler_strict.cpp
    test_graph_upgrade.cpp
    test_validator.cpp
    test_graph_registry_local.cpp
    test_pbt_roundtrip.cpp
    test_corpus.cpp
    test_evolution.cpp
    test_harness_bench.cpp
    test_schema_evolution.cpp
    test_barrier_persistence.cpp
    test_coordinator.cpp
    test_sends_interrupt_order.cpp
    test_dynamic_interrupt.cpp
    test_tool_gate.cpp
    test_multi_send_events.cpp
    test_multi_send_routing.cpp
    test_schema_provider_concurrent.cpp
    test_schema_provider_async.cpp
    test_schema_provider_stream_usage.cpp
    test_schema_provider_responses_stream.cpp
    test_schema_provider_stop_reason.cpp
    test_rate_limited_provider.cpp
    test_admin_api_barrier_preservation.cpp
    test_intent_classifier_streaming.cpp
    test_incremental_checkpoint.cpp
    test_deep_research_human_review.cpp
    test_async_conn_pool.cpp
    test_async_http_errors.cpp
    test_async_sse_parser.cpp
    test_async_ws_codec.cpp
    test_async_ws_loopback.cpp
    test_schema_provider_ws_responses.cpp
    test_async_http_stream.cpp
    test_async_http_options.cpp
    test_provider_async_default.cpp
    test_provider_invoke_default.cpp
    test_completion_provider.cpp
    test_artifact_provider.cpp
    test_run_context_store.cpp
    test_runtime_context.cpp
    test_run_result_channel.cpp
    test_typed_events.cpp
    test_error_messages_friendly.cpp
    test_schema_provider_extra_fields_temperature.cpp
    test_openai_provider_async.cpp
    test_checkpoint_async_default.cpp
    test_graph_engine_async_api.cpp
    test_async_tool.cpp
    test_executor_async_retry.cpp
    test_executor_async_parallel.cpp
    test_async_run_sync_pool.cpp
    test_node_cache.cpp
    test_node_run_dispatch.cpp
    test_cancel_token_fork.cpp
    test_concurrent_stress.cpp
    test_openinference_cpp.cpp
    test_schema_provider_stream_async_outer_io.cpp
    test_graph_invocation.cpp
    test_graph_safe_point.cpp
)
if(NEOGRAPH_BUILD_PROGRAM)
    add_executable(neograph_program_tests
        test_program_authoring.cpp
        test_program_values.cpp
        test_program_command.cpp
        test_program_native.cpp
        native_abi_c_smoke.c
        test_program_registry.cpp
        test_program_admission.cpp
        test_program_compiler.cpp
        test_program_catalog.cpp
        test_program_module.cpp
        test_program_contract.cpp
        test_program_journal.cpp
        test_program_lineage.cpp
        test_program_pending.cpp
        test_program_fork_replay.cpp
        test_graph_migration_capsule.cpp
        test_program_transition_store.cpp
        test_program_runtime.cpp
        test_program_runtime_instruction.cpp
        test_program_invocation.cpp
        test_program_task_graph_proposal.cpp
    )
    target_include_directories(neograph_program_tests PRIVATE
        ${PROJECT_SOURCE_DIR}/src/program
    )
    target_link_libraries(neograph_program_tests PRIVATE
        neograph::program
        GTest::gtest_main
    )
    if(MSVC)
        # test_program_runtime.cpp intentionally exercises the complete durable
        # state machine and exceeds COFF's default section count in optimized
        # multi-config builds.
        target_compile_options(neograph_program_tests PRIVATE /bigobj)
    endif()
    if(NEOGRAPH_BUILD_QUICKJS_CONTROL)
        target_compile_definitions(neograph_program_tests PRIVATE
            NEOGRAPH_PROGRAM_TESTS_HAVE_QUICKJS
        )
        add_executable(program_model_synthesis_probe
            program_model_synthesis_probe.cpp
        )
        target_link_libraries(program_model_synthesis_probe PRIVATE
            neograph::program
        )
        add_test(
            NAME Program.ModelSynthesisProbe
            COMMAND program_model_synthesis_probe
                ${CMAKE_CURRENT_SOURCE_DIR}/fixtures/model_program_synthesis/valid.js
        )
        set_tests_properties(Program.ModelSynthesisProbe PROPERTIES
            LABELS "program;quickjs;synthesis"
        )
        add_executable(program_dsl_capability_probe
            program_dsl_capability_probe.cpp
        )
        target_include_directories(program_dsl_capability_probe PRIVATE
            ${PROJECT_SOURCE_DIR}/src/program
        )
        target_link_libraries(program_dsl_capability_probe PRIVATE
            neograph::program
        )
        set(_neograph_dsl_capability_cases
            graph_basics
            graph_routing
            graph_fanout_barrier
            graph_hitl_retry
            registry_mediated
            program_control_flow
            program_map
            program_structured_concurrency
            program_spawn_await
            program_durability
            program_host_capability
        )
        foreach(_case IN LISTS _neograph_dsl_capability_cases)
            add_test(
                NAME Program.DslCapability.${_case}
                COMMAND program_dsl_capability_probe
                    ${_case}
                    ${CMAKE_CURRENT_SOURCE_DIR}/fixtures/dsl_capabilities/${_case}.js
            )
            set_tests_properties(Program.DslCapability.${_case} PROPERTIES
                LABELS "program;quickjs;dsl-capability"
            )
        endforeach()
        add_executable(program_model_semantic_migration_probe
            program_model_semantic_migration_probe.cpp
        )
        target_link_libraries(program_model_semantic_migration_probe PRIVATE
            neograph::program
        )
        add_test(
            NAME Program.ModelSemanticMigrationProbe
            COMMAND program_model_semantic_migration_probe
                ${CMAKE_CURRENT_SOURCE_DIR}/fixtures/model_semantic_migration/valid.js
        )
        set_tests_properties(Program.ModelSemanticMigrationProbe PROPERTIES
            LABELS "program;quickjs;synthesis;migration"
        )
    endif()
    if(TARGET neograph_program_sqlite)
        target_compile_definitions(neograph_program_tests PRIVATE
            NEOGRAPH_PROGRAM_TESTS_HAVE_SQLITE
        )
        target_link_libraries(neograph_program_tests PRIVATE
            neograph::program_sqlite
            SQLite::SQLite3
        )
        if(TARGET neograph_sqlite)
            target_compile_definitions(neograph_program_tests PRIVATE
                NEOGRAPH_PROGRAM_TESTS_HAVE_SQLITE_CHECKPOINT
            )
            target_link_libraries(neograph_program_tests PRIVATE
                neograph::sqlite
            )
        endif()
    endif()
    if(TARGET neograph_program_postgres)
        target_compile_definitions(neograph_program_tests PRIVATE
            NEOGRAPH_PROGRAM_TESTS_HAVE_POSTGRES
        )
        target_link_libraries(neograph_program_tests PRIVATE
            neograph::program_postgres
        )
    endif()
endif()

if(TARGET neograph_quickjs)
    add_executable(neograph_quickjs_tests
        test_quickjs_runtime.cpp
    )
    target_compile_features(neograph_quickjs_tests PRIVATE cxx_std_17)
    _neograph_attach_quickjs_runtime(neograph_quickjs_tests)
    target_link_libraries(neograph_quickjs_tests PRIVATE
        GTest::gtest_main
    )

    add_executable(neograph_quickjs_c_smoke
        quickjs_c_smoke.c
    )
    set_target_properties(neograph_quickjs_c_smoke PROPERTIES
        C_STANDARD 11
        C_STANDARD_REQUIRED ON)
    _neograph_attach_quickjs_runtime(neograph_quickjs_c_smoke)
endif()

if(NEOGRAPH_BUILD_MCP_CLIENT)
    # A stdio MCP tool used from inside a graph run — the combination nothing
    # covered, and a use-after-free until the session stopped depending on an
    # io_context it does not own.
    target_sources(neograph_tests PRIVATE test_mcp_stdio_in_graph.cpp)
    target_sources(neograph_tests PRIVATE
        test_mcp_client_async.cpp
        test_mcp_stdio_async.cpp
    )
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTS_HAVE_MCP_CLIENT)

    add_executable(neograph_mcp_hook_rpc_tests
        test_hook_rpc_mcp.cpp
    )
    target_link_libraries(neograph_mcp_hook_rpc_tests PRIVATE
        neograph::mcp
        GTest::gtest_main
    )
endif()

if(NEOGRAPH_BUILD_MCP_SERVER)
    target_sources(neograph_tests PRIVATE test_mcp_server.cpp)
endif()

if(TARGET neograph_harness)
    target_sources(neograph_tests PRIVATE
        test_harness_contract.cpp
    )
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTS_HAVE_HARNESS)
    if(NEOGRAPH_BUILD_QUICKJS_CONTROL)
        target_sources(neograph_tests PRIVATE
            test_harness_program_translator.cpp
            test_harness_program_cutover.cpp
        )
    endif()
endif()
if(TARGET neograph_mcp_sqlite)
    target_sources(neograph_tests PRIVATE test_harness_program_store.cpp)
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTING)

    add_executable(neograph_harness_program_store_tests
        test_harness_program_store.cpp
    )
    target_compile_definitions(neograph_harness_program_store_tests PRIVATE NEOGRAPH_TESTING)
    target_link_libraries(neograph_harness_program_store_tests PRIVATE
        neograph::mcp_sqlite
        SQLite::SQLite3
        GTest::gtest_main
    )
endif()

if(NEOGRAPH_BUILD_MCP_HTTP_SERVER)
    target_sources(neograph_tests PRIVATE test_mcp_http_server.cpp)
endif()

if(NEOGRAPH_BUILD_MCP_CLIENT AND TARGET neograph_harness)
    target_sources(neograph_tests PRIVATE test_harness_mcp_backend.cpp)
endif()

if(NEOGRAPH_BUILD_A2A)
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_A2A_TESTING)
    target_sources(neograph_tests PRIVATE
        test_a2a_types.cpp
        test_a2a_collaboration.cpp
        test_a2a_client.cpp
        test_a2a_server.cpp
    )
endif()

# The Agent Card Copy Ninja PoC intentionally has no LLM, Harness, or remote
# agent dependency. Keep its end-to-end loopback test independently runnable
# in the minimal A2A configuration.
if(NEOGRAPH_BUILD_A2A)
    add_executable(neograph_a2a_agent_card_candidate_tests
        test_a2a_agent_card_candidate.cpp
    )
    target_link_libraries(neograph_a2a_agent_card_candidate_tests PRIVATE
        neograph::a2a
        httplib
        OpenSSL::SSL
        OpenSSL::Crypto
        GTest::gtest_main
    )
endif()

if(NEOGRAPH_BUILD_UTIL)
    target_sources(neograph_tests PRIVATE test_request_queue.cpp)
endif()

if(NEOGRAPH_BUILD_ACP)
    target_sources(neograph_tests PRIVATE
        test_acp_types.cpp
        test_acp_server.cpp
    )
endif()


# Keep the protocol-neutral invocation and ACP adapter contract independently
# buildable.  The aggregate neograph_tests target also contains HTTP/schema
# tests that require OpenSSL headers; ACP itself depends only on Core and must
# retain a runnable build gate in minimal dependency environments.
if(NEOGRAPH_BUILD_ACP)
    add_executable(neograph_acp_tests
        test_graph_invocation.cpp
        test_acp_types.cpp
        test_acp_server.cpp
    )
    target_link_libraries(neograph_acp_tests PRIVATE
        neograph::core
        neograph::acp
        GTest::gtest_main
    )
endif()

# Smoke tests for the async::async_get helper added with the A2A client
# — the GET path was new and build_request gained a method parameter,
# so these guard the surface against future POST/GET regressions.
target_sources(neograph_tests PRIVATE test_async_get.cpp)

# PostgresCheckpointStore integration tests are gated on NEOGRAPH_BUILD_POSTGRES
# at the build level (so projects without libpqxx still build the test
# binary) and on NEOGRAPH_TEST_POSTGRES_URL at runtime (skipped if unset).
# The repo's habit is to gate a whole test FILE on its backend. That does not
# fit a file whose backend cases sit next to backend-independent ones (see
# test_channel_write_mode.cpp), so those get a compile definition to guard on
# instead. Without it the file references SqliteCheckpointStore /
# PostgresCheckpointStore unconditionally and the link fails on any build
# without them — which is what the Windows and TSan jobs are.
if(NEOGRAPH_BUILD_POSTGRES)
    target_sources(neograph_tests PRIVATE test_postgres_checkpoint.cpp)
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTS_HAVE_POSTGRES)

    add_executable(neograph_postgres_old_header_abi
        test_postgres_old_header_abi.cpp)
    target_link_libraries(neograph_postgres_old_header_abi PRIVATE
        neograph::postgres)
endif()

if(NEOGRAPH_BUILD_SQLITE)
    target_sources(neograph_tests PRIVATE test_sqlite_checkpoint.cpp test_evidence_ledger.cpp test_sqlite_runtime_stores.cpp)
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTS_HAVE_SQLITE)
endif()

if(NOT NEOGRAPH_USE_LIBCURL)
    target_sources(neograph_tests PRIVATE test_provider_constructor_exception_safety.cpp)
else()
    target_compile_definitions(neograph_tests PRIVATE NEOGRAPH_TESTS_HAVE_LIBCURL)
endif()

target_link_libraries(neograph_tests PRIVATE
    neograph::core
    GTest::gtest_main
)

# Keep the core and Program test targets buildable in the minimal dependency
# configuration.  The corresponding source files are already compile-gated
# where a component-specific API is used; a test target must not manufacture a
# link dependency on an optional library that was intentionally disabled.
foreach(_neograph_test_component IN ITEMS llm async mcp mcp_server harness mcp_http_server a2a acp util postgres)
    if(TARGET neograph::${_neograph_test_component})
        target_link_libraries(neograph_tests PRIVATE neograph::${_neograph_test_component})
    endif()
endforeach()
if(TARGET httplib)
    target_link_libraries(neograph_tests PRIVATE httplib)
endif()
if(TARGET cppdotenv)
    target_link_libraries(neograph_tests PRIVATE cppdotenv)
endif()
if(TARGET OpenSSL::SSL)
    target_link_libraries(neograph_tests PRIVATE OpenSSL::SSL OpenSSL::Crypto)
endif()

if(NEOGRAPH_BUILD_MCP_CLIENT)
    target_link_libraries(neograph_tests PRIVATE neograph::mcp)
endif()

if(NEOGRAPH_BUILD_MCP_SERVER)
    target_link_libraries(neograph_tests PRIVATE neograph::mcp_server)
endif()

if(TARGET neograph_harness)
    target_link_libraries(neograph_tests PRIVATE neograph::harness)
endif()

if(NEOGRAPH_BUILD_MCP_HTTP_SERVER)
    target_link_libraries(neograph_tests PRIVATE neograph::mcp_http_server)
endif()

if(NEOGRAPH_BUILD_A2A)
    target_link_libraries(neograph_tests PRIVATE neograph::a2a)
endif()

if(NEOGRAPH_BUILD_ACP)
    target_link_libraries(neograph_tests PRIVATE neograph::acp)
endif()

if(NEOGRAPH_BUILD_UTIL)
    target_link_libraries(neograph_tests PRIVATE neograph::util)
endif()

if(NEOGRAPH_BUILD_POSTGRES)
    # The test TU pokes libpq directly (PQconnectdb + pg_terminate_backend
    # sibling path in RetriesAfterBrokenConnection), so it needs the
    # libpq include / link in addition to neograph::postgres.
    target_link_libraries(neograph_tests PRIVATE neograph::postgres PostgreSQL::PostgreSQL)
endif()

if(NEOGRAPH_BUILD_SQLITE)
    target_link_libraries(neograph_tests PRIVATE neograph::sqlite SQLite::SQLite3)
    if(TARGET neograph_mcp_sqlite)
        target_link_libraries(neograph_tests PRIVATE neograph::mcp_sqlite SQLite::SQLite3)
    endif()
endif()

include(GoogleTest)

if(TARGET neograph_mcp_hook_rpc_tests)
    gtest_discover_tests(neograph_mcp_hook_rpc_tests)
endif()

# Keep durable runtime-contract verification independent from optional provider
# transports so canonical identity tests remain runnable in minimal Core builds.
add_executable(neograph_runtime_context_tests
    test_runtime_context.cpp
    test_context_transform.cpp
)
target_link_libraries(neograph_runtime_context_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_runtime_context_tests)

# Hook planning is Core-only and intentionally does not depend on providers,
# model tool calls, or optional transport libraries.
add_executable(neograph_hook_tests
    test_hook.cpp
    test_checkpoint_hook.cpp
)
target_link_libraries(neograph_hook_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_hook_tests)

add_executable(neograph_hook_rpc_tests
    test_hook_rpc.cpp
)
target_link_libraries(neograph_hook_rpc_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_hook_rpc_tests)

add_executable(neograph_context_store_tests
    test_context_store.cpp
)
target_link_libraries(neograph_context_store_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_context_store_tests)

if(NEOGRAPH_BUILD_SQLITE)
    # Keep runtime-store migration and outcome lifecycle tests independently
    # buildable on Windows; unrelated checkpoint fixtures include POSIX-only
    # test helpers in some developer configurations.
    add_executable(neograph_sqlite_runtime_store_tests
        test_sqlite_runtime_stores.cpp
    )
    target_link_libraries(neograph_sqlite_runtime_store_tests PRIVATE
        neograph::core
        neograph::sqlite
        SQLite::SQLite3
        GTest::gtest_main
    )
    gtest_discover_tests(neograph_sqlite_runtime_store_tests)
endif()

add_executable(neograph_runtime_turn_tests
    test_runtime_turn_assembler.cpp
    test_controlled_provider.cpp
)
target_link_libraries(neograph_runtime_turn_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_runtime_turn_tests)

# Keep the live safe-point boundary independently runnable from optional
# backend tests in the aggregate Core binary.
add_executable(neograph_graph_safe_point_tests
    test_graph_safe_point.cpp
)
target_link_libraries(neograph_graph_safe_point_tests PRIVATE
    neograph::core
    GTest::gtest_main
)
gtest_discover_tests(neograph_graph_safe_point_tests)

# Cross-repository compatibility metadata is owner-local. Keep its fail-closed
# check available without making a clean public checkout depend on private files.
set(NEOGRAPH_COMPATIBILITY_METADATA
    ${PROJECT_SOURCE_DIR}/spec/cross-repository-compatibility-v1.json)
set(NEOGRAPH_COMPATIBILITY_SCHEMA
    ${PROJECT_SOURCE_DIR}/spec/cross-repository-compatibility-v1.schema.json)
if(EXISTS "${NEOGRAPH_COMPATIBILITY_METADATA}" AND EXISTS "${NEOGRAPH_COMPATIBILITY_SCHEMA}")
    add_test(NAME CrossRepositoryCompatibility.Metadata
        COMMAND Python3::Interpreter
            ${PROJECT_SOURCE_DIR}/scripts/check_cross_repository_compatibility.py
            --metadata ${NEOGRAPH_COMPATIBILITY_METADATA}
            --schema ${NEOGRAPH_COMPATIBILITY_SCHEMA})
    set_tests_properties(CrossRepositoryCompatibility.Metadata
        PROPERTIES LABELS "compatibility;metadata")
endif()

# Q7 uses a frozen-storage audit rather than a claim inferred from source
# availability. Keep its Python contract runnable in minimal configurations.
add_test(NAME QuickJS.LegacyDrainAudit
    COMMAND Python3::Interpreter
        ${PROJECT_SOURCE_DIR}/tests/test_legacy_drain_audit.py)
set_tests_properties(QuickJS.LegacyDrainAudit
    PROPERTIES LABELS "quickjs;migration;metadata")

if(TARGET neograph_program_tests)
    if(NEOGRAPH_BUILD_POSTGRES)
        # Keep the Program PostgreSQL store integration case off the shared
        # checkpoint fixture while other test cases remain parallelizable.
        set(NEOGRAPH_PROGRAM_PG_LOCKED_TESTS
            "ProgramCatalogTest.PostgreSQLProgramStoreReopensActivationAndOwnerVisibility")
        gtest_discover_tests(neograph_program_tests
            TEST_FILTER "${NEOGRAPH_PROGRAM_PG_LOCKED_TESTS}"
            PROPERTIES RESOURCE_LOCK postgres_test_db)
        gtest_discover_tests(neograph_program_tests
            TEST_FILTER "-${NEOGRAPH_PROGRAM_PG_LOCKED_TESTS}")
    else()
        gtest_discover_tests(neograph_program_tests)
    endif()
endif()
if(TARGET neograph_harness_program_store_tests)
    gtest_discover_tests(neograph_harness_program_store_tests)
endif()
if(TARGET neograph_a2a_agent_card_candidate_tests)
    gtest_discover_tests(neograph_a2a_agent_card_candidate_tests)
endif()
if(TARGET neograph_acp_tests)
    gtest_discover_tests(neograph_acp_tests)
endif()
if(TARGET neograph_quickjs_tests)
    gtest_discover_tests(neograph_quickjs_tests)
endif()
if(TARGET neograph_quickjs)
    add_test(NAME QuickJS.MsvcPortSource
        COMMAND ${CMAKE_COMMAND}
            -DNEOGRAPH_SOURCE_DIR=${PROJECT_SOURCE_DIR}
            -DNEOGRAPH_BINARY_DIR=${PROJECT_BINARY_DIR}
            -P ${PROJECT_SOURCE_DIR}/tests/verify_quickjs_msvc_port.cmake)
    set_tests_properties(QuickJS.MsvcPortSource PROPERTIES LABELS "quickjs;portability")
endif()


if(TARGET neograph_quickjs_c_smoke)
    add_test(NAME QuickJS.CEmbeddingSmoke COMMAND neograph_quickjs_c_smoke)
    set_tests_properties(QuickJS.CEmbeddingSmoke PROPERTIES LABELS "quickjs;abi")
endif()
if(TARGET neograph_a2a_agent_card_candidate_tests)
    gtest_discover_tests(neograph_a2a_agent_card_candidate_tests)
endif()

if(NEOGRAPH_BUILD_POSTGRES)
    add_test(NAME PostgresCheckpointAbiTest.OldHeaderNewLibrary
        COMMAND neograph_postgres_old_header_abi)
    set_tests_properties(PostgresCheckpointAbiTest.OldHeaderNewLibrary
        PROPERTIES RESOURCE_LOCK postgres_test_db)
endif()

# ThreadSanitizer ASLR notice: when CMAKE_CXX_FLAGS contains
# `-fsanitize=thread`, the test binaries can FATAL with
# "unexpected memory mapping" on Linux kernels with high
# mmap_rnd_bits (newer Ubuntu / RHEL defaults). Workaround is to
# invoke ctest itself through `setarch x86_64 -R` — the
# ADDR_NO_RANDOMIZE flag inherits through fork, so every test
# child also gets a low-randomization layout TSan understands:
#
#     setarch x86_64 -R ctest -E "BIG_|valgrind"
#
# CI's tsan-test job does this in its run-step. There is no clean
# CMake hook to inject the launcher into add_test commands
# generated by gtest_discover_tests, so we document the contract
# rather than try to hide it.
if(CMAKE_CXX_FLAGS MATCHES "fsanitize=thread")
    message(STATUS "TSan detected — invoke ctest through "
                   "`setarch x86_64 -R ctest ...` to avoid the "
                   "ASLR/`unexpected memory mapping` FATAL.")
endif()

if(NEOGRAPH_BUILD_POSTGRES)
    # PostgresCheckpointTest cases share one DB and call drop_schema in
    # SetUp/TearDown — running them in parallel collides on DDL. Mark
    # them with a RESOURCE_LOCK so ctest serializes only this group
    # while the other ~200 tests still run concurrently.
    # ChannelWriteModeTest.OverwriteSurvivesReplayThroughPostgres joins the
    # locked group: it talks to the same database, and the Postgres suite's
    # drop_schema() will wipe its tables mid-run otherwise. Observed exactly
    # that — green standalone, red under `ctest -j8`.
    set(NEOGRAPH_PG_LOCKED_TESTS
        "PostgresCheckpointTest.*:ChannelWriteModeTest.OverwriteSurvivesReplayThroughPostgres")
    gtest_discover_tests(neograph_tests
        TEST_FILTER "${NEOGRAPH_PG_LOCKED_TESTS}"
        PROPERTIES RESOURCE_LOCK postgres_test_db
    )
    gtest_discover_tests(neograph_tests
        TEST_FILTER "-${NEOGRAPH_PG_LOCKED_TESTS}"
    )
else()
    gtest_discover_tests(neograph_tests)
endif()
