common.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /*
  2. * Copyright © 2009 Dan Nicholson <dbn.lists@gmail.com>
  3. * Copyright © 2012 Intel Corporation
  4. * Copyright © 2012 Ran Benita <ran234@gmail.com>
  5. * SPDX-License-Identifier: MIT-open-group
  6. *
  7. * Author: Dan Nicholson <dbn.lists@gmail.com>
  8. * Daniel Stone <daniel@fooishbar.org>
  9. * Ran Benita <ran234@gmail.com>
  10. */
  11. #include "config.h"
  12. #include "test-config.h"
  13. #include <stdlib.h>
  14. #include <limits.h>
  15. #include <locale.h>
  16. #include <fcntl.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include "xkbcommon/xkbcommon.h"
  22. #include "darray.h"
  23. #include "keymap.h"
  24. #include "test.h"
  25. #include "utils.h"
  26. #include "utils-paths.h"
  27. #include "src/keysym.h"
  28. #include "src/xkbcomp/rules.h"
  29. #include "src/utils-numbers.h"
  30. #include "tools/tools-common.h"
  31. /* Setup test */
  32. void
  33. test_init(void)
  34. {
  35. /* Make stdout always unbuffered, to ensure we always get it entirely */
  36. setvbuf(stdout, NULL, _IONBF, BUFSIZ);
  37. /* Enable using another locale than C or en_US, so we can catch
  38. * locale-specific bugs */
  39. setlocale(LC_ALL, "");
  40. }
  41. void
  42. print_detailed_state(struct xkb_state *state)
  43. {
  44. fprintf(stderr,
  45. " Layout: base: %"PRId32", latched: %"PRId32", locked: %"PRId32", "
  46. "effective: %"PRIu32"\n",
  47. xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_DEPRESSED),
  48. xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LATCHED),
  49. xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_LOCKED),
  50. xkb_state_serialize_layout(state, XKB_STATE_LAYOUT_EFFECTIVE));
  51. fprintf(stderr,
  52. " Modifiers: base: %#"PRIx32", latched: %#"PRIx32", "
  53. "locked: %#"PRIx32", effective: %#"PRIx32"\n",
  54. xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED),
  55. xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED),
  56. xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED),
  57. xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE));
  58. /* There is currently no xkb_state_serialize_leds */
  59. struct xkb_keymap *keymap = xkb_state_get_keymap(state);
  60. xkb_led_mask_t leds = 0;
  61. for (xkb_led_index_t led = 0; led < xkb_keymap_num_leds(keymap); led++) {
  62. if (xkb_state_led_index_is_active(state, led) > 0)
  63. leds |= UINT32_C(1) << led;
  64. }
  65. fprintf(stderr, " LEDs: 0x%"PRIx32"\n", leds);
  66. }
  67. enum events_consume_flags {
  68. ALL_EVENTS = 0,
  69. UNTIL_KEY_EVENT = (1 << 0)
  70. };
  71. static bool
  72. consume_events(struct xkb_machine *sm,
  73. struct xkb_events *events,
  74. struct xkb_state *state,
  75. enum events_consume_flags flags,
  76. xkb_keycode_t *kc)
  77. {
  78. const struct xkb_event *event;
  79. while ((event = xkb_events_next(events))) {
  80. switch (xkb_event_get_type(event)) {
  81. case XKB_EVENT_TYPE_KEY_DOWN:
  82. case XKB_EVENT_TYPE_KEY_REPEATED:
  83. case XKB_EVENT_TYPE_KEY_UP:
  84. *kc = xkb_event_get_keycode(event);
  85. if (flags & UNTIL_KEY_EVENT) {
  86. /* Stop on key event */
  87. return true;
  88. }
  89. break;
  90. case XKB_EVENT_TYPE_COMPONENTS_CHANGE:
  91. xkb_state_update_event(state, event);
  92. break;
  93. default:
  94. {} /* Label followed by declaration requires C23 */
  95. static_assert(XKB_EVENT_TYPE_COMPONENTS_CHANGE == 4 &&
  96. XKB_EVENT_TYPE_COMPONENTS_CHANGE ==
  97. (enum xkb_event_type) _LAST_XKB_EVENT_TYPE,
  98. "Missing state event type");
  99. /* ignore */
  100. }
  101. }
  102. return true;
  103. }
  104. /*
  105. * Test a sequence of keysyms, resulting from a sequence of key presses,
  106. * against the keysyms they're supposed to generate.
  107. *
  108. * - Each test runs with a clean state.
  109. * - Each line in the test is made up of:
  110. * + A keycode, given as a KEY_* from linux/input.h.
  111. * + A direction - DOWN for press, UP for release, BOTH for
  112. * immediate press + release, REPEAT to just get the syms.
  113. * + A sequence of keysyms that should result from this keypress.
  114. *
  115. * The vararg format is:
  116. * <KEY_*> <DOWN | UP | BOTH> <XKB_KEY_* (zero or more)> <NEXT | FINISH>
  117. *
  118. * See below for examples.
  119. */
  120. int
  121. test_key_seq_va(struct xkb_keymap *keymap, struct xkb_machine *sm,
  122. struct xkb_events *events, va_list ap)
  123. {
  124. assert(!(!sm ^ !events));
  125. fprintf(stderr, "----\n");
  126. struct xkb_state * const state = xkb_state_new(keymap);
  127. assert(state);
  128. unsigned int count = 0;
  129. char ksbuf[XKB_KEYSYM_NAME_MAX_SIZE];
  130. for (;;) {
  131. const xkb_keycode_t kc = va_arg(ap, int) + EVDEV_OFFSET;
  132. const int op = va_arg(ap, int);
  133. const char *opstr = NULL;
  134. switch (op) {
  135. case DOWN: opstr = "DOWN"; break;
  136. case REPEAT: opstr = "REPEAT"; break;
  137. case UP: opstr = "UP"; break;
  138. case BOTH: opstr = "BOTH"; break;
  139. case NEXT: opstr = "NEXT"; break;
  140. case FINISH: opstr = "FINISH"; break;
  141. default:
  142. fprintf(stderr, "ERROR: Unsupported operation: %d\n", op);
  143. goto fail;
  144. }
  145. /*
  146. * WARNING: the following assumes there is always exactly 1 key event in
  147. * the events queue.
  148. */
  149. xkb_keycode_t kc_new = kc;
  150. if (events) {
  151. /* xkb_machine API: consume until the first key event */
  152. if (op == DOWN || op == REPEAT || op == BOTH) {
  153. assert(!xkb_machine_process_key(
  154. sm, kc, (op == REPEAT ? XKB_KEY_REPEATED : XKB_KEY_DOWN), events
  155. ));
  156. assert(consume_events(sm, events, state, UNTIL_KEY_EVENT, &kc_new));
  157. }
  158. if (op == UP || op == BOTH) {
  159. if (op == BOTH) {
  160. /* Consume pending events */
  161. assert(consume_events(sm, events, state, ALL_EVENTS, &kc_new));
  162. }
  163. assert(xkb_machine_process_key(sm, kc, XKB_KEY_UP, events)
  164. == 0);
  165. assert(consume_events(sm, events, state, UNTIL_KEY_EVENT, &kc_new));
  166. }
  167. }
  168. const xkb_keysym_t *syms;
  169. const int nsyms = xkb_state_key_get_syms(state, kc_new, &syms);
  170. if (events) {
  171. /* xkb_machine API: consume the rest of events */
  172. assert(consume_events(sm, events, state, ALL_EVENTS, &kc_new));
  173. } else {
  174. /* Legacy state API */
  175. if (op == DOWN || op == REPEAT || op == BOTH)
  176. xkb_state_update_key(
  177. state, kc, (op == REPEAT ? XKB_KEY_REPEATED : XKB_KEY_DOWN)
  178. );
  179. if (op == UP || op == BOTH)
  180. xkb_state_update_key(state, kc, XKB_KEY_UP);
  181. }
  182. #if HAVE_TOOLS
  183. const enum xkb_key_direction direction
  184. = (op == DOWN)
  185. ? XKB_KEY_DOWN
  186. : (op == REPEAT)
  187. ? XKB_KEY_REPEATED
  188. : XKB_KEY_UP;
  189. tools_print_keycode_state("", state, NULL, kc, direction,
  190. XKB_CONSUMED_MODE_XKB,
  191. PRINT_ALL_FIELDS | PRINT_UNILINE);
  192. #endif
  193. fprintf(stderr, "#%02u op %-6s got %d syms for keycode %3"PRIu32,
  194. ++count, opstr, nsyms, kc);
  195. if (kc_new != kc) {
  196. fprintf(stderr, " (redirected to %3"PRIu32")", kc_new);
  197. }
  198. fprintf(stderr, ": [");
  199. xkb_keysym_t keysym;
  200. for (int i = 0; i < nsyms; i++) {
  201. keysym = va_arg(ap, int);
  202. xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
  203. fprintf(stderr, "%s%s", (i != 0) ? ", " : "", ksbuf);
  204. if (keysym == FINISH || keysym == NEXT) {
  205. xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
  206. fprintf(stderr, "\nERROR: Did not expect keysym: %s.\n", ksbuf);
  207. goto fail;
  208. }
  209. if (keysym != syms[i]) {
  210. xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
  211. fprintf(stderr, "\nERROR: Expected keysym: %s. ", ksbuf);;
  212. xkb_keysym_get_name(syms[i], ksbuf, sizeof(ksbuf));
  213. fprintf(stderr, " Got keysym: %s.\n", ksbuf);;
  214. goto fail;
  215. }
  216. }
  217. if (nsyms == 0) {
  218. keysym = va_arg(ap, int);
  219. if (keysym != XKB_KEY_NoSymbol) {
  220. xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
  221. fprintf(stderr, "\nERROR: Expected %s, but got no keysyms.\n", ksbuf);
  222. goto fail;
  223. }
  224. }
  225. fprintf(stderr, "]\n");
  226. keysym = va_arg(ap, int);
  227. if (keysym == NEXT)
  228. continue;
  229. if (keysym == FINISH)
  230. break;
  231. xkb_keysym_get_name(keysym, ksbuf, sizeof(ksbuf));
  232. fprintf(stderr, "\nERROR: Expected keysym: %s. Didn't get it.\n", ksbuf);
  233. goto fail;
  234. }
  235. xkb_state_unref(state);
  236. return 1;
  237. fail:
  238. fprintf(stderr, "Current state:\n");
  239. print_detailed_state(state);
  240. xkb_state_unref(state);
  241. return 0;
  242. }
  243. int
  244. test_key_seq(struct xkb_keymap *keymap, ...)
  245. {
  246. va_list ap;
  247. int ret;
  248. va_start(ap, keymap);
  249. ret = test_key_seq_va(keymap, NULL, NULL, ap);
  250. va_end(ap);
  251. return ret;
  252. }
  253. int
  254. test_key_seq2(struct xkb_keymap *keymap, struct xkb_machine *sm,
  255. struct xkb_events *events, ...)
  256. {
  257. va_list ap;
  258. int ret;
  259. va_start(ap, events);
  260. ret = test_key_seq_va(keymap, sm, events, ap);
  261. va_end(ap);
  262. return ret;
  263. }
  264. char *
  265. test_makedir(const char *parent, const char *path)
  266. {
  267. char *dirname;
  268. int err;
  269. dirname = asprintf_safe("%s/%s", parent, path);
  270. assert(dirname);
  271. #ifdef _WIN32
  272. err = _mkdir(dirname);
  273. #else
  274. err = mkdir(dirname, 0777);
  275. #endif
  276. assert(err == 0);
  277. return dirname;
  278. }
  279. char *
  280. test_maketempdir(const char *template)
  281. {
  282. #ifdef _WIN32
  283. const char *basetmp = getenv("TMP");
  284. if (basetmp == NULL) {
  285. basetmp = getenv("TEMP");
  286. }
  287. if (basetmp == NULL) {
  288. basetmp = getenv("top_builddir");
  289. }
  290. assert(basetmp != NULL);
  291. char *tmpdir = asprintf_safe("%s/%s", basetmp, template);
  292. assert(tmpdir != NULL);
  293. char *tmp = _mktemp(tmpdir);
  294. assert(tmp == tmpdir);
  295. int ret = _mkdir(tmp);
  296. assert(ret == 0);
  297. return tmpdir;
  298. #else
  299. char *tmpdir = asprintf_safe("/tmp/%s", template);
  300. assert(tmpdir != NULL);
  301. char *tmp = mkdtemp(tmpdir);
  302. assert(tmp == tmpdir);
  303. return tmpdir;
  304. #endif
  305. }
  306. char *
  307. test_get_path(const char *path_rel)
  308. {
  309. char *path;
  310. const char *srcdir;
  311. srcdir = getenv("top_srcdir");
  312. if (!srcdir)
  313. srcdir = ".";
  314. if (is_absolute_path(path_rel))
  315. return strdup(path_rel);
  316. path = asprintf_safe("%s/test/data%s%s", srcdir,
  317. path_rel[0] ? "/" : "", path_rel);
  318. if (!path) {
  319. fprintf(stderr, "Failed to allocate path for %s\n", path_rel);
  320. return NULL;
  321. }
  322. return path;
  323. }
  324. char *
  325. read_file(const char *path, FILE *file)
  326. {
  327. enum { MAX_FILE_SIZE = 1u << 20 }; /* 1 MiB */
  328. if (!file)
  329. return NULL;
  330. errno = 0;
  331. const int fd = fileno(file);
  332. if (fd < 0) {
  333. fprintf(stderr, "Error getting file descriptor for %s: %s\n",
  334. path, strerror(errno));
  335. return NULL;
  336. }
  337. errno = 0;
  338. struct stat info;
  339. if (fstat(fd, &info) != 0) {
  340. fprintf(stderr, "Error getting file stats for %s: %s\n",
  341. path, strerror(errno));
  342. return NULL;
  343. }
  344. const size_t size = (size_t)info.st_size;
  345. if (size > MAX_FILE_SIZE) {
  346. fprintf(stderr, "Error: file %s exceeds maximum size\n", path);
  347. return NULL;
  348. }
  349. char *ret = malloc(size + 1);
  350. if (!ret)
  351. return NULL;
  352. /*
  353. * Null-terminated string.
  354. * Write here to avoid clang-tidy warning about tainted index due to fread.
  355. */
  356. ret[size] = '\0';
  357. errno = 0;
  358. const size_t count = fread(ret, sizeof(*ret), size, file);
  359. if (count != size) {
  360. if (!feof(file))
  361. printf("Error reading file %s: unexpected end of file\n", path);
  362. else if (ferror(file))
  363. fprintf(stderr, "Error reading file %s: %s\n", path, strerror(errno));
  364. free(ret);
  365. return NULL;
  366. }
  367. return ret;
  368. }
  369. char *
  370. test_read_file(const char *path_rel)
  371. {
  372. char *path = test_get_path(path_rel);
  373. if (!path)
  374. return NULL;
  375. FILE* file = fopen(path, "rb");
  376. char *ret = NULL;
  377. if (!file)
  378. goto out;
  379. ret = read_file(path, file);
  380. fclose(file);
  381. out:
  382. free(path);
  383. return ret;
  384. }
  385. struct xkb_context *
  386. test_get_context(enum test_context_flags test_flags)
  387. {
  388. enum xkb_context_flags ctx_flags = XKB_CONTEXT_NO_DEFAULT_INCLUDES;
  389. if (test_flags & CONTEXT_ALLOW_ENVIRONMENT_NAMES) {
  390. unsetenv("XKB_DEFAULT_RULES");
  391. unsetenv("XKB_DEFAULT_MODEL");
  392. unsetenv("XKB_DEFAULT_LAYOUT");
  393. unsetenv("XKB_DEFAULT_VARIANT");
  394. unsetenv("XKB_DEFAULT_OPTIONS");
  395. }
  396. else {
  397. ctx_flags |= XKB_CONTEXT_NO_ENVIRONMENT_NAMES;
  398. }
  399. struct xkb_context * const ctx = xkb_context_new(ctx_flags);
  400. if (!ctx)
  401. return NULL;
  402. char * const path = test_get_path("");
  403. if (!path) {
  404. xkb_context_unref(ctx);
  405. return NULL;
  406. }
  407. xkb_context_include_path_append(ctx, path);
  408. free(path);
  409. return ctx;
  410. }
  411. struct xkb_keymap *
  412. test_compile_file(struct xkb_context *context, enum xkb_keymap_format format,
  413. const char *path_rel)
  414. {
  415. struct xkb_keymap *keymap;
  416. FILE *file;
  417. char *path;
  418. path = test_get_path(path_rel);
  419. if (!path)
  420. return NULL;
  421. file = fopen(path, "rb");
  422. if (!file) {
  423. fprintf(stderr, "Failed to open path: %s\n", path);
  424. free(path);
  425. return NULL;
  426. }
  427. assert(file != NULL);
  428. keymap = xkb_keymap_new_from_file(context, file, format,
  429. TEST_KEYMAP_COMPILE_FLAGS);
  430. fclose(file);
  431. if (!keymap) {
  432. fprintf(stderr, "Failed to compile path: %s\n", path);
  433. free(path);
  434. return NULL;
  435. }
  436. fprintf(stderr, "Successfully compiled path: %s\n", path);
  437. free(path);
  438. return keymap;
  439. }
  440. struct xkb_keymap *
  441. test_compile_string(struct xkb_context *context, enum xkb_keymap_format format,
  442. const char *string)
  443. {
  444. struct xkb_keymap *keymap;
  445. keymap = xkb_keymap_new_from_string(context, string, format,
  446. TEST_KEYMAP_COMPILE_FLAGS);
  447. if (!keymap) {
  448. fprintf(stderr, "Failed to compile string\n");
  449. return NULL;
  450. }
  451. return keymap;
  452. }
  453. struct xkb_keymap *
  454. test_compile_buffer(struct xkb_context *context, enum xkb_keymap_format format,
  455. const char *buf, size_t len)
  456. {
  457. return test_compile_buffer2(context, format, TEST_KEYMAP_COMPILE_FLAGS,
  458. buf, len);
  459. }
  460. struct xkb_keymap *
  461. test_compile_buffer2(struct xkb_context *context, enum xkb_keymap_format format,
  462. enum xkb_keymap_compile_flags flags,
  463. const char *buf, size_t len)
  464. {
  465. struct xkb_keymap *keymap;
  466. keymap = xkb_keymap_new_from_buffer(context, buf, len, format, flags);
  467. if (!keymap) {
  468. fprintf(stderr, "Failed to compile keymap from memory buffer\n");
  469. return NULL;
  470. }
  471. return keymap;
  472. }
  473. struct xkb_keymap *
  474. test_compile_rules(struct xkb_context *context, enum xkb_keymap_format format,
  475. const char *rules, const char *model, const char *layout,
  476. const char *variant, const char *options)
  477. {
  478. struct xkb_keymap *keymap;
  479. struct xkb_rule_names rmlvo = {
  480. .rules = isempty(rules) ? NULL : rules,
  481. .model = isempty(model) ? NULL : model,
  482. .layout = isempty(layout) ? NULL : layout,
  483. .variant = isempty(variant) ? NULL : variant,
  484. .options = isempty(options) ? NULL : options
  485. };
  486. if (!rules && !model && !layout && !variant && !options)
  487. keymap = xkb_keymap_new_from_names2(context, NULL, format,
  488. TEST_KEYMAP_COMPILE_FLAGS);
  489. else
  490. keymap = xkb_keymap_new_from_names2(context, &rmlvo, format,
  491. TEST_KEYMAP_COMPILE_FLAGS);
  492. if (!keymap) {
  493. fprintf(stderr,
  494. "Failed to compile RMLVO: '%s', '%s', '%s', '%s', '%s'\n",
  495. rules, model, layout, variant, options);
  496. return NULL;
  497. }
  498. return keymap;
  499. }
  500. static struct xkb_rmlvo_builder *
  501. xkb_rules_names_to_rmlvo_builder(struct xkb_context *context,
  502. const struct xkb_rule_names *names)
  503. {
  504. struct xkb_rmlvo_builder *rmlvo =
  505. xkb_rmlvo_builder_new(context, names->rules, names->model,
  506. XKB_RMLVO_BUILDER_NO_FLAGS);
  507. if (!rmlvo) {
  508. fprintf(stderr, "ERROR: xkb_rmlvo_builder_new() failed\n");
  509. return NULL;
  510. }
  511. char buf[1024] = { 0 };
  512. /* First parse options, and gather the layout-specific ones and
  513. * append the others to the builder */
  514. darray(darray_string) loptions = darray_new();
  515. if (!isempty(names->options)) {
  516. const char *o = names->options;
  517. while (*o != '\0') {
  518. /* Get option name */
  519. const char *option = o;
  520. while (*o != '\0' && *o != ',' &&
  521. *o != OPTIONS_GROUP_SPECIFIER_PREFIX) {
  522. o++;
  523. };
  524. const size_t len = o - option;
  525. if (len >= sizeof(buf))
  526. goto error;
  527. memcpy(buf, option, len);
  528. buf[len] = '\0';
  529. /* Check if layout-specific option */
  530. xkb_layout_index_t layout = XKB_LAYOUT_INVALID;
  531. if (*o == OPTIONS_GROUP_SPECIFIER_PREFIX) {
  532. o++;
  533. int count = parse_dec_to_uint32_t(o, SIZE_MAX, &layout);
  534. if (count > 0 && layout > 0 && layout <= XKB_MAX_GROUPS) {
  535. o += count;
  536. layout--;
  537. } else {
  538. layout = XKB_LAYOUT_INVALID;
  539. }
  540. const char* const layout_index_end = o;
  541. while (*o != '\0' && *o != ',') { o++; }
  542. if (count <= 0 || layout_index_end != o)
  543. layout = XKB_LAYOUT_INVALID;
  544. }
  545. if (layout != XKB_LAYOUT_INVALID) {
  546. /* Save as layout-specific option, to be added with layout */
  547. char *opt = strdup(buf);
  548. if (!opt)
  549. goto error;
  550. darray_resize0(loptions, layout + 1);
  551. darray_append(darray_item(loptions, layout), opt);
  552. } else {
  553. /* Append layout-agnostic option */
  554. if (!xkb_rmlvo_builder_append_option(rmlvo, buf))
  555. goto error;
  556. }
  557. if (*o == ',')
  558. o++;
  559. }
  560. }
  561. if (!isempty(names->layout)) {
  562. /* Process layout & variant together.
  563. * Ignore variants without corresponding layout. */
  564. const char *l = names->layout;
  565. const char *v = names->variant;
  566. if (!names->variant)
  567. v = "";
  568. xkb_layout_index_t layout_count = 0;
  569. while (*l != '\0') {
  570. const char *layout = l;
  571. const char *variant = v;
  572. char *start = buf;
  573. size_t buf_size = sizeof(buf);
  574. while (*l != '\0' && *l != ',') { l++; };
  575. while (*v != '\0' && *v != ',') { v++; };
  576. size_t len = l - layout;
  577. if (len >= buf_size)
  578. goto error;
  579. memcpy(start, layout, len);
  580. start[len] = '\0';
  581. start += len;
  582. buf_size -= len + 1;
  583. len = v - variant;
  584. if (len >= buf_size)
  585. goto error;
  586. ++start;
  587. memcpy(start, variant, len);
  588. start[len] = '\0';
  589. /* Get layout-specific options */
  590. char **opts = NULL;
  591. size_t opts_count = 0;
  592. if (layout_count < darray_size(loptions)) {
  593. opts = darray_items(darray_item(loptions, layout_count));
  594. opts_count = darray_size(darray_item(loptions, layout_count));
  595. }
  596. if (!xkb_rmlvo_builder_append_layout(rmlvo, buf, start,
  597. (const char* *) opts,
  598. opts_count))
  599. goto error;
  600. if (*l == ',')
  601. l++;
  602. if (*v == ',')
  603. v++;
  604. layout_count += 1;
  605. }
  606. }
  607. exit:
  608. {
  609. darray_string *opts;
  610. darray_foreach(opts, loptions) {
  611. char **opt;
  612. darray_foreach(opt, *opts)
  613. free(*opt);
  614. darray_free(*opts);
  615. }
  616. darray_free(loptions);
  617. }
  618. return rmlvo;
  619. error:
  620. fprintf(stderr, "ERROR: %s\n", __func__);
  621. xkb_rmlvo_builder_unref(rmlvo);
  622. rmlvo = NULL;
  623. goto exit;
  624. }
  625. struct xkb_keymap *
  626. test_compile_rmlvo(struct xkb_context *context, enum xkb_keymap_format format,
  627. const char *rules, const char *model, const char *layout,
  628. const char *variant, const char *options)
  629. {
  630. struct xkb_keymap *keymap = NULL;
  631. const struct xkb_rule_names names = {
  632. .rules = rules,
  633. .model = model,
  634. .layout = layout,
  635. .variant = variant,
  636. .options = options
  637. };
  638. struct xkb_rmlvo_builder *rmlvo = xkb_rules_names_to_rmlvo_builder(context,
  639. &names);
  640. if (!rmlvo) {
  641. fprintf(stderr,
  642. "Failed to create RMLVO builder: "
  643. "'%s', '%s', '%s', '%s', '%s'\n",
  644. rules, model, layout, variant, options);
  645. return NULL;
  646. }
  647. /* Invalid flags */
  648. assert(!xkb_keymap_new_from_rmlvo(rmlvo, format, -1));
  649. assert(!xkb_keymap_new_from_rmlvo(rmlvo, format, 0xffff));
  650. keymap = xkb_keymap_new_from_rmlvo(rmlvo, format,
  651. TEST_KEYMAP_COMPILE_FLAGS);
  652. xkb_rmlvo_builder_unref(rmlvo);
  653. if (!keymap) {
  654. fprintf(stderr,
  655. "Failed to compile RMLVO from builder: "
  656. "'%s', '%s', '%s', '%s', '%s'\n",
  657. rules, model, layout, variant, options);
  658. }
  659. return keymap;
  660. }
  661. bool
  662. test_compile_output(struct xkb_context *ctx, enum xkb_keymap_format input_format,
  663. enum xkb_keymap_format output_format,
  664. test_compile_buffer_t compile_buffer,
  665. void *compile_buffer_private, const char *test_title,
  666. const char *keymap_str, size_t keymap_len,
  667. const char *rel_path, bool update_output_files)
  668. {
  669. return test_compile_output2(ctx, input_format, output_format,
  670. TEST_KEYMAP_SERIALIZE_FLAGS,
  671. compile_buffer, compile_buffer_private,
  672. test_title, keymap_str, keymap_len, rel_path,
  673. update_output_files);
  674. }
  675. bool
  676. test_compile_output2(struct xkb_context *ctx,
  677. enum xkb_keymap_format input_format,
  678. enum xkb_keymap_format output_format,
  679. enum xkb_keymap_serialize_flags serialize_flags,
  680. test_compile_buffer_t compile_buffer,
  681. void *compile_buffer_private, const char *test_title,
  682. const char *keymap_str, size_t keymap_len,
  683. const char *rel_path, bool update_output_files)
  684. {
  685. int success = true;
  686. if (test_title)
  687. fprintf(stderr, "*** %s ***\n", test_title);
  688. struct xkb_keymap *keymap = compile_buffer(
  689. ctx, input_format, keymap_str, keymap_len, compile_buffer_private
  690. );
  691. if (!rel_path) {
  692. /* No path given: expect compilation failure */
  693. if (keymap) {
  694. char *got = xkb_keymap_get_as_string2(keymap, output_format,
  695. serialize_flags);
  696. xkb_keymap_unref(keymap);
  697. assert(got);
  698. fprintf(stderr,
  699. "Unexpected keymap compilation success:\n%s\n", got);
  700. free(got);
  701. }
  702. return !keymap;
  703. }
  704. if (!keymap) {
  705. fprintf(stderr, "Unexpected keymap compilation failure\n");
  706. return false;
  707. }
  708. char *got = xkb_keymap_get_as_string2(keymap, output_format,
  709. serialize_flags);
  710. if (!got) {
  711. fprintf(stderr, "Unexpected keymap serialization failure\n");
  712. return false;
  713. }
  714. xkb_keymap_unref(keymap);
  715. char* const path = test_get_path(rel_path);
  716. assert(path);
  717. if (update_output_files) {
  718. fprintf(stderr, "Writing golden test output to: %s\n", path);
  719. FILE *file = fopen(path, "wb");
  720. assert(file);
  721. fwrite(got, 1, strlen(got), file);
  722. fclose(file);
  723. } else {
  724. fprintf(stderr, "Reading golden test output: %s\n", path);
  725. char* const expected = test_read_file(rel_path);
  726. assert(expected);
  727. static const char *label[2] = {"Golden test", "Roundtrip"};
  728. bool test_round_trip =
  729. (output_format == input_format ||
  730. output_format == XKB_KEYMAP_USE_ORIGINAL_FORMAT);
  731. for (unsigned int k = 0; k < ARRAY_SIZE(label) && success; k++) {
  732. if (streq(expected, got)) {
  733. fprintf(stderr, "%s succeeded.\n", label[k]);
  734. if (!test_round_trip)
  735. break;
  736. /* Test round trip */
  737. keymap = compile_buffer(ctx, input_format,
  738. expected, strlen(expected),
  739. compile_buffer_private);
  740. if (!keymap) {
  741. fprintf(stderr,
  742. "Unexpected keymap roundtrip compilation failure\n");
  743. success = false;
  744. break;
  745. }
  746. free(got);
  747. got = xkb_keymap_get_as_string2(keymap, output_format,
  748. serialize_flags);
  749. if (!got) {
  750. fprintf(stderr,
  751. "Unexpected keymap roundtrip serialization failure\n");
  752. success = false;
  753. }
  754. xkb_keymap_unref(keymap);
  755. test_round_trip = false;
  756. } else {
  757. fprintf(stderr,
  758. "%s failed: dumped map differs from expected.\n",
  759. label[k]);
  760. fprintf(stderr, "Path to expected file: %s\n", path);
  761. fprintf(stderr, "Length: expected %zu, got: %zu\n",
  762. strlen(expected), strlen(got));
  763. fprintf(stderr, "Dumped map:\n");
  764. fprintf(stderr, "%s\n", got);
  765. success = false;
  766. }
  767. }
  768. free(expected);
  769. }
  770. free(got);
  771. free(path);
  772. return success;
  773. }
  774. bool
  775. test_third_pary_compile_output(test_third_party_compile_buffer_t compile_buffer,
  776. void *compile_buffer_private,
  777. const char *test_title,
  778. const char *keymap_in, size_t keymap_in_size,
  779. const char *rel_path, bool update_output_files)
  780. {
  781. int success = true;
  782. fprintf(stderr, "*** %s ***\n", test_title);
  783. char* got = NULL;
  784. size_t got_size = 0;
  785. int ret = compile_buffer(keymap_in, keymap_in_size, compile_buffer_private,
  786. &got, &got_size);
  787. if (!rel_path) {
  788. /* No path given: expect compilation failure */
  789. if (ret == EXIT_SUCCESS) {
  790. fprintf(stderr,
  791. "Unexpected keymap compilation success:\nstdout:\n%s\n",
  792. got);
  793. }
  794. free(got);
  795. return (ret != EXIT_SUCCESS);
  796. }
  797. if (ret != EXIT_SUCCESS || isempty(got)) {
  798. fprintf(stderr, "Unexpected keymap compilation failure.\nstdout:\n%s\n",
  799. got);
  800. free(got);
  801. return false;
  802. }
  803. char *path = test_get_path(rel_path);
  804. assert(path);
  805. if (update_output_files) {
  806. fprintf(stderr, "Writing golden test output to: %s\n", path);
  807. FILE *file = fopen(path, "wb");
  808. assert(file);
  809. fwrite(got, 1, got_size, file);
  810. fclose(file);
  811. } else {
  812. fprintf(stderr, "Reading golden test output: %s\n", path);
  813. char *expected = test_read_file(rel_path);
  814. assert(expected);
  815. const char *label[2] = {"Golden test", "Roundtrip"};
  816. for (unsigned int k = 0; k < ARRAY_SIZE(label) && success; k++) {
  817. if (streq(expected, got)) {
  818. fprintf(stderr, "%s succeeded.\n", label[k]);
  819. if (k > 0)
  820. continue;
  821. /* Test round trip */
  822. // TODO
  823. break;
  824. }else {
  825. fprintf(stderr,
  826. "%s failed: dumped map differs from expected.\n",
  827. label[k]);
  828. fprintf(stderr, "Path to expected file: %s\n", path);
  829. fprintf(stderr, "Length: expected %zu, got: %zu\n",
  830. strlen(expected), strlen(got));
  831. fprintf(stderr, "Dumped map:\n");
  832. fprintf(stderr, "%s\n", got);
  833. success = false;
  834. }
  835. }
  836. free(expected);
  837. }
  838. free(got);
  839. free(path);
  840. return success;
  841. }