feat(tools): support UTF-8 characters in autocompletion
Autocompletion failed for nicknames using non Latin scripts. We used `g_str_to_ascii`, which replaces characters it cannot transliterate with '?', leading search failures and false matches between different scripts. Now we do: Use `g_utf8_casefold` for case-insensitive UTF-8 comparison. This ensures that like 'Σ' correctly match 'σ' across all Unicode scripts, providing correct results for non English nicknames. If we don't fine anything typing a base ASCII character matches an accented one (typing `e` matches `è`). This pass uses `g_str_to_ascii` followed by `g_ascii_strdown` for comparison. It is now restricted to run if the search string itself is valid ASCII, preventing the "everything matches '?'" bug in non Latin scripts. Autocomplete items are sorted using `strcmp`. `g_utf8_collate` provides linguistical ordering for a specific language. But its behavior is locale dependent and undefined when comparing strings from different scripts. `strcmp` does byte-wise ordering that correctly follows Unicode code order for UTF-8 strings.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include "test_software.h"
|
||||
#include "test_muc.h"
|
||||
#include "test_disconnect.h"
|
||||
#include "test_i18n.h"
|
||||
|
||||
#define PROF_FUNC_TEST(test) cmocka_unit_test_setup_teardown(test, init_prof_test, close_prof_test)
|
||||
|
||||
@@ -116,6 +117,9 @@ main(int argc, char* argv[])
|
||||
PROF_FUNC_TEST(shows_no_message_in_console_when_window_not_focussed),
|
||||
|
||||
PROF_FUNC_TEST(disconnect_ends_session),
|
||||
|
||||
PROF_FUNC_TEST(i18n_msg_nickname),
|
||||
PROF_FUNC_TEST(i18n_win_nickname),
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(all_tests, NULL, NULL);
|
||||
|
||||
51
tests/functionaltests/test_i18n.c
Normal file
51
tests/functionaltests/test_i18n.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* test_i18n.c
|
||||
*
|
||||
* Copyright (C) 2026 Michael Vetter <jubalh@iodoru.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
#include <glib.h>
|
||||
#include "prof_cmocka.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stabber.h>
|
||||
|
||||
#include "proftest.h"
|
||||
|
||||
void
|
||||
i18n_msg_nickname(void** state)
|
||||
{
|
||||
// Connect with a roster containing a UTF-8 nickname: Σωκράτης (Socrates)
|
||||
prof_connect_with_roster(
|
||||
"<item jid='socrates@localhost' subscription='both' name='Σωκράτης'/>"
|
||||
"<item jid='buddy2@localhost' subscription='both' name='Buddy2'/>");
|
||||
|
||||
// Test that we can /msg the UTF-8 nickname successfully.
|
||||
// This verifies that the UI and command parsing handle UTF-8.
|
||||
prof_input("/msg Σωκράτης Hello");
|
||||
|
||||
// Check if we switched to the socrates window
|
||||
assert_true(prof_output_regex("socrates@localhost"));
|
||||
}
|
||||
|
||||
void
|
||||
i18n_win_nickname(void** state)
|
||||
{
|
||||
prof_connect_with_roster(
|
||||
"<item jid='socrates@localhost' subscription='both' name='Σωκράτης'/>");
|
||||
|
||||
// Open a chat with Socrates
|
||||
prof_input("/msg Σωκράτης");
|
||||
assert_true(prof_output_regex("socrates@localhost"));
|
||||
|
||||
// Switch back to console
|
||||
prof_input("/win 1");
|
||||
assert_true(prof_output_regex("Console"));
|
||||
|
||||
// Switch to Socrates window using name
|
||||
prof_input("/win Σωκράτης");
|
||||
assert_true(prof_output_regex("socrates@localhost"));
|
||||
}
|
||||
9
tests/functionaltests/test_i18n.h
Normal file
9
tests/functionaltests/test_i18n.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* test_i18n.h
|
||||
*
|
||||
* Copyright (C) 2026 Michael Vetter <jubalh@iodoru.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
void i18n_msg_nickname(void** state);
|
||||
void i18n_win_nickname(void** state);
|
||||
Reference in New Issue
Block a user