1 /*
2 * Copyright © 2014 Ran Benita <ran234@gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include "xkbcommon/xkbcommon-compose.h"
27
28 #include "test.h"
29
30 static const char *
compose_status_string(enum xkb_compose_status status)31 compose_status_string(enum xkb_compose_status status)
32 {
33 switch (status) {
34 case XKB_COMPOSE_NOTHING:
35 return "nothing";
36 case XKB_COMPOSE_COMPOSING:
37 return "composing";
38 case XKB_COMPOSE_COMPOSED:
39 return "composed";
40 case XKB_COMPOSE_CANCELLED:
41 return "cancelled";
42 }
43
44 return "<invalid-status>";
45 }
46
47 static const char *
feed_result_string(enum xkb_compose_feed_result result)48 feed_result_string(enum xkb_compose_feed_result result)
49 {
50 switch (result) {
51 case XKB_COMPOSE_FEED_IGNORED:
52 return "ignored";
53 case XKB_COMPOSE_FEED_ACCEPTED:
54 return "accepted";
55 }
56
57 return "<invalid-result>";
58 }
59
60 /*
61 * Feed a sequence of keysyms to a fresh compose state and test the outcome.
62 *
63 * The varargs consists of lines in the following format:
64 * <input keysym> <expected feed result> <expected status> <expected string> <expected keysym>
65 * Terminated by a line consisting only of XKB_KEY_NoSymbol.
66 */
67 static bool
test_compose_seq_va(struct xkb_compose_table * table,va_list ap)68 test_compose_seq_va(struct xkb_compose_table *table, va_list ap)
69 {
70 int ret;
71 struct xkb_compose_state *state;
72 char buffer[64];
73
74 state = xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS);
75 assert(state);
76
77 for (int i = 1; ; i++) {
78 xkb_keysym_t input_keysym;
79 enum xkb_compose_feed_result result, expected_result;
80 enum xkb_compose_status status, expected_status;
81 const char *expected_string;
82 xkb_keysym_t keysym, expected_keysym;
83
84 input_keysym = va_arg(ap, xkb_keysym_t);
85 if (input_keysym == XKB_KEY_NoSymbol)
86 break;
87
88 expected_result = va_arg(ap, enum xkb_compose_feed_result);
89 expected_status = va_arg(ap, enum xkb_compose_status);
90 expected_string = va_arg(ap, const char *);
91 expected_keysym = va_arg(ap, xkb_keysym_t);
92
93 result = xkb_compose_state_feed(state, input_keysym);
94
95 if (result != expected_result) {
96 fprintf(stderr, "after feeding %d keysyms:\n", i);
97 fprintf(stderr, "expected feed result: %s\n",
98 feed_result_string(expected_result));
99 fprintf(stderr, "got feed result: %s\n",
100 feed_result_string(result));
101 goto fail;
102 }
103
104 status = xkb_compose_state_get_status(state);
105 if (status != expected_status) {
106 fprintf(stderr, "after feeding %d keysyms:\n", i);
107 fprintf(stderr, "expected status: %s\n",
108 compose_status_string(expected_status));
109 fprintf(stderr, "got status: %s\n",
110 compose_status_string(status));
111 goto fail;
112 }
113
114 ret = xkb_compose_state_get_utf8(state, buffer, sizeof(buffer));
115 if (ret < 0 || (size_t) ret >= sizeof(buffer)) {
116 fprintf(stderr, "after feeding %d keysyms:\n", i);
117 fprintf(stderr, "expected string: %s\n", expected_string);
118 fprintf(stderr, "got error: %d\n", ret);
119 goto fail;
120 }
121 if (!streq(buffer, expected_string)) {
122 fprintf(stderr, "after feeding %d keysyms:\n", i);
123 fprintf(stderr, "expected string: %s\n", strempty(expected_string));
124 fprintf(stderr, "got string: %s\n", buffer);
125 goto fail;
126 }
127
128 keysym = xkb_compose_state_get_one_sym(state);
129 if (keysym != expected_keysym) {
130 fprintf(stderr, "after feeding %d keysyms:\n", i);
131 xkb_keysym_get_name(expected_keysym, buffer, sizeof(buffer));
132 fprintf(stderr, "expected keysym: %s\n", buffer);
133 xkb_keysym_get_name(keysym, buffer, sizeof(buffer));
134 fprintf(stderr, "got keysym (%#x): %s\n", keysym, buffer);
135 goto fail;
136 }
137 }
138
139 xkb_compose_state_unref(state);
140 return true;
141
142 fail:
143 xkb_compose_state_unref(state);
144 return false;
145 }
146
147 static bool
test_compose_seq(struct xkb_compose_table * table,...)148 test_compose_seq(struct xkb_compose_table *table, ...)
149 {
150 va_list ap;
151 bool ok;
152 va_start(ap, table);
153 ok = test_compose_seq_va(table, ap);
154 va_end(ap);
155 return ok;
156 }
157
158 static bool
test_compose_seq_buffer(struct xkb_context * ctx,const char * buffer,...)159 test_compose_seq_buffer(struct xkb_context *ctx, const char *buffer, ...)
160 {
161 va_list ap;
162 bool ok;
163 struct xkb_compose_table *table;
164 table = xkb_compose_table_new_from_buffer(ctx, buffer, strlen(buffer), "",
165 XKB_COMPOSE_FORMAT_TEXT_V1,
166 XKB_COMPOSE_COMPILE_NO_FLAGS);
167 assert(table);
168 va_start(ap, buffer);
169 ok = test_compose_seq_va(table, ap);
170 va_end(ap);
171 xkb_compose_table_unref(table);
172 return ok;
173 }
174
175 static void
test_seqs(struct xkb_context * ctx)176 test_seqs(struct xkb_context *ctx)
177 {
178 struct xkb_compose_table *table;
179 char *path;
180 FILE *file;
181
182 path = test_get_path("locale/en_US.UTF-8/Compose");
183 file = fopen(path, "rb");
184 assert(file);
185 free(path);
186
187 table = xkb_compose_table_new_from_file(ctx, file, "",
188 XKB_COMPOSE_FORMAT_TEXT_V1,
189 XKB_COMPOSE_COMPILE_NO_FLAGS);
190 assert(table);
191 fclose(file);
192
193 assert(test_compose_seq(table,
194 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
195 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
196 XKB_KEY_NoSymbol));
197
198 assert(test_compose_seq(table,
199 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
200 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
201 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
202 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
203 XKB_KEY_NoSymbol));
204
205 assert(test_compose_seq(table,
206 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
207 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
208 XKB_KEY_NoSymbol));
209
210 assert(test_compose_seq(table,
211 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
212 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "'", XKB_KEY_apostrophe,
213 XKB_KEY_Caps_Lock, XKB_COMPOSE_FEED_IGNORED, XKB_COMPOSE_COMPOSED, "'", XKB_KEY_apostrophe,
214 XKB_KEY_NoSymbol));
215
216 assert(test_compose_seq(table,
217 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
218 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "´", XKB_KEY_acute,
219 XKB_KEY_NoSymbol));
220
221 assert(test_compose_seq(table,
222 XKB_KEY_Multi_key, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
223 XKB_KEY_Shift_L, XKB_COMPOSE_FEED_IGNORED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
224 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
225 XKB_KEY_Caps_Lock, XKB_COMPOSE_FEED_IGNORED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
226 XKB_KEY_Control_L, XKB_COMPOSE_FEED_IGNORED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
227 XKB_KEY_T, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "@", XKB_KEY_at,
228 XKB_KEY_NoSymbol));
229
230 assert(test_compose_seq(table,
231 XKB_KEY_7, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
232 XKB_KEY_a, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
233 XKB_KEY_b, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
234 XKB_KEY_NoSymbol));
235
236 assert(test_compose_seq(table,
237 XKB_KEY_Multi_key, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
238 XKB_KEY_apostrophe, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
239 XKB_KEY_7, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_CANCELLED, "", XKB_KEY_NoSymbol,
240 XKB_KEY_7, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
241 XKB_KEY_Caps_Lock, XKB_COMPOSE_FEED_IGNORED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
242 XKB_KEY_NoSymbol));
243
244 xkb_compose_table_unref(table);
245
246 /* Make sure one-keysym sequences work. */
247 assert(test_compose_seq_buffer(ctx,
248 "<A> : \"foo\" X \n"
249 "<B> <A> : \"baz\" Y \n",
250 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "foo", XKB_KEY_X,
251 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "foo", XKB_KEY_X,
252 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
253 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
254 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "baz", XKB_KEY_Y,
255 XKB_KEY_NoSymbol));
256
257 /* No sequences at all. */
258 assert(test_compose_seq_buffer(ctx,
259 "",
260 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
261 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
262 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
263 XKB_KEY_Multi_key, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
264 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
265 XKB_KEY_NoSymbol));
266
267 /* Only keysym - string derived from keysym. */
268 assert(test_compose_seq_buffer(ctx,
269 "<A> <B> : X \n"
270 "<B> <A> : dollar \n"
271 "<C> : dead_acute \n",
272 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
273 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "X", XKB_KEY_X,
274 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
275 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "$", XKB_KEY_dollar,
276 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "", XKB_KEY_dead_acute,
277 XKB_KEY_NoSymbol));
278
279 /* Make sure a cancelling keysym doesn't start a new sequence. */
280 assert(test_compose_seq_buffer(ctx,
281 "<A> <B> : X \n"
282 "<C> <D> : Y \n",
283 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
284 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_CANCELLED, "", XKB_KEY_NoSymbol,
285 XKB_KEY_D, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
286 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
287 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_CANCELLED, "", XKB_KEY_NoSymbol,
288 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
289 XKB_KEY_D, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "Y", XKB_KEY_Y,
290 XKB_KEY_NoSymbol));
291 }
292
293 static void
test_conflicting(struct xkb_context * ctx)294 test_conflicting(struct xkb_context *ctx)
295 {
296 // new is prefix of old
297 assert(test_compose_seq_buffer(ctx,
298 "<A> <B> <C> : \"foo\" A \n"
299 "<A> <B> : \"bar\" B \n",
300 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
301 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
302 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "foo", XKB_KEY_A,
303 XKB_KEY_NoSymbol));
304
305 // old is a prefix of new
306 assert(test_compose_seq_buffer(ctx,
307 "<A> <B> : \"bar\" B \n"
308 "<A> <B> <C> : \"foo\" A \n",
309 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
310 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
311 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "foo", XKB_KEY_A,
312 XKB_KEY_NoSymbol));
313
314 // new duplicate of old
315 assert(test_compose_seq_buffer(ctx,
316 "<A> <B> : \"bar\" B \n"
317 "<A> <B> : \"bar\" B \n",
318 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
319 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "bar", XKB_KEY_B,
320 XKB_KEY_C, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_NOTHING, "", XKB_KEY_NoSymbol,
321 XKB_KEY_NoSymbol));
322
323 // new same length as old #1
324 assert(test_compose_seq_buffer(ctx,
325 "<A> <B> : \"foo\" A \n"
326 "<A> <B> : \"bar\" B \n",
327 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
328 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "bar", XKB_KEY_B,
329 XKB_KEY_NoSymbol));
330
331 // new same length as old #2
332 assert(test_compose_seq_buffer(ctx,
333 "<A> <B> : \"foo\" A \n"
334 "<A> <B> : \"foo\" B \n",
335 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
336 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "foo", XKB_KEY_B,
337 XKB_KEY_NoSymbol));
338
339 // new same length as old #3
340 assert(test_compose_seq_buffer(ctx,
341 "<A> <B> : \"foo\" A \n"
342 "<A> <B> : \"bar\" A \n",
343 XKB_KEY_A, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
344 XKB_KEY_B, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "bar", XKB_KEY_A,
345 XKB_KEY_NoSymbol));
346 }
347
348 static void
test_state(struct xkb_context * ctx)349 test_state(struct xkb_context *ctx)
350 {
351 struct xkb_compose_table *table;
352 struct xkb_compose_state *state;
353 char *path;
354 FILE *file;
355
356 path = test_get_path("locale/en_US.UTF-8/Compose");
357 file = fopen(path, "rb");
358 assert(file);
359 free(path);
360
361 table = xkb_compose_table_new_from_file(ctx, file, "",
362 XKB_COMPOSE_FORMAT_TEXT_V1,
363 XKB_COMPOSE_COMPILE_NO_FLAGS);
364 assert(table);
365 fclose(file);
366
367 state = xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS);
368 assert(state);
369
370 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
371 xkb_compose_state_reset(state);
372 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
373 xkb_compose_state_feed(state, XKB_KEY_NoSymbol);
374 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
375 xkb_compose_state_feed(state, XKB_KEY_Multi_key);
376 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSING);
377 xkb_compose_state_reset(state);
378 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
379 xkb_compose_state_feed(state, XKB_KEY_Multi_key);
380 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSING);
381 xkb_compose_state_feed(state, XKB_KEY_Multi_key);
382 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_CANCELLED);
383 xkb_compose_state_feed(state, XKB_KEY_Multi_key);
384 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSING);
385 xkb_compose_state_feed(state, XKB_KEY_Multi_key);
386 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_CANCELLED);
387 xkb_compose_state_reset(state);
388 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
389 xkb_compose_state_feed(state, XKB_KEY_dead_acute);
390 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSING);
391 xkb_compose_state_feed(state, XKB_KEY_A);
392 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSED);
393 xkb_compose_state_reset(state);
394 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
395 xkb_compose_state_feed(state, XKB_KEY_dead_acute);
396 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSING);
397 xkb_compose_state_feed(state, XKB_KEY_A);
398 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_COMPOSED);
399 xkb_compose_state_reset(state);
400 xkb_compose_state_feed(state, XKB_KEY_NoSymbol);
401 assert(xkb_compose_state_get_status(state) == XKB_COMPOSE_NOTHING);
402
403 xkb_compose_state_unref(state);
404 xkb_compose_table_unref(table);
405 }
406
407 static void
test_XCOMPOSEFILE(struct xkb_context * ctx)408 test_XCOMPOSEFILE(struct xkb_context *ctx)
409 {
410 struct xkb_compose_table *table;
411 char *path;
412
413 path = test_get_path("locale/en_US.UTF-8/Compose");
414 setenv("XCOMPOSEFILE", path, 1);
415 free(path);
416
417 table = xkb_compose_table_new_from_locale(ctx, "blabla",
418 XKB_COMPOSE_COMPILE_NO_FLAGS);
419 assert(table);
420
421 unsetenv("XCOMPOSEFILE");
422
423 assert(test_compose_seq(table,
424 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
425 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
426 XKB_KEY_NoSymbol));
427
428 xkb_compose_table_unref(table);
429 }
430
431 static void
test_from_locale(struct xkb_context * ctx)432 test_from_locale(struct xkb_context *ctx)
433 {
434 struct xkb_compose_table *table;
435 char *path;
436
437 path = test_get_path("locale");
438 setenv("XLOCALEDIR", path, 1);
439 free(path);
440
441 /* Direct directory name match. */
442 table = xkb_compose_table_new_from_locale(ctx, "en_US.UTF-8",
443 XKB_COMPOSE_COMPILE_NO_FLAGS);
444 assert(table);
445 xkb_compose_table_unref(table);
446
447 /* Direct locale name match. */
448 table = xkb_compose_table_new_from_locale(ctx, "C.UTF-8",
449 XKB_COMPOSE_COMPILE_NO_FLAGS);
450 assert(table);
451 xkb_compose_table_unref(table);
452
453 /* Alias. */
454 table = xkb_compose_table_new_from_locale(ctx, "univ.utf8",
455 XKB_COMPOSE_COMPILE_NO_FLAGS);
456 assert(table);
457 xkb_compose_table_unref(table);
458
459 /* Special case - C. */
460 table = xkb_compose_table_new_from_locale(ctx, "C",
461 XKB_COMPOSE_COMPILE_NO_FLAGS);
462 assert(table);
463 xkb_compose_table_unref(table);
464
465 /* Bogus - not found. */
466 table = xkb_compose_table_new_from_locale(ctx, "blabla",
467 XKB_COMPOSE_COMPILE_NO_FLAGS);
468 assert(!table);
469
470 unsetenv("XLOCALEDIR");
471 }
472
473
474 static void
test_modifier_syntax(struct xkb_context * ctx)475 test_modifier_syntax(struct xkb_context *ctx)
476 {
477 const char *table_string;
478
479 /* We don't do anything with the modifiers, but make sure we can parse
480 * them. */
481
482 assert(test_compose_seq_buffer(ctx,
483 "None <A> : X \n"
484 "Shift <B> : Y \n"
485 "Ctrl <C> : Y \n"
486 "Alt <D> : Y \n"
487 "Caps <E> : Y \n"
488 "Lock <F> : Y \n"
489 "Shift Ctrl <G> : Y \n"
490 "~Shift <H> : Y \n"
491 "~Shift Ctrl <I> : Y \n"
492 "Shift ~Ctrl <J> : Y \n"
493 "Shift ~Ctrl ~Alt <K> : Y \n"
494 "! Shift <B> : Y \n"
495 "! Ctrl <C> : Y \n"
496 "! Alt <D> : Y \n"
497 "! Caps <E> : Y \n"
498 "! Lock <F> : Y \n"
499 "! Shift Ctrl <G> : Y \n"
500 "! ~Shift <H> : Y \n"
501 "! ~Shift Ctrl <I> : Y \n"
502 "! Shift ~Ctrl <J> : Y \n"
503 "! Shift ~Ctrl ~Alt <K> : Y \n"
504 "<L> ! Shift <M> : Y \n"
505 "None <N> ! Shift <O> : Y \n"
506 "None <P> ! Shift <Q> : Y \n",
507 XKB_KEY_NoSymbol));
508
509 fprintf(stderr, "<START bad input string>\n");
510 table_string =
511 "! None <A> : X \n"
512 "! Foo <B> : X \n"
513 "None ! Shift <C> : X \n"
514 "! ! <D> : X \n"
515 "! ~ <E> : X \n"
516 "! ! <F> : X \n"
517 "! Ctrl ! Ctrl <G> : X \n"
518 "<H> ! : X \n"
519 "<I> None : X \n"
520 "None None <J> : X \n"
521 "<K> : !Shift X \n";
522 assert(!xkb_compose_table_new_from_buffer(ctx, table_string,
523 strlen(table_string), "C",
524 XKB_COMPOSE_FORMAT_TEXT_V1,
525 XKB_COMPOSE_COMPILE_NO_FLAGS));
526 fprintf(stderr, "<END bad input string>\n");
527 }
528
529 static void
test_include(struct xkb_context * ctx)530 test_include(struct xkb_context *ctx)
531 {
532 char *path, *table_string;
533
534 path = test_get_path("locale/en_US.UTF-8/Compose");
535 assert(path);
536
537 /* We don't have a mechanism to change the include paths like we
538 * have for keymaps. So we must include the full path. */
539 table_string = asprintf_safe("<dead_tilde> <space> : \"foo\" X\n"
540 "include \"%s\"\n"
541 "<dead_tilde> <dead_tilde> : \"bar\" Y\n", path);
542 assert(table_string);
543
544 assert(test_compose_seq_buffer(ctx, table_string,
545 /* No conflict. */
546 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
547 XKB_KEY_dead_acute, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "´", XKB_KEY_acute,
548
549 /* Comes before - doesn't override. */
550 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
551 XKB_KEY_space, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "~", XKB_KEY_asciitilde,
552
553 /* Comes after - does override. */
554 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSING, "", XKB_KEY_NoSymbol,
555 XKB_KEY_dead_tilde, XKB_COMPOSE_FEED_ACCEPTED, XKB_COMPOSE_COMPOSED, "bar", XKB_KEY_Y,
556
557 XKB_KEY_NoSymbol));
558
559 free(path);
560 free(table_string);
561 }
562
563 int
main(int argc,char * argv[])564 main(int argc, char *argv[])
565 {
566 struct xkb_context *ctx;
567
568 ctx = test_get_context(CONTEXT_NO_FLAG);
569 assert(ctx);
570
571 test_seqs(ctx);
572 test_conflicting(ctx);
573 test_XCOMPOSEFILE(ctx);
574 test_from_locale(ctx);
575 test_state(ctx);
576 test_modifier_syntax(ctx);
577 test_include(ctx);
578
579 xkb_context_unref(ctx);
580 return 0;
581 }
582