Open files in binary mode
[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%s", srcdir,
175                    path_rel[0] ? "/" : "", path_rel);
176     if (ret < 0) {
177         fprintf(stderr, "Failed to allocate path for %s\n", path_rel);
178         return NULL;
179     }
180     return path;
181 }
182
183 char *
184 test_read_file(const char *path_rel)
185 {
186     struct stat info;
187     char *ret, *tmp, *path;
188     int fd, count, remaining;
189
190     path = test_get_path(path_rel);
191     if (!path)
192         return NULL;
193
194     fd = open(path, O_RDONLY);
195     free(path);
196     if (fd < 0)
197         return NULL;
198
199     if (fstat(fd, &info) != 0) {
200         close(fd);
201         return NULL;
202     }
203
204     ret = malloc(info.st_size + 1);
205     if (!ret) {
206         close(fd);
207         return NULL;
208     }
209
210     remaining = info.st_size;
211     tmp = ret;
212     while ((count = read(fd, tmp, remaining))) {
213         remaining -= count;
214         tmp += count;
215     }
216     ret[info.st_size] = '\0';
217     close(fd);
218
219     if (remaining != 0) {
220         free(ret);
221         return NULL;
222     }
223
224     return ret;
225 }
226
227 struct xkb_context *
228 test_get_context(enum test_context_flags test_flags)
229 {
230     enum xkb_context_flags ctx_flags;
231     struct xkb_context *ctx;
232     char *path;
233
234     ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES;
235     if (test_flags & CONTEXT_ALLOW_ENVIRONMENT_NAMES) {
236         unsetenv("XKB_DEFAULT_RULES");
237         unsetenv("XKB_DEFAULT_MODEL");
238         unsetenv("XKB_DEFAULT_LAYOUT");
239         unsetenv("XKB_DEFAULT_VARIANT");
240         unsetenv("XKB_DEFAULT_OPTIONS");
241     }
242     else {
243         ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES;
244     }
245
246     ctx = xkb_context_new(ctx_flags);
247     if (!ctx)
248         return NULL;
249
250     path = test_get_path("");
251     if (!path) {
252         xkb_context_unref(ctx);
253         return NULL;
254     }
255
256     xkb_context_include_path_append(ctx, path);
257     free(path);
258
259     return ctx;
260 }
261
262 struct xkb_keymap *
263 test_compile_file(struct xkb_context *context, const char *path_rel)
264 {
265     struct xkb_keymap *keymap;
266     FILE *file;
267     char *path;
268
269     path = test_get_path(path_rel);
270     if (!path)
271         return NULL;
272
273     file = fopen(path, "rb");
274     if (!file) {
275         fprintf(stderr, "Failed to open path: %s\n", path);
276         free(path);
277         return NULL;
278     }
279     assert(file != NULL);
280
281     keymap = xkb_keymap_new_from_file(context, file,
282                                       XKB_KEYMAP_FORMAT_TEXT_V1, 0);
283     fclose(file);
284
285     if (!keymap) {
286         fprintf(stderr, "Failed to compile path: %s\n", path);
287         free(path);
288         return NULL;
289     }
290
291     fprintf(stderr, "Successfully compiled path: %s\n", path);
292     free(path);
293
294     return keymap;
295 }
296
297 struct xkb_keymap *
298 test_compile_string(struct xkb_context *context, const char *string)
299 {
300     struct xkb_keymap *keymap;
301
302     keymap = xkb_keymap_new_from_string(context, string,
303                                         XKB_KEYMAP_FORMAT_TEXT_V1, 0);
304     if (!keymap) {
305         fprintf(stderr, "Failed to compile string\n");
306         return NULL;
307     }
308
309     return keymap;
310 }
311
312 struct xkb_keymap *
313 test_compile_buffer(struct xkb_context *context, const char *buf, size_t len)
314 {
315     struct xkb_keymap *keymap;
316
317     keymap = xkb_keymap_new_from_buffer(context, buf, len,
318                                         XKB_KEYMAP_FORMAT_TEXT_V1, 0);
319     if (!keymap) {
320         fprintf(stderr, "Failed to compile keymap from memory buffer\n");
321         return NULL;
322     }
323
324     return keymap;
325 }
326
327 struct xkb_keymap *
328 test_compile_rules(struct xkb_context *context, const char *rules,
329                    const char *model, const char *layout,
330                    const char *variant, const char *options)
331 {
332     struct xkb_keymap *keymap;
333     struct xkb_rule_names rmlvo = {
334         .rules = isempty(rules) ? NULL : rules,
335         .model = isempty(model) ? NULL : model,
336         .layout = isempty(layout) ? NULL : layout,
337         .variant = isempty(variant) ? NULL : variant,
338         .options = isempty(options) ? NULL : options
339     };
340
341     if (!rules && !model && !layout && !variant && !options)
342         keymap = xkb_keymap_new_from_names(context, NULL, 0);
343     else
344         keymap = xkb_keymap_new_from_names(context, &rmlvo, 0);
345
346     if (!keymap) {
347         fprintf(stderr,
348                 "Failed to compile RMLVO: '%s', '%s', '%s', '%s', '%s'\n",
349                 rules, model, layout, variant, options);
350         return NULL;
351     }
352
353     return keymap;
354 }
355
356 void
357 test_print_keycode_state(struct xkb_state *state,
358                          struct xkb_compose_state *compose_state,
359                          xkb_keycode_t keycode,
360                          enum xkb_consumed_mode consumed_mode)
361 {
362     struct xkb_keymap *keymap;
363
364     xkb_keysym_t sym;
365     const xkb_keysym_t *syms;
366     int nsyms;
367     char s[16];
368     xkb_layout_index_t layout;
369     enum xkb_compose_status status;
370
371     keymap = xkb_state_get_keymap(state);
372
373     nsyms = xkb_state_key_get_syms(state, keycode, &syms);
374
375     if (nsyms <= 0)
376         return;
377
378     status = XKB_COMPOSE_NOTHING;
379     if (compose_state)
380         status = xkb_compose_state_get_status(compose_state);
381
382     if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED)
383         return;
384
385     if (status == XKB_COMPOSE_COMPOSED) {
386         sym = xkb_compose_state_get_one_sym(compose_state);
387         syms = &sym;
388         nsyms = 1;
389     }
390     else if (nsyms == 1) {
391         sym = xkb_state_key_get_one_sym(state, keycode);
392         syms = &sym;
393     }
394
395     printf("keysyms [ ");
396     for (int i = 0; i < nsyms; i++) {
397         xkb_keysym_get_name(syms[i], s, sizeof(s));
398         printf("%-*s ", (int) sizeof(s), s);
399     }
400     printf("] ");
401
402     if (status == XKB_COMPOSE_COMPOSED)
403         xkb_compose_state_get_utf8(compose_state, s, sizeof(s));
404     else
405         xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
406     printf("unicode [ %s ] ", s);
407
408     layout = xkb_state_key_get_layout(state, keycode);
409     printf("layout [ %s (%d) ] ",
410            xkb_keymap_layout_get_name(keymap, layout), layout);
411
412     printf("level [ %d ] ",
413            xkb_state_key_get_level(state, keycode, layout));
414
415     printf("mods [ ");
416     for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
417         if (xkb_state_mod_index_is_active(state, mod,
418                                           XKB_STATE_MODS_EFFECTIVE) <= 0)
419             continue;
420         if (xkb_state_mod_index_is_consumed2(state, keycode, mod,
421                                              consumed_mode))
422             printf("-%s ", xkb_keymap_mod_get_name(keymap, mod));
423         else
424             printf("%s ", xkb_keymap_mod_get_name(keymap, mod));
425     }
426     printf("] ");
427
428     printf("leds [ ");
429     for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) {
430         if (xkb_state_led_index_is_active(state, led) <= 0)
431             continue;
432         printf("%s ", xkb_keymap_led_get_name(keymap, led));
433     }
434     printf("] ");
435
436     printf("\n");
437 }
438
439 void
440 test_print_state_changes(enum xkb_state_component changed)
441 {
442     if (changed == 0)
443         return;
444
445     printf("changed [ ");
446     if (changed & XKB_STATE_LAYOUT_EFFECTIVE)
447         printf("effective-layout ");
448     if (changed & XKB_STATE_LAYOUT_DEPRESSED)
449         printf("depressed-layout ");
450     if (changed & XKB_STATE_LAYOUT_LATCHED)
451         printf("latched-layout ");
452     if (changed & XKB_STATE_LAYOUT_LOCKED)
453         printf("locked-layout ");
454     if (changed & XKB_STATE_MODS_EFFECTIVE)
455         printf("effective-mods ");
456     if (changed & XKB_STATE_MODS_DEPRESSED)
457         printf("depressed-mods ");
458     if (changed & XKB_STATE_MODS_LATCHED)
459         printf("latched-mods ");
460     if (changed & XKB_STATE_MODS_LOCKED)
461         printf("locked-mods ");
462     if (changed & XKB_STATE_LEDS)
463         printf("leds ");
464     printf("]\n");
465 }
466
467 void
468 test_disable_stdin_echo(void)
469 {
470     /* Same as `stty -echo`. */
471     struct termios termios;
472     if (tcgetattr(STDIN_FILENO, &termios) == 0) {
473         termios.c_lflag &= ~ECHO;
474         (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
475     }
476 }
477
478 void
479 test_enable_stdin_echo(void)
480 {
481     /* Same as `stty echo`. */
482     struct termios termios;
483     if (tcgetattr(STDIN_FILENO, &termios) == 0) {
484         termios.c_lflag |= ECHO;
485         (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
486     }
487 }