Declare libdconf_service as a dependency
[dconf.git] / tests / writer.c
blob955ba918ac72637e73a539ef02b9b852ec23bcfa
1 /*
2 * Copyright © 2018 Endless Mobile, Inc
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Author: Philip Withnall <withnall@endlessm.com>
20 #include <glib.h>
21 #include <glib/gstdio.h>
22 #include <locale.h>
24 #include "service/dconf-generated.h"
25 #include "service/dconf-writer.h"
27 static guint n_warnings = 0;
29 static GLogWriterOutput
30 log_writer_cb (GLogLevelFlags log_level,
31 const GLogField *fields,
32 gsize n_fields,
33 gpointer user_data)
35 if (log_level & G_LOG_LEVEL_WARNING)
36 n_warnings++;
38 return G_LOG_WRITER_HANDLED;
41 static void
42 assert_n_warnings (guint expected_n_warnings)
44 g_assert_cmpuint (n_warnings, ==, expected_n_warnings);
45 n_warnings = 0;
48 typedef struct
50 gchar *dconf_dir; /* (owned) */
51 } Fixture;
53 gchar *config_dir = NULL;
55 static void
56 set_up (Fixture *fixture,
57 gconstpointer test_data)
59 fixture->dconf_dir = g_build_filename (config_dir, "dconf", NULL);
60 g_assert_cmpint (g_mkdir (fixture->dconf_dir, 0755), ==, 0);
62 g_test_message ("Using dconf directory: %s", fixture->dconf_dir);
65 static void
66 tear_down (Fixture *fixture,
67 gconstpointer test_data)
69 g_assert_cmpint (g_rmdir (fixture->dconf_dir), ==, 0);
70 g_clear_pointer (&fixture->dconf_dir, g_free);
72 assert_n_warnings (0);
75 /* Test basic initialisation of a #DConfWriter. This is essentially a smoketest. */
76 static void
77 test_writer_basic (Fixture *fixture,
78 gconstpointer test_data)
80 g_autoptr(DConfWriter) writer = NULL;
82 writer = DCONF_WRITER (dconf_writer_new (DCONF_TYPE_WRITER, "some-name"));
83 g_assert_nonnull (writer);
85 g_assert_cmpstr (dconf_writer_get_name (writer), ==, "some-name");
88 /* Test that beginning a write operation when no database exists succeeds. Note
89 * that the database will not actually be created until some changes are made
90 * and the write is committed. */
91 static void
92 test_writer_begin_missing (Fixture *fixture,
93 gconstpointer test_data)
95 g_autoptr(DConfWriter) writer = NULL;
96 DConfWriterClass *writer_class;
97 gboolean retval;
98 g_autoptr(GError) local_error = NULL;
99 g_autofree gchar *db_filename = g_build_filename (fixture->dconf_dir, "missing", NULL);
101 /* Check the database doesn’t exist. */
102 g_assert_false (g_file_test (db_filename, G_FILE_TEST_EXISTS));
104 /* Create a writer. */
105 writer = DCONF_WRITER (dconf_writer_new (DCONF_TYPE_WRITER, "missing"));
106 g_assert_nonnull (writer);
108 writer_class = DCONF_WRITER_GET_CLASS (writer);
109 retval = writer_class->begin (writer, &local_error);
110 g_assert_no_error (local_error);
111 g_assert_true (retval);
114 /* Test that beginning a write operation when a corrupt or empty database exists
115 * will take a backup of the database and then succeed. Note that a new empty
116 * database will not actually be created until some changes are made and the
117 * write is committed. */
118 typedef struct
120 const gchar *corrupt_db_contents;
121 guint n_existing_backups;
122 } BeginCorruptFileData;
124 static void
125 test_writer_begin_corrupt_file (Fixture *fixture,
126 gconstpointer test_data)
128 const BeginCorruptFileData *data = test_data;
129 g_autoptr(DConfWriter) writer = NULL;
130 DConfWriterClass *writer_class;
131 gboolean retval;
132 g_autoptr(GError) local_error = NULL;
133 g_autofree gchar *db_filename = g_build_filename (fixture->dconf_dir, "corrupt", NULL);
134 g_autofree gchar *new_db_filename_backup = NULL;
135 g_autofree gchar *backup_file_contents = NULL;
136 gsize backup_file_contents_len = 0;
137 guint i;
139 /* Create a corrupt database. */
140 g_file_set_contents (db_filename, data->corrupt_db_contents, -1, &local_error);
141 g_assert_no_error (local_error);
143 /* Create any existing backups, to test we don’t overwrite them. */
144 for (i = 0; i < data->n_existing_backups; i++)
146 g_autofree gchar *db_filename_backup = g_strdup_printf ("%s~%u", db_filename, i);
147 g_file_set_contents (db_filename_backup, "backup", -1, &local_error);
148 g_assert_no_error (local_error);
151 new_db_filename_backup = g_strdup_printf ("%s~%u", db_filename, data->n_existing_backups);
153 /* Create a writer. */
154 writer = DCONF_WRITER (dconf_writer_new (DCONF_TYPE_WRITER, "corrupt"));
155 g_assert_nonnull (writer);
157 writer_class = DCONF_WRITER_GET_CLASS (writer);
158 retval = writer_class->begin (writer, &local_error);
159 g_assert_no_error (local_error);
160 g_assert_true (retval);
162 /* The writer should have printed a warning about the corrupt database. */
163 assert_n_warnings (1);
165 /* Check a backup file has been created and has the right content. */
166 g_file_get_contents (new_db_filename_backup, &backup_file_contents,
167 &backup_file_contents_len, &local_error);
168 g_assert_no_error (local_error);
169 g_assert_cmpstr (backup_file_contents, ==, data->corrupt_db_contents);
170 g_assert_cmpuint (backup_file_contents_len, ==, strlen (data->corrupt_db_contents));
172 /* Clean up. */
173 g_assert_cmpint (g_unlink (new_db_filename_backup), ==, 0);
175 for (i = 0; i < data->n_existing_backups; i++)
177 g_autofree gchar *db_filename_backup = g_strdup_printf ("%s~%u", db_filename, i);
178 g_assert_cmpint (g_unlink (db_filename_backup), ==, 0);
183 main (int argc, char **argv)
185 g_autoptr(GError) local_error = NULL;
186 int retval;
187 const BeginCorruptFileData empty_data = { "", 0 };
188 const BeginCorruptFileData corrupt_file_data0 = {
189 "secretly not a valid GVDB database 😧", 0
191 const BeginCorruptFileData corrupt_file_data1 = {
192 "secretly not a valid GVDB database 😧", 1
194 const BeginCorruptFileData corrupt_file_data2 = {
195 "secretly not a valid GVDB database 😧", 2
198 setlocale (LC_ALL, "");
200 g_test_init (&argc, &argv, NULL);
202 /* Set up a fake $XDG_CONFIG_HOME. We can’t do this in the fixture, as
203 * g_get_user_config_dir() caches its return value. */
204 config_dir = g_dir_make_tmp ("dconf-test-writer_XXXXXX", &local_error);
205 g_assert_no_error (local_error);
206 g_assert_true (g_setenv ("XDG_CONFIG_HOME", config_dir, TRUE));
207 g_test_message ("Using config directory: %s", config_dir);
209 /* Log handling so we don’t abort on the first g_warning(). */
210 g_log_set_writer_func (log_writer_cb, NULL, NULL);
212 g_test_add ("/writer/basic", Fixture, NULL, set_up,
213 test_writer_basic, tear_down);
214 g_test_add ("/writer/begin/missing", Fixture, NULL, set_up,
215 test_writer_begin_missing, tear_down);
216 g_test_add ("/writer/begin/empty", Fixture, &empty_data, set_up,
217 test_writer_begin_corrupt_file, tear_down);
218 g_test_add ("/writer/begin/corrupt-file/0", Fixture, &corrupt_file_data0, set_up,
219 test_writer_begin_corrupt_file, tear_down);
220 g_test_add ("/writer/begin/corrupt-file/1", Fixture, &corrupt_file_data1, set_up,
221 test_writer_begin_corrupt_file, tear_down);
222 g_test_add ("/writer/begin/corrupt-file/2", Fixture, &corrupt_file_data2, set_up,
223 test_writer_begin_corrupt_file, tear_down);
225 retval = g_test_run ();
227 /* Clean up the config dir. */
228 g_unsetenv ("XDG_CONFIG_HOME");
229 g_assert_cmpint (g_rmdir (config_dir), ==, 0);
230 g_clear_pointer (&config_dir, g_free);
232 return retval;