Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright 2025 GNOME Foundation, 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 <pwithnall@gnome.org>
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <glib.h>
28 : : #include <gio/gio.h>
29 : : #include <libmalcontent/manager.h>
30 : : #include <libmalcontent/web-filter.h>
31 : : #include <libglib-testing/dbus-queue.h>
32 : : #include <locale.h>
33 : : #include <string.h>
34 : : #include "accounts-service-iface.h"
35 : : #include "accounts-service-extension-iface.h"
36 : :
37 : :
38 : : /* Test that the #GType definitions for various types work. */
39 : : static void
40 : 1 : test_web_filter_types (void)
41 : : {
42 : 1 : g_type_ensure (mct_web_filter_get_type ());
43 : 1 : g_type_ensure (mct_web_filter_builder_get_type ());
44 : 1 : }
45 : :
46 : : /* Test that ref() and unref() work on an #MctWebFilter. */
47 : : static void
48 : 1 : test_web_filter_refs (void)
49 : : {
50 : 1 : g_auto(MctWebFilterBuilder) builder = MCT_WEB_FILTER_BUILDER_INIT ();
51 : 1 : g_autoptr(MctWebFilter) filter = NULL;
52 : :
53 : : /* Use an empty #MctWebFilter. */
54 : 1 : filter = mct_web_filter_builder_end (&builder);
55 : :
56 : 1 : g_assert_nonnull (filter);
57 : :
58 : : /* Call a method to check that the filter hasn’t been finalised. */
59 : 1 : g_assert_false (mct_web_filter_get_force_safe_search (filter));
60 : 1 : mct_web_filter_ref (filter);
61 : 1 : g_assert_false (mct_web_filter_get_force_safe_search (filter));
62 : 1 : mct_web_filter_unref (filter);
63 : 1 : g_assert_false (mct_web_filter_get_force_safe_search (filter));
64 : :
65 : : /* Final ref is dropped by g_autoptr(). */
66 : 1 : }
67 : :
68 : : /* Basic test of mct_web_filter_serialize() on a web filter. */
69 : : static void
70 : 1 : test_web_filter_serialize (void)
71 : : {
72 : 1 : g_auto(MctWebFilterBuilder) builder = MCT_WEB_FILTER_BUILDER_INIT ();
73 : 1 : g_autoptr(MctWebFilter) filter = NULL;
74 : 1 : g_autoptr(GVariant) serialized = NULL;
75 : :
76 : : /* Use an empty #MctWebFilter. */
77 : 1 : filter = mct_web_filter_builder_end (&builder);
78 : :
79 : : /* We can’t assert anything about the serialisation format, since it’s opaque. */
80 : 1 : serialized = mct_web_filter_serialize (filter);
81 : 1 : g_assert_nonnull (serialized);
82 : 1 : }
83 : :
84 : : /* Basic test of mct_web_filter_deserialize() on various current and historic
85 : : * serialised web filter variants. */
86 : : static void
87 : 1 : test_web_filter_deserialize (void)
88 : : {
89 : : /* These are all opaque. Older versions should be kept around to test
90 : : * backwards compatibility. */
91 : 1 : const gchar *valid_web_filters[] =
92 : : {
93 : : "@a{sv} {}",
94 : : "{ 'FilterType': <@u 0> }",
95 : : "{ 'FilterType': <@u 1>, 'BlockLists': <{'easylist': 'https://v.firebog.net/hosts/Easylist.txt'}> }",
96 : : "{ 'ForceSafeSearch': <true> }",
97 : : };
98 : :
99 [ + + ]: 5 : for (gsize i = 0; i < G_N_ELEMENTS (valid_web_filters); i++)
100 : : {
101 : 4 : g_autoptr(GVariant) serialized = NULL;
102 : 4 : g_autoptr(MctWebFilter) filter = NULL;
103 : 4 : g_autoptr(GError) local_error = NULL;
104 : :
105 : 4 : g_test_message ("%" G_GSIZE_FORMAT ": %s", i, valid_web_filters[i]);
106 : :
107 : 4 : serialized = g_variant_parse (NULL, valid_web_filters[i], NULL, NULL, NULL);
108 : 4 : g_assert (serialized != NULL);
109 : :
110 : 4 : filter = mct_web_filter_deserialize (serialized, 1, &local_error);
111 : 4 : g_assert_no_error (local_error);
112 : 4 : g_assert_nonnull (filter);
113 : : }
114 : 1 : }
115 : :
116 : : /* Test of mct_web_filter_deserialize() on various invalid variants. */
117 : : static void
118 : 1 : test_web_filter_deserialize_invalid (void)
119 : : {
120 : 1 : const gchar *invalid_web_filters[] =
121 : : {
122 : : "false",
123 : : "()",
124 : : "{ 'FilterType': <@u 600> }",
125 : : };
126 : :
127 [ + + ]: 4 : for (gsize i = 0; i < G_N_ELEMENTS (invalid_web_filters); i++)
128 : : {
129 : 3 : g_autoptr(GVariant) serialized = NULL;
130 : 3 : g_autoptr(MctWebFilter) filter = NULL;
131 : 3 : g_autoptr(GError) local_error = NULL;
132 : :
133 : 3 : g_test_message ("%" G_GSIZE_FORMAT ": %s", i, invalid_web_filters[i]);
134 : :
135 : 3 : serialized = g_variant_parse (NULL, invalid_web_filters[i], NULL, NULL, NULL);
136 : 3 : g_assert (serialized != NULL);
137 : :
138 : 3 : filter = mct_web_filter_deserialize (serialized, 1, &local_error);
139 : 3 : g_assert_error (local_error, MCT_MANAGER_ERROR, MCT_MANAGER_ERROR_INVALID_DATA);
140 : 3 : g_assert_null (filter);
141 : : }
142 : 1 : }
143 : :
144 : : /* Test that mct_web_filter_equal() returns the correct results on various
145 : : * web filters. */
146 : : static void
147 : 1 : test_web_filter_equal (void)
148 : : {
149 : 1 : g_auto(MctWebFilterBuilder) builder = MCT_WEB_FILTER_BUILDER_INIT ();
150 : : MctWebFilter *equal_filters[2];
151 : 1 : const char *unequal_filters_serialised[] =
152 : : {
153 : : "@a{sv} {}",
154 : : "{ 'FilterType': <@u 1>, 'BlockLists': <{'easylist': 'https://v.firebog.net/hosts/Easylist.txt'}> }",
155 : : "{ 'FilterType': <@u 1>, 'BlockLists': <{'easylist': 'https://v.firebog.net/hosts/Easylist.txt', 'hardlist': 'https://v.firebog.net/hosts/Hardlist.txt'}> }",
156 : : "{ 'FilterType': <@u 1>, 'AllowLists': <{'easylist': 'https://v.firebog.net/hosts/Easylist.txt'}> }",
157 : : "{ 'ForceSafeSearch': <true> }",
158 : : };
159 : : MctWebFilter *unequal_filters[G_N_ELEMENTS (unequal_filters_serialised)];
160 : :
161 : : /* Build a couple of filters which are identical. */
162 : 1 : equal_filters[0] = mct_web_filter_builder_end (&builder);
163 : :
164 : 1 : mct_web_filter_builder_init (&builder);
165 : 1 : equal_filters[1] = mct_web_filter_builder_end (&builder);
166 : :
167 : : /* And a load of filters which are not. */
168 [ + + ]: 6 : for (size_t i = 0; i < G_N_ELEMENTS (unequal_filters_serialised); i++)
169 : : {
170 : 5 : g_autoptr(GVariant) serialized = NULL;
171 : :
172 : 5 : serialized = g_variant_parse (NULL, unequal_filters_serialised[i], NULL, NULL, NULL);
173 : 5 : g_assert (serialized != NULL);
174 : :
175 : 5 : unequal_filters[i] = mct_web_filter_deserialize (serialized, 1, NULL);
176 : 5 : g_assert (unequal_filters[i] != NULL);
177 : : }
178 : :
179 : : /* Test the equality checks on them all. */
180 [ + + ]: 3 : for (size_t i = 0; i < G_N_ELEMENTS (equal_filters); i++)
181 [ + + ]: 6 : for (size_t j = 0; j < G_N_ELEMENTS (equal_filters); j++)
182 : 4 : g_assert_true (mct_web_filter_equal (equal_filters[i], equal_filters[j]));
183 : :
184 [ + + ]: 6 : for (size_t i = 0; i < G_N_ELEMENTS (unequal_filters); i++)
185 : : {
186 [ + + ]: 15 : for (size_t j = 0; j < G_N_ELEMENTS (equal_filters); j++)
187 : 10 : g_assert_false (mct_web_filter_equal (unequal_filters[i], equal_filters[j]));
188 [ + + ]: 30 : for (size_t j = 0; j < G_N_ELEMENTS (unequal_filters); j++)
189 : : {
190 [ + + ]: 25 : if (i != j)
191 : 20 : g_assert_false (mct_web_filter_equal (unequal_filters[i], unequal_filters[j]));
192 : : else
193 : 5 : g_assert_true (mct_web_filter_equal (unequal_filters[i], unequal_filters[j]));
194 : : }
195 : : }
196 : :
197 [ + + ]: 3 : for (size_t i = 0; i < G_N_ELEMENTS (equal_filters); i++)
198 : 2 : mct_web_filter_unref (equal_filters[i]);
199 [ + + ]: 6 : for (size_t i = 0; i < G_N_ELEMENTS (unequal_filters); i++)
200 : 5 : mct_web_filter_unref (unequal_filters[i]);
201 : 1 : }
202 : :
203 : : static void
204 : 1 : test_web_filter_validate_filter_id (void)
205 : : {
206 : 1 : const char *valid_ids[] =
207 : : {
208 : : "a",
209 : : "hi",
210 : : };
211 : 1 : const char *invalid_ids[] =
212 : : {
213 : : "",
214 : : };
215 : :
216 [ + + ]: 3 : for (size_t i = 0; i < G_N_ELEMENTS (valid_ids); i++)
217 : 2 : g_assert_true (mct_web_filter_validate_filter_id (valid_ids[i]));
218 : :
219 [ + + ]: 2 : for (size_t i = 0; i < G_N_ELEMENTS (invalid_ids); i++)
220 : 1 : g_assert_false (mct_web_filter_validate_filter_id (invalid_ids[i]));
221 : 1 : }
222 : :
223 : : static void
224 : 1 : test_web_filter_validate_hostname (void)
225 : : {
226 : 1 : const char *valid_hostnames[] =
227 : : {
228 : : "a",
229 : : "reddit.com",
230 : : "www.rfc-editor.org",
231 : : "reddit.com.",
232 : : };
233 : 1 : const char *invalid_hostnames[] =
234 : : {
235 : : "",
236 : : "123456781234567812345678123456781234567812345678123456781234567."
237 : : "123456781234567812345678123456781234567812345678123456781234567."
238 : : "123456781234567812345678123456781234567812345678123456781234567."
239 : : "12345678123456781234567812345678123456781234567812345678123456",
240 : : "1234567812345678123456781234567812345678123456781234567812345678.labeltoolong",
241 : : "@",
242 : : "@.invalidcharacter",
243 : : "-.hyphenonlylabel",
244 : : "-startswithhyphen",
245 : : "endswithhyphen-",
246 : : "underscores_not_allowed.some-site.nl",
247 : : ".leadingdotnotallowed",
248 : : "hyphenbeforedot-.com",
249 : : ".",
250 : : ".-",
251 : : "reddit.com.-",
252 : : "-",
253 : : "finallabeltoolong.1234567812345678123456781234567812345678123456781234567812345678",
254 : : "finallabeltoolong.1234567812345678123456781234567812345678123456781234567812345678.",
255 : : "reddit.com..",
256 : : "..",
257 : : };
258 : :
259 [ + + ]: 5 : for (size_t i = 0; i < G_N_ELEMENTS (valid_hostnames); i++)
260 : : {
261 : 4 : g_assert_true (mct_web_filter_validate_hostname (valid_hostnames[i]));
262 : :
263 : : /* All valid hostnames should be valid domain names by definition */
264 : 4 : g_assert_true (mct_web_filter_validate_domain_name (valid_hostnames[i]));
265 : : }
266 : :
267 [ + + ]: 20 : for (size_t i = 0; i < G_N_ELEMENTS (invalid_hostnames); i++)
268 : 19 : g_assert_false (mct_web_filter_validate_hostname (invalid_hostnames[i]));
269 : 1 : }
270 : :
271 : : static void
272 : 1 : test_web_filter_validate_domain_name (void)
273 : : {
274 : 1 : const char *valid_domain_names[] =
275 : : {
276 : : "a",
277 : : "reddit.com",
278 : : "www.rfc-editor.org",
279 : : "10000_gratis_fotos.some-site.nl",
280 : : };
281 : 1 : const char *invalid_domain_names[] =
282 : : {
283 : : "",
284 : : "123456781234567812345678123456781234567812345678123456781234567."
285 : : "123456781234567812345678123456781234567812345678123456781234567."
286 : : "123456781234567812345678123456781234567812345678123456781234567."
287 : : "12345678123456781234567812345678123456781234567812345678123456",
288 : : "1234567812345678123456781234567812345678123456781234567812345678.labeltoolong",
289 : : "finallabeltoolong.1234567812345678123456781234567812345678123456781234567812345678",
290 : : "finallabeltoolong.1234567812345678123456781234567812345678123456781234567812345678.",
291 : : "\0",
292 : : "øh nø",
293 : : "reddit.com..",
294 : : ".",
295 : : "..",
296 : : };
297 : :
298 [ + + ]: 5 : for (size_t i = 0; i < G_N_ELEMENTS (valid_domain_names); i++)
299 : 4 : g_assert_true (mct_web_filter_validate_domain_name (valid_domain_names[i]));
300 : :
301 [ + + ]: 11 : for (size_t i = 0; i < G_N_ELEMENTS (invalid_domain_names); i++)
302 : 10 : g_assert_false (mct_web_filter_validate_domain_name (invalid_domain_names[i]));
303 : 1 : }
304 : :
305 : : int
306 : 1 : main (int argc,
307 : : char **argv)
308 : : {
309 : 1 : setlocale (LC_ALL, "");
310 : 1 : g_test_init (&argc, &argv, NULL);
311 : :
312 : 1 : g_test_add_func ("/web-filter/types", test_web_filter_types);
313 : 1 : g_test_add_func ("/web-filter/refs", test_web_filter_refs);
314 : :
315 : 1 : g_test_add_func ("/web-filter/serialize", test_web_filter_serialize);
316 : 1 : g_test_add_func ("/web-filter/deserialize", test_web_filter_deserialize);
317 : 1 : g_test_add_func ("/web-filter/deserialize/invalid", test_web_filter_deserialize_invalid);
318 : :
319 : 1 : g_test_add_func ("/web-filter/equal", test_web_filter_equal);
320 : :
321 : 1 : g_test_add_func ("/web-filter/validate-filter-id", test_web_filter_validate_filter_id);
322 : 1 : g_test_add_func ("/web-filter/validate-hostname", test_web_filter_validate_hostname);
323 : 1 : g_test_add_func ("/web-filter/validate-domain-name", test_web_filter_validate_domain_name);
324 : :
325 : 1 : return g_test_run ();
326 : : }
|