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