GCC Code Coverage Report


Directory: ./
File: libgsystemservice/tests/config-file.c
Date: 2024-04-09 14:29:48
Exec Total Coverage
Lines: 161 170 94.7%
Functions: 13 13 100.0%
Branches: 41 90 45.6%

Line Branch Exec Source
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright © 2017, 2018 Endless Mobile, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * Authors:
22 * - Philip Withnall <withnall@endlessm.com>
23 */
24
25 #include <glib.h>
26 #include <glib/gstdio.h>
27 #include <libgsystemservice/config-file.h>
28 #include <libgsystemservice/tests/config-file-resources.h>
29 #include <locale.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 typedef struct
35 {
36 gchar *tmp_dir;
37 gchar *key_file1_path;
38 gchar *key_file2_path;
39 gchar *key_file_nonexistent_path;
40 gchar *key_file_unreadable_path;
41 gchar *key_file_invalid_path;
42
43 GResource *default_resource; /* unowned */
44 const gchar *default_path;
45 const gchar *default_path_invalid;
46 } Fixture;
47
48 /* Set up a temporary directory with various test configuration files in. */
49 static void
50 9 setup (Fixture *fixture,
51 gconstpointer user_data G_GNUC_UNUSED)
52 {
53 18 g_autoptr(GError) error = NULL;
54
55
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if (g_test_subprocess ())
56 {
57 const char *tmp_dir = g_getenv ("LIBGSYSTEMSERVICE_TESTS_TMPDIR");
58 g_assert_nonnull (tmp_dir);
59 fixture->tmp_dir = g_strdup (tmp_dir);
60 }
61 else
62 {
63 9 fixture->tmp_dir = g_dir_make_tmp ("libgsystemservice-tests-config-XXXXXX", &error);
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 g_assert_no_error (error);
65 9 g_setenv ("LIBGSYSTEMSERVICE_TESTS_TMPDIR", fixture->tmp_dir, TRUE);
66 }
67
68 9 fixture->key_file1_path = g_build_filename (fixture->tmp_dir, "key-file1",
69 NULL);
70 9 g_file_set_contents (fixture->key_file1_path,
71 "[Test]\n"
72 "File=1\n"
73 "File1=true\n"
74 "[Group1]\n",
75 -1, &error);
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 g_assert_no_error (error);
77
78 9 fixture->key_file2_path = g_build_filename (fixture->tmp_dir, "key-file2",
79 NULL);
80 9 g_file_set_contents (fixture->key_file2_path,
81 "[Test]\n"
82 "File=2\n"
83 "File2=true\n"
84 "[Group2]\n",
85 -1, &error);
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 g_assert_no_error (error);
87
88 9 fixture->key_file_nonexistent_path = g_build_filename (fixture->tmp_dir,
89 "key-file-nonexistent",
90 NULL);
91
92 9 fixture->key_file_unreadable_path = g_build_filename (fixture->tmp_dir,
93 "key-file-unreadable",
94 NULL);
95 9 g_file_set_contents (fixture->key_file_unreadable_path, "[Test]\nFile=3",
96 -1, &error);
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 g_assert_no_error (error);
98
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 g_assert_cmpint (g_chmod (fixture->key_file_unreadable_path, 0200), ==, 0);
99
100 9 fixture->key_file_invalid_path = g_build_filename (fixture->tmp_dir,
101 "key-file-invalid",
102 NULL);
103 9 g_file_set_contents (fixture->key_file_invalid_path, "really not valid", -1,
104 &error);
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 g_assert_no_error (error);
106
107 9 fixture->default_resource = config_file_resources_get_resource ();
108 9 fixture->default_path = "/org/gnome/libgsystemservice/config/config-test.conf";
109 9 fixture->default_path_invalid = "/org/gnome/libgsystemservice/config/config-test-invalid.conf";
110 9 }
111
112 static void
113 36 unlink_and_free (gchar **path)
114 {
115
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (*path != NULL)
116
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 g_assert_cmpint (g_unlink (*path), ==, 0);
117
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 g_clear_pointer (path, g_free);
118 36 }
119
120 /* Inverse of setup(). */
121 static void
122 9 teardown (Fixture *fixture,
123 gconstpointer user_data G_GNUC_UNUSED)
124 {
125 9 unlink_and_free (&fixture->key_file_invalid_path);
126 9 unlink_and_free (&fixture->key_file_unreadable_path);
127 9 g_free (fixture->key_file_nonexistent_path);
128 9 unlink_and_free (&fixture->key_file2_path);
129 9 unlink_and_free (&fixture->key_file1_path);
130
131
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 g_assert_cmpint (g_rmdir (fixture->tmp_dir), ==, 0);
132 9 g_free (fixture->tmp_dir);
133 9 }
134
135 /* Test that loading a single configuration file works. */
136 static void
137 1 test_config_file_load_one (Fixture *fixture,
138 gconstpointer user_data G_GNUC_UNUSED)
139 {
140 1 g_autoptr(GError) error = NULL;
141 1 g_autoptr(GssConfigFile) config = NULL;
142 1 const gchar * const paths[] =
143 {
144 1 fixture->key_file1_path,
145 NULL
146 };
147 guint loaded_file;
148
149 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
150
151 1 loaded_file = gss_config_file_get_uint (config, "Test", "File", 0, G_MAXUINT, &error);
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (loaded_file, ==, 1);
154 1 }
155
156 /* Test that priority ordering of configuration files works. */
157 static void
158 1 test_config_file_load_many (Fixture *fixture,
159 gconstpointer user_data G_GNUC_UNUSED)
160 {
161 1 g_autoptr(GError) error = NULL;
162 1 g_autoptr(GssConfigFile) config = NULL;
163 1 const gchar * const paths[] =
164 {
165 1 fixture->key_file1_path,
166 1 fixture->key_file2_path,
167 NULL
168 };
169 guint loaded_file;
170
171 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
172
173 1 loaded_file = gss_config_file_get_uint (config, "Test", "File", 0, G_MAXUINT, &error);
174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (loaded_file, ==, 1);
176 1 }
177
178 /* Test that error reporting from an unreadable file reports an error. */
179 static void
180 1 test_config_file_unreadable (Fixture *fixture,
181 gconstpointer user_data G_GNUC_UNUSED)
182 {
183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_autoptr(GError) error = NULL;
184
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_autoptr(GssConfigFile) config = NULL;
185
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_autofree gchar *temp = NULL;
186 1 const gchar * const paths[] =
187 {
188 1 fixture->key_file_nonexistent_path,
189 1 fixture->key_file_unreadable_path,
190 1 fixture->key_file1_path,
191 NULL
192 };
193
194 /* If the test is run as root (or another user with CAP_DAC_OVERRIDE), the
195 * user can read any file anyway. */
196
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (g_file_get_contents (fixture->key_file_unreadable_path, &temp, NULL, NULL))
197 {
198 1 g_test_skip ("Test cannot be run as a user with CAP_DAC_OVERRIDE or "
199 "CAP_DAC_READ_SEARCH.");
200 1 return;
201 }
202
203 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
204
205 gss_config_file_get_uint (config, "Any", "Thing", 0, G_MAXUINT, &error);
206 g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES);
207 }
208
209 /* Test that error reporting from an invalid file reports an error. */
210 static void
211 1 test_config_file_invalid (Fixture *fixture,
212 gconstpointer user_data G_GNUC_UNUSED)
213 {
214 1 g_autoptr(GError) error = NULL;
215 1 g_autoptr(GssConfigFile) config = NULL;
216 1 const gchar * const paths[] =
217 {
218 1 fixture->key_file_invalid_path,
219 1 fixture->key_file1_path,
220 NULL
221 };
222
223 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
224
225 1 gss_config_file_get_uint (config, "Any", "Thing", 0, G_MAXUINT, &error);
226
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
1 g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
227 1 }
228
229 /* Test that multiple non-existent paths are handled correctly. */
230 static void
231 1 test_config_file_nonexistent (Fixture *fixture,
232 gconstpointer user_data G_GNUC_UNUSED)
233 {
234 1 g_autoptr(GError) error = NULL;
235 1 g_autoptr(GssConfigFile) config = NULL;
236 1 const gchar * const paths[] =
237 {
238 1 fixture->key_file_nonexistent_path,
239 1 fixture->key_file_nonexistent_path,
240 1 fixture->key_file_nonexistent_path,
241 1 fixture->key_file_nonexistent_path,
242 1 fixture->key_file1_path,
243 NULL
244 };
245 guint loaded_file;
246
247 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
248
249 1 loaded_file = gss_config_file_get_uint (config, "Test", "File", 0, G_MAXUINT, &error);
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (loaded_file, ==, 1);
252 1 }
253
254 /* Test that if none of the files exist, but the GResource does, we successfully
255 * use that. */
256 static void
257 1 test_config_file_resource_only (Fixture *fixture,
258 gconstpointer user_data G_GNUC_UNUSED)
259 {
260 1 g_autoptr(GError) error = NULL;
261 1 g_autoptr(GssConfigFile) config = NULL;
262 1 const gchar * const paths[] =
263 {
264 1 fixture->key_file_nonexistent_path,
265 NULL
266 };
267 guint loaded_file;
268
269 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
270
271 1 loaded_file = gss_config_file_get_uint (config, "Test", "File", 0, G_MAXUINT, &error);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (loaded_file, ==, 1000);
274 1 }
275
276 /* Test that if no configuration files are found, we abort. */
277 static void
278 1 test_config_file_fallback_per_file (Fixture *fixture,
279 gconstpointer user_data G_GNUC_UNUSED)
280 {
281 1 const gchar * const paths[] =
282 {
283 1 fixture->key_file_nonexistent_path,
284 1 fixture->key_file_nonexistent_path,
285 NULL
286 };
287
288
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (g_test_subprocess ())
289 {
290 g_autoptr(GssConfigFile) config = NULL;
291
292 config = gss_config_file_new (paths, fixture->default_resource,
293 fixture->default_path_invalid);
294 g_assert_not_reached ();
295 }
296 else
297 {
298 1 g_test_trap_subprocess (NULL, 0, 0);
299 1 g_test_trap_assert_failed ();
300 1 g_test_trap_assert_stderr ("*ERROR*gss_config_file_constructed: "
301 "assertion failed (error == NULL)*");
302 }
303 1 }
304
305 /* Test that loading a key from the second file works if it’s not set in the
306 * first. */
307 static void
308 1 test_config_file_fallback_per_key (Fixture *fixture,
309 gconstpointer user_data G_GNUC_UNUSED)
310 {
311 1 g_autoptr(GError) error = NULL;
312 1 g_autoptr(GssConfigFile) config = NULL;
313 1 const gchar * const paths[] =
314 {
315 1 fixture->key_file1_path,
316 1 fixture->key_file2_path,
317 NULL
318 };
319 guint loaded_file;
320 gboolean file1_key, file2_key;
321
322 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
323
324 1 loaded_file = gss_config_file_get_uint (config, "Test", "File", 0, G_MAXUINT, &error);
325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (loaded_file, ==, 1);
327
328 1 file1_key = gss_config_file_get_boolean (config, "Test", "File1", &error);
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_true (file1_key);
331
332 1 file2_key = gss_config_file_get_boolean (config, "Test", "File2", &error);
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_true (file2_key);
335 1 }
336
337 /* Test that the groups from all loaded files are returned. */
338 static void
339 1 test_config_file_groups (Fixture *fixture,
340 gconstpointer user_data G_GNUC_UNUSED)
341 {
342 1 g_autoptr(GError) error = NULL;
343 1 g_autoptr(GssConfigFile) config = NULL;
344 1 const gchar * const paths[] =
345 {
346 1 fixture->key_file1_path,
347 1 fixture->key_file2_path,
348 NULL
349 };
350 1 g_auto(GStrv) groups = NULL;
351 gsize n_groups;
352
353 1 config = gss_config_file_new (paths, fixture->default_resource, fixture->default_path);
354
355 1 groups = gss_config_file_get_groups (config, &n_groups, &error);
356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_no_error (error);
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_cmpuint (n_groups, ==, 4);
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_nonnull (groups);
359
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_assert_cmpstr (groups[0], ==, "DefaultGroup");
360
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_assert_cmpstr (groups[1], ==, "Group1");
361
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_assert_cmpstr (groups[2], ==, "Group2");
362
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 g_assert_cmpstr (groups[3], ==, "Test");
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert_null (groups[4]);
364 1 }
365
366 int
367 1 main (int argc,
368 char *argv[])
369 {
370 1 setlocale (LC_ALL, "");
371
372 1 g_test_init (&argc, &argv, NULL);
373
374 1 g_test_add ("/config/load-one", Fixture, NULL, setup,
375 test_config_file_load_one, teardown);
376 1 g_test_add ("/config/load-many", Fixture, NULL, setup,
377 test_config_file_load_many, teardown);
378 1 g_test_add ("/config/unreadable", Fixture, NULL, setup,
379 test_config_file_unreadable, teardown);
380 1 g_test_add ("/config/invalid", Fixture, NULL, setup,
381 test_config_file_invalid, teardown);
382 1 g_test_add ("/config/nonexistent", Fixture, NULL, setup,
383 test_config_file_nonexistent, teardown);
384 1 g_test_add ("/config/resource-only", Fixture, NULL, setup,
385 test_config_file_resource_only, teardown);
386 1 g_test_add ("/config/fallback/per-file", Fixture, NULL, setup,
387 test_config_file_fallback_per_file, teardown);
388 1 g_test_add ("/config/fallback/per-key", Fixture, NULL, setup,
389 test_config_file_fallback_per_key, teardown);
390 1 g_test_add ("/config/groups", Fixture, NULL, setup,
391 test_config_file_groups, teardown);
392
393 1 return g_test_run ();
394 }
395