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