stringcomp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Copyright © 2009 Dan Nicholson
  3. * SPDX-License-Identifier: MIT
  4. */
  5. #include "config.h"
  6. #include "features/enums.h"
  7. #include "test-config.h"
  8. #include <assert.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include "xkbcommon/xkbcommon.h"
  12. #include "test.h"
  13. #include "test/utils-text.h"
  14. #include "utils.h"
  15. #include "keymap-compare.h"
  16. static void
  17. test_keymap_comparison(struct xkb_context *ctx)
  18. {
  19. static const struct {
  20. const char* keymap1;
  21. const char* keymap2;
  22. enum xkb_keymap_compare_property properties;
  23. bool same;
  24. } tests[] = {
  25. {
  26. .keymap1 = "xkb_keymap {};",
  27. .keymap2 = "xkb_keymap {};",
  28. .properties = XKB_KEYMAP_CMP_ALL,
  29. .same = true
  30. },
  31. {
  32. .keymap1 =
  33. "xkb_keymap {\n"
  34. " xkb_keycodes { <> = 1; };\n"
  35. "};",
  36. .keymap2 = "xkb_keymap {};",
  37. .properties = XKB_KEYMAP_CMP_ALL,
  38. .same = false
  39. },
  40. {
  41. .keymap1 =
  42. "xkb_keymap {\n"
  43. " xkb_keycodes {\n"
  44. " <a> = 1;\n"
  45. " <b> = 2;\n"
  46. " };\n"
  47. " xkb_compat { include \"caps\" };\n"
  48. " xkb_types { include \"basic+iso9995\" };\n"
  49. " xkb_symbols {\n"
  50. " key <a> { [a, A] };\n"
  51. " key <b> { [Caps_Lock] };\n" /* implicit action */
  52. " };\n"
  53. "};",
  54. .keymap2 =
  55. "xkb_keymap {\n"
  56. " xkb_keycodes {\n"
  57. " <a> = 1;\n"
  58. " <b> = 2;\n"
  59. " };\n"
  60. " xkb_compat {};\n" /* empty */
  61. " xkb_types { include \"basic\" };\n" /* less types */
  62. " xkb_symbols {\n"
  63. /* Change key order + explicit actions and types */
  64. " key <b> {\n"
  65. " [Caps_Lock],\n"
  66. " [LockMods(modifiers = Lock)],\n"
  67. " type=\"ONE_LEVEL\"\n"
  68. " };\n"
  69. " key <a> { [a, A], type=\"ALPHABETIC\" };\n"
  70. /* Definition in different section */
  71. " virtual_modifiers LevelThree;\n"
  72. " };\n"
  73. "};",
  74. .properties = (XKB_KEYMAP_CMP_ALL & ~(XKB_KEYMAP_CMP_POSSIBLY_DROPPED)),
  75. .same = true
  76. },
  77. };
  78. for (size_t t = 0; t < ARRAY_SIZE(tests); t++) {
  79. fprintf(stderr, "------\n%s: #%zu\n", __func__, t);
  80. struct xkb_keymap * const keymap1 = test_compile_string(
  81. ctx, XKB_KEYMAP_FORMAT_TEXT_V1, tests[t].keymap1
  82. );
  83. assert(keymap1);
  84. struct xkb_keymap * const keymap2 = test_compile_string(
  85. ctx, XKB_KEYMAP_FORMAT_TEXT_V1, tests[t].keymap2
  86. );
  87. assert(keymap2);
  88. assert(xkb_keymap_compare(ctx, keymap1, keymap2, tests[t].properties) ==
  89. tests[t].same);
  90. xkb_keymap_unref(keymap1);
  91. xkb_keymap_unref(keymap2);
  92. }
  93. }
  94. static void
  95. test_explicit_actions(struct xkb_context *ctx)
  96. {
  97. struct xkb_keymap *keymap;
  98. char *original = test_read_file("keymaps/explicit-actions.xkb");
  99. assert(original);
  100. char *tmp = uncomment(original, strlen(original), "//");
  101. assert(tmp);
  102. char *expected = strip_lines(tmp, strlen(tmp), "//");
  103. free(tmp);
  104. assert(expected);
  105. char *got = NULL;
  106. /* Try original */
  107. keymap = test_compile_string(ctx, XKB_KEYMAP_FORMAT_TEXT_V1, original);
  108. free(original);
  109. assert(keymap);
  110. got = xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  111. TEST_KEYMAP_SERIALIZE_FLAGS);
  112. xkb_keymap_unref(keymap);
  113. assert_streq_not_null("Check output from original", expected, got);
  114. free(got);
  115. /* Try round-trip */
  116. keymap = test_compile_string(ctx, XKB_KEYMAP_FORMAT_TEXT_V1, expected);
  117. assert(keymap);
  118. got = xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  119. TEST_KEYMAP_SERIALIZE_FLAGS);
  120. xkb_keymap_unref(keymap);
  121. assert_streq_not_null("Check roundtrip", expected, got);
  122. free(got);
  123. free(expected);
  124. }
  125. static struct xkb_keymap*
  126. compile_string(struct xkb_context *context, enum xkb_keymap_format format,
  127. const char *buf, size_t len, void *private)
  128. {
  129. return test_compile_string(context, format, buf);
  130. }
  131. int
  132. main(int argc, char *argv[])
  133. {
  134. test_init();
  135. bool update_output_files = false;
  136. if (argc > 1) {
  137. if (streq(argv[1], "update")) {
  138. /* Update files with *obtained* results */
  139. update_output_files = true;
  140. } else {
  141. fprintf(stderr, "ERROR: unsupported argument: \"%s\".\n", argv[1]);
  142. exit(EXIT_FAILURE);
  143. }
  144. }
  145. struct xkb_context *ctx = test_get_context(CONTEXT_NO_FLAG);
  146. struct xkb_keymap *keymap;
  147. char *dump, *dump2;
  148. assert(ctx);
  149. /* Reject unsupported flags */
  150. assert(!xkb_keymap_new_from_string(ctx, "xkb_keymap {};",
  151. XKB_KEYMAP_FORMAT_TEXT_V1, -1));
  152. assert(!xkb_keymap_new_from_string(ctx, "xkb_keymap {};",
  153. XKB_KEYMAP_FORMAT_TEXT_V1, 0xffff));
  154. /* Make sure we can't (falsely claim to) compile an empty string. */
  155. keymap = test_compile_string(ctx, XKB_KEYMAP_FORMAT_TEXT_V1, "");
  156. assert(!keymap);
  157. /* Load in a prebuilt keymap, make sure we can compile it from a string,
  158. * then compare it to make sure we get the same result when dumping it
  159. * to a string. */
  160. static const struct {
  161. const char* path;
  162. enum xkb_keymap_format format;
  163. enum xkb_keymap_serialize_flags serialize_flags;
  164. } data[] = {
  165. {
  166. .path = "keymaps/stringcomp-v1.xkb",
  167. .format = XKB_KEYMAP_FORMAT_TEXT_V1,
  168. .serialize_flags = TEST_KEYMAP_SERIALIZE_FLAGS
  169. },
  170. {
  171. .path = "keymaps/stringcomp-v1-no-prettyfied.xkb",
  172. .format = XKB_KEYMAP_FORMAT_TEXT_V1,
  173. .serialize_flags = TEST_KEYMAP_SERIALIZE_FLAGS
  174. & ~XKB_KEYMAP_SERIALIZE_PRETTY
  175. },
  176. {
  177. .path = "keymaps/stringcomp-v1-no-flags.xkb",
  178. .format = XKB_KEYMAP_FORMAT_TEXT_V1,
  179. .serialize_flags = XKB_KEYMAP_SERIALIZE_NO_FLAGS
  180. },
  181. {
  182. .path = "keymaps/stringcomp-v2.xkb",
  183. .format = XKB_KEYMAP_FORMAT_TEXT_V2,
  184. .serialize_flags = TEST_KEYMAP_SERIALIZE_FLAGS
  185. },
  186. {
  187. .path = "keymaps/stringcomp-v2-explicit.xkb",
  188. .format = XKB_KEYMAP_FORMAT_TEXT_V2,
  189. .serialize_flags = TEST_KEYMAP_SERIALIZE_FLAGS
  190. | TEST_KEYMAP_SERIALIZE_EXPLICIT
  191. },
  192. {
  193. .path = "keymaps/stringcomp-v2-explicit-drop-unused.xkb",
  194. .format = XKB_KEYMAP_FORMAT_TEXT_V2,
  195. .serialize_flags = ( TEST_KEYMAP_SERIALIZE_FLAGS
  196. | TEST_KEYMAP_SERIALIZE_EXPLICIT )
  197. & ~XKB_KEYMAP_SERIALIZE_KEEP_UNUSED
  198. },
  199. };
  200. for (unsigned int k = 0; k < ARRAY_SIZE(data); k++) {
  201. fprintf(stderr, "------\nTest roundtrip of: %s\n", data[k].path);
  202. char *original = test_read_file(data[k].path);
  203. assert(original);
  204. /* Check round-trip with same serialize flags */
  205. assert(test_compile_output2(ctx, data[k].format,
  206. XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  207. data[k].serialize_flags,
  208. compile_string, NULL,
  209. "Round-trip with same serialize flags",
  210. original, 0 /* unused */, data[k].path,
  211. update_output_files));
  212. /*
  213. * Check round-trip by dropping/keeping unused keymap items
  214. * We obviously cannot compare the serializations, so only keymap
  215. * objects are compared.
  216. */
  217. keymap = xkb_keymap_new_from_string(ctx, original, data[k].format,
  218. TEST_KEYMAP_COMPILE_FLAGS);
  219. assert(keymap);
  220. free(original);
  221. const enum xkb_keymap_serialize_flags test_serialize_flags[] = {
  222. (data[k].serialize_flags & ~XKB_KEYMAP_SERIALIZE_KEEP_UNUSED),
  223. (data[k].serialize_flags | XKB_KEYMAP_SERIALIZE_KEEP_UNUSED)
  224. };
  225. for (size_t f = 0; f < ARRAY_SIZE(test_serialize_flags); f++) {
  226. original = xkb_keymap_get_as_string2(keymap, data[k].format,
  227. test_serialize_flags[f]);
  228. assert(original);
  229. struct xkb_keymap *keymap2 = xkb_keymap_new_from_string(
  230. ctx, original, data[k].format, TEST_KEYMAP_COMPILE_FLAGS
  231. );
  232. assert(keymap2);
  233. free(original);
  234. assert(xkb_keymap_compare(ctx, keymap, keymap2,
  235. (XKB_KEYMAP_CMP_ALL &
  236. ~(XKB_KEYMAP_CMP_POSSIBLY_DROPPED))));
  237. xkb_keymap_unref(keymap2);
  238. }
  239. /*
  240. * Check pretty/no-pretty round-trip, i.e. check that changing the
  241. * pretty-print flags results in the same keymap, for both keymap
  242. * objects and serializations.
  243. */
  244. const enum xkb_keymap_serialize_flags serialize_flags =
  245. (data[k].serialize_flags & XKB_KEYMAP_SERIALIZE_PRETTY)
  246. ? (data[k].serialize_flags & ~XKB_KEYMAP_SERIALIZE_PRETTY)
  247. : (data[k].serialize_flags | XKB_KEYMAP_SERIALIZE_PRETTY);
  248. original = xkb_keymap_get_as_string2(keymap, data[k].format,
  249. serialize_flags);
  250. assert(original);
  251. struct xkb_keymap *keymap2 = xkb_keymap_new_from_string(
  252. ctx, original, data[k].format, TEST_KEYMAP_COMPILE_FLAGS
  253. );
  254. assert(keymap2);
  255. assert(xkb_keymap_compare(ctx, keymap, keymap2, XKB_KEYMAP_CMP_ALL));
  256. xkb_keymap_unref(keymap2);
  257. assert(test_compile_output2(ctx, data[k].format,
  258. XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  259. data[k].serialize_flags,
  260. compile_string, NULL,
  261. "Round-trip with different serialize flags",
  262. original, 0 /* unused */, data[k].path,
  263. update_output_files));
  264. free(original);
  265. xkb_keymap_unref(keymap);
  266. }
  267. /* Make sure we can recompile our output for a normal keymap from rules. */
  268. keymap = test_compile_rules(ctx, XKB_KEYMAP_FORMAT_TEXT_V1, NULL,
  269. NULL, "ru,ca,de,us", ",multix,neo,intl", NULL);
  270. assert(keymap);
  271. dump = xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  272. TEST_KEYMAP_SERIALIZE_FLAGS);
  273. assert(dump);
  274. xkb_keymap_unref(keymap);
  275. keymap = test_compile_string(ctx, XKB_KEYMAP_FORMAT_TEXT_V1, dump);
  276. assert(keymap);
  277. /* Now test that the dump of the dump is equal to the dump! */
  278. dump2 = xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT,
  279. TEST_KEYMAP_SERIALIZE_FLAGS);
  280. assert(dump2);
  281. assert(streq(dump, dump2));
  282. /* Test response to invalid formats and flags. */
  283. assert(!xkb_keymap_new_from_string(ctx, dump, 0, 0));
  284. assert(!xkb_keymap_new_from_string(ctx, dump, -1, 0));
  285. assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_USE_ORIGINAL_FORMAT, 0));
  286. assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V2+1, 0));
  287. assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V1, -1));
  288. assert(!xkb_keymap_new_from_string(ctx, dump, XKB_KEYMAP_FORMAT_TEXT_V1, 1414));
  289. assert(!xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT, -1));
  290. assert(!xkb_keymap_get_as_string2(keymap, XKB_KEYMAP_USE_ORIGINAL_FORMAT, 3333));
  291. assert(!xkb_keymap_get_as_string2(keymap, 0, TEST_KEYMAP_SERIALIZE_FLAGS));
  292. assert(!xkb_keymap_get_as_string2(keymap, 4893, TEST_KEYMAP_SERIALIZE_FLAGS));
  293. xkb_keymap_unref(keymap);
  294. free(dump);
  295. free(dump2);
  296. test_keymap_comparison(ctx);
  297. test_explicit_actions(ctx);
  298. xkb_context_unref(ctx);
  299. return EXIT_SUCCESS;
  300. }