/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ #include #include "ibus.h" static IBusBus *bus = NULL; static int create_config_count = 0; static void finish_create_config_async_success (GObject *source_object, GAsyncResult *res, gpointer user_data) { GMainLoop *loop = (GMainLoop *)user_data; GError *error = NULL; IBusConfig *config = ibus_config_new_async_finish (res, &error); g_assert (IBUS_IS_CONFIG (config)); /* Since we reuse single D-Bus connection, we need to remove the default match rule for the next ibus_config_new() call. */ ibus_config_unwatch (config, NULL, NULL); g_object_unref (config); if (--create_config_count == 0) g_main_loop_quit (loop); } static void finish_create_config_async_failed (GObject *source_object, GAsyncResult *res, gpointer user_data) { GMainLoop *loop = (GMainLoop *)user_data; GError *error = NULL; IBusConfig *config = ibus_config_new_async_finish (res, &error); g_assert (config == NULL); g_assert (error != NULL); g_error_free (error); if (--create_config_count <= 0) g_main_loop_quit (loop); } static void test_create_config_async (void) { GMainLoop *loop = NULL; GCancellable *cancellable = NULL; /* create an IC */ create_config_count = 1; loop = g_main_loop_new (NULL, TRUE); ibus_config_new_async (ibus_bus_get_connection (bus), NULL, finish_create_config_async_success, loop); g_main_loop_run (loop); g_main_loop_unref (loop); /* call create, and then cancel */ create_config_count = 1; loop = g_main_loop_new (NULL, TRUE); cancellable = g_cancellable_new (); ibus_config_new_async (ibus_bus_get_connection (bus), cancellable, finish_create_config_async_failed, loop); g_cancellable_cancel (cancellable); g_object_unref (cancellable); g_main_loop_run (loop); g_main_loop_unref (loop); } static void test_config_set_get (void) { IBusConfig *config = ibus_config_new (ibus_bus_get_connection (bus), NULL, NULL); g_assert (config); ibus_config_set_value (config, "test", "v1", g_variant_new_int32(1)); ibus_config_set_value (config, "test", "v2", g_variant_new_string("2")); GVariant *var; var = ibus_config_get_value (config, "test", "v1"); g_assert (var); g_assert_cmpint (g_variant_get_int32(var), ==, 1); g_variant_unref (var); var = ibus_config_get_value (config, "test", "v2"); g_assert (var); g_assert_cmpstr (g_variant_get_string(var, NULL), ==, "2"); g_variant_unref (var); var = ibus_config_get_values (config, "test"); g_assert (var); GVariantIter iter; gchar *name; GVariant *value; g_variant_iter_init (&iter, var); gint value_bits = 0; while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) { if (g_strcmp0 (name, "v1") == 0) { g_assert_cmpint (g_variant_get_int32(value), ==, 1); value_bits |= 1; } else if (g_strcmp0 (name, "v2") == 0) { g_assert_cmpstr (g_variant_get_string(value, NULL), ==, "2"); value_bits |= (1 << 1); } else { g_warning ("unknow value name=%s", name); } ibus_config_unset (config, "test", name); g_variant_unref (value); } g_assert_cmpint (value_bits, ==, 1 | (1 << 1)); g_variant_unref (var); var = ibus_config_get_values (config, "test"); g_assert (var); g_assert_cmpint (g_variant_n_children (var), ==, 0); g_variant_unref (var); /* Since we reuse single D-Bus connection, we need to remove the default match rule for the next ibus_config_new() call. */ ibus_config_unwatch (config, NULL, NULL); g_object_unref (config); } typedef struct { GMainLoop *loop; guint timeout_id; gchar *section; gchar *name; } WatchData; typedef struct { gchar *section; gchar *name; } WatchKey; typedef struct { WatchKey *watched; /* watched keys (null-terminated) */ WatchKey *changed; /* changed keys (null-terminated) */ WatchKey *notified; /* notified keys (same length as changed, not null-terminated) */ } WatchTestData; static WatchKey default_watched[] = { { NULL } }; static WatchKey default_changed[] = { { "test/s1", "n1" }, { "test/s1", "n2" }, { "test/s2", "n1" }, { "test/s2", "n2" }, { NULL } }; static WatchKey default_notified[] = { { "test/s1", "n1" }, { "test/s1", "n2" }, { "test/s2", "n1" }, { "test/s2", "n2" } }; static WatchTestData default_data = { default_watched, default_changed, default_notified }; static WatchKey section_watched[] = { { "test/s1", NULL }, { NULL } }; static WatchKey section_notified[] = { { "test/s1", "n1" }, { "test/s1", "n2" }, { NULL, NULL }, { NULL, NULL }, }; static WatchTestData section_data = { section_watched, default_changed, section_notified }; static WatchKey section_multiple_watched[] = { { "test/s1", NULL }, { "test/s2", NULL }, { NULL } }; static WatchKey section_multiple_notified[] = { { "test/s1", "n1" }, { "test/s1", "n2" }, { "test/s2", "n1" }, { "test/s2", "n2" }, }; static WatchTestData section_multiple_data = { section_multiple_watched, default_changed, section_multiple_notified }; static WatchKey section_name_watched[] = { { "test/s1", "n1" }, { NULL } }; static WatchKey section_name_notified[] = { { "test/s1", "n1" }, { NULL, NULL }, { NULL, NULL }, { NULL, NULL }, }; static WatchTestData section_name_data = { section_name_watched, default_changed, section_name_notified }; static WatchKey section_name_multiple_watched[] = { { "test/s1", "n1" }, { "test/s2", "n2" }, { NULL } }; static WatchKey section_name_multiple_notified[] = { { "test/s1", "n1" }, { NULL, NULL }, { NULL, NULL }, { "test/s2", "n2" }, }; static WatchTestData section_name_multiple_data = { section_name_multiple_watched, default_changed, section_name_multiple_notified }; typedef struct { IBusConfig *config; WatchData data; } WatchFixture; static void value_changed_cb (IBusConfig *config, const gchar *section, const gchar *name, GVariant *value, gpointer user_data) { WatchData *data = (WatchData *) user_data; data->section = g_strdup (section); data->name = g_strdup (name); g_main_loop_quit (data->loop); } static gboolean timeout_cb (gpointer user_data) { WatchData *data = (WatchData *) user_data; g_main_loop_quit (data->loop); data->timeout_id = 0; return FALSE; } static void change_and_test (IBusConfig *config, const gchar *section, const gchar *name, const gchar *expected_section, const gchar *expected_name, WatchData *data) { gboolean retval; GVariant *var; data->section = NULL; data->name = NULL; /* Unset won't notify value-changed signal. */ var = ibus_config_get_values (config, section); if (var != NULL) { GVariant *value = g_variant_lookup_value (var, name, G_VARIANT_TYPE_VARIANT); if (value != NULL) { ibus_config_unset (config, section, name); g_variant_unref (value); } g_variant_unref (var); } data->timeout_id = g_timeout_add (1, timeout_cb, data); g_main_loop_run (data->loop); if (data->timeout_id != 0) { g_source_remove (data->timeout_id); } retval = ibus_config_set_value (config, section, name, g_variant_new_int32 (1)); g_assert (retval); data->timeout_id = g_timeout_add (1, timeout_cb, data); g_main_loop_run (data->loop); if (data->timeout_id != 0) { g_source_remove (data->timeout_id); } g_assert_cmpstr (data->section, ==, expected_section); g_assert_cmpstr (data->name, ==, expected_name); g_free (data->section); g_free (data->name); } static void watch_fixture_setup (WatchFixture *fixture, gconstpointer user_data) { fixture->config = ibus_config_new (ibus_bus_get_connection (bus), NULL, NULL); g_assert (fixture->config); fixture->data.loop = g_main_loop_new (NULL, FALSE); g_signal_connect (fixture->config, "value-changed", G_CALLBACK (value_changed_cb), &fixture->data); } static void watch_fixture_teardown (WatchFixture *fixture, gconstpointer user_data) { g_main_loop_unref (fixture->data.loop); ibus_proxy_destroy (IBUS_PROXY (fixture->config)); g_object_unref (fixture->config); } static void test_config_watch (WatchFixture *fixture, gconstpointer user_data) { const WatchTestData *data = user_data; gint i; for (i = 0; data->watched[i].section != NULL; i++) { ibus_config_watch (fixture->config, data->watched[i].section, data->watched[i].name); } for (i = 0; data->changed[i].section != NULL; i++) { change_and_test (fixture->config, data->changed[i].section, data->changed[i].name, data->notified[i].section, data->notified[i].name, &fixture->data); } for (i = 0; data->watched[i].section != NULL; i++) { ibus_config_unwatch (fixture->config, data->watched[i].section, data->watched[i].name); } if (i > 0) { /* Check if the above unwatch takes effect. */ for (i = 0; data->changed[i].section != NULL; i++) { change_and_test (fixture->config, data->changed[i].section, data->changed[i].name, NULL, NULL, &fixture->data); } } else { /* Since we reuse single D-Bus connection, we need to remove the default match rule for the next ibus_config_new() call. */ ibus_config_unwatch (fixture->config, NULL, NULL); } } gint main (gint argc, gchar **argv) { gint result; ibus_init (); g_test_init (&argc, &argv, NULL); bus = ibus_bus_new (); g_test_add ("/ibus/config-watch/default", WatchFixture, &default_data, watch_fixture_setup, test_config_watch, watch_fixture_teardown); g_test_add ("/ibus/config-watch/section", WatchFixture, §ion_data, watch_fixture_setup, test_config_watch, watch_fixture_teardown); g_test_add ("/ibus/config-watch/section-multiple", WatchFixture, §ion_multiple_data, watch_fixture_setup, test_config_watch, watch_fixture_teardown); g_test_add ("/ibus/config-watch/section-name", WatchFixture, §ion_name_data, watch_fixture_setup, test_config_watch, watch_fixture_teardown); g_test_add ("/ibus/config-watch/section-name-multiple", WatchFixture, §ion_name_multiple_data, watch_fixture_setup, test_config_watch, watch_fixture_teardown); g_test_add_func ("/ibus/create-config-async", test_create_config_async); g_test_add_func ("/ibus/config-set-get", test_config_set_get); result = g_test_run (); g_object_unref (bus); return result; }