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