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