context.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Copyright © 2012 Intel Corporation
  3. * SPDX-License-Identifier: MIT
  4. *
  5. * Author: Daniel Stone <daniel@fooishbar.org>
  6. */
  7. #include "config.h"
  8. #include "test-config.h"
  9. #include <stdlib.h>
  10. #include <sys/stat.h>
  11. #include <sys/types.h>
  12. #include "test.h"
  13. #include "xkbcommon/xkbcommon.h"
  14. #include "context.h"
  15. /* keeps a cache of all makedir/maketmpdir directories so we can free and
  16. * rmdir them in one go, see unmakedirs() */
  17. static char *dirnames[64];
  18. static int ndirs;
  19. /* keeps a cache of all buffered env vars so we can restore
  20. * them in one go, see restore_env() */
  21. static struct env {
  22. char *key;
  23. char *value;
  24. } environment[64];
  25. static int nenviron;
  26. static void
  27. buffer_env(const char *key)
  28. {
  29. char *v = getenv(key);
  30. environment[nenviron].key = strdup(key);
  31. environment[nenviron].value = v ? strdup(v) : NULL;
  32. nenviron++;
  33. }
  34. static void
  35. restore_env(void)
  36. {
  37. for (int i = 0; i < nenviron; i++) {
  38. char *key = environment[i].key,
  39. *value = environment[i].value;
  40. if (value)
  41. setenv(key, value, 1);
  42. else
  43. unsetenv(key);
  44. free(key);
  45. free(value);
  46. }
  47. nenviron = 0;
  48. memset(environment, 0, sizeof(environment));
  49. }
  50. static const char *
  51. makedir(const char *parent, const char *path)
  52. {
  53. char *dirname = test_makedir(parent, path);
  54. dirnames[ndirs++] = dirname;
  55. return dirname;
  56. }
  57. static const char *maketmpdir(void)
  58. {
  59. char *tmpdir = test_maketempdir("xkbcommon-test.XXXXXX");
  60. dirnames[ndirs++] = tmpdir;
  61. return tmpdir;
  62. }
  63. static void
  64. unmakedirs(void)
  65. {
  66. /* backwards order for rmdir to work */
  67. for (int i = ndirs - 1; i >= 0; i--) {
  68. char *dir = dirnames[i];
  69. if (!dir)
  70. break;
  71. rmdir(dir);
  72. free(dir);
  73. }
  74. ndirs = 0;
  75. memset(dirnames, 0, sizeof(dirnames));
  76. }
  77. static void
  78. test_config_root_include_path(void)
  79. {
  80. struct xkb_context *ctx;
  81. const char *tmpdir;
  82. const char *context_path;
  83. buffer_env("XKB_CONFIG_ROOT");
  84. buffer_env("HOME");
  85. buffer_env("XDG_CONFIG_HOME");
  86. tmpdir = maketmpdir();
  87. setenv("XKB_CONFIG_ROOT", tmpdir, 1);
  88. unsetenv("HOME");
  89. unsetenv("XDG_CONFIG_HOME");
  90. /* Valid built-in path is last */
  91. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  92. const unsigned int nincludes = xkb_context_num_include_paths(ctx);
  93. assert(nincludes >= 1);
  94. context_path = xkb_context_include_path_get(ctx, nincludes - 1);
  95. assert(strcmp(context_path, tmpdir) == 0);
  96. xkb_context_unref(ctx);
  97. unmakedirs();
  98. restore_env();
  99. }
  100. static void
  101. test_config_root_include_path_fallback(void)
  102. {
  103. struct xkb_context *ctx;
  104. const char *xkbdir = DFLT_XKB_CONFIG_ROOT;
  105. const char *context_path;
  106. /* quick and dirty check that the default directory exists.
  107. * It may not on a vanilla test box if we just run the test
  108. * suite, so where it's not there just skip this test. */
  109. struct stat stat_buf;
  110. int err = stat(xkbdir, &stat_buf);
  111. if (err != 0)
  112. return;
  113. if (!S_ISDIR(stat_buf.st_mode))
  114. return;
  115. buffer_env("XKB_CONFIG_ROOT");
  116. buffer_env("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH");
  117. buffer_env("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH");
  118. buffer_env("XKB_CONFIG_EXTRA_PATH");
  119. buffer_env("HOME");
  120. buffer_env("XDG_CONFIG_HOME");
  121. unsetenv("XKB_CONFIG_ROOT");
  122. unsetenv("HOME");
  123. unsetenv("XDG_CONFIG_HOME");
  124. /* Valid built-in path is last */
  125. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  126. unsigned int nincludes = xkb_context_num_include_paths(ctx);
  127. assert(nincludes >= 1);
  128. context_path = xkb_context_include_path_get(ctx, nincludes - 1);
  129. assert(strcmp(context_path, xkbdir) == 0);
  130. xkb_context_unref(ctx);
  131. /* Invalid built-in path is replaced with legacy X11 path */
  132. setenv("XKB_CONFIG_ROOT", "¡NONSENSE!", 1);
  133. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  134. nincludes = xkb_context_num_include_paths(ctx);
  135. assert(nincludes >= 1);
  136. context_path = xkb_context_include_path_get(ctx, nincludes - 1);
  137. assert(strcmp(context_path, DFLT_XKB_LEGACY_ROOT) == 0);
  138. xkb_context_unref(ctx);
  139. setenv("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH", "", 1);
  140. setenv("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH", "", 1);
  141. /* Ensure some path is available */
  142. const char *tmpdir = maketmpdir();
  143. setenv("XKB_CONFIG_EXTRA_PATH", tmpdir, 1);
  144. /* Invalid built-in path and deliberately skipped legacy X11 path */
  145. setenv("XKB_CONFIG_ROOT", "", 1);
  146. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  147. nincludes = xkb_context_num_include_paths(ctx);
  148. assert(nincludes >= 1);
  149. context_path = xkb_context_include_path_get(ctx, nincludes - 1);
  150. assert(strcmp(context_path, tmpdir) == 0);
  151. xkb_context_unref(ctx);
  152. /* No valid path */
  153. setenv("XKB_CONFIG_EXTRA_PATH", "", 1);
  154. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  155. nincludes = xkb_context_num_include_paths(ctx);
  156. assert(nincludes == 0);
  157. xkb_context_unref(ctx);
  158. unmakedirs();
  159. restore_env();
  160. }
  161. static void
  162. test_xkbdir_include_path(void)
  163. {
  164. struct xkb_context *ctx;
  165. const char *tmpdir;
  166. const char *xkb_path;
  167. const char *context_path;
  168. buffer_env("HOME");
  169. buffer_env("XDG_CONFIG_HOME");
  170. tmpdir = maketmpdir();
  171. xkb_path = makedir(tmpdir, ".xkb");
  172. setenv("HOME", tmpdir, 1);
  173. setenv("XDG_CONFIG_HOME", tmpdir, 1);
  174. /* No XDG directory in our tmpdir, so we expect
  175. * the $HOME/.xkb to be the first include path */
  176. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  177. assert(xkb_context_num_include_paths(ctx) >= 1);
  178. context_path = xkb_context_include_path_get(ctx, 0);
  179. assert(strcmp(context_path, xkb_path) == 0);
  180. xkb_context_unref(ctx);
  181. unmakedirs();
  182. restore_env();
  183. }
  184. static void
  185. test_xdg_include_path(void)
  186. {
  187. struct xkb_context *ctx;
  188. const char *tmpdir;
  189. const char *xdg_path;
  190. const char *context_path;
  191. buffer_env("XDG_CONFIG_HOME");
  192. tmpdir = maketmpdir();
  193. xdg_path = makedir(tmpdir, "xkb");
  194. setenv("XDG_CONFIG_HOME", tmpdir, 1);
  195. /* XDG path is always first */
  196. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  197. assert(xkb_context_num_include_paths(ctx) >= 1);
  198. context_path = xkb_context_include_path_get(ctx, 0);
  199. assert(strcmp(context_path, xdg_path) == 0);
  200. xkb_context_unref(ctx);
  201. unmakedirs();
  202. restore_env();
  203. }
  204. static void
  205. test_xdg_include_path_fallback(void)
  206. {
  207. struct xkb_context *ctx;
  208. const char *tmpdir;
  209. const char *xdg_root, *xdg_path;
  210. const char *context_path;
  211. buffer_env("XDG_CONFIG_HOME");
  212. buffer_env("HOME");
  213. tmpdir = maketmpdir();
  214. xdg_root = makedir(tmpdir, ".config");
  215. xdg_path = makedir(xdg_root, "xkb");
  216. setenv("HOME", tmpdir, 1);
  217. unsetenv("XDG_CONFIG_HOME");
  218. /* XDG path is always first, even if fallback */
  219. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  220. assert(xkb_context_num_include_paths(ctx) >= 1);
  221. context_path = xkb_context_include_path_get(ctx, 0);
  222. assert(strcmp(context_path, xdg_path) == 0);
  223. xkb_context_unref(ctx);
  224. unmakedirs();
  225. restore_env();
  226. }
  227. static void
  228. test_include_order(void)
  229. {
  230. struct xkb_context *ctx;
  231. const char *tmpdir;
  232. const char *xdg_path;
  233. const char *xkb_home_path;
  234. const char *xkb_root_path;
  235. const char *context_path;
  236. buffer_env("XKB_CONFIG_ROOT");
  237. buffer_env("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH");
  238. buffer_env("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH");
  239. buffer_env("XDG_CONFIG_HOME");
  240. buffer_env("HOME");
  241. tmpdir = maketmpdir();
  242. xdg_path = makedir(tmpdir, "xkb");
  243. xkb_home_path = makedir(tmpdir, ".xkb");
  244. xkb_root_path = makedir(tmpdir, "xkbroot");
  245. setenv("HOME", tmpdir, 1);
  246. setenv("XDG_CONFIG_HOME", tmpdir, 1);
  247. setenv("XKB_CONFIG_ROOT", xkb_root_path, 1);
  248. setenv("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH", "", 1);
  249. setenv("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH", "", 1);
  250. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  251. assert(xkb_context_num_include_paths(ctx) >= 3);
  252. /* XDG is first */
  253. context_path = xkb_context_include_path_get(ctx, 0);
  254. assert(strcmp(context_path, xdg_path) == 0);
  255. /* $HOME/.xkb is second */
  256. context_path = xkb_context_include_path_get(ctx, 1);
  257. assert(strcmp(context_path, xkb_home_path) == 0);
  258. /* CONFIG_ROOT is last */
  259. context_path = xkb_context_include_path_get(ctx, 2);
  260. assert(strcmp(context_path, xkb_root_path) == 0);
  261. xkb_context_unref(ctx);
  262. unmakedirs();
  263. restore_env();
  264. }
  265. static void
  266. test_delayed_includes(void)
  267. {
  268. buffer_env("XKB_CONFIG_ROOT");
  269. buffer_env("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH");
  270. buffer_env("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH");
  271. buffer_env("XKB_CONFIG_EXTRA_PATH");
  272. buffer_env("XDG_CONFIG_HOME");
  273. buffer_env("HOME");
  274. const char * const xkb_root_path = maketmpdir();
  275. /* Empty paths, so that currently a call to
  276. * xkb_context_include_path_append_default() would fail */
  277. setenv("XKB_CONFIG_ROOT", "", 1);
  278. setenv("XKB_CONFIG_UNVERSIONED_EXTENSIONS_PATH", "", 1);
  279. setenv("XKB_CONFIG_VERSIONED_EXTENSIONS_PATH", "", 1);
  280. setenv("XKB_CONFIG_EXTRA_PATH", "", 1);
  281. unsetenv("XDG_CONFIG_HOME");
  282. unsetenv("HOME");
  283. struct xkb_context *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  284. /* Context should initialize correctly, despite no include path is
  285. * currently available */
  286. assert(ctx);
  287. assert(xkb_context_num_include_paths(ctx) == 0);
  288. /* Setting XKB_CONFIG_ROOT correctly is too late, because we used API that
  289. * requires to initialize the include paths */
  290. setenv("XKB_CONFIG_ROOT", xkb_root_path, 1);
  291. assert(xkb_context_num_include_paths(ctx) == 0);
  292. /* We cannot add further paths, since the default paths failed */
  293. assert(!xkb_context_include_path_append(ctx, xkb_root_path));
  294. xkb_context_unref(ctx);
  295. setenv("XKB_CONFIG_ROOT", "", 1);
  296. ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  297. /* Context should initialize correctly, despite no include path is
  298. * currently available */
  299. assert(ctx);
  300. /* Set XKB_CONFIG_ROOT correctly before using any API that requires the
  301. * to initialize the include paths */
  302. setenv("XKB_CONFIG_ROOT", xkb_root_path, 1);
  303. assert(xkb_context_num_include_paths(ctx) == 1);
  304. const char * const context_path = xkb_context_include_path_get(ctx, 0);
  305. assert(strcmp(context_path, xkb_root_path) == 0);
  306. assert(xkb_context_include_path_append(ctx, xkb_root_path) == 1);
  307. assert(xkb_context_num_include_paths(ctx) == 2);
  308. xkb_context_unref(ctx);
  309. unmakedirs();
  310. restore_env();
  311. }
  312. int
  313. main(void)
  314. {
  315. test_init();
  316. /* Reject invalid flags */
  317. assert(!xkb_context_new(-1));
  318. assert(!xkb_context_new(0xffff));
  319. struct xkb_context *context = test_get_context(CONTEXT_NO_FLAG);
  320. assert(context);
  321. assert(xkb_context_num_include_paths(context) == 1);
  322. assert(!xkb_context_include_path_append(context, "¡NONSENSE!"));
  323. assert(xkb_context_num_include_paths(context) == 1);
  324. xkb_atom_t atom = xkb_atom_intern(context, "HELLOjunkjunkjunk", 5);
  325. assert(atom != XKB_ATOM_NONE);
  326. assert(streq(xkb_atom_text(context, atom), "HELLO"));
  327. atom = xkb_atom_intern_literal(context, "HELLOjunkjunkjunk");
  328. assert(atom != XKB_ATOM_NONE);
  329. assert(streq(xkb_atom_text(context, atom), "HELLOjunkjunkjunk"));
  330. xkb_context_unref(context);
  331. test_config_root_include_path();
  332. test_config_root_include_path_fallback();
  333. test_xkbdir_include_path();
  334. test_xdg_include_path();
  335. test_xdg_include_path_fallback();
  336. test_include_order();
  337. test_delayed_includes();
  338. return EXIT_SUCCESS;
  339. }