Merge branch 'master' into merge/upstream-full
Some checks failed
CI Code / Check spelling (pull_request) Successful in 17s
CI Code / Check coding style (pull_request) Successful in 31s
CI Code / Linux (debian) (pull_request) Failing after 39s
CI Code / Linux (ubuntu) (pull_request) Failing after 42s
CI Code / Linux (arch) (pull_request) Failing after 4m59s
CI Code / Code Coverage (pull_request) Failing after 4m48s

Resolve conflicts after master gained the flat-file database backend,
AI client, and other cproof-fork features:

- CHANGELOG: keep cproof-fork unreleased section atop full upstream
  history (0.17.0 / 0.16.0 / 0.15.1)
- src/command/cmd_ac.c: keep both upstream spellcheck AC and cproof
  /history switch|verify|export|import autocompletion
- src/config/preferences.c: merge upstream [spellcheck] group with the
  cproof [ai]/[ai/<provider>] groups
- src/database.c: take master (thin dispatcher); upstream SQLite
  improvements (v3 migration, auto_gchar) belong in database_sqlite.c
  and will land in a follow-up commit
- src/tools/autocomplete.c: take upstream unescape of search_str
- src/ui/statusbar.c: keep guint signatures (per project preference)
  and adapt _status_bar_draw_dbbackend to guint as well
- src/xmpp/jid.c: combine the new jid_is_valid/jid_is_valid_user_jid
  with the "(null)" legacy-placeholder guard in
  jid_create_from_bare_and_resource; use auto_gchar
- tests/functionaltests/proftest.c: keep unsigned-safe pre-check on
  output_len before subtracting OUTPUT_BUF_SIZE
- tests/unittests/unittests.c: keep upstream subdirectory include
  layout plus cproof-only test_ai_client/database_export/database_stress
- tests/unittests/test_jid.c: drop orphan top-level copy (the
  restructured version lives in tests/unittests/xmpp/test_jid.c)

Upstream is included up to 1ac05754b (release 0.18.0 era). Follow-up:
pull 1ac05754b..upstream/master (esp. 42a849d16 db migration fix and
4749645c7 receipt-request restore), and adapt the SQLite improvements
into database_sqlite.c.
This commit is contained in:
2026-05-18 11:42:48 +03:00
76 changed files with 19454 additions and 1185 deletions

View File

