40565e57245d3e386563d35c6a5d959061ad5f6b
[platform/upstream/libxkbcommon.git] / test / common.c
1 /*
2  * Copyright © 2009 Dan Nicholson <dbn.lists@gmail.com>
3  * Copyright © 2012 Intel Corporation
4  * Copyright © 2012 Ran Benita <ran234@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Except as contained in this notice, the names of the authors or their
24  * institutions shall not be used in advertising or otherwise to promote the
25  * sale, use or other dealings in this Software without prior written
26  * authorization from the authors.
27  *
28  * Author: Dan Nicholson <dbn.lists@gmail.com>
29  *         Daniel Stone <daniel@fooishbar.org>
30  *         Ran Benita <ran234@gmail.com>
31  */
32
33 #include "config.h"
34
35 #include <limits.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <termios.h>
41
42 #include "test.h"
43
44 /*
45  * Test a sequence of keysyms, resulting from a sequence of key presses,
46  * against the keysyms they're supposed to generate.
47  *
48  * - Each test runs with a clean state.
49  * - Each line in the test is made up of:
50  *   + A keycode, given as a KEY_* from linux/input.h.
51  *   + A direction - DOWN for press, UP for release, BOTH for
52  *     immediate press + release, REPEAT to just get the syms.
53  *   + A sequence of keysyms that should result from this keypress.
54  *
55  * The vararg format is:
56  * <KEY_*>  <DOWN | UP | BOTH>  <XKB_KEY_* (zero or more)>  <NEXT | FINISH>
57  *
58  * See below for examples.
59  */
60 int
61 test_key_seq_va(struct xkb_keymap *keymap, va_list ap)
62 {
63     struct xkb_state *state;
64
65     xkb_keycode_t kc;
66     int op;
67     xkb_keysym_t keysym;
68
69     const xkb_keysym_t *syms;
70     xkb_keysym_t sym;
71     unsigned int nsyms, i;
72     char ksbuf[64];
73
74     fprintf(stderr, "----\n");
75
76     state = xkb_state_new(keymap);
77     assert(state);
78
79     for (;;) {
80         kc = va_arg(ap, int) + EVDEV_OFFSET;
81         op = va_arg(ap, int);
82
83         nsyms = xkb_state_key_get_syms(state, kc, &syms);
84         if (nsyms == 1) {
85             sym = xkb_state_key_get_one_sym(state, kc);
86             syms = &sym;
87         }
88
89         fprintf(stderr, "got %u syms for keycode %u: [", nsyms, kc);
90
91         if (op == DOWN || op == BOTH)
92             xkb_state_update_key(state, kc, XKB_KEY_DOWN);
93         if (op == UP || op == BOTH)
94             xkb_state_update_key(state, kc, XKB_KEY_UP);
95
96         for (i = 0; i < nsyms; i++) {
97             keysym = va_arg(ap, int);
98             xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
99             fprintf(stderr, "%s%s", (i != 0) ? ", " : "", ksbuf);
100
101             if (keysym == FINISH || keysym == NEXT) {
102                 xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
103                 fprintf(stderr, "Did not expect keysym: %s.\n", ksbuf);
104                 goto fail;
105             }
106
107             if (keysym != syms[i]) {
108                 xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
109                 fprintf(stderr, "Expected keysym: %s. ", ksbuf);;
110                 xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
111                 fprintf(stderr, "Got keysym: %s.\n", ksbuf);;
112                 goto fail;
113             }
114         }
115
116         if (nsyms == 0) {
117             keysym = va_arg(ap, int);
118             if (keysym != XKB_KEY_NoSymbol) {
119                 xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
120                 fprintf(stderr, "Expected %s, but got no keysyms.\n", ksbuf);
121                 goto fail;
122             }
123         }
124
125         fprintf(stderr, "]\n");
126
127         keysym = va_arg(ap, int);
128         if (keysym == NEXT)
129             continue;
130         if (keysym == FINISH)
131             break;
132
133         xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
134         fprintf(stderr, "Expected keysym: %s. Didn't get it.\n", ksbuf);
135         goto fail;
136     }
137
138     xkb_state_unref(state);
139     return 1;
140
141 fail:
142     xkb_state_unref(state);
143     return 0;
144 }
145
146 int
147 test_key_seq(struct xkb_keymap *keymap, ...)
148 {
149     va_list ap;
150     int ret;
151
152     va_start(ap, keymap);
153     ret = test_key_seq_va(keymap, ap);
154     va_end(ap);
155
156     return ret;
157 }
158
159 char *
160 test_get_path(const char *path_rel)
161 {
162     char *path;
163     size_t path_len;
164     const char *srcdir = getenv("top_srcdir");
165
166     if (path_rel[0] == '/')
167         return strdup(path_rel);
168
169     path_len = strlen(srcdir ? srcdir : ".") +
170                strlen(path_rel) + 12;
171     path = malloc(path_len);
172     if (!path) {
173         fprintf(stderr, "Failed to allocate path (%d chars) for %s\n",
174                 (int) path_len, path_rel);
175         return NULL;
176     }
177     snprintf(path, path_len,
178              "%s/test/data/%s", srcdir ? srcdir : ".",
179              path_rel ? path_rel : "");
180
181     return path;
182 }
183
184 char *
185 test_read_file(const char *path_rel)
186 {
187     struct stat info;
188     char *ret, *tmp, *path;
189     int fd, count, remaining;
190
191     path = test_get_path(path_rel);
192     if (!path)
193         return NULL;
194
195     fd = open(path, O_RDONLY);
196     free(path);
197     if (fd < 0)
198         return NULL;
199
200     if (fstat(fd, &info) != 0) {
201         close(fd);
202         return NULL;
203     }
204
205     ret = malloc(info.st_size + 1);
206     if (!ret) {
207         close(fd);
208         return NULL;
209     }
210
211     remaining = info.st_size;
212     tmp = ret;
213     while ((count = read(fd, tmp, remaining))) {
214         remaining -= count;
215         tmp += count;
216     }
217     ret[info.st_size] = '\0';
218     close(fd);
219
220     if (remaining != 0) {
221         free(ret);
222         return NULL;
223     }
224
225     return ret;
226 }
227
228 struct xkb_context *
229 test_get_context(enum test_context_flags test_flags)
230 {
231     enum xkb_context_flags ctx_flags;
232     struct xkb_context *ctx;
233     char *path;
234
235     ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES;
236     if (test_flags & CONTEXT_ALLOW_ENVIRONMENT_NAMES) {
237         unsetenv("XKB_DEFAULT_RULES");
238         unsetenv("XKB_DEFAULT_MODEL");
239         unsetenv("XKB_DEFAULT_LAYOUT");
240         unsetenv("XKB_DEFAULT_VARIANT");
241         unsetenv("XKB_DEFAULT_OPTIONS");
242     }
243     else {
244         ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES;
245     }
246
247     ctx = xkb_context_new(ctx_flags);
248     if (!ctx)
249         return NULL;
250
251     path = test_get_path("");
252     if (!path) {
253         xkb_context_unref(ctx);
254         return NULL;
255     }
256
257     xkb_context_include_path_append(ctx, path);
258     free(path);
259
260     return ctx;
261 }
262
263 struct xkb_keymap *
264 test_compile_file(struct xkb_context *context, const char *path_rel)
265 {
266     struct xkb_keymap *keymap;
267     FILE *file;
268     char *path;
269
270     path = test_get_path(path_rel);
271     if (!path)
272         return NULL;
273
274     file = fopen(path, "r");
275     if (!file) {
276         fprintf(stderr, "Failed to open path: %s\n", path);
277         free(path);
278         return NULL;
279     }
280     assert(file != NULL);
281
282     keymap = xkb_keymap_new_from_file(context, file,
283                                       XKB_KEYMAP_FORMAT_TEXT_V1, 0);
284     fclose(file);
285
286     if (!keymap) {
287         fprintf(stderr, "Failed to compile path: %s\n", path);
288         free(path);
289         return NULL;
290     }
291
292     fprintf(stderr, "Successfully compiled path: %s\n", path);
293     free(path);
294
295     return keymap;
296 }
297
298 struct xkb_keymap *
299 test_compile_string(struct xkb_context *context, const char *string)
300 {
301     struct xkb_keymap *keymap;
302
303     keymap = xkb_keymap_new_from_string(context, string,
304                                         XKB_KEYMAP_FORMAT_TEXT_V1, 0);
305     if (!keymap) {
306         fprintf(stderr, "Failed to compile string\n");
307         return NULL;
308     }
309
310     return keymap;
311 }
312
313 struct xkb_keymap *
314 test_compile_buffer(struct xkb_context *context, const char *buf, size_t len)
315 {
316     struct xkb_keymap *keymap;
317
318     keymap = xkb_keymap_new_from_buffer(context, buf, len,
319                                         XKB_KEYMAP_FORMAT_TEXT_V1, 0);
320     if (!keymap) {
321         fprintf(stderr, "Failed to compile keymap from memory buffer\n");
322         return NULL;
323     }
324
325     return keymap;
326 }
327
328 struct xkb_keymap *
329 test_compile_rules(struct xkb_context *context, const char *rules,
330                    const char *model, const char *layout,
331                    const char *variant, const char *options)
332 {
333     struct xkb_keymap *keymap;
334     struct xkb_rule_names rmlvo = {
335         .rules = isempty(rules) ? NULL : rules,
336         .model = isempty(model) ? NULL : model,
337         .layout = isempty(layout) ? NULL : layout,
338         .variant = isempty(variant) ? NULL : variant,
339         .options = isempty(options) ? NULL : options
340     };
341
342     if (!rules && !model && !layout && !variant && !options)
343         keymap = xkb_keymap_new_from_names(context, NULL, 0);
344     else
345         keymap = xkb_keymap_new_from_names(context, &rmlvo, 0);
346
347     if (!keymap) {
348         fprintf(stderr,
349                 "Failed to compile RMLVO: '%s', '%s', '%s', '%s', '%s'\n",
350                 rules, model, layout, variant, options);
351         return NULL;
352     }
353
354     return keymap;
355 }
356
357 void
358 test_print_keycode_state(struct xkb_state *state,
359                          struct xkb_compose_state *compose_state,
360                          xkb_keycode_t keycode,
361                          enum xkb_consumed_mode consumed_mode)
362 {
363     struct xkb_keymap *keymap;
364
365     xkb_keysym_t sym;
366     const xkb_keysym_t *syms;
367     int nsyms;
368     char s[16];
369     xkb_layout_index_t layout;
370     enum xkb_compose_status status;
371
372     keymap = xkb_state_get_keymap(state);
373
374     nsyms = xkb_state_key_get_syms(state, keycode, &syms);
375
376     if (nsyms <= 0)
377         return;
378
379     status = XKB_COMPOSE_NOTHING;
380     if (compose_state)
381         status = xkb_compose_state_get_status(compose_state);
382
383     if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED)
384         return;
385
386     if (status == XKB_COMPOSE_COMPOSED) {
387         sym = xkb_compose_state_get_one_sym(compose_state);
388         syms = &sym;
389         nsyms = 1;
390     }
391     else if (nsyms == 1) {
392         sym = xkb_state_key_get_one_sym(state, keycode);
393         syms = &sym;
394     }
395
396     printf("keysyms [ ");
397     for (int i = 0; i < nsyms; i++) {
398         xkb_keysym_get_name(syms[i], s, sizeof(s));
399         printf("%-*s ", (int) sizeof(s), s);
400     }
401     printf("] ");
402
403     if (status == XKB_COMPOSE_COMPOSED)
404         xkb_compose_state_get_utf8(compose_state, s, sizeof(s));
405     else
406         xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
407     printf("unicode [ %s ] ", s);
408
409     layout = xkb_state_key_get_layout(state, keycode);
410     printf("layout [ %s (%d) ] ",
411            xkb_keymap_layout_get_name(keymap, layout), layout);
412
413     printf("level [ %d ] ",
414            xkb_state_key_get_level(state, keycode, layout));
415
416     printf("mods [ ");
417     for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
418         if (xkb_state_mod_index_is_active(state, mod,
419                                           XKB_STATE_MODS_EFFECTIVE) <= 0)
420             continue;
421         if (xkb_state_mod_index_is_consumed2(state, keycode, mod,
422                                              consumed_mode))
423             printf("-%s ", xkb_keymap_mod_get_name(keymap, mod));
424         else
425             printf("%s ", xkb_keymap_mod_get_name(keymap, mod));
426     }
427     printf("] ");
428
429     printf("leds [ ");
430     for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) {
431         if (xkb_state_led_index_is_active(state, led) <= 0)
432             continue;
433         printf("%s ", xkb_keymap_led_get_name(keymap, led));
434     }
435     printf("] ");
436
437     printf("\n");
438 }
439
440 void
441 test_print_state_changes(enum xkb_state_component changed)
442 {
443     if (changed == 0)
444         return;
445
446     printf("changed [ ");
447     if (changed & XKB_STATE_LAYOUT_EFFECTIVE)
448         printf("effective-layout ");
449     if (changed & XKB_STATE_LAYOUT_DEPRESSED)
450         printf("depressed-layout ");
451     if (changed & XKB_STATE_LAYOUT_LATCHED)
452         printf("latched-layout ");
453     if (changed & XKB_STATE_LAYOUT_LOCKED)
454         printf("locked-layout ");
455     if (changed & XKB_STATE_MODS_EFFECTIVE)
456         printf("effective-mods ");
457     if (changed & XKB_STATE_MODS_DEPRESSED)
458         printf("depressed-mods ");
459     if (changed & XKB_STATE_MODS_LATCHED)
460         printf("latched-mods ");
461     if (changed & XKB_STATE_MODS_LOCKED)
462         printf("locked-mods ");
463     if (changed & XKB_STATE_LEDS)
464         printf("leds ");
465     printf("]\n");
466 }
467
468 void
469 test_disable_stdin_echo(void)
470 {
471     /* Same as `stty -echo`. */
472     struct termios termios;
473     if (tcgetattr(STDIN_FILENO, &termios) == 0) {
474         termios.c_lflag &= ~ECHO;
475         (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
476     }
477 }
478
479 void
480 test_enable_stdin_echo(void)
481 {
482     /* Same as `stty echo`. */
483     struct termios termios;
484     if (tcgetattr(STDIN_FILENO, &termios) == 0) {
485         termios.c_lflag |= ECHO;
486         (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
487     }
488 }