# Reusable object library compiling the fcitx5-side sources once per compiler build,
# shared across all headless integration test executables.
add_library(ngosen_test_core OBJECT ${ngosen_fcitx_sources})
set_target_properties(ngosen_test_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_include_directories(ngosen_test_core PRIVATE
    ${PROJECT_BINARY_DIR}
    ${PROJECT_SOURCE_DIR}/src
)
target_compile_definitions(ngosen_test_core PRIVATE
    NGOSEN_SETTINGS_PATH="${CMAKE_INSTALL_FULL_BINDIR}/fcitx5-ngosen-settings"
    NGOSEN_ICON_DIR="${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps"
    # No catalog here, so tests see English whatever is installed on the machine.
    NGOSEN_LOCALEDIR="${PROJECT_BINARY_DIR}/test/no-locale"
)
target_link_libraries(ngosen_test_core PRIVATE
    ngosen_core
    Fcitx5::Core
    Fcitx5::Config
    Fcitx5::Module::Emoji
    ${NGOSEN_DBUS_MODULE}
    ${NGOSEN_NOTIFICATIONS_MODULE}
    Bamboo::Core
    Pthread::Pthread
)

# Helper macro to compile standalone headless integration test linked with the engine.
#
# Usage:
#   add_ngosen_headless_test(<target_name> <source_file> "<labels>")
# Example:
#   add_ngosen_headless_test(my_test my-test.cpp "integration;myfeature")
function(add_ngosen_headless_test target source labels)
    add_executable(${target} ${source} $<TARGET_OBJECTS:ngosen_test_core>)
    ngosen_headless_test_settings(${target})
    if(TARGET ngosen_test_pch)
        target_precompile_headers(${target} REUSE_FROM ngosen_test_pch)
    endif()
    add_test(NAME ${target} COMMAND ${target})
    # An empty DISPLAY keeps XTEST off, so no test presses keys in the developer's X session.
    set_tests_properties(${target} PROPERTIES LABELS "${labels}" TIMEOUT 20 ENVIRONMENT "DISPLAY=")
endfunction()

# The precompiled header is reused only by targets with the same flags, so the tests and its host
# share one set.
function(ngosen_headless_test_settings target)
    target_include_directories(${target} PRIVATE
        ${PROJECT_BINARY_DIR}
        ${PROJECT_SOURCE_DIR}/src
    )
    target_compile_definitions(${target} PRIVATE
        NGOSEN_SETTINGS_PATH="${CMAKE_INSTALL_FULL_BINDIR}/fcitx5-ngosen-settings"
        NGOSEN_ICON_DIR="${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps"
        NGOSEN_TEST_DICTIONARY="${PROJECT_SOURCE_DIR}/data/dictionaries/vietnamese.cm.dict"
        NGOSEN_TEST_ENGLISH_WORDS="${PROJECT_SOURCE_DIR}/data/english-common.txt"
    )
    target_link_libraries(${target} PRIVATE
        ngosen_core
        ngosen_migration
        Fcitx5::Core
        Fcitx5::Config
        Fcitx5::Module::Emoji
        ${NGOSEN_DBUS_MODULE}
        ${NGOSEN_NOTIFICATIONS_MODULE}
        Bamboo::Core
        Pthread::Pthread
    )
endfunction()

# Every headless test parses the same fcitx5 headers; parse them once.
if(NOT CMAKE_VERSION VERSION_LESS 3.16)
    add_library(ngosen_test_pch OBJECT EXCLUDE_FROM_ALL test-pch.cpp)
    ngosen_headless_test_settings(ngosen_test_pch)
    target_precompile_headers(ngosen_test_pch PRIVATE
        <filesystem>
        <iostream>
        <memory>
        <string>
        <vector>
        <fcitx-config/iniparser.h>
        <fcitx-utils/event.h>
        <fcitx-utils/utf8.h>
        <fcitx/action.h>
        <fcitx/addonfactory.h>
        <fcitx/addonmanager.h>
        <fcitx/candidatelist.h>
        <fcitx/inputcontext.h>
        <fcitx/inputcontextmanager.h>
        <fcitx/inputmethodengine.h>
        <fcitx/inputpanel.h>
        <fcitx/instance.h>
        <fcitx/text.h>
    )
endif()

# Helper macro to compile lightweight unit test linked with Bamboo engine core.
function(add_bamboo_test target source labels)
    add_executable(${target} ${source})
    target_link_libraries(${target} PRIVATE Bamboo::Core)
    add_test(NAME ${target} COMMAND ${target})
    set_tests_properties(${target} PROPERTIES LABELS "${labels}" TIMEOUT 20)
endfunction()

add_ngosen_headless_test(preedit_lifecycle preedit-lifecycle.cpp "integration;preedit")
add_ngosen_headless_test(click_keeps_preedit click-keeps-preedit.cpp "integration;preedit")
add_ngosen_headless_test(app_rule_reset app-rule-reset.cpp "integration;apprule")
add_ngosen_headless_test(default_app_mode default-app-mode.cpp "integration;apprule")
add_test(NAME default_app_mode_override COMMAND default_app_mode override)
set_tests_properties(default_app_mode_override PROPERTIES LABELS "integration;apprule" TIMEOUT 20 ENVIRONMENT "DISPLAY=")
add_ngosen_headless_test(ctx_rule_cleanup ctx-rule-cleanup.cpp "integration;apprule")
add_ngosen_headless_test(mode_menu_keys mode-menu-keys.cpp "integration;apprule")
add_ngosen_headless_test(toggle_key toggle-key.cpp "integration;apprule")
add_ngosen_headless_test(app_switch_memory app-switch-memory.cpp "integration;apprule")
add_ngosen_headless_test(retype_after_switch retype-after-switch.cpp "integration;retype")
add_ngosen_headless_test(gnome_shared_ibus_context gnome-shared-ibus-context.cpp "integration;apprule;gnome")
add_ngosen_headless_test(mode_name_migration mode-name-migration.cpp "integration;mode")
add_ngosen_headless_test(messenger_defaults messenger-defaults.cpp "integration;mode")
add_ngosen_headless_test(options_sync options-sync.cpp "integration;config")
add_ngosen_headless_test(tray_menu_items tray-menu-items.cpp "integration;config")
add_ngosen_headless_test(ui_language ui-language.cpp "integration;config")
target_compile_definitions(ui_language PRIVATE NGOSEN_TEST_CATALOG="${PROJECT_BINARY_DIR}/po/fcitx5-ngosen-vi.mo")
add_dependencies(ui_language fcitx5-ngosen-translation)
add_ngosen_headless_test(typing_log_file typing-log-file.cpp "integration;log")
add_ngosen_headless_test(host_field_mapping host-field-mapping.cpp "unit;host")
add_ngosen_headless_test(custom_keymap custom-keymap.cpp "integration;keymap")
add_ngosen_headless_test(preedit_smoke_client preedit-smoke-client.cpp "integration;preedit")
add_ngosen_headless_test(preedit_smoke_server preedit-smoke-server.cpp "integration;preedit")
add_ngosen_headless_test(sen_buffered_key_replay
    sen-buffered-key-replay.cpp "integration;sen")
add_ngosen_headless_test(held_key_repeat
    held-key-repeat.cpp "integration;sen")
add_ngosen_headless_test(sen_half_updated_snapshot
    sen-half-updated-snapshot.cpp "integration;sen")
add_ngosen_headless_test(sen_half_updated_mid_word
    sen-half-updated-mid-word.cpp "integration;sen")
add_ngosen_headless_test(surrounding_wait_event
    surrounding-wait-event.cpp "integration;sen")
add_ngosen_headless_test(sen_settle_wait
    sen-settle-wait.cpp "integration;sen")
add_ngosen_headless_test(wayland_forward_backspaces
    wayland-forward-backspaces.cpp "integration;sen")
add_ngosen_headless_test(xim_key_handback
    xim-key-handback.cpp "integration;sen")
add_ngosen_headless_test(xim_forward_handback
    xim-forward-handback.cpp "integration;sen")
add_ngosen_headless_test(ibus_dbus_forward_backspaces
    ibus-dbus-forward-backspaces.cpp "integration;sen")
add_ngosen_headless_test(cursor_jump_reset
    cursor-jump-reset.cpp "integration;surrounding")
add_ngosen_headless_test(click_switch_fuzz
    click-switch-fuzz.cpp "integration;surrounding")
set_tests_properties(click_switch_fuzz PROPERTIES TIMEOUT 120)
add_ngosen_headless_test(cell_click_key_report
    cell-click-key-report.cpp "integration;surrounding")
add_ngosen_headless_test(calc_text_input_cell_click
    calc-text-input-cell-click.cpp "integration;surrounding")
add_ngosen_headless_test(x11_pointer_click
    x11-pointer-click.cpp "unit;x11")
add_ngosen_headless_test(x11_xtest_replacement
    x11-xtest-replacement.cpp "integration;sen")
add_ngosen_headless_test(sen_settle_wait_immediate
    sen-settle-wait-immediate.cpp "integration;sen")
add_ngosen_headless_test(sen_settle_plain_field
    sen-settle-plain-field.cpp "integration;sen")
add_ngosen_headless_test(sen_settle_empty_composer
    sen-settle-empty-composer.cpp "integration;sen")
add_ngosen_headless_test(sen_messenger_select_overtype
    sen-messenger-select-overtype.cpp "integration;sen")
add_ngosen_headless_test(replay_single_commit
    replay-single-commit.cpp "integration;sen")
add_ngosen_headless_test(sen_settle_first_word
    sen-settle-first-word.cpp "integration;sen")
add_ngosen_headless_test(emoji_candidate_keys emoji-candidate-keys.cpp "integration;emoji")
add_ngosen_headless_test(emoji_history_page_navigation
    emoji-history-page-navigation.cpp "integration;emoji")
add_ngosen_headless_test(property_invariants
    property-invariants.cpp "integration;property")
add_bamboo_test(numeric_macro_case_preservation
    numeric-macro-case-preservation.cpp "unit;macro")

add_executable(emoji_backspace_utf8
    test-emoji-backspace.cpp
    ${PROJECT_SOURCE_DIR}/src/core/ngosen-utf8.cpp
)
target_include_directories(emoji_backspace_utf8 PRIVATE
    ${PROJECT_SOURCE_DIR}/src/core
)
target_link_libraries(emoji_backspace_utf8 PRIVATE
    Fcitx5::Core
)
add_test(NAME emoji_backspace_utf8 COMMAND emoji_backspace_utf8)
set_tests_properties(emoji_backspace_utf8 PROPERTIES
    LABELS "unit;emoji"
    TIMEOUT 20
)

add_executable(plasma_panel_theme
    plasma-panel-theme.cpp
    ${PROJECT_SOURCE_DIR}/src/ngosen-plasma-theme.cpp
    ${PROJECT_SOURCE_DIR}/src/ngosen-utils.cpp
)
target_include_directories(plasma_panel_theme PRIVATE
    ${PROJECT_BINARY_DIR}
    ${PROJECT_SOURCE_DIR}/src
    ${PROJECT_SOURCE_DIR}/src/core
)
target_link_libraries(plasma_panel_theme PRIVATE
    Fcitx5::Core
    Fcitx5::Utils
)
add_test(NAME plasma_panel_theme COMMAND plasma_panel_theme)
set_tests_properties(plasma_panel_theme PROPERTIES
    LABELS "unit;icon"
    TIMEOUT 20
)

add_executable(gnome_panel_theme
    gnome-panel-theme.cpp
    ${PROJECT_SOURCE_DIR}/src/ngosen-gnome-theme.cpp
    ${PROJECT_SOURCE_DIR}/src/ngosen-utils.cpp
)
target_include_directories(gnome_panel_theme PRIVATE
    ${PROJECT_BINARY_DIR}
    ${PROJECT_SOURCE_DIR}/src
    ${PROJECT_SOURCE_DIR}/src/core
)
target_link_libraries(gnome_panel_theme PRIVATE
    Fcitx5::Core
    Fcitx5::Utils
)
add_test(NAME gnome_panel_theme COMMAND gnome_panel_theme)
set_tests_properties(gnome_panel_theme PROPERTIES
    LABELS "unit;icon"
    TIMEOUT 20
)

add_executable(menu_icon menu-icon.cpp ${PROJECT_SOURCE_DIR}/src/ngosen-menu-icon.cpp)
target_include_directories(menu_icon PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(menu_icon PRIVATE Fcitx5::Core Fcitx5::Utils)
add_test(NAME menu_icon COMMAND menu_icon)
set_tests_properties(menu_icon PROPERTIES LABELS "unit;icon" TIMEOUT 20)

# Compares the typing logic's own UTF-8 helpers with the fcitx5 ones they replace.
add_executable(utf8_matches_fcitx utf8-matches-fcitx.cpp ${PROJECT_SOURCE_DIR}/src/core/ngosen-utf8.cpp)
target_include_directories(utf8_matches_fcitx PRIVATE ${PROJECT_SOURCE_DIR}/src/core)
target_link_libraries(utf8_matches_fcitx PRIVATE Fcitx5::Utils)
add_test(NAME utf8_matches_fcitx COMMAND utf8_matches_fcitx)
set(utf8_matches_fcitx_timeout 60)
# The exhaustive check is slow in the sanitizer build.
if (CMAKE_CXX_FLAGS MATCHES "-fsanitize=")
    set(utf8_matches_fcitx_timeout 240)
endif()
set_tests_properties(utf8_matches_fcitx PROPERTIES LABELS "unit" TIMEOUT ${utf8_matches_fcitx_timeout})

# Settings saved under the lotus names carry over to the ngosen names.
add_executable(ngosen_migration_test ngosen-migration.cpp)
target_link_libraries(ngosen_migration_test PRIVATE ngosen_migration)
add_test(NAME ngosen_migration COMMAND ngosen_migration_test)
set_tests_properties(ngosen_migration PROPERTIES LABELS "unit;config" TIMEOUT 20)

# fcitx5 reads the dependencies declared in the generated addon files.
add_executable(addon_conf_test addon-conf.cpp)
target_link_libraries(addon_conf_test PRIVATE Fcitx5::Core Fcitx5::Config)
target_compile_definitions(addon_conf_test PRIVATE
    NGOSEN_ADDON_CONF="${PROJECT_BINARY_DIR}/src/ngosen-addon.conf"
    NGOSEN_MIGRATE_CONF="${PROJECT_BINARY_DIR}/src/ngosenmigrate.conf"
)
# ngosen-addon.conf comes from the translation step, not from the ngosen target.
add_dependencies(addon_conf_test ngosen-addon.conf.in-fmt ngosenmigrate)
add_test(NAME addon_conf COMMAND addon_conf_test)
set_tests_properties(addon_conf PROPERTIES LABELS "unit;config" TIMEOUT 20)

add_test(NAME copr_makefile COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/copr-makefile.sh ${PROJECT_SOURCE_DIR})
set_tests_properties(copr_makefile PROPERTIES LABELS "unit;packaging" TIMEOUT 20 SKIP_RETURN_CODE 77)

add_test(NAME settings_gui_install
         COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/settings-gui-install.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR})
set_tests_properties(settings_gui_install PROPERTIES LABELS "unit;packaging" TIMEOUT 120)

# The typing core's own tests.
add_test(NAME bamboo_rs_cargo_test
    COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${NGOSEN_CARGO_TARGET_DIR}
            ${CARGO_EXECUTABLE} test --offline ${NGOSEN_CARGO_LOCKED}
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bamboo-rs)
set_tests_properties(bamboo_rs_cargo_test PROPERTIES LABELS "unit;core" TIMEOUT 600)

add_test(NAME vendored_crates_switch
         COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/vendored-crates-switch.sh ${CMAKE_COMMAND} ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
set_tests_properties(vendored_crates_switch PROPERTIES LABELS "unit;packaging" TIMEOUT 60)

# Tests of the typing logic alone; NGOSEN_CORE_ONLY builds just these.
add_subdirectory(core)
