#include <gtk/gtk.h>
#include <locale.h>
#include <glib/gstdio.h>
#include "../gtk/gtkcomposetable.h"
#include "../gtk/gtkimcontextsimpleseqs.h"
#include "testsuite/testutils.h"
static void
append_escaped (GString *str,
const char *s)
{
for (const char *p = s; *p; p = g_utf8_next_char (p))
{
gunichar ch = g_utf8_get_char (p);
if (ch == '"' )
g_string_append (str, "\\\" ");
else if (ch == '\\' )
g_string_append (str, "\\\\" );
else if (g_unichar_isprint (ch))
g_string_append_unichar (str, ch);
else
{
guint n[8 ] = { 0 , };
int i = 0 ;
while (ch != 0 )
{
n[i++] = ch & 7 ;
ch = ch >> 3 ;
}
for (; i >= 0 ; i--)
g_string_append_printf (str, "\\%o" , n[i]);
}
}
}
static void
print_sequence (gunichar *sequence,
int len,
const char *value,
gpointer data)
{
GString *str = data;
for (int j = 0 ; j < len; j++)
g_string_append_printf (str, "<U%x> " , sequence[j]);
g_string_append (str, ": \" ");
append_escaped (str, value);
g_string_append (str, "\" ");
if (g_utf8_strlen (value, -1 ) == 1 )
{
gunichar ch = g_utf8_get_char (value);
g_string_append_printf (str, " # U%x" , ch);
}
g_string_append_c (str, '\n' );
}
static char *
gtk_compose_table_print (GtkComposeTable *table)
{
GString *str;
str = g_string_new ("" );
g_string_append_printf (str, "# n_sequences: %d\n# max_seq_len: %d\n# n_index_size: %d\n# data_size: %d\n# n_chars: %d\n" ,
table->n_sequences,
table->max_seq_len,
table->n_index_size,
table->data_size,
table->n_chars);
gtk_compose_table_foreach (table, print_sequence, str);
return g_string_free (str, FALSE );
}
static void
generate_output (const char *file)
{
GtkComposeTable *table;
char *output;
table = gtk_compose_table_parse (file, NULL);
output = gtk_compose_table_print (table);
g_print ("%s" , output);
}
static void
compose_table_compare (gconstpointer data)
{
const char *basename = data;
GtkComposeTable *table;
char *file;
char *expected;
char *output;
char *diff;
GError *error = NULL;
file = g_test_build_filename (G_TEST_DIST, "compose" , basename, NULL);
expected = g_strconcat (file, ".expected" , NULL);
table = gtk_compose_table_parse (file, NULL);
g_assert_nonnull (table);
output = gtk_compose_table_print (table);
diff = diff_string_with_file (expected, output, -1 , &error);
g_assert_no_error (error);
if (diff && diff[0 ])
{
g_print ("Resulting output doesn't match reference:\n%s" , diff);
g_test_fail ();
}
g_free (output);
g_free (file);
g_free (expected);
}
static void
compose_table_cycle (void )
{
if (g_test_subprocess ())
{
char *file;
GtkComposeTable *table;
file = g_test_build_filename (G_TEST_DIST, "compose" , "cycle" , NULL);
table = gtk_compose_table_parse (file, NULL);
g_assert_nonnull (table);
g_free (file);
return ;
}
g_test_trap_subprocess (NULL, 0 , 0 );
g_test_trap_assert_stderr ("*include cycle detected*" );
g_test_trap_assert_failed ();
}
static void
compose_table_nofile (void )
{
if (g_test_subprocess ())
{
char *file;
GtkComposeTable *table;
file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose" , "nofile" , NULL);
table = gtk_compose_table_parse (file, NULL);
g_assert_nonnull (table);
g_free (file);
return ;
}
g_test_trap_subprocess (NULL, 0 , 0 );
g_test_trap_assert_stderr ("*No such file or directory*" );
g_test_trap_assert_failed ();
}
/* Check matching against a small table */
static void
compose_table_match (void )
{
GtkComposeTable *table;
char *file;
guint buffer[8 ] = { 0 , };
gboolean finish, match, ret;
GString *output;
output = g_string_new ("" );
file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose" , "match" , NULL);
table = gtk_compose_table_parse (file, NULL);
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 1 , &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_false (match);
g_assert_true (output->len == 0 );
buffer[0 ] = GDK_KEY_a;
buffer[1 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 1 , &finish, &match, output);
g_assert_false (ret);
g_assert_false (finish);
g_assert_false (match);
g_assert_true (output->len == 0 );
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = GDK_KEY_s;
buffer[2 ] = GDK_KEY_e;
ret = gtk_compose_table_check (table, buffer, 3 , &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_false (match);
g_assert_true (output->len == 0 );
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = GDK_KEY_s;
buffer[2 ] = GDK_KEY_e;
buffer[3 ] = GDK_KEY_q;
ret = gtk_compose_table_check (table, buffer, 4 , &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "!" );
g_string_set_size (output, 0 );
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = GDK_KEY_s;
buffer[2 ] = GDK_KEY_e;
buffer[3 ] = GDK_KEY_q;
buffer[4 ] = GDK_KEY_u;
ret = gtk_compose_table_check (table, buffer, 5 , &finish, &match, output);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "?" );
g_string_set_size (output, 0 );
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = GDK_KEY_l;
buffer[2 ] = GDK_KEY_o;
buffer[3 ] = GDK_KEY_n;
buffer[4 ] = GDK_KEY_g;
ret = gtk_compose_table_check (table, buffer, 5 , &finish, &match, output);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "this is a long replacement string" );
g_string_set_size (output, 0 );
buffer[0 ] = GDK_KEY_q;
buffer[1 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 1 , &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "qq" );
g_string_set_size (output, 0 );
buffer[0 ] = 0 xfdd7;
buffer[1 ] = GDK_KEY_s;
buffer[2 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 2 , &finish, &match, output);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "∫" );
g_string_free (output, TRUE );
g_free (file);
}
extern const GtkComposeTable builtin_compose_table;
/* just check some random sequences */
static void
compose_table_match_builtin (void )
{
const GtkComposeTable *table = &builtin_compose_table;
guint buffer[8 ] = { 0 , };
gboolean finish, match, ret;
GString *s;
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = 0 ;
s = g_string_new ("" );
ret = gtk_compose_table_check (table, buffer, 1 , &finish, &match, s);
g_assert_true (ret);
g_assert_false (finish);
g_assert_false (match);
g_assert_true (s->len == 0 );
buffer[0 ] = GDK_KEY_a;
buffer[1 ] = GDK_KEY_b;
buffer[2 ] = GDK_KEY_c;
buffer[3 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 3 , &finish, &match, s);
g_assert_false (ret);
g_assert_false (finish);
g_assert_false (match);
g_assert_true (s->len == 0 );
buffer[0 ] = GDK_KEY_Multi_key;
buffer[1 ] = GDK_KEY_parenleft;
buffer[2 ] = GDK_KEY_j;
buffer[3 ] = GDK_KEY_parenright;
buffer[4 ] = 0 ;
ret = gtk_compose_table_check (table, buffer, 4 , &finish, &match, s);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (s->str, ==, "ⓙ" ); /* CIRCLED LATIN SMALL LETTER J */
buffer[0 ] = GDK_KEY_dead_acute;
buffer[1 ] = GDK_KEY_space;
buffer[2 ] = 0 ;
g_string_set_size (s, 0 );
ret = gtk_compose_table_check (table, buffer, 2 , &finish, &match, s);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (s->str, ==, "'" );
buffer[0 ] = GDK_KEY_dead_acute;
buffer[1 ] = GDK_KEY_dead_acute;
buffer[2 ] = 0 ;
g_string_set_size (s, 0 );
ret = gtk_compose_table_check (table, buffer, 2 , &finish, &match, s);
g_assert_true (ret);
g_assert_true (finish);
g_assert_true (match);
g_assert_cmpstr (s->str, ==, "´" );
g_string_free (s, TRUE );
}
static void
match_algorithmic (void )
{
guint buffer[8 ] = { 0 , };
gboolean ret;
GString *output;
output = g_string_new ("" );
buffer[0 ] = GDK_KEY_a;
buffer[1 ] = GDK_KEY_b;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_false (ret);
g_assert_cmpstr (output->str, ==, "" );
buffer[0 ] = GDK_KEY_dead_abovering;
buffer[1 ] = GDK_KEY_A;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "Å" );
buffer[0 ] = GDK_KEY_A;
buffer[1 ] = GDK_KEY_dead_abovering;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_false (ret);
g_assert_cmpstr (output->str, ==, "" );
buffer[0 ] = GDK_KEY_dead_dasia;
buffer[1 ] = GDK_KEY_dead_perispomeni;
buffer[2 ] = GDK_KEY_Greek_alpha;
ret = gtk_check_algorithmically (buffer, 3 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "ᾶ\xcc\x94" );
buffer[0 ] = GDK_KEY_dead_perispomeni;
buffer[1 ] = GDK_KEY_dead_dasia;
buffer[2 ] = GDK_KEY_Greek_alpha;
ret = gtk_check_algorithmically (buffer, 3 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "ἇ" );
buffer[0 ] = GDK_KEY_dead_acute;
buffer[1 ] = GDK_KEY_dead_cedilla;
buffer[2 ] = GDK_KEY_c;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "" );
ret = gtk_check_algorithmically (buffer, 3 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "ḉ" );
buffer[0 ] = GDK_KEY_dead_cedilla;
buffer[1 ] = GDK_KEY_dead_acute;
buffer[2 ] = GDK_KEY_c;
ret = gtk_check_algorithmically (buffer, 3 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "ḉ" );
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
buffer[0 ] = GDK_KEY_dead_acute;
buffer[1 ] = GDK_KEY_dead_cedilla;
buffer[2 ] = GDK_KEY_dead_grave;
ret = gtk_check_algorithmically (buffer, 3 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "" );
buffer[0 ] = GDK_KEY_dead_diaeresis;
buffer[1 ] = GDK_KEY_a;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "ä" );
buffer[0 ] = GDK_KEY_dead_a;
buffer[1 ] = GDK_KEY_a;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "aͣ" );
buffer[0 ] = GDK_KEY_dead_a;
buffer[1 ] = GDK_KEY_a;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "aͣ" );
buffer[0 ] = GDK_KEY_dead_schwa;
buffer[1 ] = GDK_KEY_a;
ret = gtk_check_algorithmically (buffer, 2 , output);
g_assert_true (ret);
g_assert_cmpstr (output->str, ==, "aᷪ" );
g_string_free (output, TRUE );
}
static void
compose_table_large (void )
{
if (g_test_subprocess ())
{
char *file;
GtkComposeTable *table;
file = g_test_build_filename (G_TEST_DIST, "compose" , "large" , NULL);
table = gtk_compose_table_parse (file, NULL);
g_assert_nonnull (table);
g_free (file);
return ;
}
g_test_trap_subprocess (NULL, 0 , 0 );
g_test_trap_assert_stderr ("*can't handle compose tables this large*" );
g_test_trap_assert_failed ();
}
int
main (int argc, char *argv[])
{
if (argc == 3 && strcmp (argv[1 ], "--generate" ) == 0 )
{
gtk_disable_setlocale();
setlocale (LC_ALL, "en_US.UTF-8" );
gtk_init ();
/* Ensure that the builtin table is initialized */
GtkIMContext *ctx = gtk_im_context_simple_new ();
g_object_unref (ctx);
generate_output (argv[2 ]);
return 0 ;
}
gtk_test_init (&argc, &argv, NULL);
/* Ensure that the builtin table is initialized */
GtkIMContext *ctx = gtk_im_context_simple_new ();
g_object_unref (ctx);
g_test_add_data_func ("/compose-table/basic" , "basic" , compose_table_compare);
g_test_add_data_func ("/compose-table/long" , "long" , compose_table_compare);
g_test_add_data_func ("/compose-table/octal" , "octal" , compose_table_compare);
g_test_add_data_func ("/compose-table/hex" , "hex" , compose_table_compare);
g_test_add_data_func ("/compose-table/codepoint" , "codepoint" , compose_table_compare);
g_test_add_data_func ("/compose-table/multi" , "multi" , compose_table_compare);
g_test_add_data_func ("/compose-table/strings" , "strings" , compose_table_compare);
g_test_add_data_func ("/compose-table/single" , "single" , compose_table_compare);
g_test_add_data_func ("/compose-table/include" , "include" , compose_table_compare);
g_test_add_data_func ("/compose-table/system" , "system" , compose_table_compare);
g_test_add_data_func ("/compose-table/bepo" , "bepo" , compose_table_compare);
g_test_add_func ("/compose-table/include-cycle" , compose_table_cycle);
g_test_add_func ("/compose-table/include-nofile" , compose_table_nofile);
g_test_add_func ("/compose-table/match" , compose_table_match);
g_test_add_func ("/compose-table/match-builtin" , compose_table_match_builtin);
g_test_add_func ("/compose-table/match-algorithmic" , match_algorithmic);
g_test_add_func ("/compose-table/large" , compose_table_large);
return g_test_run ();
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland