1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4 * Copyright (C) 2011 Google, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 #include <string.h>
23 #include "ibus.h"
24
25 static IBusBus *bus;
26 static void
27 call_next_async_function (IBusInputContext *context);
28
29 static gboolean
fatal_handler(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)30 fatal_handler(const gchar *log_domain,
31 GLogLevelFlags log_level,
32 const gchar *message,
33 gpointer user_data)
34 {
35 if (!g_strcmp0 (message, "org.freedesktop.IBus.InputContext.GetEngine: GDBus.Error:org.freedesktop.DBus.Error.Failed: Input context does not have engine."))
36 return FALSE; /* do not call abort. */
37 return TRUE;
38 }
39
40 static void
call_basic_ipcs(IBusInputContext * context)41 call_basic_ipcs (IBusInputContext *context)
42 {
43 ibus_input_context_set_cursor_location (context, 0, 0, 1, 1);
44 ibus_input_context_set_capabilities (context, IBUS_CAP_FOCUS);
45 ibus_input_context_property_activate (context, "dummy.prop.name", PROP_STATE_CHECKED);
46 ibus_input_context_reset (context);
47
48 /* When enable() is called, ibus-daemon may start a global (or preloaded,
49 * or default) engine in an asynchrnous manner and return immediately.
50 * Therefore, it is not guaranteed that ibus_input_context_is_enabled()
51 * returns TRUE. */
52
53 ibus_input_context_focus_in (context);
54 }
55
56 static void
test_input_context(void)57 test_input_context (void)
58 {
59 IBusInputContext *context;
60 GLogLevelFlags flags;
61 IBusEngineDesc *engine_desc;
62 gchar *active_engine_name = NULL;
63 gchar *current_ic;
64
65 context = ibus_bus_create_input_context (bus, "test");
66 call_basic_ipcs (context);
67
68 /* "No global engine." warning is not critical message. */
69 flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
70 engine_desc = ibus_bus_get_global_engine (bus);
71 g_log_set_always_fatal (flags);
72 if (engine_desc != NULL) {
73 active_engine_name = g_strdup (ibus_engine_desc_get_name(engine_desc));
74 g_object_unref (engine_desc);
75 engine_desc = NULL;
76 } else {
77 active_engine_name = g_strdup ("dummy");
78 }
79 g_assert (active_engine_name);
80 g_debug ("Use '%s' for testing.", active_engine_name);
81
82 ibus_input_context_set_engine (context, active_engine_name);
83 current_ic = ibus_bus_current_input_context (bus);
84 g_assert (!strcmp (current_ic, g_dbus_proxy_get_object_path ((GDBusProxy *)context)));
85
86 g_test_log_set_fatal_handler (fatal_handler, NULL);
87 engine_desc = ibus_input_context_get_engine (context);
88 if (engine_desc) {
89 /* FIXME race condition between ibus_input_context_set_engine and _get_engine.
90 * ibus_input_context_get_engine is not guaranteed to return non-NULL
91 * (even if we use synchronous set_engine()) because ibus-daemon sets a context
92 * engine in an asynchronous manner. See _context_request_engine_cb in
93 * ibusimpl.c which handles context_signals[REQUEST_ENGINE] signal. */
94 g_assert (!strcmp (active_engine_name, ibus_engine_desc_get_name(engine_desc)));
95 g_object_unref (engine_desc);
96 engine_desc = NULL;
97 }
98 ibus_input_context_process_key_event (context, 0, 0, 0);
99
100 /* An engine is set. Try to call basic IPCs again. */
101 call_basic_ipcs (context);
102
103 g_free (current_ic);
104 g_object_unref (context);
105
106 g_free (active_engine_name);
107 }
108
109 static void
finish_get_engine_async(GObject * source_object,GAsyncResult * res,gpointer user_data)110 finish_get_engine_async (GObject *source_object,
111 GAsyncResult *res,
112 gpointer user_data)
113 {
114 IBusInputContext *context = IBUS_INPUT_CONTEXT (source_object);
115 GError *error = NULL;
116 IBusEngineDesc *desc = ibus_input_context_get_engine_async_finish (context,
117 res,
118 &error);
119 if (desc) {
120 g_object_unref (desc);
121 }
122 g_debug ("ibus_context_get_engine_async_finish: OK");
123 call_next_async_function (context);
124 }
125
126 static void
start_get_engine_async(IBusInputContext * context)127 start_get_engine_async (IBusInputContext *context)
128 {
129 ibus_input_context_get_engine_async (context,
130 -1, /* timeout */
131 NULL, /* cancellable */
132 finish_get_engine_async,
133 NULL); /* user_data */
134 }
135
136 static void
finish_process_key_event_async(GObject * source_object,GAsyncResult * res,gpointer user_data)137 finish_process_key_event_async (GObject *source_object,
138 GAsyncResult *res,
139 gpointer user_data)
140 {
141 IBusInputContext *context = IBUS_INPUT_CONTEXT (source_object);
142 GError *error = NULL;
143 gboolean result = ibus_input_context_process_key_event_async_finish (context,
144 res,
145 &error);
146 g_assert (result || error == NULL);
147 g_debug ("ibus_context_process_key_event_async_finish: OK");
148 call_next_async_function (context);
149 }
150
151 static void
start_process_key_event_async(IBusInputContext * context)152 start_process_key_event_async (IBusInputContext *context)
153 {
154 ibus_input_context_process_key_event_async (context,
155 0, 0, 0,
156 -1, /* timeout */
157 NULL, /* cancellable */
158 finish_process_key_event_async,
159 NULL); /* user_data */
160 }
161
162 static gboolean
test_async_apis_finish(gpointer user_data)163 test_async_apis_finish (gpointer user_data)
164 {
165 ibus_quit ();
166 return FALSE;
167 }
168
169 static void
test_async_apis(void)170 test_async_apis (void)
171 {
172 g_debug ("start");
173 IBusInputContext *context;
174 context = ibus_bus_create_input_context (bus, "test");
175 call_basic_ipcs (context);
176
177 call_next_async_function (context);
178 ibus_main ();
179 }
180
181 static void
call_next_async_function(IBusInputContext * context)182 call_next_async_function (IBusInputContext *context)
183 {
184 static void (*async_functions[])(IBusInputContext *) = {
185 start_get_engine_async,
186 start_process_key_event_async,
187 };
188 static guint index = 0;
189
190 // Use g_timeout_add to make sure test_async_apis finishes even if async_functions is empty.
191 if (index >= G_N_ELEMENTS (async_functions))
192 g_timeout_add (1, test_async_apis_finish, NULL);
193 else
194 (*async_functions[index++])(context);
195 }
196
197 gint
main(gint argc,gchar ** argv)198 main (gint argc,
199 gchar **argv)
200 {
201 gint result;
202 ibus_init ();
203 g_test_init (&argc, &argv, NULL);
204 bus = ibus_bus_new ();
205
206 g_test_add_func ("/ibus/input_context", test_input_context);
207 g_test_add_func ("/ibus/input_context_async_with_callback", test_async_apis);
208
209 result = g_test_run ();
210 g_object_unref (bus);
211
212 return result;
213 }
214