• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
test_key_seq_va(struct xkb_keymap * keymap,va_list ap)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
test_key_seq(struct xkb_keymap * keymap,...)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 *
test_get_path(const char * path_rel)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 *
test_read_file(const char * path_rel)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 *
test_get_context(enum test_context_flags test_flags)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 *
test_compile_file(struct xkb_context * context,const char * path_rel)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 *
test_compile_string(struct xkb_context * context,const char * string)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 *
test_compile_buffer(struct xkb_context * context,const char * buf,size_t len)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 *
test_compile_rules(struct xkb_context * context,const char * rules,const char * model,const char * layout,const char * variant,const char * options)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
test_print_keycode_state(struct xkb_state * state,struct xkb_compose_state * compose_state,xkb_keycode_t keycode)350 test_print_keycode_state(struct xkb_state *state,
351                          struct xkb_compose_state *compose_state,
352                          xkb_keycode_t keycode)
353 {
354     struct xkb_keymap *keymap;
355 
356     xkb_keysym_t sym;
357     const xkb_keysym_t *syms;
358     int nsyms;
359     char s[16];
360     xkb_layout_index_t layout;
361     enum xkb_compose_status status;
362 
363     keymap = xkb_state_get_keymap(state);
364 
365     nsyms = xkb_state_key_get_syms(state, keycode, &syms);
366 
367     if (nsyms <= 0)
368         return;
369 
370     status = XKB_COMPOSE_NOTHING;
371     if (compose_state)
372         status = xkb_compose_state_get_status(compose_state);
373 
374     if (status == XKB_COMPOSE_COMPOSING || status == XKB_COMPOSE_CANCELLED)
375         return;
376 
377     if (status == XKB_COMPOSE_COMPOSED) {
378         sym = xkb_compose_state_get_one_sym(compose_state);
379         syms = &sym;
380         nsyms = 1;
381     }
382     else if (nsyms == 1) {
383         sym = xkb_state_key_get_one_sym(state, keycode);
384         syms = &sym;
385     }
386 
387     printf("keysyms [ ");
388     for (int i = 0; i < nsyms; i++) {
389         xkb_keysym_get_name(syms[i], s, sizeof(s));
390         printf("%-*s ", (int) sizeof(s), s);
391     }
392     printf("] ");
393 
394     if (status == XKB_COMPOSE_COMPOSED)
395         xkb_compose_state_get_utf8(compose_state, s, sizeof(s));
396     else
397         xkb_state_key_get_utf8(state, keycode, s, sizeof(s));
398     printf("unicode [ %s ] ", s);
399 
400     layout = xkb_state_key_get_layout(state, keycode);
401     printf("layout [ %s (%d) ] ",
402            xkb_keymap_layout_get_name(keymap, layout), layout);
403 
404     printf("level [ %d ] ",
405            xkb_state_key_get_level(state, keycode, layout));
406 
407     printf("mods [ ");
408     for (xkb_mod_index_t mod = 0; mod < xkb_keymap_num_mods(keymap); mod++) {
409         if (xkb_state_mod_index_is_active(state, mod,
410                                           XKB_STATE_MODS_EFFECTIVE) <= 0)
411             continue;
412         if (xkb_state_mod_index_is_consumed(state, keycode, mod))
413             printf("-%s ", xkb_keymap_mod_get_name(keymap, mod));
414         else
415             printf("%s ", xkb_keymap_mod_get_name(keymap, mod));
416     }
417     printf("] ");
418 
419     printf("leds [ ");
420     for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) {
421         if (xkb_state_led_index_is_active(state, led) <= 0)
422             continue;
423         printf("%s ", xkb_keymap_led_get_name(keymap, led));
424     }
425     printf("] ");
426 
427     printf("\n");
428 }
429 
430 void
test_print_state_changes(enum xkb_state_component changed)431 test_print_state_changes(enum xkb_state_component changed)
432 {
433     if (changed == 0)
434         return;
435 
436     printf("changed [ ");
437     if (changed & XKB_STATE_LAYOUT_EFFECTIVE)
438         printf("effective-layout ");
439     if (changed & XKB_STATE_LAYOUT_DEPRESSED)
440         printf("depressed-layout ");
441     if (changed & XKB_STATE_LAYOUT_LATCHED)
442         printf("latched-layout ");
443     if (changed & XKB_STATE_LAYOUT_LOCKED)
444         printf("locked-layout ");
445     if (changed & XKB_STATE_MODS_EFFECTIVE)
446         printf("effective-mods ");
447     if (changed & XKB_STATE_MODS_DEPRESSED)
448         printf("depressed-mods ");
449     if (changed & XKB_STATE_MODS_LATCHED)
450         printf("latched-mods ");
451     if (changed & XKB_STATE_MODS_LOCKED)
452         printf("locked-mods ");
453     if (changed & XKB_STATE_LEDS)
454         printf("leds ");
455     printf("]\n");
456 }
457