@@ -45,6 +45,9 @@
#include "xmpp/test_form.h"
#include "plugins/test_callbacks.h"
#include "plugins/test_plugins_disco.h"
#include "test_ai_client.h"
#include "test_database_export.h"
#include "test_database_stress.h"
#define muc_unit_test(f) cmocka_unit_test_setup_teardown(f, muc_before_test, muc_after_test)
@@ -712,6 +715,202 @@ main(int argc, char* argv[])
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_confirms_on_second_attempt, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_invalid_policy, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_invalid_mode, load_preferences, close_preferences),
// AI client tests
cmocka_unit_test_setup_teardown(test_ai_client_init, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_add_provider, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_remove_provider, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_list_providers, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_set_provider_key, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_get_provider_key, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_create, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_ref_unref, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_add_message, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_clear_history, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_set_model, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_api_key_is_copied, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_add_provider_update_existing, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_add_provider_null_name_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_add_provider_null_url_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_create_null_provider_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_create_null_model_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_api_key_null_when_no_key_set, ai_client_setup, ai_client_teardown),
/* Provider autocomplete tests */
cmocka_unit_test_setup_teardown(test_ai_providers_find_forward, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_forward_custom, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_forward_no_match, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_forward_partial_match, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_next, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_previous, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_empty_search_str, ai_client_setup, ai_client_teardown),
/* SIGSEGV on ai_providers_find(NULL, ...) — see test body and
* AI_AUTOCOMPLETE_POSSIBLE_ISSUES.md, issue 1. Re-enable once the
* NULL-search path is guarded. */
/* cmocka_unit_test_setup_teardown(test_ai_providers_find_null_search_str, ai_client_setup, ai_client_teardown), */
cmocka_unit_test_setup_teardown(test_ai_providers_find_case_insensitive, ai_client_setup, ai_client_teardown),
/* Provider default model and settings tests */
cmocka_unit_test_setup_teardown(test_ai_set_provider_default_model, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_get_provider_default_model, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_set_provider_setting, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_get_provider_setting, ai_client_setup, ai_client_teardown),
/* Model caching tests */
cmocka_unit_test_setup_teardown(test_ai_models_are_fresh_initial, ai_client_setup, ai_client_teardown),
/* Model parsing tests */
cmocka_unit_test(test_ai_parse_models_openai_format),
cmocka_unit_test(test_ai_parse_models_perplexity_format),
cmocka_unit_test(test_ai_parse_models_array_format),
cmocka_unit_test(test_ai_parse_models_empty_json),
cmocka_unit_test(test_ai_parse_models_null_handling),
cmocka_unit_test(test_ai_parse_models_escaped_quotes),
cmocka_unit_test(test_ai_parse_models_with_whitespace),
/* AI autocomplete integration tests */
cmocka_unit_test_setup_teardown(test_ai_start_provider_autocomplete_only_on_exact, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_cycling, ai_client_setup, ai_client_teardown),
cmocka_unit_test(test_ai_json_escape),
cmocka_unit_test(test_ai_json_escape_null),
cmocka_unit_test(test_ai_json_escape_empty),
cmocka_unit_test(test_ai_json_escape_special_chars),
cmocka_unit_test(test_ai_json_escape_percent_signs),
cmocka_unit_test(test_ai_json_escape_backslash_quote),
/* Chat response parser */
cmocka_unit_test(test_ai_parse_response_openai_content),
cmocka_unit_test(test_ai_parse_response_perplexity_text),
cmocka_unit_test(test_ai_parse_response_text_preferred_over_content),
cmocka_unit_test(test_ai_parse_response_escaped_quote),
cmocka_unit_test(test_ai_parse_response_newline_escape),
cmocka_unit_test(test_ai_parse_response_empty_content),
cmocka_unit_test(test_ai_parse_response_missing_field),
cmocka_unit_test(test_ai_parse_response_null_input),
cmocka_unit_test(test_ai_parse_response_empty_input),
cmocka_unit_test(test_ai_parse_response_percent_signs_safe),
cmocka_unit_test(test_ai_parse_response_braces_in_content),
cmocka_unit_test(test_ai_parse_response_multiline_content),
/* Error response parser */
cmocka_unit_test(test_ai_parse_error_standard_envelope),
cmocka_unit_test(test_ai_parse_error_with_escapes),
cmocka_unit_test(test_ai_parse_error_no_error_field),
cmocka_unit_test(test_ai_parse_error_no_message_field),
cmocka_unit_test(test_ai_parse_error_null_input),
cmocka_unit_test(test_ai_parse_error_empty_input),
cmocka_unit_test(test_ai_parse_error_tab_escape),
cmocka_unit_test(test_ai_parse_error_backslash_escape),
/* Extended JSON escape coverage */
cmocka_unit_test(test_ai_json_escape_backspace),
cmocka_unit_test(test_ai_json_escape_formfeed),
cmocka_unit_test(test_ai_json_escape_carriage_return),
cmocka_unit_test(test_ai_json_escape_all_specials_combined),
cmocka_unit_test(test_ai_json_escape_passes_utf8_through),
/* Autocomplete cycling */
cmocka_unit_test_setup_teardown(test_ai_providers_find_cycles_through_many, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_previous_walks_backwards, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_providers_find_wraps_around, ai_client_setup, ai_client_teardown),
/* Session edge cases */
cmocka_unit_test_setup_teardown(test_ai_session_add_message_null_session_no_crash, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_add_message_null_role_no_crash, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_add_message_null_content_no_crash, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_history_preserves_large_order, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_clear_empty_history, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_set_model_null_keeps_old, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_unref_null_no_crash, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_session_ref_null_returns_null, ai_client_setup, ai_client_teardown),
/* Provider edge cases */
cmocka_unit_test_setup_teardown(test_ai_get_provider_null_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_remove_provider_null_returns_false, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_remove_provider_twice_second_fails, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_provider_survives_via_session_after_removal, ai_client_setup, ai_client_teardown),
/* Settings */
cmocka_unit_test_setup_teardown(test_ai_settings_multiple_keys_independent, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_settings_get_missing_returns_null, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_settings_isolated_between_providers, ai_client_setup, ai_client_teardown),
/* Model parsing edge cases */
cmocka_unit_test_setup_teardown(test_ai_parse_models_data_not_array, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_parse_models_empty_data_array, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_parse_models_id_outside_data_ignored, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_parse_models_multiple_models, ai_client_setup, ai_client_teardown),
/* Prefs round-trip (uses prefs+ai setup) */
cmocka_unit_test_setup_teardown(test_ai_prefs_round_trip_api_key, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
cmocka_unit_test_setup_teardown(test_ai_prefs_round_trip_remove_key, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
cmocka_unit_test_setup_teardown(test_ai_prefs_multiple_providers_persist, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
/* Autocomplete deeper coverage */
cmocka_unit_test_setup_teardown(test_ai_providers_find_after_remove_skips_removed, ai_client_setup, ai_client_teardown),
/* Reset hook + persistence */
cmocka_unit_test_setup_teardown(test_ai_providers_reset_ac_restarts_cycle, ai_client_setup, ai_client_teardown),
cmocka_unit_test_setup_teardown(test_ai_add_provider_persisted_across_init, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
cmocka_unit_test_setup_teardown(test_ai_remove_provider_persisted_across_init, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
cmocka_unit_test_setup_teardown(test_ai_models_persisted_across_init, ai_client_setup_with_prefs, ai_client_teardown_with_prefs),
// Flatfile export/import round-trip
cmocka_unit_test(test_ff_roundtrip_simple_chat),
cmocka_unit_test(test_ff_roundtrip_with_all_metadata),
cmocka_unit_test(test_ff_roundtrip_with_resource),
cmocka_unit_test(test_ff_roundtrip_newline_in_body),
cmocka_unit_test(test_ff_roundtrip_pipe_in_stanza_id),
cmocka_unit_test(test_ff_roundtrip_backslash_in_body),
cmocka_unit_test(test_ff_roundtrip_unicode_body),
cmocka_unit_test(test_ff_roundtrip_empty_body),
cmocka_unit_test(test_ff_roundtrip_colonspace_in_resource),
cmocka_unit_test(test_ff_roundtrip_muc_type),
cmocka_unit_test(test_ff_roundtrip_omemo_enc),
cmocka_unit_test(test_ff_roundtrip_replace_id),
cmocka_unit_test(test_ff_roundtrip_to_jid_and_marked_read),
// Escape / unescape
cmocka_unit_test(test_ff_escape_unescape_message_identity),
cmocka_unit_test(test_ff_escape_unescape_meta_identity),
cmocka_unit_test(test_ff_escape_meta_null_returns_null),
cmocka_unit_test(test_ff_escape_message_null_returns_empty),
// jid_to_dir
cmocka_unit_test(test_ff_jid_to_dir_simple),
cmocka_unit_test(test_ff_jid_to_dir_with_at),
cmocka_unit_test(test_ff_jid_to_dir_path_traversal_rejected),
cmocka_unit_test(test_ff_jid_to_dir_null),
// Parser edge cases
cmocka_unit_test(test_ff_parse_line_empty),
cmocka_unit_test(test_ff_parse_line_comment),
cmocka_unit_test(test_ff_parse_line_legacy_format),
cmocka_unit_test(test_ff_parse_line_no_metadata),
cmocka_unit_test(test_ff_parse_line_invalid_timestamp),
cmocka_unit_test(test_ff_parse_line_empty_timestamp),
cmocka_unit_test(test_ff_parse_line_partial_iso_timestamp),
cmocka_unit_test(test_ff_parse_line_garbage_timestamp),
cmocka_unit_test(test_ff_parse_line_impossible_calendar_date),
cmocka_unit_test(test_ff_parse_line_negative_year_timestamp),
cmocka_unit_test(test_ff_parse_line_far_future_timestamp),
// Type/enc round-trip
cmocka_unit_test(test_ff_type_str_roundtrip),
cmocka_unit_test(test_ff_enc_str_roundtrip),
// Additional round-trip
cmocka_unit_test(test_ff_roundtrip_bracket_in_stanza_id),
cmocka_unit_test(test_ff_roundtrip_backslash_in_resource),
cmocka_unit_test(test_ff_roundtrip_mucpm_type),
cmocka_unit_test(test_ff_roundtrip_all_enc_types),
cmocka_unit_test(test_ff_roundtrip_crlf_handling),
cmocka_unit_test(test_ff_roundtrip_to_jid_special_chars),
cmocka_unit_test(test_ff_roundtrip_multiple_lines),
// Additional parser edge cases
cmocka_unit_test(test_ff_parsed_line_free_null_safe),
cmocka_unit_test(test_ff_parse_line_no_space_rejected),
cmocka_unit_test(test_ff_parse_line_unclosed_bracket),
// Stress tests
cmocka_unit_test(test_stress_rapid_write_parse_1000),
cmocka_unit_test(test_stress_rapid_write_parse_10000),
cmocka_unit_test(test_stress_muc_many_participants),
cmocka_unit_test(test_stress_muc_rapid_messages),
cmocka_unit_test(test_stress_large_message_1mb),
cmocka_unit_test(test_stress_large_message_body_with_special_chars),
cmocka_unit_test(test_stress_many_large_messages_100),
cmocka_unit_test(test_stress_index_build_10000_lines),
cmocka_unit_test(test_stress_index_extend_append),
cmocka_unit_test(test_stress_id_cache_dedup_correctness),
cmocka_unit_test(test_stress_export_merge_dedup_1000),
cmocka_unit_test(test_stress_mixed_types_and_encodings),
cmocka_unit_test(test_stress_lmc_chain_deep),
cmocka_unit_test(test_stress_lmc_many_corrections),
};
return cmocka_run_group_tests(all_tests, NULL, NULL);
}