Add asprintf_safe helper function
[platform/upstream/libxkbcommon.git] / test / context.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Author: Daniel Stone <daniel@fooishbar.org>
24  */
25
26 #include "config.h"
27
28 #include "test.h"
29 #include "context.h"
30
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #ifdef _MSC_VER
34 # include <io.h>
35 # include <direct.h>
36 # ifndef S_ISDIR
37 #  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
38 # endif
39 #else
40 # include <unistd.h>
41 #endif
42
43 /* keeps a cache of all makedir/maketmpdir directories so we can free and
44  * rmdir them in one go, see unmakedirs() */
45 char *dirnames[64];
46 int ndirs;
47
48 /* keeps a cache of all buffered env vars so we can restore
49  * them in one go, see restore_env() */
50 struct env {
51     char *key;
52     char *value;
53 } environment[64];
54 int nenviron;
55
56 static void buffer_env(const char *key)
57 {
58     char *v = getenv(key);
59
60     environment[nenviron].key = strdup(key);
61     environment[nenviron].value = v ? strdup(v) : NULL;
62     nenviron++;
63 }
64
65 static void restore_env(void)
66 {
67     for (int i = 0; i < nenviron; i++) {
68         char *key = environment[i].key,
69              *value = environment[i].value;
70
71         if (value)
72             setenv(key, value, 1);
73         else
74             unsetenv(key);
75
76         free(key);
77         free(value);
78     }
79     nenviron = 0;
80     memset(environment, 0, sizeof(environment));
81 }
82
83 static const char *makedir(const char *parent, const char *path)
84 {
85     char *dirname;
86     int err;
87
88     dirname = asprintf_safe("%s/%s", parent, path);
89     assert(dirname);
90     err = mkdir(dirname, 0777);
91     assert(err == 0);
92
93     dirnames[ndirs++] = dirname;
94
95     return dirname;
96 }
97
98 static const char *maketmpdir(void)
99 {
100     const char *template = "/tmp/xkbcommon-test.XXXXXX";
101     char *tmpdir = strdup(template);
102
103     tmpdir = mkdtemp(tmpdir);
104     assert(tmpdir != NULL);
105
106     dirnames[ndirs++] = tmpdir;
107
108     return tmpdir;
109 }
110
111 static void unmakedirs(void)
112 {
113     /* backwards order for rmdir to work */
114     for (int i = ndirs - 1; i >= 0; i--) {
115         char *dir = dirnames[i];
116         if (!dir)
117             break;
118         rmdir(dir);
119         free(dir);
120     }
121     ndirs = 0;
122     memset(dirnames, 0, sizeof(dirnames));
123 }
124
125 static void
126 test_config_root_include_path(void)
127 {
128     struct xkb_context *ctx;
129     const char *tmpdir;
130     const char *context_path;
131     int nincludes;
132
133     buffer_env("XKB_CONFIG_ROOT");
134     buffer_env("HOME");
135     buffer_env("XDG_CONFIG_HOME");
136
137     tmpdir = maketmpdir();
138     setenv("XKB_CONFIG_ROOT", tmpdir, 1);
139     unsetenv("HOME");
140     unsetenv("XDG_CONFIG_HOME");
141
142     /* built-in path is last */
143     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
144     nincludes = xkb_context_num_include_paths(ctx);
145     assert(nincludes >= 1);
146     context_path = xkb_context_include_path_get(ctx, nincludes - 1);
147     assert(strcmp(context_path, tmpdir) == 0);
148     xkb_context_unref(ctx);
149
150     unmakedirs();
151     restore_env();
152 }
153
154 static void
155 test_config_root_include_path_fallback(void)
156 {
157     struct xkb_context *ctx;
158     const char *xkbdir = DFLT_XKB_CONFIG_ROOT;
159     const char *context_path;
160     int nincludes;
161
162     /* quick and dirty check that the default directory exists.
163      * It may not on a vanilla test box if we just run the test
164      * suite, so where it's not there just skip this test. */
165     struct stat stat_buf;
166     int err = stat(xkbdir, &stat_buf);
167     if (err != 0)
168         return;
169     if (!S_ISDIR(stat_buf.st_mode))
170         return;
171
172     buffer_env("XKB_CONFIG_ROOT");
173     buffer_env("HOME");
174     buffer_env("XDG_CONFIG_HOME");
175
176     unsetenv("XKB_CONFIG_ROOT");
177     unsetenv("HOME");
178     unsetenv("XDG_CONFIG_HOME");
179
180     /* built-in path is last */
181     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
182     nincludes = xkb_context_num_include_paths(ctx);
183     assert(nincludes >= 1);
184     context_path = xkb_context_include_path_get(ctx, nincludes - 1);
185     assert(strcmp(context_path, xkbdir) == 0);
186     xkb_context_unref(ctx);
187
188     unmakedirs();
189     restore_env();
190 }
191
192 static void
193 test_xkbdir_include_path(void)
194 {
195     struct xkb_context *ctx;
196     const char *tmpdir;
197     const char *xkb_path;
198     const char *context_path;
199
200     buffer_env("HOME");
201     buffer_env("XDG_CONFIG_HOME");
202
203     tmpdir = maketmpdir();
204     xkb_path = makedir(tmpdir, ".xkb");
205     setenv("HOME", tmpdir, 1);
206     setenv("XDG_CONFIG_HOME", tmpdir, 1);
207
208     /* No XDG directory in our tmpdir, so we expect
209      * the $HOME/.xkb to be the first include path */
210     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
211     assert(xkb_context_num_include_paths(ctx) >= 1);
212     context_path = xkb_context_include_path_get(ctx, 0);
213     assert(strcmp(context_path, xkb_path) == 0);
214     xkb_context_unref(ctx);
215
216     unmakedirs();
217     restore_env();
218 }
219
220 static void
221 test_xdg_include_path(void)
222 {
223     struct xkb_context *ctx;
224     const char *tmpdir;
225     const char *xdg_path;
226     const char *context_path;
227
228     buffer_env("XDG_CONFIG_HOME");
229
230     tmpdir = maketmpdir();
231     xdg_path = makedir(tmpdir, "xkb");
232     setenv("XDG_CONFIG_HOME", tmpdir, 1);
233
234     /* XDG path is always first */
235     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
236     assert(xkb_context_num_include_paths(ctx) >= 1);
237     context_path = xkb_context_include_path_get(ctx, 0);
238     assert(strcmp(context_path, xdg_path) == 0);
239     xkb_context_unref(ctx);
240
241     unmakedirs();
242     restore_env();
243 }
244
245 static void
246 test_xdg_include_path_fallback(void)
247 {
248     struct xkb_context *ctx;
249     const char *tmpdir;
250     const char *xdg_root, *xdg_path;
251     const char *context_path;
252
253     buffer_env("XDG_CONFIG_HOME");
254     buffer_env("HOME");
255
256     tmpdir = maketmpdir();
257     xdg_root = makedir(tmpdir, ".config");
258     xdg_path = makedir(xdg_root, "xkb");
259     setenv("HOME", tmpdir, 1);
260     unsetenv("XDG_CONFIG_HOME");
261
262     /* XDG path is always first, even if fallback */
263     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
264     assert(xkb_context_num_include_paths(ctx) >= 1);
265     context_path = xkb_context_include_path_get(ctx, 0);
266     assert(strcmp(context_path, xdg_path) == 0);
267     xkb_context_unref(ctx);
268
269     unmakedirs();
270     restore_env();
271 }
272
273 static void
274 test_include_order(void)
275 {
276     struct xkb_context *ctx;
277     const char *tmpdir;
278     const char *xdg_path;
279     const char *xkb_home_path;
280     const char *xkb_root_path;
281     const char *context_path;
282
283     buffer_env("XKB_CONFIG_ROOT");
284     buffer_env("XDG_CONFIG_HOME");
285     buffer_env("HOME");
286
287     tmpdir = maketmpdir();
288     xdg_path = makedir(tmpdir, "xkb");
289     xkb_home_path = makedir(tmpdir, ".xkb");
290     xkb_root_path = makedir(tmpdir, "xkbroot");
291     setenv("HOME", tmpdir, 1);
292     setenv("XDG_CONFIG_HOME", tmpdir, 1);
293     setenv("XKB_CONFIG_ROOT", xkb_root_path, 1);
294
295     ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
296     assert(xkb_context_num_include_paths(ctx) >= 3);
297     /* XDG is first */
298     context_path = xkb_context_include_path_get(ctx, 0);
299     assert(strcmp(context_path, xdg_path) == 0);
300     /* $HOME/.xkb is second */
301     context_path = xkb_context_include_path_get(ctx, 1);
302     assert(strcmp(context_path, xkb_home_path) == 0);
303     /* CONFIG_ROOT is last */
304     context_path = xkb_context_include_path_get(ctx, 2);
305     assert(strcmp(context_path, xkb_root_path) == 0);
306
307     xkb_context_unref(ctx);
308
309     unmakedirs();
310     restore_env();
311 }
312
313 int
314 main(void)
315 {
316     struct xkb_context *context = test_get_context(0);
317     xkb_atom_t atom;
318
319     assert(context);
320
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
325     atom = xkb_atom_intern(context, "HELLOjunkjunkjunk", 5);
326     assert(atom != XKB_ATOM_NONE);
327     assert(streq(xkb_atom_text(context, atom), "HELLO"));
328
329     atom = xkb_atom_intern_literal(context, "HELLOjunkjunkjunk");
330     assert(atom != XKB_ATOM_NONE);
331     assert(streq(xkb_atom_text(context, atom), "HELLOjunkjunkjunk"));
332
333     xkb_context_unref(context);
334
335     test_config_root_include_path();
336     test_config_root_include_path_fallback();
337     test_xkbdir_include_path();
338     test_xdg_include_path();
339     test_xdg_include_path_fallback();
340     test_include_order();
341
342     return 0;
343 }