1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2014-2018 Richard Hughes <richard@hughsie.com>
4  * Copyright (C) 2019 Kalev Lember <klember@redhat.com>
5  *
6  * SPDX-License-Identifier: LGPL-2.1+
7  */
8 
9 #include "config.h"
10 
11 #include <glib.h>
12 #include <glib/gstdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "as-agreement-private.h"
17 #include "as-app-private.h"
18 #include "as-app-builder.h"
19 #include "as-bundle-private.h"
20 #include "as-translation-private.h"
21 #include "as-checksum-private.h"
22 #include "as-content-rating-private.h"
23 #include "as-enums.h"
24 #include "as-icon-private.h"
25 #include "as-image-private.h"
26 #include "as-require-private.h"
27 #include "as-review-private.h"
28 #include "as-markup.h"
29 #include "as-monitor.h"
30 #include "as-node-private.h"
31 #include "as-problem.h"
32 #include "as-launchable-private.h"
33 #include "as-provide-private.h"
34 #include "as-ref-string.h"
35 #include "as-release-private.h"
36 #include "as-suggest-private.h"
37 #include "as-screenshot-private.h"
38 #include "as-store.h"
39 #include "as-tag.h"
40 #include "as-utils-private.h"
41 #include "as-yaml.h"
42 
43 #ifndef _WIN32
44 #include <fnmatch.h>
45 #else
46 #include <windows.h>
47 #endif
48 
49 #define AS_TEST_WILDCARD_SHA1	"\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?\?"
50 
51 static gboolean
as_test_compare_lines(const gchar * txt1,const gchar * txt2,GError ** error)52 as_test_compare_lines (const gchar *txt1, const gchar *txt2, GError **error)
53 {
54 	g_autofree gchar *output = NULL;
55 
56 	/* exactly the same */
57 	if (g_strcmp0 (txt1, txt2) == 0)
58 		return TRUE;
59 
60 	/* matches a pattern */
61 #ifdef _WIN32
62 	if (g_strcmp0 (txt2, txt1) == 0)
63 		return TRUE;
64 #else
65 	if (fnmatch (txt2, txt1, FNM_NOESCAPE) == 0)
66 		return TRUE;
67 #endif
68 
69 	/* save temp files and diff them */
70 	if (!g_file_set_contents ("/tmp/a", txt1, -1, error))
71 		return FALSE;
72 	if (!g_file_set_contents ("/tmp/b", txt2, -1, error))
73 		return FALSE;
74 	if (!g_spawn_command_line_sync ("diff -urNp /tmp/b /tmp/a",
75 					&output, NULL, NULL, error))
76 		return FALSE;
77 
78 	/* just output the diff */
79 	g_set_error_literal (error, 1, 0, output);
80 	return FALSE;
81 }
82 
83 static gchar *
as_test_get_filename(const gchar * filename)84 as_test_get_filename (const gchar *filename)
85 {
86 	g_autofree gchar *path = NULL;
87 
88 	/* try the source then the destdir */
89 	path = g_build_filename (TESTDIRSRC, filename, NULL);
90 	if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
91 		g_free (path);
92 		path = g_build_filename (TESTDIRBUILD, filename, NULL);
93 	}
94 #ifdef _WIN32
95 	{
96 		char full_path[PATH_MAX];
97 		if (_fullpath (full_path, path, PATH_MAX) == NULL)
98 			return NULL;
99 		if (!g_file_test (full_path, G_FILE_TEST_EXISTS))
100 			return NULL;
101 		return g_strdup (full_path);
102 	}
103 #else
104 	return realpath (path, NULL);
105 #endif
106 }
107 
108 static GMainLoop *_test_loop = NULL;
109 static guint _test_loop_timeout_id = 0;
110 
111 static gboolean
as_test_hang_check_cb(gpointer user_data)112 as_test_hang_check_cb (gpointer user_data)
113 {
114 	g_main_loop_quit (_test_loop);
115 	_test_loop_timeout_id = 0;
116 	_test_loop = NULL;
117 	return G_SOURCE_REMOVE;
118 }
119 
120 static void
as_test_loop_run_with_timeout(guint timeout_ms)121 as_test_loop_run_with_timeout (guint timeout_ms)
122 {
123 	g_assert (_test_loop_timeout_id == 0);
124 	g_assert (_test_loop == NULL);
125 	_test_loop = g_main_loop_new (NULL, FALSE);
126 	_test_loop_timeout_id = g_timeout_add (timeout_ms, as_test_hang_check_cb, NULL);
127 	g_main_loop_run (_test_loop);
128 }
129 
130 static void
as_test_loop_quit(void)131 as_test_loop_quit (void)
132 {
133 	if (_test_loop_timeout_id > 0) {
134 		g_source_remove (_test_loop_timeout_id);
135 		_test_loop_timeout_id = 0;
136 	}
137 	if (_test_loop != NULL) {
138 		g_main_loop_quit (_test_loop);
139 		g_main_loop_unref (_test_loop);
140 		_test_loop = NULL;
141 	}
142 }
143 
144 static void
monitor_test_cb(AsMonitor * mon,const gchar * filename,guint * cnt)145 monitor_test_cb (AsMonitor *mon, const gchar *filename, guint *cnt)
146 {
147 	(*cnt)++;
148 }
149 
150 static void
as_test_monitor_dir_func(void)151 as_test_monitor_dir_func (void)
152 {
153 	gboolean ret;
154 	guint cnt_added = 0;
155 	guint cnt_removed = 0;
156 	guint cnt_changed = 0;
157 	g_autoptr(AsMonitor) mon = NULL;
158 	g_autoptr(GError) error = NULL;
159 	const gchar *tmpdir = "/tmp/monitor-test/usr/share/app-info/xmls";
160 	g_autofree gchar *tmpfile = NULL;
161 	g_autofree gchar *tmpfile_new = NULL;
162 	g_autofree gchar *cmd_touch = NULL;
163 
164 	tmpfile = g_build_filename (tmpdir, "test.txt", NULL);
165 	tmpfile_new = g_build_filename (tmpdir, "newtest.txt", NULL);
166 	g_unlink (tmpfile);
167 	g_unlink (tmpfile_new);
168 
169 	mon = as_monitor_new ();
170 	g_signal_connect (mon, "added",
171 			  G_CALLBACK (monitor_test_cb), &cnt_added);
172 	g_signal_connect (mon, "removed",
173 			  G_CALLBACK (monitor_test_cb), &cnt_removed);
174 	g_signal_connect (mon, "changed",
175 			  G_CALLBACK (monitor_test_cb), &cnt_changed);
176 
177 	/* add watch */
178 	ret = as_monitor_add_directory (mon, tmpdir, NULL, &error);
179 	g_assert_no_error (error);
180 	g_assert (ret);
181 
182 	/* create directory */
183 	g_mkdir_with_parents (tmpdir, 0700);
184 
185 	/* touch file */
186 	cmd_touch = g_strdup_printf ("touch %s", tmpfile);
187 	ret = g_spawn_command_line_sync (cmd_touch, NULL, NULL, NULL, &error);
188 	g_assert_no_error (error);
189 	g_assert (ret);
190 	as_test_loop_run_with_timeout (2000);
191 	as_test_loop_quit ();
192 	g_assert_cmpint (cnt_added, ==, 1);
193 	g_assert_cmpint (cnt_removed, ==, 0);
194 	g_assert_cmpint (cnt_changed, ==, 0);
195 
196 	/* just change the mtime */
197 	cnt_added = cnt_removed = cnt_changed = 0;
198 	ret = g_spawn_command_line_sync (cmd_touch, NULL, NULL, NULL, &error);
199 	g_assert_no_error (error);
200 	g_assert (ret);
201 	as_test_loop_run_with_timeout (2000);
202 	as_test_loop_quit ();
203 	g_assert_cmpint (cnt_added, ==, 0);
204 	g_assert_cmpint (cnt_removed, ==, 0);
205 	g_assert_cmpint (cnt_changed, ==, 1);
206 
207 	/* delete it */
208 	cnt_added = cnt_removed = cnt_changed = 0;
209 	g_unlink (tmpfile);
210 	as_test_loop_run_with_timeout (2000);
211 	as_test_loop_quit ();
212 	g_assert_cmpint (cnt_added, ==, 0);
213 	g_assert_cmpint (cnt_removed, ==, 1);
214 	g_assert_cmpint (cnt_changed, ==, 0);
215 
216 	/* save a new file with temp copy */
217 	cnt_added = cnt_removed = cnt_changed = 0;
218 	ret = g_file_set_contents (tmpfile, "foo", -1, &error);
219 	g_assert_no_error (error);
220 	g_assert (ret);
221 	as_test_loop_run_with_timeout (2000);
222 	as_test_loop_quit ();
223 	g_assert_cmpint (cnt_added, ==, 1);
224 	g_assert_cmpint (cnt_removed, ==, 0);
225 	g_assert_cmpint (cnt_changed, ==, 0);
226 
227 	/* modify file with temp copy */
228 	cnt_added = cnt_removed = cnt_changed = 0;
229 	ret = g_file_set_contents (tmpfile, "bar", -1, &error);
230 	g_assert_no_error (error);
231 	g_assert (ret);
232 	as_test_loop_run_with_timeout (2000);
233 	as_test_loop_quit ();
234 	g_assert_cmpint (cnt_added, ==, 0);
235 	g_assert_cmpint (cnt_removed, ==, 0);
236 	g_assert_cmpint (cnt_changed, ==, 1);
237 
238 	/* rename the file */
239 	cnt_added = cnt_removed = cnt_changed = 0;
240 	g_assert_cmpint (g_rename (tmpfile, tmpfile_new), ==, 0);
241 	as_test_loop_run_with_timeout (2000);
242 	as_test_loop_quit ();
243 	g_assert_cmpint (cnt_added, ==, 1);
244 	g_assert_cmpint (cnt_removed, ==, 1);
245 	g_assert_cmpint (cnt_changed, ==, 0);
246 
247 	g_unlink (tmpfile);
248 	g_unlink (tmpfile_new);
249 }
250 
251 static void
as_test_monitor_file_func(void)252 as_test_monitor_file_func (void)
253 {
254 	gboolean ret;
255 	guint cnt_added = 0;
256 	guint cnt_removed = 0;
257 	guint cnt_changed = 0;
258 	g_autoptr(AsMonitor) mon = NULL;
259 	g_autoptr(GError) error = NULL;
260 	const gchar *tmpfile = "/tmp/one.txt";
261 	const gchar *tmpfile_new = "/tmp/two.txt";
262 	g_autofree gchar *cmd_touch = NULL;
263 
264 	g_unlink (tmpfile);
265 	g_unlink (tmpfile_new);
266 
267 	mon = as_monitor_new ();
268 	g_signal_connect (mon, "added",
269 			  G_CALLBACK (monitor_test_cb), &cnt_added);
270 	g_signal_connect (mon, "removed",
271 			  G_CALLBACK (monitor_test_cb), &cnt_removed);
272 	g_signal_connect (mon, "changed",
273 			  G_CALLBACK (monitor_test_cb), &cnt_changed);
274 
275 	/* add a single file */
276 	ret = as_monitor_add_file (mon, tmpfile, NULL, &error);
277 	g_assert_no_error (error);
278 	g_assert (ret);
279 
280 	/* touch file */
281 	cnt_added = cnt_removed = cnt_changed = 0;
282 	cmd_touch = g_strdup_printf ("touch %s", tmpfile);
283 	ret = g_spawn_command_line_sync (cmd_touch, NULL, NULL, NULL, &error);
284 	g_assert_no_error (error);
285 	g_assert (ret);
286 	as_test_loop_run_with_timeout (2000);
287 	as_test_loop_quit ();
288 	g_assert_cmpint (cnt_added, ==, 1);
289 	g_assert_cmpint (cnt_removed, ==, 0);
290 	g_assert_cmpint (cnt_changed, ==, 0);
291 
292 	/* just change the mtime */
293 	cnt_added = cnt_removed = cnt_changed = 0;
294 	ret = g_spawn_command_line_sync (cmd_touch, NULL, NULL, NULL, &error);
295 	g_assert_no_error (error);
296 	g_assert (ret);
297 	as_test_loop_run_with_timeout (2000);
298 	as_test_loop_quit ();
299 	g_assert_cmpint (cnt_added, ==, 0);
300 	g_assert_cmpint (cnt_removed, ==, 0);
301 	g_assert_cmpint (cnt_changed, ==, 1);
302 
303 	/* delete it */
304 	cnt_added = cnt_removed = cnt_changed = 0;
305 	g_unlink (tmpfile);
306 	as_test_loop_run_with_timeout (2000);
307 	as_test_loop_quit ();
308 	g_assert_cmpint (cnt_added, ==, 0);
309 	g_assert_cmpint (cnt_removed, ==, 1);
310 	g_assert_cmpint (cnt_changed, ==, 0);
311 
312 	/* save a new file with temp copy */
313 	cnt_added = cnt_removed = cnt_changed = 0;
314 	ret = g_file_set_contents (tmpfile, "foo", -1, &error);
315 	g_assert_no_error (error);
316 	g_assert (ret);
317 	as_test_loop_run_with_timeout (2000);
318 	as_test_loop_quit ();
319 	g_assert_cmpint (cnt_added, ==, 1);
320 	g_assert_cmpint (cnt_removed, ==, 0);
321 	g_assert_cmpint (cnt_changed, ==, 0);
322 
323 	/* modify file with temp copy */
324 	cnt_added = cnt_removed = cnt_changed = 0;
325 	ret = g_file_set_contents (tmpfile, "bar", -1, &error);
326 	g_assert_no_error (error);
327 	g_assert (ret);
328 	as_test_loop_run_with_timeout (2000);
329 	as_test_loop_quit ();
330 	g_assert_cmpint (cnt_added, ==, 0);
331 	g_assert_cmpint (cnt_removed, ==, 0);
332 	g_assert_cmpint (cnt_changed, ==, 1);
333 }
334 
335 static void
as_test_app_builder_gettext_func(void)336 as_test_app_builder_gettext_func (void)
337 {
338 	GError *error = NULL;
339 	gboolean ret;
340 	guint i;
341 	g_autofree gchar *fn = NULL;
342 	g_autoptr(AsApp) app = NULL;
343 	g_autoptr(GList) list = NULL;
344 	const gchar *gettext_domains[] = { "app", "notgoingtoexist", NULL };
345 
346 	app = as_app_new ();
347 	fn = as_test_get_filename ("usr");
348 	g_assert (fn != NULL);
349 	for (i = 0; gettext_domains[i] != NULL; i++) {
350 		g_autoptr(AsTranslation) translation = NULL;
351 		translation = as_translation_new ();
352 		as_translation_set_kind (translation, AS_TRANSLATION_KIND_GETTEXT);
353 		as_translation_set_id (translation, gettext_domains[i]);
354 		as_app_add_translation (app, translation);
355 	}
356 	ret = as_app_builder_search_translations (app, fn, 25,
357 						  AS_APP_BUILDER_FLAG_NONE,
358 						  NULL, &error);
359 	g_assert_no_error (error);
360 	g_assert (ret);
361 
362 	/* check langs */
363 	g_assert_cmpint (as_app_get_language (app, "en_GB"), ==, 100);
364 	g_assert_cmpint (as_app_get_language (app, "ru"), ==, 33);
365 	g_assert_cmpint (as_app_get_language (app, "fr_FR"), ==, -1);
366 
367 	/* check fallback */
368 	g_assert_cmpint (as_app_get_language (app, "ru_RU"), ==, 33);
369 
370 	/* check size */
371 	list = as_app_get_languages (app);
372 	g_assert_cmpint (g_list_length (list), ==, 2);
373 }
374 
375 static void
as_test_app_builder_gettext_nodomain_func(void)376 as_test_app_builder_gettext_nodomain_func (void)
377 {
378 	GError *error = NULL;
379 	gboolean ret;
380 	g_autofree gchar *fn = NULL;
381 	g_autoptr(AsApp) app = NULL;
382 	g_autoptr(GList) list = NULL;
383 
384 	app = as_app_new ();
385 	fn = as_test_get_filename ("usr");
386 	ret = as_app_builder_search_translations (app, fn, 50,
387 						  AS_APP_BUILDER_FLAG_USE_FALLBACKS,
388 						  NULL, &error);
389 	g_assert_no_error (error);
390 	g_assert (ret);
391 
392 	/* check langs */
393 	g_assert_cmpint (as_app_get_language (app, "en_GB"), ==, 100);
394 	g_assert_cmpint (as_app_get_language (app, "ru"), ==, -1);
395 	g_assert_cmpint (as_app_get_language (app, "fr_FR"), ==, -1);
396 
397 	/* check size */
398 	list = as_app_get_languages (app);
399 	g_assert_cmpint (g_list_length (list), ==, 1);
400 }
401 
402 static void
as_test_app_builder_qt_func(void)403 as_test_app_builder_qt_func (void)
404 {
405 	GError *error = NULL;
406 	gboolean ret;
407 	guint i;
408 	g_autofree gchar *fn = NULL;
409 	g_autoptr(AsApp) app = NULL;
410 	g_autoptr(GList) list = NULL;
411 	const gchar *gettext_domains[] = { "kdeapp", "notgoingtoexist", NULL };
412 
413 	app = as_app_new ();
414 	fn = as_test_get_filename ("usr");
415 	g_assert (fn != NULL);
416 	for (i = 0; gettext_domains[i] != NULL; i++) {
417 		g_autoptr(AsTranslation) translation = NULL;
418 		translation = as_translation_new ();
419 		as_translation_set_kind (translation, AS_TRANSLATION_KIND_QT);
420 		as_translation_set_id (translation, gettext_domains[i]);
421 		as_app_add_translation (app, translation);
422 	}
423 	ret = as_app_builder_search_translations (app, fn, 25,
424 						  AS_APP_BUILDER_FLAG_NONE,
425 						  NULL, &error);
426 	g_assert_no_error (error);
427 	g_assert (ret);
428 
429 	/* check langs */
430 	g_assert_cmpint (as_app_get_language (app, "fr"), ==, 100);
431 	g_assert_cmpint (as_app_get_language (app, "en_GB"), ==, -1);
432 
433 	/* check size */
434 	list = as_app_get_languages (app);
435 	g_assert_cmpint (g_list_length (list), ==, 1);
436 }
437 
438 static void
as_test_app_builder_qt_subdir_func(void)439 as_test_app_builder_qt_subdir_func (void)
440 {
441 	GError *error = NULL;
442 	gboolean ret;
443 	guint i;
444 	g_autofree gchar *fn = NULL;
445 	g_autoptr(AsApp) app = NULL;
446 	g_autoptr(GList) list = NULL;
447 	const gchar *gettext_domains[] = { "kdeapp2", "notgoingtoexist", NULL };
448 
449 	app = as_app_new ();
450 	fn = as_test_get_filename ("usr");
451 	g_assert (fn != NULL);
452 	for (i = 0; gettext_domains[i] != NULL; i++) {
453 		g_autoptr(AsTranslation) translation = NULL;
454 		translation = as_translation_new ();
455 		as_translation_set_kind (translation, AS_TRANSLATION_KIND_QT);
456 		as_translation_set_id (translation, gettext_domains[i]);
457 		as_app_add_translation (app, translation);
458 	}
459 	ret = as_app_builder_search_translations (app, fn, 25,
460 						  AS_APP_BUILDER_FLAG_NONE,
461 						  NULL, &error);
462 	g_assert_no_error (error);
463 	g_assert (ret);
464 
465 	/* check langs */
466 	g_assert_cmpint (as_app_get_language (app, "fr"), ==, 100);
467 	g_assert_cmpint (as_app_get_language (app, "en_GB"), ==, -1);
468 
469 	/* check size */
470 	list = as_app_get_languages (app);
471 	g_assert_cmpint (g_list_length (list), ==, 1);
472 }
473 
474 static void
as_test_tag_func(void)475 as_test_tag_func (void)
476 {
477 	guint i;
478 
479 	/* simple test */
480 	g_assert_cmpstr (as_tag_to_string (AS_TAG_URL), ==, "url");
481 	g_assert_cmpstr (as_tag_to_string (AS_TAG_UNKNOWN), ==, "unknown");
482 	g_assert_cmpint (as_tag_from_string ("url"), ==, AS_TAG_URL);
483 	g_assert_cmpint (as_tag_from_string ("xxx"), ==, AS_TAG_UNKNOWN);
484 	g_assert_cmpint (as_tag_from_string (NULL), ==, AS_TAG_UNKNOWN);
485 
486 	/* deprecated names */
487 	g_assert_cmpint (as_tag_from_string_full ("appcategories",
488 						  AS_TAG_FLAG_USE_FALLBACKS),
489 						  ==, AS_TAG_CATEGORIES);
490 
491 	/* test we can go back and forth */
492 	for (i = 0; i < AS_TAG_LAST; i++)
493 		g_assert_cmpint (as_tag_from_string (as_tag_to_string (i)), ==, i);
494 }
495 
496 static void
as_test_release_func(void)497 as_test_release_func (void)
498 {
499 	GError *error = NULL;
500 	AsNode *n;
501 	AsNode *root;
502 	GString *xml;
503 	const gchar *src = "<release type=\"stable\" install_duration=\"120\" "
504 			   "timestamp=\"123\" urgency=\"critical\" version=\"0.1.2\"/>";
505 	gboolean ret;
506 	g_autoptr(AsNodeContext) ctx = NULL;
507 	g_autoptr(AsRelease) release = NULL;
508 
509 	release = as_release_new ();
510 
511 	/* to object */
512 	root = as_node_from_xml (src, 0, &error);
513 	g_assert_no_error (error);
514 	g_assert (root != NULL);
515 	n = as_node_find (root, "release");
516 	g_assert (n != NULL);
517 	ctx = as_node_context_new ();
518 	ret = as_release_node_parse (release, n, ctx, &error);
519 	g_assert_no_error (error);
520 	g_assert (ret);
521 	as_node_unref (root);
522 
523 	/* verify */
524 	g_assert_cmpint ((gint32) as_release_get_timestamp (release), ==, 123);
525 	g_assert_cmpint (as_release_get_urgency (release), ==, AS_URGENCY_KIND_CRITICAL);
526 	g_assert_cmpint (as_release_get_state (release), ==, AS_RELEASE_STATE_UNKNOWN);
527 	g_assert_cmpint (as_release_get_kind (release), ==, AS_RELEASE_KIND_STABLE);
528 	g_assert_cmpstr (as_release_get_version (release), ==, "0.1.2");
529 
530 	/* state is not stored in the XML */
531 	as_release_set_state (release, AS_RELEASE_STATE_INSTALLED);
532 	g_assert_cmpint (as_release_get_state (release), ==, AS_RELEASE_STATE_INSTALLED);
533 
534 	/* back to node */
535 	root = as_node_new ();
536 	as_node_context_set_version (ctx, 0.4);
537 	n = as_release_node_insert (release, root, ctx);
538 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
539 	ret = as_test_compare_lines (xml->str, src, &error);
540 	g_assert_no_error (error);
541 	g_assert (ret);
542 	g_string_free (xml, TRUE);
543 	as_node_unref (root);
544 }
545 
546 static void
as_test_release_date_func(void)547 as_test_release_date_func (void)
548 {
549 	GError *error = NULL;
550 	AsNode *n;
551 	AsNode *root;
552 	const gchar *src = "<release date=\"2016-01-18\"/>";
553 	gboolean ret;
554 	g_autoptr(AsNodeContext) ctx = NULL;
555 	g_autoptr(AsRelease) release = NULL;
556 
557 	release = as_release_new ();
558 
559 	/* to object */
560 	root = as_node_from_xml (src, 0, &error);
561 	g_assert_no_error (error);
562 	g_assert (root != NULL);
563 	n = as_node_find (root, "release");
564 	g_assert (n != NULL);
565 	ctx = as_node_context_new ();
566 	ret = as_release_node_parse (release, n, ctx, &error);
567 	g_assert_no_error (error);
568 	g_assert (ret);
569 	as_node_unref (root);
570 
571 	/* verify */
572 	g_assert_cmpint ((gint32) as_release_get_timestamp (release), ==, 1453075200);
573 }
574 
575 static void
as_test_provide_func(void)576 as_test_provide_func (void)
577 {
578 	GError *error = NULL;
579 	AsNode *n;
580 	AsNode *root;
581 	GString *xml;
582 	const gchar *src = "<binary>/usr/bin/gnome-shell</binary>";
583 	gboolean ret;
584 	g_autoptr(AsNodeContext) ctx = NULL;
585 	g_autoptr(AsProvide) provide = NULL;
586 
587 	provide = as_provide_new ();
588 
589 	/* to object */
590 	root = as_node_from_xml (src, 0, &error);
591 	g_assert_no_error (error);
592 	g_assert (root != NULL);
593 	n = as_node_find (root, "binary");
594 	g_assert (n != NULL);
595 	ctx = as_node_context_new ();
596 	ret = as_provide_node_parse (provide, n, ctx, &error);
597 	g_assert_no_error (error);
598 	g_assert (ret);
599 	as_node_unref (root);
600 
601 	/* verify */
602 	g_assert_cmpint (as_provide_get_kind (provide), ==, AS_PROVIDE_KIND_BINARY);
603 	g_assert_cmpstr (as_provide_get_value (provide), ==, "/usr/bin/gnome-shell");
604 
605 	/* back to node */
606 	root = as_node_new ();
607 	as_node_context_set_version (ctx, 0.4);
608 	n = as_provide_node_insert (provide, root, ctx);
609 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
610 	ret = as_test_compare_lines (xml->str, src, &error);
611 	g_assert_no_error (error);
612 	g_assert (ret);
613 	g_string_free (xml, TRUE);
614 	as_node_unref (root);
615 }
616 
617 static void
as_test_launchable_func(void)618 as_test_launchable_func (void)
619 {
620 	GError *error = NULL;
621 	AsNode *n;
622 	AsNode *root;
623 	GString *xml;
624 	const gchar *src = "<launchable type=\"desktop-id\">gnome-software.desktop</launchable>";
625 	gboolean ret;
626 	g_autoptr(AsNodeContext) ctx = NULL;
627 	g_autoptr(AsLaunchable) launchable = NULL;
628 
629 	launchable = as_launchable_new ();
630 
631 	/* to object */
632 	root = as_node_from_xml (src, 0, &error);
633 	g_assert_no_error (error);
634 	g_assert (root != NULL);
635 	n = as_node_find (root, "launchable");
636 	g_assert (n != NULL);
637 	ctx = as_node_context_new ();
638 	ret = as_launchable_node_parse (launchable, n, ctx, &error);
639 	g_assert_no_error (error);
640 	g_assert (ret);
641 	as_node_unref (root);
642 
643 	/* verify */
644 	g_assert_cmpint (as_launchable_get_kind (launchable), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
645 	g_assert_cmpstr (as_launchable_get_value (launchable), ==, "gnome-software.desktop");
646 
647 	/* back to node */
648 	root = as_node_new ();
649 	as_node_context_set_version (ctx, 0.4);
650 	n = as_launchable_node_insert (launchable, root, ctx);
651 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
652 	ret = as_test_compare_lines (xml->str, src, &error);
653 	g_assert_no_error (error);
654 	g_assert (ret);
655 	g_string_free (xml, TRUE);
656 	as_node_unref (root);
657 }
658 
659 static void
as_test_release_appstream_func(void)660 as_test_release_appstream_func (void)
661 {
662 	const gchar *url;
663 	AsChecksum *csum;
664 	GError *error = NULL;
665 	AsNode *n;
666 	AsNode *root;
667 	GString *xml;
668 	gboolean ret;
669 	guint64 sz;
670 	const gchar *src =
671 		"<release timestamp=\"123\" version=\"0.1.2\">\n"
672 		"<location>http://foo.com/bar.zip</location>\n"
673 		"<location>http://baz.com/bar.cab</location>\n"
674 		"<checksum type=\"sha1\" filename=\"firmware.cab\" target=\"container\">12345</checksum>\n"
675 		"<checksum type=\"md5\" filename=\"firmware.cab\" target=\"container\">deadbeef</checksum>\n"
676 		"<url type=\"details\">http://foo.bar/</url>\n"
677 		"<description><p>This is a new release</p><ul><li>Point</li></ul></description>\n"
678 		"<description xml:lang=\"pl\"><p>Oprogramowanie</p></description>\n"
679 		"<size type=\"installed\">123456</size>\n"
680 		"<size type=\"download\">654321</size>\n"
681 		"</release>\n";
682 	g_autoptr(AsNodeContext) ctx = NULL;
683 	g_autoptr(AsRelease) release = NULL;
684 
685 	release = as_release_new ();
686 
687 	/* to object */
688 	root = as_node_from_xml (src, 0, &error);
689 	g_assert_no_error (error);
690 	g_assert (root != NULL);
691 	n = as_node_find (root, "release");
692 	g_assert (n != NULL);
693 	ctx = as_node_context_new ();
694 	ret = as_release_node_parse (release, n, ctx, &error);
695 	g_assert_no_error (error);
696 	g_assert (ret);
697 	as_node_unref (root);
698 
699 	/* verify */
700 	g_assert_cmpint ((gint32) as_release_get_timestamp (release), ==, 123);
701 	g_assert_cmpstr (as_release_get_version (release), ==, "0.1.2");
702 	g_assert_cmpstr (as_release_get_location_default (release), ==, "http://foo.com/bar.zip");
703 	g_assert_cmpstr (as_release_get_description (release, "pl"), ==,
704 				"<p>Oprogramowanie</p>");
705 	g_assert_cmpstr (as_release_get_description (release, NULL), ==,
706 				"<p>This is a new release</p><ul><li>Point</li></ul>");
707 
708 	/* checksum */
709 	g_assert_cmpint (as_release_get_checksums(release)->len, ==, 2);
710 	csum = as_release_get_checksum_by_fn (release, "firmware.inf");
711 	g_assert (csum == NULL);
712 	csum = as_release_get_checksum_by_fn (release, "firmware.cab");
713 	g_assert (csum != NULL);
714 	g_assert_cmpint (as_checksum_get_kind (csum), ==, G_CHECKSUM_SHA1);
715 	g_assert_cmpint (as_checksum_get_target (csum), ==, AS_CHECKSUM_TARGET_CONTAINER);
716 	g_assert_cmpstr (as_checksum_get_filename (csum), ==, "firmware.cab");
717 	g_assert_cmpstr (as_checksum_get_value (csum), ==, "12345");
718 
719 	/* get by target type */
720 	csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT);
721 	g_assert (csum == NULL);
722 	csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTAINER);
723 	g_assert (csum != NULL);
724 	g_assert_cmpstr (as_checksum_get_value (csum), ==, "12345");
725 
726 	/* test size */
727 	sz = as_release_get_size (release, AS_SIZE_KIND_INSTALLED);
728 	g_assert_cmpuint (sz, ==, 123456);
729 	sz = as_release_get_size (release, AS_SIZE_KIND_DOWNLOAD);
730 	g_assert_cmpuint (sz, ==, 654321);
731 
732 	/* URL */
733 	url = as_release_get_url (release, AS_URL_KIND_DETAILS);
734 	g_assert_cmpstr (url, ==, "http://foo.bar/");
735 	url = as_release_get_url (release, AS_URL_KIND_HOMEPAGE);
736 	g_assert_null (url);
737 
738 	/* back to node */
739 	root = as_node_new ();
740 	as_node_context_set_version (ctx, 1.0);
741 	as_node_context_set_format_kind (ctx, AS_FORMAT_KIND_APPSTREAM);
742 	n = as_release_node_insert (release, root, ctx);
743 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
744 	ret = as_test_compare_lines (xml->str, src, &error);
745 	g_assert_no_error (error);
746 	g_assert (ret);
747 
748 	g_string_free (xml, TRUE);
749 	as_node_unref (root);
750 }
751 
752 static void
as_test_release_appdata_func(void)753 as_test_release_appdata_func (void)
754 {
755 	GError *error = NULL;
756 	AsNode *n;
757 	AsNode *root;
758 	gboolean ret;
759 	const gchar *src =
760 		"<release version=\"0.1.2\" timestamp=\"123\">\n"
761 		"<description>\n"
762 		"<p>This is a new release</p>\n"
763 		"<p xml:lang=\"pl\">Oprogramowanie</p>\n"
764 		"</description>\n"
765 		"</release>\n";
766 	g_autoptr(AsNodeContext) ctx = NULL;
767 	g_autoptr(AsRelease) release = NULL;
768 
769 	release = as_release_new ();
770 
771 	/* to object */
772 	root = as_node_from_xml (src, 0, &error);
773 	g_assert_no_error (error);
774 	g_assert (root != NULL);
775 	n = as_node_find (root, "release");
776 	g_assert (n != NULL);
777 	ctx = as_node_context_new ();
778 	as_node_context_set_format_kind (ctx, AS_FORMAT_KIND_APPDATA);
779 	ret = as_release_node_parse (release, n, ctx, &error);
780 	g_assert_no_error (error);
781 	g_assert (ret);
782 	as_node_unref (root);
783 
784 	/* verify */
785 	g_assert_cmpint ((gint32) as_release_get_timestamp (release), ==, 123);
786 	g_assert_cmpstr (as_release_get_version (release), ==, "0.1.2");
787 	g_assert_cmpstr (as_release_get_description (release, NULL), ==,
788 				"<p>This is a new release</p>");
789 	g_assert_cmpstr (as_release_get_description (release, "pl"), ==,
790 				"<p>Oprogramowanie</p>");
791 }
792 
793 typedef enum {
794 	AS_TEST_RESIZE_NEAREST,
795 	AS_TEST_RESIZE_TILES,
796 	AS_TEST_RESIZE_BILINEAR,
797 	AS_TEST_RESIZE_HYPER,
798 	AS_TEST_RESIZE_BILINEAR_SHARP,
799 	AS_TEST_RESIZE_HYPER_SHARP,
800 	AS_TEST_RESIZE_LAST,
801 } AsTestResize;
802 
803 static const gchar *
as_test_resize_to_string(AsTestResize rz)804 as_test_resize_to_string (AsTestResize rz)
805 {
806 	if (rz == AS_TEST_RESIZE_NEAREST)
807 		return "nearest";
808 	if (rz == AS_TEST_RESIZE_TILES)
809 		return "tiles";
810 	if (rz == AS_TEST_RESIZE_BILINEAR)
811 		return "bilinear";
812 	if (rz == AS_TEST_RESIZE_HYPER)
813 		return "hyper";
814 	if (rz == AS_TEST_RESIZE_BILINEAR_SHARP)
815 		return "bilinear-sharp";
816 	if (rz == AS_TEST_RESIZE_HYPER_SHARP)
817 		return "hyper-sharp";
818 	return NULL;
819 }
820 
821 static void
as_test_image_resize_filename(AsTestResize rz,const gchar * in,const gchar * out)822 as_test_image_resize_filename (AsTestResize rz, const gchar *in, const gchar *out)
823 {
824 	gboolean ret;
825 	g_autoptr(GdkPixbuf) pb = NULL;
826 	g_autoptr(GdkPixbuf) pb2 = NULL;
827 
828 	pb = gdk_pixbuf_new_from_file (in, NULL);
829 	g_assert (pb != NULL);
830 
831 	switch (rz) {
832 	case AS_TEST_RESIZE_NEAREST:
833 		pb2 = gdk_pixbuf_scale_simple (pb,
834 					       AS_IMAGE_LARGE_WIDTH,
835 					       AS_IMAGE_LARGE_HEIGHT,
836 					       GDK_INTERP_NEAREST);
837 		break;
838 	case AS_TEST_RESIZE_TILES:
839 		pb2 = gdk_pixbuf_scale_simple (pb,
840 					       AS_IMAGE_LARGE_WIDTH,
841 					       AS_IMAGE_LARGE_HEIGHT,
842 					       GDK_INTERP_TILES);
843 		break;
844 	case AS_TEST_RESIZE_BILINEAR:
845 		pb2 = gdk_pixbuf_scale_simple (pb,
846 					       AS_IMAGE_LARGE_WIDTH,
847 					       AS_IMAGE_LARGE_HEIGHT,
848 					       GDK_INTERP_BILINEAR);
849 		break;
850 	case AS_TEST_RESIZE_HYPER:
851 		pb2 = gdk_pixbuf_scale_simple (pb,
852 					       AS_IMAGE_LARGE_WIDTH,
853 					       AS_IMAGE_LARGE_HEIGHT,
854 					       GDK_INTERP_HYPER);
855 		break;
856 	case AS_TEST_RESIZE_BILINEAR_SHARP:
857 		pb2 = gdk_pixbuf_scale_simple (pb,
858 					       AS_IMAGE_LARGE_WIDTH,
859 					       AS_IMAGE_LARGE_HEIGHT,
860 					       GDK_INTERP_BILINEAR);
861 		as_pixbuf_sharpen (pb2, 1, -0.5);
862 		break;
863 	case AS_TEST_RESIZE_HYPER_SHARP:
864 		pb2 = gdk_pixbuf_scale_simple (pb,
865 					       AS_IMAGE_LARGE_WIDTH,
866 					       AS_IMAGE_LARGE_HEIGHT,
867 					       GDK_INTERP_HYPER);
868 		as_pixbuf_sharpen (pb2, 1, -0.5);
869 		break;
870 	default:
871 		g_assert_not_reached ();
872 	}
873 
874 	ret = gdk_pixbuf_save (pb2, out, "png", NULL, NULL);
875 	g_assert (ret);
876 }
877 
878 static void
as_test_image_alpha_func(void)879 as_test_image_alpha_func (void)
880 {
881 	gboolean ret;
882 	g_autoptr(GError) error = NULL;
883 	g_autofree gchar *fn_both = NULL;
884 	g_autofree gchar *fn_horiz = NULL;
885 	g_autofree gchar *fn_internal1 = NULL;
886 	g_autofree gchar *fn_internal2 = NULL;
887 	g_autofree gchar *fn_none = NULL;
888 	g_autofree gchar *fn_vert = NULL;
889 	g_autoptr(AsImage) im = NULL;
890 
891 	/* horiz */
892 	fn_horiz = as_test_get_filename ("alpha-horiz.png");
893 	im = as_image_new ();
894 	ret = as_image_load_filename (im, fn_horiz, &error);
895 	g_assert_no_error (error);
896 	g_assert (ret);
897 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
898 			 AS_IMAGE_ALPHA_FLAG_LEFT |
899 			 AS_IMAGE_ALPHA_FLAG_RIGHT);
900 
901 	/* vert */
902 	fn_vert = as_test_get_filename ("alpha-vert.png");
903 	ret = as_image_load_filename (im, fn_vert, &error);
904 	g_assert_no_error (error);
905 	g_assert (ret);
906 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
907 			 AS_IMAGE_ALPHA_FLAG_TOP |
908 			 AS_IMAGE_ALPHA_FLAG_BOTTOM);
909 
910 	/* both */
911 	fn_both = as_test_get_filename ("alpha-both.png");
912 	ret = as_image_load_filename (im, fn_both, &error);
913 	g_assert_no_error (error);
914 	g_assert (ret);
915 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
916 			 AS_IMAGE_ALPHA_FLAG_LEFT |
917 			 AS_IMAGE_ALPHA_FLAG_RIGHT |
918 			 AS_IMAGE_ALPHA_FLAG_TOP |
919 			 AS_IMAGE_ALPHA_FLAG_BOTTOM);
920 
921 	/* internal */
922 	fn_internal1 = as_test_get_filename ("alpha-internal1.png");
923 	ret = as_image_load_filename (im, fn_internal1, &error);
924 	g_assert_no_error (error);
925 	g_assert (ret);
926 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
927 			 AS_IMAGE_ALPHA_FLAG_INTERNAL);
928 
929 	fn_internal2 = as_test_get_filename ("alpha-internal2.png");
930 	ret = as_image_load_filename (im, fn_internal2, &error);
931 	g_assert_no_error (error);
932 	g_assert (ret);
933 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
934 			 AS_IMAGE_ALPHA_FLAG_INTERNAL);
935 
936 	fn_none = as_test_get_filename ("ss-small.png");
937 	ret = as_image_load_filename (im, fn_none, &error);
938 	g_assert_no_error (error);
939 	g_assert (ret);
940 	g_assert_cmpint (as_image_get_alpha_flags (im), ==,
941 			 AS_IMAGE_ALPHA_FLAG_NONE);
942 }
943 
944 static void
as_test_image_resize_func(void)945 as_test_image_resize_func (void)
946 {
947 	GError *error = NULL;
948 	const gchar *tmp;
949 	g_autoptr(GDir) dir = NULL;
950 	g_autofree gchar *output_dir = NULL;
951 
952 	/* only do this test if an "output" directory exists */
953 	output_dir = g_build_filename (TESTDIRSRC, "output", NULL);
954 	if (!g_file_test (output_dir, G_FILE_TEST_EXISTS))
955 		return;
956 
957 	/* look for test screenshots */
958 	dir = g_dir_open (TESTDIRSRC, 0, &error);
959 	g_assert_no_error (error);
960 	g_assert (dir != NULL);
961 	while ((tmp = g_dir_read_name (dir)) != NULL) {
962 		guint i;
963 		g_autofree gchar *path = NULL;
964 
965 		if (!g_str_has_prefix (tmp, "ss-"))
966 			continue;
967 		path = g_build_filename (TESTDIRSRC, tmp, NULL);
968 
969 		for (i = 0; i < AS_TEST_RESIZE_LAST; i++) {
970 			g_autofree gchar *new_path = NULL;
971 			g_autoptr(GString) basename = NULL;
972 
973 			basename = g_string_new (tmp);
974 			g_string_truncate (basename, basename->len - 4);
975 			g_string_append_printf (basename, "-%s.png",
976 						as_test_resize_to_string (i));
977 			new_path = g_build_filename (output_dir, basename->str, NULL);
978 			as_test_image_resize_filename (i, path, new_path);
979 		}
980 	}
981 }
982 
983 static void
as_test_icon_func(void)984 as_test_icon_func (void)
985 {
986 	GError *error = NULL;
987 	AsNode *n;
988 	AsNode *root;
989 	GString *xml;
990 	const gchar *src = "<icon type=\"cached\">app.png</icon>";
991 	gboolean ret;
992 	g_autoptr(AsNodeContext) ctx = NULL;
993 	g_autofree gchar *prefix = NULL;
994 	g_autoptr(AsIcon) icon = NULL;
995 	g_autoptr(GdkPixbuf) pixbuf = NULL;
996 
997 	icon = as_icon_new ();
998 
999 	/* to object */
1000 	root = as_node_from_xml (src, 0, &error);
1001 	g_assert_no_error (error);
1002 	g_assert (root != NULL);
1003 	n = as_node_find (root, "icon");
1004 	g_assert (n != NULL);
1005 	ctx = as_node_context_new ();
1006 	ret = as_icon_node_parse (icon, n, ctx, &error);
1007 	g_assert_no_error (error);
1008 	g_assert (ret);
1009 	as_node_unref (root);
1010 
1011 	/* verify */
1012 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_CACHED);
1013 	g_assert_cmpstr (as_icon_get_name (icon), ==, "app.png");
1014 	g_assert_cmpstr (as_icon_get_filename (icon), ==, NULL);
1015 	g_assert_cmpstr (as_icon_get_url (icon), ==, NULL);
1016 	g_assert_cmpint (as_icon_get_height (icon), ==, 64);
1017 	g_assert_cmpint (as_icon_get_width (icon), ==, 64);
1018 	g_assert_cmpint (as_icon_get_scale (icon), ==, 1);
1019 	g_assert (as_icon_get_pixbuf (icon) == NULL);
1020 	g_assert (as_icon_get_data (icon) == NULL);
1021 
1022 	/* back to node */
1023 	root = as_node_new ();
1024 	as_node_context_set_version (ctx, 0.4);
1025 	n = as_icon_node_insert (icon, root, ctx);
1026 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1027 	ret = as_test_compare_lines (xml->str, "<icon type=\"cached\" height=\"64\" width=\"64\">app.png</icon>", &error);
1028 	g_assert_no_error (error);
1029 	g_assert (ret);
1030 	g_string_free (xml, TRUE);
1031 	as_node_unref (root);
1032 
1033 	/* convert to embedded icon */
1034 	prefix = as_test_get_filename ("rpmbuild");
1035 	g_assert (prefix != NULL);
1036 	as_icon_set_prefix (icon, prefix);
1037 	ret = as_icon_convert_to_kind (icon, AS_ICON_KIND_EMBEDDED, &error);
1038 	g_assert_no_error (error);
1039 	g_assert (ret);
1040 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_EMBEDDED);
1041 	g_assert_cmpstr (as_icon_get_filename (icon), ==, NULL);
1042 	g_assert_cmpstr (as_icon_get_url (icon), ==, NULL);
1043 	g_assert (as_icon_get_pixbuf (icon) != NULL);
1044 	g_assert (as_icon_get_data (icon) != NULL);
1045 }
1046 
1047 static void
as_test_icon_scale_func(void)1048 as_test_icon_scale_func (void)
1049 {
1050 	GError *error = NULL;
1051 	AsNode *n;
1052 	AsNode *root;
1053 	GString *xml;
1054 	const gchar *src = "<icon type=\"cached\" height=\"128\" scale=\"2\" width=\"128\">app.png</icon>";
1055 	gboolean ret;
1056 	g_autoptr(AsNodeContext) ctx = NULL;
1057 	g_autoptr(AsIcon) icon = NULL;
1058 	g_autoptr(GdkPixbuf) pixbuf = NULL;
1059 
1060 	icon = as_icon_new ();
1061 
1062 	/* to object */
1063 	root = as_node_from_xml (src, 0, &error);
1064 	g_assert_no_error (error);
1065 	g_assert (root != NULL);
1066 	n = as_node_find (root, "icon");
1067 	g_assert (n != NULL);
1068 	ctx = as_node_context_new ();
1069 	ret = as_icon_node_parse (icon, n, ctx, &error);
1070 	g_assert_no_error (error);
1071 	g_assert (ret);
1072 	as_node_unref (root);
1073 
1074 	/* verify */
1075 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_CACHED);
1076 	g_assert_cmpstr (as_icon_get_name (icon), ==, "app.png");
1077 	g_assert_cmpstr (as_icon_get_filename (icon), ==, NULL);
1078 	g_assert_cmpstr (as_icon_get_url (icon), ==, NULL);
1079 	g_assert_cmpint (as_icon_get_height (icon), ==, 128);
1080 	g_assert_cmpint (as_icon_get_width (icon), ==, 128);
1081 	g_assert_cmpint (as_icon_get_scale (icon), ==, 2);
1082 	g_assert (as_icon_get_pixbuf (icon) == NULL);
1083 	g_assert (as_icon_get_data (icon) == NULL);
1084 
1085 	/* back to node */
1086 	root = as_node_new ();
1087 	as_node_context_set_version (ctx, 0.9);
1088 	n = as_icon_node_insert (icon, root, ctx);
1089 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1090 	ret = as_test_compare_lines (xml->str, src, &error);
1091 	g_assert_no_error (error);
1092 	g_assert (ret);
1093 	g_string_free (xml, TRUE);
1094 	as_node_unref (root);
1095 }
1096 
1097 static void
as_test_checksum_func(void)1098 as_test_checksum_func (void)
1099 {
1100 	GError *error = NULL;
1101 	AsNode *n;
1102 	AsNode *root;
1103 	GString *xml;
1104 	const gchar *src = "<checksum type=\"sha1\" filename=\"f&amp;n.cab\" target=\"container\">12&amp;45</checksum>";
1105 	gboolean ret;
1106 	g_autoptr(AsNodeContext) ctx = NULL;
1107 	g_autoptr(AsChecksum) csum = NULL;
1108 
1109 	/* helpers */
1110 	g_assert_cmpint (as_checksum_target_from_string ("container"), ==, AS_CHECKSUM_TARGET_CONTAINER);
1111 	g_assert_cmpint (as_checksum_target_from_string ("content"), ==, AS_CHECKSUM_TARGET_CONTENT);
1112 	g_assert_cmpint (as_checksum_target_from_string (NULL), ==, AS_CHECKSUM_TARGET_UNKNOWN);
1113 	g_assert_cmpstr (as_checksum_target_to_string (AS_CHECKSUM_TARGET_CONTAINER), ==, "container");
1114 	g_assert_cmpstr (as_checksum_target_to_string (AS_CHECKSUM_TARGET_CONTENT), ==, "content");
1115 	g_assert_cmpstr (as_checksum_target_to_string (AS_CHECKSUM_TARGET_UNKNOWN), ==, NULL);
1116 
1117 	csum = as_checksum_new ();
1118 
1119 	/* to object */
1120 	root = as_node_from_xml (src, 0, &error);
1121 	g_assert_no_error (error);
1122 	g_assert (root != NULL);
1123 	n = as_node_find (root, "checksum");
1124 	g_assert (n != NULL);
1125 	ctx = as_node_context_new ();
1126 	ret = as_checksum_node_parse (csum, n, ctx, &error);
1127 	g_assert_no_error (error);
1128 	g_assert (ret);
1129 	as_node_unref (root);
1130 
1131 	/* verify */
1132 	g_assert_cmpint (as_checksum_get_kind (csum), ==, G_CHECKSUM_SHA1);
1133 	g_assert_cmpint (as_checksum_get_target (csum), ==, AS_CHECKSUM_TARGET_CONTAINER);
1134 	g_assert_cmpstr (as_checksum_get_filename (csum), ==, "f&n.cab");
1135 	g_assert_cmpstr (as_checksum_get_value (csum), ==, "12&45");
1136 
1137 	/* back to node */
1138 	root = as_node_new ();
1139 	as_node_context_set_version (ctx, 0.4);
1140 	n = as_checksum_node_insert (csum, root, ctx);
1141 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1142 	ret = as_test_compare_lines (xml->str, src, &error);
1143 	g_assert_no_error (error);
1144 	g_assert (ret);
1145 	g_string_free (xml, TRUE);
1146 	as_node_unref (root);
1147 }
1148 
1149 static void
as_test_icon_embedded_func(void)1150 as_test_icon_embedded_func (void)
1151 {
1152 	GError *error = NULL;
1153 	AsNode *n;
1154 	AsNode *root;
1155 	GString *xml;
1156 	const gchar *src =
1157 "<icon type=\"embedded\" height=\"32\" width=\"32\"><name>app.png</name>"
1158 "<filecontent>\n"
1159 "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJ\n"
1160 "TUUH1gsaCxQZBldDDAAACLxJREFUWIW9lmtsHNUVx/8zd3Zm9uFd73ptZ/3Gid+OoUlwyAscSJw4\n"
1161 "tIEKCGCQUPuBIlUIhbbEwIfuh0oRUYtKUEEIVQIJSpomPJKACYKQENNg7BiDE8dJnDi7drzrxz5m\n"
1162 "d3a9O3Nnbj8YaOo6qSFSj3Q0V3Nnzv93z9x7znD4kbZzZ4dbM8QWSbBsAoc2XdeLJFH8OJ2m9/j9\n"
1163 "/vRC4wgLfdDv9zsIobcKgqWVF8idAhHKljU20aol1daCggJOFCUcP3709u7uE88CePa6AZ5/frs1\n"
1164 "lbKvAi+0ihbxpzyPqsaGFXp1dY2tsHARJ8syKKWiruvQdQpKDSxf3iz29Pa0/xAA7rvBK688apmY\n"
1165 "KGwmhGwURHErGGtoaGjUa2vqrIsW+Xir1QpKDVCqg1INuk6vCMNgmgxOZy5eevnFbEJJVfr9/vEF\n"
1166 "ZcDv91fabMIrcQVrG5fWmA31jXJxcQlvs9lAqSF+JxaPxwAwMPbvl1NpFUpCQSw+CSWRwrIbb8aN\n"
1167 "TU3m5593tQJ4bUEAVru4b9u2B28qKy3nDGN2hbquIR6PgX2vNiucyWagJOKIK9NQEgnwAoMgJsCL\n"
1168 "Scg5NoTCY7ihcom192TPPQsGoLpWU1ZaziUScRiG8R+Tmp5FXFEQT0SgKHGAmaCaBqaZ4OUoBi8M\n"
1169 "YvCby5gIq8ikDciyFdVV1Uil1Na2trb8zs7Oqf8JIFgs/el0ajXH8aA0i0QyjpgShZKIgeoUpm4A\n"
1170 "1AAhFAwzWFzajO7+Xrz9eidWr1qN9m13o7ysHA6HA6qqIhAM4Msve8Tg6Fjg9g0tuySLdWdnZ2f2\n"
1171 "agCk5bY1zqKikjvcbjfp+uIYdKrA4UzDV8QhEkhh1eoNWPqT5XC5FqFz7xF83H0MqVQKT+/oAC/I\n"
1172 "6Ds1gk9OHkXXmc/x1UAYmmZBbVUl2u+/zzIdibSMBC7dUVpbeiA4HJy3NvCUJx/2f91HRVGCy5UD\n"
1173 "XzGPgkJAsKhIJROwOexIj53AzGfbMTxyBDdUlGPbvfdi7579EJ1leLj9fjze/hhEyxREWwRTioLR\n"
1174 "uIAXXjsY3/qzreamjRtXCTo52NbWJs0L4H/GPzQ6GkwzMHhyvVBiJpRoCn2fKpgcTaJ7910IvfdL\n"
1175 "HB4ahc23FCubm3Hi3V3YuNyHG4sBqps4/OFHICQMrzeNbGoKlaUFiMUVe8dfPn1h2bLlRm1t7cqM\n"
1176 "ln5mXgAAMBn7YGpyAnmeAsTjJoa+pLh1wzY8+rtfw5Xph5Ar4mCPiDs3b0H/P/+OW9dvxqI8J47v\n"
1177 "2op3//oq0lNhWKRJ2B0RuOwmBGRQfUOpoWtJ/uV9PW9sWH8HCBF+09LS4p0XQNP1d86eOzuT68oF\n"
1178 "pYAgisj15IIXZNjK1uPQZyZqapsQHDmHClmD21WAvjd+j4r6tXhsx5PY8vO74c2sh6bH4HAlEY+M\n"
1179 "4aal1VKhzWj6OiR0XQiMRevr6uwgeGheAEnIHhkY6CeECHDluEDsFO/v24vXX3wJB4cbMcSWoqKi\n"
1180 "AuGRYdg8DbjwzVe47NgIx+0dIISDr6QIMnFDFGTkejkEg2dRXVnGWZBesf2B5iWnR+K9xSUl4MC2\n"
1181 "zgvQ0fGcks1qQ6mUijxPPiwOAkflIARbBr/a8QTGYxnIshXBVCGK1z4MX8ujcC6ux7Gut3DondfR\n"
1182 "dfwAbMUJmGoRIpclTE7E4HLYUFNVITYt9qw8P8EGRNECgGuYC/B9MzKovj84GqgvKS4Vhi+JYFYD\n"
1183 "jFogyTISiQQMg0KwyNB1Cosgoq6pCYK9DjwkqIkM5GQ+il0SnPUueHK9IIRH6/p1lsnpqDuWESZ1\n"
1184 "XQeAvKsCUGq8f/rUwFPVVdWCRbBAz4gQigPYv+dVSKIF09PT4J1ZdPd0Y3FZPjwuO0TeDlm2wuuW\n"
1185 "QAgBADDGYDIGMAabLYe/1H/O5+QzBZFIEgAiVwUwTfLV2NioaRizxzEUzYNsNwBJg8frxsTEBDgp\n"
1186 "D26PF+Vl5ZBEAoHnwX3bTxkAZppgAEzTRFY3IYgyhi+OuvPk+NKp6RkA7PS8ewAA/H6/yTgcmZqa\n"
1187 "gMedD6b54OSbUeq9BWtWrcN4KAQzHQMnyNB0A1nNgGEyGObsig2DAeDAgQM4gtSMjoHB8ywYjk/Y\n"
1188 "eWXF9NQ0GLgDV80AAGiZ7L7h4XOtzc23WFfcdDO4b5fnXO/EewcOwJaK4mRfH3JzVsHrsoMaJqyS\n"
1189 "BaJFAGMmpqNRBIJjdGBomI5enuSn4vR8NJY4I1vT9yaTyRQMvHlNANMkHw2eOU1Wr177vTgA5OTk\n"
1190 "YEtbGw59cAhp9SN48grRVL8YIm9CUeJmODSqhcNholMEZij6VM1+9pLquxweu1BeaZt8SlVVAOxP\n"
1191 "R48em54LwM298dxzfzj/yCO/WMLzs1+HEAGEEFBKsePpDoRC47BaraBSsZmb5ws5nTmnrTbHUBau\n"
1192 "s4l0VguEEkYoqhKXNtxSZJ14MDMzwxsmxnjGLZmvK/7XP6Fh0L/1njy5Y+2adZKqJhEKBdiFi8Pq\n"
1193 "xYsXpSJf/sj4+LhDTaWLHRjnI8GQ7RJ1mHGWl8kwryhz0+W5XKRpsaCulKzMrabSAPixhrqyktLx\n"
1194 "VzOb20mXoRt3PfkPRK+agd27H5cymYI9OjU3CYQfN0z2vka1w+mkdnzXrl3JtrY2KavPPA1wv5Uk\n"
1195 "yS5KIgQigOMAxgBqUGhZDdlsNgWwP0oW685Wz5FYfX2NdSZjaoGLZ6IGjNYn38TAvAALtU2bNnk0\n"
1196 "qj2A2fLaiNkiEwFwCuAOiIK45/Dhw1EAeKFdOLvIa6uorLtZVNQ0G/ymV2VU3/LEW+j60QA/xHbf\n"
1197 "h3wmksFKn8NbWN6IGUPA170nUpRqbf8XAAD48wNYyRHyyZIim91b0gCNy0HvF0dAriMmd4XzVziZ\n"
1198 "4wIA8uEphNdV8X1qRr9LZnHRoFlElMTla2VgrgB3Fb/W3Nw42L6ZrClzs7d5ngtrmvHQQgEWInYt\n"
1199 "xxVXYLZ16ADU690D3JzxXLG581caBWBep/71278AZpn8hFce4VcAAAAASUVORK5CYII=\n"
1200 "</filecontent>"
1201 "</icon>";
1202 	gboolean ret;
1203 	g_autoptr(AsNodeContext) ctx = NULL;
1204 	g_autoptr(AsIcon) icon = NULL;
1205 	g_autoptr(GdkPixbuf) pixbuf = NULL;
1206 
1207 	icon = as_icon_new ();
1208 
1209 	/* to object */
1210 	root = as_node_from_xml (src, 0, &error);
1211 	g_assert_no_error (error);
1212 	g_assert (root != NULL);
1213 	n = as_node_find (root, "icon");
1214 	g_assert (n != NULL);
1215 	ctx = as_node_context_new ();
1216 	ret = as_icon_node_parse (icon, n, ctx, &error);
1217 	g_assert_no_error (error);
1218 	g_assert (ret);
1219 	as_node_unref (root);
1220 
1221 	/* verify */
1222 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_EMBEDDED);
1223 	g_assert_cmpstr (as_icon_get_name (icon), ==, "app.png");
1224 	g_assert_cmpstr (as_icon_get_filename (icon), ==, NULL);
1225 	g_assert_cmpstr (as_icon_get_url (icon), ==, NULL);
1226 	g_assert_cmpint (as_icon_get_height (icon), ==, 32);
1227 	g_assert_cmpint (as_icon_get_width (icon), ==, 32);
1228 	g_assert (as_icon_get_data (icon) != NULL);
1229 	g_assert (as_icon_get_pixbuf (icon) != NULL);
1230 
1231 	/* back to node */
1232 	root = as_node_new ();
1233 	as_node_context_set_version (ctx, 0.4);
1234 	n = as_icon_node_insert (icon, root, ctx);
1235 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1236 	ret = as_test_compare_lines (xml->str, src, &error);
1237 	g_assert_no_error (error);
1238 	g_assert (ret);
1239 	g_string_free (xml, TRUE);
1240 	as_node_unref (root);
1241 
1242 	/* convert to cached icon */
1243 	as_icon_set_prefix (icon, "/tmp");
1244 	ret = as_icon_convert_to_kind (icon, AS_ICON_KIND_CACHED, &error);
1245 	g_assert_no_error (error);
1246 	g_assert (ret);
1247 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_CACHED);
1248 	g_assert_cmpstr (as_icon_get_filename (icon), ==, NULL);
1249 	g_assert_cmpstr (as_icon_get_url (icon), ==, NULL);
1250 	g_assert (as_icon_get_pixbuf (icon) != NULL);
1251 	g_assert (as_icon_get_data (icon) != NULL);
1252 	g_assert (g_file_test ("/tmp/32x32/app.png", G_FILE_TEST_EXISTS));
1253 }
1254 
1255 static void
as_test_image_func(void)1256 as_test_image_func (void)
1257 {
1258 	GError *error = NULL;
1259 	AsNode *n;
1260 	AsNode *root;
1261 	GString *xml;
1262 	const gchar *src =
1263 		"<image type=\"thumbnail\" height=\"12\" width=\"34\" xml:lang=\"en_GB\">"
1264 		"http://www.hughsie.com/a.jpg</image>";
1265 	gboolean ret;
1266 	g_autoptr(AsNodeContext) ctx = NULL;
1267 	g_autofree gchar *filename = NULL;
1268 	g_autoptr(AsImage) image = NULL;
1269 	g_autoptr(GdkPixbuf) pixbuf = NULL;
1270 
1271 	image = as_image_new ();
1272 
1273 	/* to object */
1274 	root = as_node_from_xml (src, 0, &error);
1275 	g_assert_no_error (error);
1276 	g_assert (root != NULL);
1277 	n = as_node_find (root, "image");
1278 	g_assert (n != NULL);
1279 	ctx = as_node_context_new ();
1280 	ret = as_image_node_parse (image, n, ctx, &error);
1281 	g_assert_no_error (error);
1282 	g_assert (ret);
1283 	as_node_unref (root);
1284 
1285 	/* verify */
1286 	g_assert_cmpint (as_image_get_kind (image), ==, AS_IMAGE_KIND_THUMBNAIL);
1287 	g_assert_cmpint (as_image_get_height (image), ==, 12);
1288 	g_assert_cmpint (as_image_get_width (image), ==, 34);
1289 	g_assert_cmpstr (as_image_get_locale (image), ==, "en_GB");
1290 	g_assert_cmpstr (as_image_get_url (image), ==, "http://www.hughsie.com/a.jpg");
1291 
1292 	/* back to node */
1293 	root = as_node_new ();
1294 	as_node_context_set_version (ctx, 0.4);
1295 	n = as_image_node_insert (image, root, ctx);
1296 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1297 	ret = as_test_compare_lines (xml->str, src, &error);
1298 	g_assert_no_error (error);
1299 	g_assert (ret);
1300 	g_string_free (xml, TRUE);
1301 	as_node_unref (root);
1302 
1303 	/* read from image */
1304 	filename = as_test_get_filename ("screenshot.png");
1305 	ret = as_image_load_filename (image, filename, &error);
1306 	g_assert_no_error (error);
1307 	g_assert (ret);
1308 	g_assert_cmpint (as_image_get_width (image), ==, 800);
1309 	g_assert_cmpint (as_image_get_height (image), ==, 600);
1310 	g_assert_cmpstr (as_image_get_basename (image), ==, "screenshot.png");
1311 	g_assert_cmpstr (as_image_get_md5 (image), ==, "9de72240c27a6f8f2eaab692795cdafc");
1312 
1313 	/* resample */
1314 	pixbuf = as_image_save_pixbuf (image,
1315 				       752, 423,
1316 				       AS_IMAGE_SAVE_FLAG_PAD_16_9);
1317 	g_assert_cmpint (gdk_pixbuf_get_width (pixbuf), ==, 752);
1318 	g_assert_cmpint (gdk_pixbuf_get_height (pixbuf), ==, 423);
1319 
1320 	/* save */
1321 	ret = as_image_save_filename (image,
1322 				      "/tmp/foo.png",
1323 				      0, 0,
1324 				      AS_IMAGE_SAVE_FLAG_NONE,
1325 				      &error);
1326 	g_assert_no_error (error);
1327 	g_assert (ret);
1328 }
1329 
1330 static void
as_test_agreement_func(void)1331 as_test_agreement_func (void)
1332 {
1333 	GError *error = NULL;
1334 	AsAgreementSection *sect;
1335 	AsNode *n;
1336 	AsNode *root;
1337 	GString *xml;
1338 	const gchar *src =
1339 		"<agreement type=\"eula\" version_id=\"1.2.3a\">\n"
1340 		"<agreement_section type=\"intro\">\n"
1341 		"<description><p>Mighty Fine</p></description>\n"
1342 		"</agreement_section>\n"
1343 		"</agreement>\n";
1344 	gboolean ret;
1345 	g_autoptr(AsAgreement) agreement = NULL;
1346 	g_autoptr(AsNodeContext) ctx = NULL;
1347 
1348 	agreement = as_agreement_new ();
1349 
1350 	/* to object */
1351 	root = as_node_from_xml (src, 0, &error);
1352 	g_assert_no_error (error);
1353 	g_assert (root != NULL);
1354 	n = as_node_find (root, "agreement");
1355 	g_assert (n != NULL);
1356 	ctx = as_node_context_new ();
1357 	ret = as_agreement_node_parse (agreement, n, ctx, &error);
1358 	g_assert_no_error (error);
1359 	g_assert (ret);
1360 	as_node_unref (root);
1361 
1362 	/* verify */
1363 	g_assert_cmpint (as_agreement_get_kind (agreement), ==, AS_AGREEMENT_KIND_EULA);
1364 	g_assert_cmpstr (as_agreement_get_version_id (agreement), ==, "1.2.3a");
1365 	sect = as_agreement_get_section_default (agreement);
1366 	g_assert_nonnull (sect);
1367 	g_assert_cmpstr (as_agreement_section_get_kind (sect), ==, "intro");
1368 	g_assert_cmpstr (as_agreement_section_get_description (sect, NULL), ==, "<p>Mighty Fine</p>");
1369 
1370 	/* back to node */
1371 	root = as_node_new ();
1372 	as_node_context_set_version (ctx, 0.4);
1373 	n = as_agreement_node_insert (agreement, root, ctx);
1374 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1375 	ret = as_test_compare_lines (xml->str, src, &error);
1376 	g_assert_no_error (error);
1377 	g_assert (ret);
1378 	g_string_free (xml, TRUE);
1379 	as_node_unref (root);
1380 }
1381 
1382 static void
as_test_review_func(void)1383 as_test_review_func (void)
1384 {
1385 	GError *error = NULL;
1386 	AsNode *n;
1387 	AsNode *root;
1388 	GString *xml;
1389 	const gchar *src =
1390 		"<review date=\"2016-09-15\" id=\"17\" rating=\"80\">\n"
1391 		"<priority>5</priority>\n"
1392 		"<summary>Hello world</summary>\n"
1393 		"<description><p>Mighty Fine</p></description>\n"
1394 		"<version>1.2.3</version>\n"
1395 		"<reviewer_id>deadbeef</reviewer_id>\n"
1396 		"<reviewer_name>Richard Hughes</reviewer_name>\n"
1397 		"<lang>en_GB</lang>\n"
1398 		"<metadata>\n"
1399 		"<value key=\"foo\">bar</value>\n"
1400 		"</metadata>\n"
1401 		"</review>\n";
1402 	gboolean ret;
1403 	g_autoptr(AsNodeContext) ctx = NULL;
1404 	g_autoptr(AsReview) review = NULL;
1405 
1406 	review = as_review_new ();
1407 
1408 	/* to object */
1409 	root = as_node_from_xml (src, 0, &error);
1410 	g_assert_no_error (error);
1411 	g_assert (root != NULL);
1412 	n = as_node_find (root, "review");
1413 	g_assert (n != NULL);
1414 	ctx = as_node_context_new ();
1415 	ret = as_review_node_parse (review, n, ctx, &error);
1416 	g_assert_no_error (error);
1417 	g_assert (ret);
1418 	as_node_unref (root);
1419 
1420 	/* verify */
1421 	g_assert_cmpint (as_review_get_priority (review), ==, 5);
1422 	g_assert (as_review_get_date (review) != NULL);
1423 	g_assert_cmpstr (as_review_get_id (review), ==, "17");
1424 	g_assert_cmpstr (as_review_get_version (review), ==, "1.2.3");
1425 	g_assert_cmpstr (as_review_get_reviewer_id (review), ==, "deadbeef");
1426 	g_assert_cmpstr (as_review_get_reviewer_name (review), ==, "Richard Hughes");
1427 	g_assert_cmpstr (as_review_get_summary (review), ==, "Hello world");
1428 	g_assert_cmpstr (as_review_get_locale (review), ==, "en_GB");
1429 	g_assert_cmpstr (as_review_get_description (review), ==, "<p>Mighty Fine</p>");
1430 	g_assert_cmpstr (as_review_get_metadata_item (review, "foo"), ==, "bar");
1431 
1432 	/* back to node */
1433 	root = as_node_new ();
1434 	as_node_context_set_version (ctx, 0.4);
1435 	n = as_review_node_insert (review, root, ctx);
1436 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1437 	ret = as_test_compare_lines (xml->str, src, &error);
1438 	g_assert_no_error (error);
1439 	g_assert (ret);
1440 	g_string_free (xml, TRUE);
1441 	as_node_unref (root);
1442 }
1443 
1444 static void
as_test_require_func(void)1445 as_test_require_func (void)
1446 {
1447 	GError *error = NULL;
1448 	AsNode *n;
1449 	AsNode *root;
1450 	const gchar *src =
1451 		"<component type=\"desktop\">\n"
1452 		"<requires>\n"
1453 		"<id>gimp.desktop</id>\n"
1454 		"<firmware compare=\"ge\" version=\"0.1.2\">bootloader</firmware>\n"
1455 		"<firmware compare=\"eq\" version=\"1.0.0\">runtime</firmware>\n"
1456 		"<hardware>4be0643f-1d98-573b-97cd-ca98a65347dd</hardware>\n"
1457 		"</requires>\n"
1458 		"</component>\n";
1459 	gboolean ret;
1460 	GPtrArray *requires;
1461 	g_autoptr(AsApp) app = NULL;
1462 	g_autoptr(AsNodeContext) ctx = NULL;
1463 	g_autoptr(AsRequire) require = NULL;
1464 	g_autoptr(GString) xml = NULL;
1465 
1466 	/* to object */
1467 	root = as_node_from_xml (src, 0, &error);
1468 	g_assert_no_error (error);
1469 	g_assert (root != NULL);
1470 	n = as_node_find (root, "component");
1471 	g_assert (n != NULL);
1472 	ctx = as_node_context_new ();
1473 	app = as_app_new ();
1474 	ret = as_app_node_parse (app, n, ctx, &error);
1475 	g_assert_no_error (error);
1476 	g_assert (ret);
1477 	as_node_unref (root);
1478 
1479 	/* verify */
1480 	requires = as_app_get_requires (app);
1481 	g_assert_cmpint (requires->len, ==, 4);
1482 	require = g_ptr_array_index (requires, 0);
1483 	g_assert_cmpint (as_require_get_kind (require), ==, AS_REQUIRE_KIND_ID);
1484 	g_assert_cmpint (as_require_get_compare (require), ==, AS_REQUIRE_COMPARE_UNKNOWN);
1485 	g_assert_cmpstr (as_require_get_version (require), ==, NULL);
1486 	g_assert_cmpstr (as_require_get_value (require), ==, "gimp.desktop");
1487 	require = as_app_get_require_by_value (app, AS_REQUIRE_KIND_FIRMWARE, "bootloader");
1488 	g_assert_cmpint (as_require_get_kind (require), ==, AS_REQUIRE_KIND_FIRMWARE);
1489 	g_assert_cmpint (as_require_get_compare (require), ==, AS_REQUIRE_COMPARE_GE);
1490 	g_assert_cmpstr (as_require_get_version (require), ==, "0.1.2");
1491 	g_assert_cmpstr (as_require_get_value (require), ==, "bootloader");
1492 	require = g_ptr_array_index (requires, 3);
1493 	g_assert_cmpint (as_require_get_kind (require), ==, AS_REQUIRE_KIND_HARDWARE);
1494 	g_assert_cmpint (as_require_get_compare (require), ==, AS_REQUIRE_COMPARE_UNKNOWN);
1495 	g_assert_cmpstr (as_require_get_version (require), ==, NULL);
1496 	g_assert_cmpstr (as_require_get_value (require), ==, "4be0643f-1d98-573b-97cd-ca98a65347dd");
1497 
1498 	/* back to node */
1499 	root = as_node_new ();
1500 	as_node_context_set_version (ctx, 0.4);
1501 	n = as_app_node_insert (app, root, ctx);
1502 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1503 	ret = as_test_compare_lines (xml->str, src, &error);
1504 	g_assert_no_error (error);
1505 	g_assert (ret);
1506 	as_node_unref (root);
1507 
1508 	/* test we can go back and forth */
1509 	for (guint i = 0; i < AS_REQUIRE_COMPARE_LAST; i++) {
1510 		const gchar *tmp = as_require_compare_to_string (i);
1511 		g_assert_cmpint (as_require_compare_from_string (tmp), ==, i);
1512 	}
1513 
1514 	/* check predicates */
1515 	require = as_require_new ();
1516 	as_require_set_version (require, "0.1.2");
1517 	as_require_set_compare (require, AS_REQUIRE_COMPARE_EQ);
1518 	ret = as_require_version_compare (require, "0.1.2", &error);
1519 	g_assert_no_error (error);
1520 	g_assert (ret);
1521 	as_require_set_compare (require, AS_REQUIRE_COMPARE_LT);
1522 	ret = as_require_version_compare (require, "0.1.1", &error);
1523 	g_assert_no_error (error);
1524 	g_assert (ret);
1525 	as_require_set_compare (require, AS_REQUIRE_COMPARE_LE);
1526 	ret = as_require_version_compare (require, "0.1.2", &error);
1527 	g_assert_no_error (error);
1528 	g_assert (ret);
1529 
1530 	as_require_set_version (require, "0.1.?");
1531 	as_require_set_compare (require, AS_REQUIRE_COMPARE_GLOB);
1532 	ret = as_require_version_compare (require, "0.1.9", &error);
1533 	g_assert_no_error (error);
1534 	g_assert (ret);
1535 
1536 	as_require_set_version (require, "0.1.[0-9]");
1537 	as_require_set_compare (require, AS_REQUIRE_COMPARE_REGEX);
1538 	ret = as_require_version_compare (require, "0.1.9", &error);
1539 	g_assert_no_error (error);
1540 	g_assert (ret);
1541 }
1542 
1543 static void
as_test_suggest_func(void)1544 as_test_suggest_func (void)
1545 {
1546 	GError *error = NULL;
1547 	AsNode *n;
1548 	AsNode *root;
1549 	GString *xml;
1550 	const gchar *src =
1551 		"<suggests type=\"upstream\">\n"
1552 		"<id>gimp.desktop</id>\n"
1553 		"<id>mypaint.desktop</id>\n"
1554 		"</suggests>\n";
1555 	gboolean ret;
1556 	g_autoptr(AsNodeContext) ctx = NULL;
1557 	g_autoptr(AsSuggest) suggest = NULL;
1558 	g_autoptr(GdkPixbuf) pixbuf = NULL;
1559 
1560 	suggest = as_suggest_new ();
1561 
1562 	/* to object */
1563 	root = as_node_from_xml (src, 0, &error);
1564 	g_assert_no_error (error);
1565 	g_assert (root != NULL);
1566 	n = as_node_find (root, "suggests");
1567 	g_assert (n != NULL);
1568 	ctx = as_node_context_new ();
1569 	ret = as_suggest_node_parse (suggest, n, ctx, &error);
1570 	g_assert_no_error (error);
1571 	g_assert (ret);
1572 	as_node_unref (root);
1573 
1574 	/* verify */
1575 	g_assert_cmpint (as_suggest_get_kind (suggest), ==, AS_SUGGEST_KIND_UPSTREAM);
1576 	g_assert_cmpint (as_suggest_get_ids(suggest)->len, ==, 2);
1577 
1578 	/* back to node */
1579 	root = as_node_new ();
1580 	as_node_context_set_version (ctx, 0.4);
1581 	n = as_suggest_node_insert (suggest, root, ctx);
1582 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1583 	ret = as_test_compare_lines (xml->str, src, &error);
1584 	g_assert_no_error (error);
1585 	g_assert (ret);
1586 	g_string_free (xml, TRUE);
1587 	as_node_unref (root);
1588 }
1589 
1590 static void
as_test_bundle_func(void)1591 as_test_bundle_func (void)
1592 {
1593 	GError *error = NULL;
1594 	AsNode *n;
1595 	AsNode *root;
1596 	GString *xml;
1597 	const gchar *src =
1598 		"<bundle type=\"limba\" runtime=\"1\" sdk=\"2\">gnome-3-16</bundle>";
1599 	gboolean ret;
1600 	g_autoptr(AsNodeContext) ctx = NULL;
1601 	g_autoptr(AsBundle) bundle = NULL;
1602 
1603 	bundle = as_bundle_new ();
1604 
1605 	/* to object */
1606 	root = as_node_from_xml (src, 0, &error);
1607 	g_assert_no_error (error);
1608 	g_assert (root != NULL);
1609 	n = as_node_find (root, "bundle");
1610 	g_assert (n != NULL);
1611 	ctx = as_node_context_new ();
1612 	ret = as_bundle_node_parse (bundle, n, ctx, &error);
1613 	g_assert_no_error (error);
1614 	g_assert (ret);
1615 	as_node_unref (root);
1616 
1617 	/* verify */
1618 	g_assert_cmpint (as_bundle_get_kind (bundle), ==, AS_BUNDLE_KIND_LIMBA);
1619 	g_assert_cmpstr (as_bundle_get_id (bundle), ==, "gnome-3-16");
1620 	g_assert_cmpstr (as_bundle_get_runtime (bundle), ==, "1");
1621 	g_assert_cmpstr (as_bundle_get_sdk (bundle), ==, "2");
1622 
1623 	/* back to node */
1624 	root = as_node_new ();
1625 	as_node_context_set_version (ctx, 0.4);
1626 	n = as_bundle_node_insert (bundle, root, ctx);
1627 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1628 	ret = as_test_compare_lines (xml->str, src, &error);
1629 	g_assert_no_error (error);
1630 	g_assert (ret);
1631 	g_string_free (xml, TRUE);
1632 	as_node_unref (root);
1633 }
1634 
1635 static void
as_test_translation_func(void)1636 as_test_translation_func (void)
1637 {
1638 	GError *error = NULL;
1639 	AsNode *n;
1640 	AsNode *root;
1641 	GString *xml;
1642 	const gchar *src =
1643 		"<translation type=\"gettext\">gnome-software</translation>";
1644 	gboolean ret;
1645 	g_autoptr(AsNodeContext) ctx = NULL;
1646 	g_autoptr(AsTranslation) translation = NULL;
1647 
1648 	translation = as_translation_new ();
1649 
1650 	/* to object */
1651 	root = as_node_from_xml (src, 0, &error);
1652 	g_assert_no_error (error);
1653 	g_assert (root != NULL);
1654 	n = as_node_find (root, "translation");
1655 	g_assert (n != NULL);
1656 	ctx = as_node_context_new ();
1657 	ret = as_translation_node_parse (translation, n, ctx, &error);
1658 	g_assert_no_error (error);
1659 	g_assert (ret);
1660 	as_node_unref (root);
1661 
1662 	/* verify */
1663 	g_assert_cmpint (as_translation_get_kind (translation), ==, AS_TRANSLATION_KIND_GETTEXT);
1664 	g_assert_cmpstr (as_translation_get_id (translation), ==, "gnome-software");
1665 
1666 	/* back to node */
1667 	root = as_node_new ();
1668 	as_node_context_set_version (ctx, 0.4);
1669 	n = as_translation_node_insert (translation, root, ctx);
1670 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
1671 	ret = as_test_compare_lines (xml->str, src, &error);
1672 	g_assert_no_error (error);
1673 	g_assert (ret);
1674 	g_string_free (xml, TRUE);
1675 	as_node_unref (root);
1676 }
1677 
1678 static void
as_test_screenshot_func(void)1679 as_test_screenshot_func (void)
1680 {
1681 	GPtrArray *images;
1682 	AsImage *im;
1683 	GError *error = NULL;
1684 	AsNode *n;
1685 	AsNode *root;
1686 	GString *xml;
1687 	const gchar *src =
1688 		"<screenshot priority=\"-64\">\n"
1689 		"<caption>Hello</caption>\n"
1690 		"<image type=\"source\" height=\"800\" width=\"600\">http://1.png</image>\n"
1691 		"<image type=\"thumbnail\" height=\"100\" width=\"100\">http://2.png</image>\n"
1692 		"</screenshot>\n";
1693 	gboolean ret;
1694 	g_autoptr(AsNodeContext) ctx = NULL;
1695 	g_autoptr(AsScreenshot) screenshot = NULL;
1696 
1697 	screenshot = as_screenshot_new ();
1698 
1699 	/* to object */
1700 	root = as_node_from_xml (src, 0, &error);
1701 	g_assert_no_error (error);
1702 	g_assert (root != NULL);
1703 	n = as_node_find (root, "screenshot");
1704 	g_assert (n != NULL);
1705 	ctx = as_node_context_new ();
1706 	ret = as_screenshot_node_parse (screenshot, n, ctx, &error);
1707 	g_assert_no_error (error);
1708 	g_assert (ret);
1709 
1710 	/* verify */
1711 	g_assert_cmpint (as_screenshot_get_kind (screenshot), ==, AS_SCREENSHOT_KIND_NORMAL);
1712 	g_assert_cmpint (as_screenshot_get_priority (screenshot), ==, -64);
1713 	g_assert_cmpstr (as_screenshot_get_caption (screenshot, "C"), ==, "Hello");
1714 	images = as_screenshot_get_images (screenshot);
1715 	g_assert_cmpint (images->len, ==, 2);
1716 	im = as_screenshot_get_source (screenshot);
1717 	g_assert (im != NULL);
1718 	g_assert_cmpstr (as_image_get_url (im), ==, "http://1.png");
1719 	as_node_unref (root);
1720 
1721 	/* get closest */
1722 	im = as_screenshot_get_image (screenshot, 120, 120);
1723 	g_assert (im != NULL);
1724 	g_assert_cmpstr (as_image_get_url (im), ==, "http://2.png");
1725 	im = as_screenshot_get_image (screenshot, 800, 560);
1726 	g_assert (im != NULL);
1727 	g_assert_cmpstr (as_image_get_url (im), ==, "http://1.png");
1728 
1729 	/* back to node */
1730 	root = as_node_new ();
1731 	as_node_context_set_version (ctx, 0.8);
1732 	n = as_screenshot_node_insert (screenshot, root, ctx);
1733 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1734 	ret = as_test_compare_lines (xml->str, src, &error);
1735 	g_assert_no_error (error);
1736 	g_assert (ret);
1737 	g_string_free (xml, TRUE);
1738 	as_node_unref (root);
1739 }
1740 
1741 static void
as_test_content_rating_func(void)1742 as_test_content_rating_func (void)
1743 {
1744 	GError *error = NULL;
1745 	AsNode *n;
1746 	AsNode *root;
1747 	GString *xml;
1748 	const gchar *src =
1749 		"<content_rating type=\"oars-1.0\">\n"
1750 		"<content_attribute id=\"drugs-alcohol\">moderate</content_attribute>\n"
1751 		"<content_attribute id=\"violence-cartoon\">mild</content_attribute>\n"
1752 		"</content_rating>\n";
1753 	gboolean ret;
1754 	g_autoptr(AsNodeContext) ctx = NULL;
1755 	g_autoptr(AsContentRating) content_rating = NULL;
1756 	g_autofree const gchar **rating_ids = NULL;
1757 	const gchar *expected_rating_ids[] = { "drugs-alcohol", "violence-cartoon", NULL };
1758 	gsize i;
1759 
1760 	content_rating = as_content_rating_new ();
1761 
1762 	/* to object */
1763 	root = as_node_from_xml (src, 0, &error);
1764 	g_assert_no_error (error);
1765 	g_assert (root != NULL);
1766 	n = as_node_find (root, "content_rating");
1767 	g_assert (n != NULL);
1768 	ctx = as_node_context_new ();
1769 	ret = as_content_rating_node_parse (content_rating, n, ctx, &error);
1770 	g_assert_no_error (error);
1771 	g_assert (ret);
1772 
1773 	/* verify */
1774 	g_assert_cmpstr (as_content_rating_get_kind (content_rating), ==, "oars-1.0");
1775 	g_assert_cmpint (as_content_rating_get_value (content_rating, "drugs-alcohol"), ==,
1776 			 AS_CONTENT_RATING_VALUE_MODERATE);
1777 	g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-cartoon"), ==,
1778 			 AS_CONTENT_RATING_VALUE_MILD);
1779 	g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-bloodshed"), ==,
1780 			 AS_CONTENT_RATING_VALUE_NONE);
1781 
1782 	rating_ids = as_content_rating_get_rating_ids (content_rating);
1783 	g_assert_nonnull (rating_ids);
1784 
1785 	for (i = 0; rating_ids[i] != NULL && expected_rating_ids[i] != NULL; i++)
1786 		g_assert_cmpstr (rating_ids[i], ==, expected_rating_ids[i]);
1787 	g_assert_null (rating_ids[i]);
1788 	g_assert_null (expected_rating_ids[i]);
1789 
1790 	as_node_unref (root);
1791 
1792 	/* check CSM */
1793 	g_assert_cmpint (as_content_rating_get_minimum_age (content_rating), ==, 13);
1794 
1795 	/* back to node */
1796 	root = as_node_new ();
1797 	as_node_context_set_version (ctx, 0.8);
1798 	n = as_content_rating_node_insert (content_rating, root, ctx);
1799 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
1800 	ret = as_test_compare_lines (xml->str, src, &error);
1801 	g_assert_no_error (error);
1802 	g_assert (ret);
1803 	g_string_free (xml, TRUE);
1804 	as_node_unref (root);
1805 }
1806 
1807 /* Test that parsing an empty content rating correctly returns `none` as the
1808  * value for all the ratings defined by that particular kind of content rating,
1809  * and `unknown` for everything else. */
1810 static void
as_test_content_rating_empty(void)1811 as_test_content_rating_empty (void)
1812 {
1813 	GError *error = NULL;
1814 	AsNode *n;
1815 	AsNode *root;
1816 	const gchar *src =
1817 		"<content_rating type=\"oars-1.0\">\n"
1818 		"</content_rating>\n";
1819 	gboolean ret;
1820 	g_autoptr(AsNodeContext) ctx = NULL;
1821 	g_autoptr(AsContentRating) content_rating = NULL;
1822 
1823 	content_rating = as_content_rating_new ();
1824 
1825 	/* to object */
1826 	root = as_node_from_xml (src, 0, &error);
1827 	g_assert_no_error (error);
1828 	g_assert_nonnull (root);
1829 	n = as_node_find (root, "content_rating");
1830 	g_assert_nonnull (n);
1831 	ctx = as_node_context_new ();
1832 	ret = as_content_rating_node_parse (content_rating, n, ctx, &error);
1833 	g_assert_no_error (error);
1834 	g_assert_true (ret);
1835 
1836 	/* verify */
1837 	g_assert_cmpstr (as_content_rating_get_kind (content_rating), ==, "oars-1.0");
1838 	g_assert_cmpint (as_content_rating_get_value (content_rating, "drugs-alcohol"), ==,
1839 			 AS_CONTENT_RATING_VALUE_NONE);
1840 	g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-cartoon"), ==,
1841 			 AS_CONTENT_RATING_VALUE_NONE);
1842 	g_assert_cmpint (as_content_rating_get_value (content_rating, "violence-bloodshed"), ==,
1843 			 AS_CONTENT_RATING_VALUE_NONE);
1844 
1845 	/* This one was only added in OARS-1.1, so it shouldn’t have a value of `none`. */
1846 	g_assert_cmpint (as_content_rating_get_value (content_rating, "sex-adultery"), ==,
1847 			 AS_CONTENT_RATING_VALUE_UNKNOWN);
1848 
1849 	as_node_unref (root);
1850 }
1851 
1852 /* Test that the OARS → CSM mapping table in as_content_rating_attribute_to_csm_age()
1853  * is complete (contains mappings for all known IDs), and that the ages it
1854  * returns are non-decreasing for increasing values of #AsContentRatingValue in
1855  * each ID.
1856  *
1857  * Also test that unknown values of #AsContentRatingValue return an unknown age,
1858  * and unknown IDs do similarly. */
1859 static void
as_test_content_rating_mappings(void)1860 as_test_content_rating_mappings (void)
1861 {
1862 	const AsContentRatingValue values[] = {
1863 		AS_CONTENT_RATING_VALUE_NONE,
1864 		AS_CONTENT_RATING_VALUE_MILD,
1865 		AS_CONTENT_RATING_VALUE_MODERATE,
1866 		AS_CONTENT_RATING_VALUE_INTENSE,
1867 	};
1868 	g_autofree const gchar **ids = as_content_rating_get_all_rating_ids ();
1869 
1870 	for (gsize i = 0; ids[i] != NULL; i++) {
1871 		guint max_age = 0;
1872 
1873 		for (gsize j = 0; j < G_N_ELEMENTS (values); j++) {
1874 			guint age = as_content_rating_attribute_to_csm_age (ids[i], values[j]);
1875 			g_assert_cmpuint (age, >=, max_age);
1876 			max_age = age;
1877 		}
1878 
1879 		g_assert_cmpuint (max_age, >, 0);
1880 		g_assert_cmpuint (as_content_rating_attribute_to_csm_age (ids[i], AS_CONTENT_RATING_VALUE_UNKNOWN), ==, 0);
1881 		g_assert_cmpuint (as_content_rating_attribute_to_csm_age (ids[i], AS_CONTENT_RATING_VALUE_LAST), ==, 0);
1882 	}
1883 
1884 	g_assert_cmpuint (as_content_rating_attribute_to_csm_age ("not-valid-id", AS_CONTENT_RATING_VALUE_INTENSE), ==, 0);
1885 }
1886 
1887 /* Test that gs_utils_content_rating_system_from_locale() returns the correct
1888  * rating system for various standard locales and various forms of locale name.
1889  * See `locale -a` for the list of all available locales which some of these
1890  * test vectors were derived from. */
1891 static void
as_test_content_rating_from_locale(void)1892 as_test_content_rating_from_locale (void)
1893 {
1894 	const struct {
1895 		const gchar *locale;
1896 		AsContentRatingSystem expected_system;
1897 	} vectors[] = {
1898 		/* Simple tests to get coverage of each rating system: */
1899 		{ "es_AR", AS_CONTENT_RATING_SYSTEM_INCAA },
1900 		{ "en_AU", AS_CONTENT_RATING_SYSTEM_ACB },
1901 		{ "pt_BR", AS_CONTENT_RATING_SYSTEM_DJCTQ },
1902 		{ "zh_TW", AS_CONTENT_RATING_SYSTEM_GSRR },
1903 		{ "en_GB", AS_CONTENT_RATING_SYSTEM_PEGI },
1904 		{ "hy_AM", AS_CONTENT_RATING_SYSTEM_PEGI },
1905 		{ "bg_BG", AS_CONTENT_RATING_SYSTEM_PEGI },
1906 		{ "fi_FI", AS_CONTENT_RATING_SYSTEM_KAVI },
1907 		{ "de_DE", AS_CONTENT_RATING_SYSTEM_USK },
1908 		{ "az_IR", AS_CONTENT_RATING_SYSTEM_ESRA },
1909 		{ "jp_JP", AS_CONTENT_RATING_SYSTEM_CERO },
1910 		{ "en_NZ", AS_CONTENT_RATING_SYSTEM_OFLCNZ },
1911 		{ "ru_RU", AS_CONTENT_RATING_SYSTEM_RUSSIA },
1912 		{ "en_SQ", AS_CONTENT_RATING_SYSTEM_MDA },
1913 		{ "ko_KR", AS_CONTENT_RATING_SYSTEM_GRAC },
1914 		{ "en_US", AS_CONTENT_RATING_SYSTEM_ESRB },
1915 		{ "en_US", AS_CONTENT_RATING_SYSTEM_ESRB },
1916 		{ "en_CA", AS_CONTENT_RATING_SYSTEM_ESRB },
1917 		{ "es_MX", AS_CONTENT_RATING_SYSTEM_ESRB },
1918 		/* Fallback (arbitrarily chosen Venezuela since it seems to use IARC): */
1919 		{ "es_VE", AS_CONTENT_RATING_SYSTEM_IARC },
1920 		/* Locale with a codeset: */
1921 		{ "nl_NL.iso88591", AS_CONTENT_RATING_SYSTEM_PEGI },
1922 		/* Locale with a codeset and modifier: */
1923 		{ "nl_NL.iso885915@euro", AS_CONTENT_RATING_SYSTEM_PEGI },
1924 		/* Locale with a less esoteric codeset: */
1925 		{ "en_GB.UTF-8", AS_CONTENT_RATING_SYSTEM_PEGI },
1926 		/* Locale with a modifier but no codeset: */
1927 		{ "fi_FI@euro", AS_CONTENT_RATING_SYSTEM_KAVI },
1928 		/* Invalid locale: */
1929 		{ "_invalid", AS_CONTENT_RATING_SYSTEM_IARC },
1930 	};
1931 
1932 	for (gsize i = 0; i < G_N_ELEMENTS (vectors); i++) {
1933 		g_test_message ("Test %" G_GSIZE_FORMAT ": %s", i, vectors[i].locale);
1934 		g_assert_cmpint (as_content_rating_system_from_locale (vectors[i].locale), ==, vectors[i].expected_system);
1935 	}
1936 }
1937 
1938 static void
as_test_app_func(void)1939 as_test_app_func (void)
1940 {
1941 	AsIcon *ic;
1942 	AsBundle *bu;
1943 	AsRelease *rel;
1944 	AsLaunchable *lau;
1945 	GError *error = NULL;
1946 	AsNode *n;
1947 	AsNode *root;
1948 	GPtrArray *icons;
1949 	GString *xml;
1950 	gboolean ret;
1951 	const gchar *src =
1952 		"<component type=\"desktop\" merge=\"replace\" priority=\"-4\">\n"
1953 		"<id>org.gnome.Software.desktop</id>\n"
1954 		"<pkgname>gnome-software</pkgname>\n"
1955 		"<source_pkgname>gnome-software-src</source_pkgname>\n"
1956 		"<bundle type=\"flatpak\">app/org.gnome.Software/x86_64/master</bundle>\n"
1957 		"<translation type=\"gettext\">gnome-software</translation>\n"
1958 		"<suggests type=\"upstream\">\n"
1959 		"<id>gimp.desktop</id>\n"
1960 		"<id>mypaint.desktop</id>\n"
1961 		"</suggests>\n"
1962 		"<name>Software</name>\n"
1963 		"<name xml:lang=\"pl\">Oprogramowanie</name>\n"
1964 		"<summary>Application manager</summary>\n"
1965 		"<developer_name>GNOME Foundation</developer_name>\n"
1966 		"<description><p>Software allows you to find stuff</p></description>\n"
1967 		"<description xml:lang=\"pt_BR\"><p>O aplicativo Software.</p></description>\n"
1968 		"<icon type=\"cached\" height=\"64\" width=\"64\">org.gnome.Software1.png</icon>\n"
1969 		"<icon type=\"cached\" height=\"64\" width=\"64\">org.gnome.Software2.png</icon>\n"
1970 		"<categories>\n"
1971 		"<category>System</category>\n"
1972 		"</categories>\n"
1973 		"<architectures>\n"
1974 		"<arch>i386</arch>\n"
1975 		"</architectures>\n"
1976 		"<keywords>\n"
1977 		"<keyword>Installing</keyword>\n"
1978 		"</keywords>\n"
1979 		"<kudos>\n"
1980 		"<kudo>SearchProvider</kudo>\n"
1981 		"</kudos>\n"
1982 		"<permissions>\n"
1983 		"<permission>Network</permission>\n"
1984 		"</permissions>\n"
1985 		"<vetos>\n"
1986 		"<veto>Required AppData: ConsoleOnly</veto>\n"
1987 		"</vetos>\n"
1988 		"<mimetypes>\n"
1989 		"<mimetype>application/vnd.oasis.opendocument.spreadsheet</mimetype>\n"
1990 		"</mimetypes>\n"
1991 		"<project_license>GPLv2+</project_license>\n"
1992 		"<url type=\"homepage\">https://wiki.gnome.org/Design/Apps/Software</url>\n"
1993 		"<project_group>GNOME</project_group>\n"
1994 		"<compulsory_for_desktop>GNOME</compulsory_for_desktop>\n"
1995 		"<screenshots>\n"
1996 		"<screenshot type=\"default\">\n"
1997 		"<image type=\"thumbnail\" height=\"351\" width=\"624\">http://a.png</image>\n"
1998 		"</screenshot>\n"
1999 		"<screenshot>\n"
2000 		"<image type=\"thumbnail\">http://b.png</image>\n"
2001 		"</screenshot>\n"
2002 		"</screenshots>\n"
2003 		"<reviews>\n"
2004 		"<review date=\"2016-09-15\">\n"
2005 		"<summary>Hello world</summary>\n"
2006 		"</review>\n"
2007 		"</reviews>\n"
2008 		"<content_rating type=\"oars-1.0\">\n"
2009 		"<content_attribute id=\"drugs-alcohol\">moderate</content_attribute>\n"
2010 		"</content_rating>\n"
2011 		"<releases>\n"
2012 		"<release timestamp=\"1392724801\" version=\"3.11.91\"/>\n"
2013 		"<release timestamp=\"1392724800\" version=\"3.11.90\"/>\n"
2014 		"</releases>\n"
2015 		"<provides>\n"
2016 		"<binary>/usr/bin/gnome-shell</binary>\n"
2017 		"<dbus type=\"session\">org.gnome.Software</dbus>\n"
2018 		"<dbus type=\"system\">org.gnome.Software2</dbus>\n"
2019 		"</provides>\n"
2020 		"<launchable type=\"desktop-id\">gnome-software.desktop</launchable>\n"
2021 		"<languages>\n"
2022 		"<lang percentage=\"90\">en_GB</lang>\n"
2023 		"<lang>pl</lang>\n"
2024 		"</languages>\n"
2025 		"<custom>\n"
2026 		"<value key=\"SomethingRandom\"/>\n"
2027 		"</custom>\n"
2028 		"</component>\n";
2029 	g_autoptr(AsNodeContext) ctx = NULL;
2030 	g_autoptr(AsApp) app = NULL;
2031 
2032 	app = as_app_new ();
2033 
2034 	/* to object */
2035 	root = as_node_from_xml (src, 0, &error);
2036 	g_assert_no_error (error);
2037 	g_assert (root != NULL);
2038 	n = as_node_find (root, "component");
2039 	g_assert (n != NULL);
2040 	ctx = as_node_context_new ();
2041 	ret = as_app_node_parse (app, n, ctx, &error);
2042 	g_assert_no_error (error);
2043 	g_assert (ret);
2044 
2045 	/* verify */
2046 	g_assert_cmpstr (as_app_get_id (app), ==, "org.gnome.Software.desktop");
2047 	g_assert_cmpstr (as_app_get_id_filename (app), ==, "org.gnome.Software");
2048 	g_assert_cmpstr (as_app_get_unique_id (app), ==, "*/flatpak/*/desktop/org.gnome.Software.desktop/master");
2049 	g_assert_cmpstr (as_app_get_name (app, "pl"), ==, "Oprogramowanie");
2050 	g_assert_cmpstr (as_app_get_comment (app, NULL), ==, "Application manager");
2051 	g_assert_cmpstr (as_app_get_description (app, NULL), ==, "<p>Software allows you to find stuff</p>");
2052 	g_assert_cmpstr (as_app_get_description (app, "pt_BR"), ==, "<p>O aplicativo Software.</p>");
2053 	g_assert_cmpstr (as_app_get_developer_name (app, NULL), ==, "GNOME Foundation");
2054 	g_assert_cmpstr (as_app_get_source_pkgname (app), ==, "gnome-software-src");
2055 	g_assert_cmpstr (as_app_get_project_group (app), ==, "GNOME");
2056 	g_assert_cmpstr (as_app_get_project_license (app), ==, "GPLv2+");
2057 	g_assert_cmpstr (as_app_get_branch (app), ==, "master");
2058 	g_assert_cmpint (as_app_get_categories(app)->len, ==, 1);
2059 	g_assert_cmpint (as_app_get_priority (app), ==, -4);
2060 	g_assert_cmpint (as_app_get_screenshots(app)->len, ==, 2);
2061 	g_assert_cmpint (as_app_get_releases(app)->len, ==, 2);
2062 	g_assert_cmpint (as_app_get_launchables(app)->len, ==, 1);
2063 	g_assert_cmpint (as_app_get_provides(app)->len, ==, 3);
2064 	g_assert_cmpint (as_app_get_kudos(app)->len, ==, 1);
2065 	g_assert_cmpint (as_app_get_permissions(app)->len, ==, 1);
2066 	g_assert_cmpstr (as_app_get_metadata_item (app, "SomethingRandom"), ==, "");
2067 	g_assert_cmpint (as_app_get_language (app, "en_GB"), ==, 90);
2068 	g_assert_cmpint (as_app_get_language (app, "pl"), ==, 0);
2069 	g_assert_cmpint (as_app_get_language (app, "xx_XX"), ==, -1);
2070 	g_assert (as_app_has_kudo (app, "SearchProvider"));
2071 	g_assert (as_app_has_kudo_kind (app, AS_KUDO_KIND_SEARCH_PROVIDER));
2072 	g_assert (as_app_has_permission (app, "Network"));
2073 	g_assert (!as_app_has_kudo (app, "MagicValue"));
2074 	g_assert (!as_app_has_kudo_kind (app, AS_KUDO_KIND_USER_DOCS));
2075 	g_assert (as_app_has_compulsory_for_desktop (app, "GNOME"));
2076 	g_assert (!as_app_has_compulsory_for_desktop (app, "KDE"));
2077 	as_node_unref (root);
2078 
2079 	/* check equality */
2080 	g_assert (as_app_equal (app, app));
2081 
2082 	/* check newest release */
2083 	rel = as_app_get_release_default (app);
2084 	g_assert (rel != NULL);
2085 	g_assert_cmpstr (as_release_get_version (rel), ==, "3.11.91");
2086 
2087 	/* check specific release */
2088 	rel = as_app_get_release_by_version (app, "3.11.91");
2089 	g_assert (rel != NULL);
2090 	g_assert_cmpstr (as_release_get_version (rel), ==, "3.11.91");
2091 
2092 	/* check icons */
2093 	icons = as_app_get_icons (app);
2094 	g_assert (icons != NULL);
2095 	g_assert_cmpint (icons->len, ==, 2);
2096 
2097 	/* check bundle */
2098 	bu = as_app_get_bundle_default (app);
2099 	g_assert (bu != NULL);
2100 	g_assert_cmpint (as_bundle_get_kind (bu), ==, AS_BUNDLE_KIND_FLATPAK);
2101 	g_assert_cmpstr (as_bundle_get_id (bu), ==, "app/org.gnome.Software/x86_64/master");
2102 
2103 	/* check launchable */
2104 	lau = as_app_get_launchable_by_kind (app, AS_LAUNCHABLE_KIND_DESKTOP_ID);
2105 	g_assert (lau != NULL);
2106 	g_assert_cmpint (as_launchable_get_kind (lau), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
2107 	g_assert_cmpstr (as_launchable_get_value (lau), ==, "gnome-software.desktop");
2108 
2109 	/* check we can get a specific icon */
2110 	ic = as_app_get_icon_for_size (app, 999, 999);
2111 	g_assert (ic == NULL);
2112 	ic = as_app_get_icon_for_size (app, 64, 64);
2113 	g_assert (ic != NULL);
2114 	g_assert_cmpstr (as_icon_get_name (ic), ==, "org.gnome.Software1.png");
2115 	g_assert_cmpint (as_icon_get_kind (ic), ==, AS_ICON_KIND_CACHED);
2116 
2117 	/* we can't extend ourself */
2118 	as_app_add_extends (app, "org.gnome.Software.desktop");
2119 	g_assert_cmpint (as_app_get_extends(app)->len, ==, 0);
2120 
2121 	/* back to node */
2122 	root = as_node_new ();
2123 	as_node_context_set_version (ctx, 1.0);
2124 	n = as_app_node_insert (app, root, ctx);
2125 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
2126 	ret = as_test_compare_lines (xml->str, src, &error);
2127 	g_assert_no_error (error);
2128 	g_assert (ret);
2129 	g_string_free (xml, TRUE);
2130 	as_node_unref (root);
2131 
2132 	/* test contact demunging */
2133 	as_app_set_update_contact (app, "richard_at_hughsie_dot_co_dot_uk");
2134 	g_assert_cmpstr (as_app_get_update_contact (app), ==, "richard@hughsie.co.uk");
2135 }
2136 
2137 static void
as_test_app_launchable_fallback_func(void)2138 as_test_app_launchable_fallback_func (void)
2139 {
2140 	AsLaunchable *lau;
2141 	AsNode *n;
2142 	gboolean ret;
2143 	const gchar *src =
2144 		"<component type=\"desktop\">\n"
2145 		"<id>org.gnome.Software</id>\n"
2146 		"</component>\n";
2147 	g_autoptr(AsApp) app = NULL;
2148 	g_autoptr(AsNodeContext) ctx = NULL;
2149 	g_autoptr(AsNode) root = NULL;
2150 	g_autoptr(GError) error = NULL;
2151 
2152 	app = as_app_new ();
2153 
2154 	/* to object */
2155 	root = as_node_from_xml (src, 0, &error);
2156 	g_assert_no_error (error);
2157 	g_assert (root != NULL);
2158 	n = as_node_find (root, "component");
2159 	g_assert (n != NULL);
2160 	ctx = as_node_context_new ();
2161 	ret = as_app_node_parse (app, n, ctx, &error);
2162 	g_assert_no_error (error);
2163 	g_assert (ret);
2164 
2165 	/* verify */
2166 	g_assert_cmpstr (as_app_get_id (app), ==, "org.gnome.Software");
2167 	g_assert_cmpint (as_app_get_launchables(app)->len, ==, 1);
2168 	lau = as_app_get_launchable_by_kind (app, AS_LAUNCHABLE_KIND_DESKTOP_ID);
2169 	g_assert (lau != NULL);
2170 	g_assert_cmpint (as_launchable_get_kind (lau), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
2171 	g_assert_cmpstr (as_launchable_get_value (lau), ==, "org.gnome.Software.desktop");
2172 }
2173 
2174 static void
as_test_app_validate_check(GPtrArray * array,AsProblemKind kind,const gchar * message)2175 as_test_app_validate_check (GPtrArray *array,
2176 			    AsProblemKind kind,
2177 			    const gchar *message)
2178 {
2179 	AsProblem *problem;
2180 	gchar *tmp;
2181 	guint i;
2182 
2183 	for (i = 0; i < array->len; i++) {
2184 		g_autofree gchar *message_no_data = NULL;
2185 		problem = g_ptr_array_index (array, i);
2186 		if (as_problem_get_kind (problem) != kind)
2187 			continue;
2188 		message_no_data = g_strdup (as_problem_get_message (problem));
2189 		tmp = g_strrstr (message_no_data, " [");
2190 		if (tmp != NULL)
2191 			*tmp = '\0';
2192 		tmp = g_strrstr (message_no_data, ", ");
2193 		if (tmp != NULL)
2194 			*tmp = '\0';
2195 		if (g_strcmp0 (message_no_data, message) == 0)
2196 			return;
2197 	}
2198 	g_print ("\n");
2199 	for (i = 0; i < array->len; i++) {
2200 		problem = g_ptr_array_index (array, i);
2201 		g_print ("%u\t%s\n",
2202 			 as_problem_get_kind (problem),
2203 			 as_problem_get_message (problem));
2204 	}
2205 	g_assert_cmpstr (message, ==, "not-found");
2206 }
2207 
2208 static void
as_test_app_validate_appdata_good_func(void)2209 as_test_app_validate_appdata_good_func (void)
2210 {
2211 	AsImage *im;
2212 	AsProblem *problem;
2213 	AsScreenshot *ss;
2214 	GError *error = NULL;
2215 	GPtrArray *images;
2216 	GPtrArray *probs;
2217 	GPtrArray *screenshots;
2218 	gboolean ret;
2219 	guint i;
2220 	g_autofree gchar *filename = NULL;
2221 	g_autoptr(AsApp) app = NULL;
2222 
2223 	/* open file */
2224 	app = as_app_new ();
2225 	filename = as_test_get_filename ("success.appdata.xml");
2226 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2227 	g_assert_no_error (error);
2228 	g_assert (ret);
2229 
2230 	/* check success */
2231 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
2232 	g_assert_cmpstr (as_app_get_id (app), ==, "gnome-power-statistics.desktop");
2233 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "0 A.D.");
2234 	g_assert_cmpstr (as_app_get_comment (app, "C"), ==, "Observe power management");
2235 	g_assert_cmpstr (as_app_get_metadata_license (app), ==, "CC0-1.0 AND CC-BY-3.0");
2236 	g_assert_cmpstr (as_app_get_update_contact (app), ==, "richard@hughsie.com");
2237 	g_assert_cmpstr (as_app_get_project_group (app), ==, "GNOME");
2238 	g_assert_cmpstr (as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE), ==,
2239 			 "http://www.gnome.org/projects/gnome-power-manager/");
2240 	g_assert_cmpstr (as_app_get_description (app, "C"), !=, NULL);
2241 	g_assert_cmpint (as_app_get_description_size (app), ==, 1);
2242 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NO_NETWORK, &error);
2243 	g_assert_no_error (error);
2244 	g_assert (probs != NULL);
2245 	for (i = 0; i < probs->len; i++) {
2246 		problem = g_ptr_array_index (probs, i);
2247 		g_print ("%s\n", as_problem_get_message (problem));
2248 	}
2249 	g_assert_cmpint (probs->len, ==, 0);
2250 	g_ptr_array_unref (probs);
2251 
2252 	/* check screenshots were loaded */
2253 	screenshots = as_app_get_screenshots (app);
2254 	g_assert_cmpint (screenshots->len, ==, 1);
2255 	ss = as_app_get_screenshot_default (app);
2256 	g_assert_cmpint (as_screenshot_get_kind (ss), ==, AS_SCREENSHOT_KIND_DEFAULT);
2257 	images = as_screenshot_get_images (ss);
2258 	g_assert_cmpint (images->len, ==, 1);
2259 	im = g_ptr_array_index (images, 0);
2260 	g_assert_cmpstr (as_image_get_url (im), ==, "https://projects.gnome.org/gnome-power-manager/images/gpm-low-batt.png");
2261 	g_assert_cmpint (as_image_get_width (im), ==, 355);
2262 	g_assert_cmpint (as_image_get_height (im), ==, 134);
2263 	g_assert_cmpint (as_image_get_kind (im), ==, AS_IMAGE_KIND_SOURCE);
2264 }
2265 
2266 static void
as_test_app_validate_metainfo_good_func(void)2267 as_test_app_validate_metainfo_good_func (void)
2268 {
2269 	AsProblem *problem;
2270 	GError *error = NULL;
2271 	GPtrArray *probs;
2272 	gboolean ret;
2273 	guint i;
2274 	g_autofree gchar *filename = NULL;
2275 	g_autoptr(AsApp) app = NULL;
2276 
2277 	/* open file */
2278 	app = as_app_new ();
2279 	filename = as_test_get_filename ("example.metainfo.xml");
2280 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2281 	g_assert_no_error (error);
2282 	g_assert (ret);
2283 
2284 	/* check success */
2285 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_ADDON);
2286 	g_assert_cmpstr (as_app_get_id (app), ==, "gedit-code-assistance");
2287 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "Code assistance");
2288 	g_assert_cmpstr (as_app_get_comment (app, "C"), ==, "Code assistance for C, C++ and Objective-C");
2289 	g_assert_cmpstr (as_app_get_metadata_license (app), ==, "CC0-1.0");
2290 	g_assert_cmpstr (as_app_get_project_license (app), ==, "GPL-3.0+");
2291 	g_assert_cmpstr (as_app_get_update_contact (app), ==, "richard@hughsie.com");
2292 	g_assert_cmpstr (as_app_get_url_item (app, AS_URL_KIND_HOMEPAGE), ==,
2293 			 "http://projects.gnome.org/gedit");
2294 	g_assert_cmpstr (as_app_get_description (app, "C"), ==, NULL);
2295 
2296 	/* validate */
2297 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NO_NETWORK, &error);
2298 	g_assert_no_error (error);
2299 	g_assert (probs != NULL);
2300 	for (i = 0; i < probs->len; i++) {
2301 		problem = g_ptr_array_index (probs, i);
2302 		g_warning ("%s", as_problem_get_message (problem));
2303 	}
2304 	g_assert_cmpint (probs->len, ==, 0);
2305 	g_ptr_array_unref (probs);
2306 }
2307 
2308 static void
as_test_app_validate_intltool_func(void)2309 as_test_app_validate_intltool_func (void)
2310 {
2311 	AsProblem *problem;
2312 	GError *error = NULL;
2313 	GPtrArray *probs;
2314 	gboolean ret;
2315 	guint i;
2316 	g_autofree gchar *filename = NULL;
2317 	g_autoptr(AsApp) app = NULL;
2318 
2319 	/* open file */
2320 	app = as_app_new ();
2321 	filename = as_test_get_filename ("intltool.appdata.xml.in");
2322 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2323 	g_assert_no_error (error);
2324 	g_assert (ret);
2325 
2326 	/* check success */
2327 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
2328 	g_assert_cmpstr (as_app_get_id (app), ==, "gnome-power-statistics.desktop");
2329 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "0 A.D.");
2330 	g_assert_cmpstr (as_app_get_comment (app, "C"), ==, "Observe power management");
2331 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NO_NETWORK, &error);
2332 	g_assert_no_error (error);
2333 	g_assert (probs != NULL);
2334 	for (i = 0; i < probs->len; i++) {
2335 		problem = g_ptr_array_index (probs, i);
2336 		g_warning ("%s", as_problem_get_message (problem));
2337 	}
2338 	g_assert_cmpint (probs->len, ==, 0);
2339 	g_ptr_array_unref (probs);
2340 }
2341 
2342 static void
as_test_app_translated_func(void)2343 as_test_app_translated_func (void)
2344 {
2345 	GError *error = NULL;
2346 	gboolean ret;
2347 	g_autofree gchar *filename = NULL;
2348 	g_autoptr(AsApp) app = NULL;
2349 
2350 	/* open file */
2351 	app = as_app_new ();
2352 	filename = as_test_get_filename ("translated.appdata.xml");
2353 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2354 	g_assert_no_error (error);
2355 	g_assert (ret);
2356 
2357 	/* check success */
2358 	g_assert_cmpstr (as_app_get_description (app, "C"), ==, "<p>Awesome</p>");
2359 	g_assert_cmpstr (as_app_get_description (app, "pl"), ==, "<p>Asomeski</p>");
2360 	g_assert_cmpint (as_app_get_description_size (app), ==, 2);
2361 }
2362 
2363 static void
as_test_app_validate_file_bad_func(void)2364 as_test_app_validate_file_bad_func (void)
2365 {
2366 	AsProblem *problem;
2367 	GError *error = NULL;
2368 	gboolean ret;
2369 	guint i;
2370 	g_autofree gchar *filename = NULL;
2371 	g_autoptr(AsApp) app = NULL;
2372 	g_autoptr(GPtrArray) probs = NULL;
2373 	g_autoptr(GPtrArray) probs2 = NULL;
2374 
2375 	/* open file */
2376 	app = as_app_new ();
2377 	filename = as_test_get_filename ("broken.appdata.xml");
2378 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2379 	g_assert_no_error (error);
2380 	g_assert (ret);
2381 
2382 	g_assert_cmpstr (as_app_get_description (app, "C"), !=, NULL);
2383 	g_assert_cmpint (as_app_get_description_size (app), ==, 1);
2384 
2385 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NONE, &error);
2386 	g_assert_no_error (error);
2387 	g_assert (probs != NULL);
2388 	for (i = 0; i < probs->len; i++) {
2389 		problem = g_ptr_array_index (probs, i);
2390 		g_debug ("%s", as_problem_get_message (problem));
2391 	}
2392 
2393 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
2394 				    "<component> has invalid type attribute");
2395 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2396 				    "<metadata_license> is not valid");
2397 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2398 				    "<project_license> is not valid");
2399 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2400 				    "<url> does not start with 'http://'");
2401 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_MARKUP_INVALID,
2402 				    "<?xml> header not found");
2403 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2404 				    "<name> cannot end in '.'");
2405 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2406 				    "Not enough <screenshot> tags");
2407 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2408 				    "<li> is too short");
2409 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2410 				    "<ul> cannot start a description");
2411 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2412 				    "<ul> cannot start a description");
2413 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2414 				    "<p> should not start with 'This application'");
2415 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2416 				    "<p> is too short");
2417 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2418 				    "<p> cannot contain a hyperlink");
2419 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2420 				    "<release> description should be "
2421 				    "prose and not contain hyperlinks");
2422 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
2423 				    "<release> timestamp should be a UNIX time");
2424 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_MISSING,
2425 				    "<release> has no version");
2426 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_MISSING,
2427 				    "<release> has no timestamp");
2428 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2429 				    "<release> versions are not in order");
2430 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2431 				    "<release> version was duplicated");
2432 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
2433 				    "<release> timestamp is in the future");
2434 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_MARKUP_INVALID,
2435 				    "<id> has invalid character");
2436 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_ATTRIBUTE_INVALID,
2437 				    "<launchable> has invalid type attribute");
2438 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_VALUE_MISSING,
2439 				    "<launchable> missing value");
2440 	g_assert_cmpint (probs->len, ==, 23);
2441 
2442 	/* again, harder */
2443 	probs2 = as_app_validate (app, AS_APP_VALIDATE_FLAG_STRICT, &error);
2444 	g_assert_no_error (error);
2445 	g_assert (probs2 != NULL);
2446 	as_test_app_validate_check (probs2, AS_PROBLEM_KIND_TAG_INVALID,
2447 				    "XML data contains unknown tag");
2448 	g_assert_cmpint (probs2->len, ==, 37);
2449 }
2450 
2451 static void
as_test_app_validate_meta_bad_func(void)2452 as_test_app_validate_meta_bad_func (void)
2453 {
2454 	AsProblem *problem;
2455 	GError *error = NULL;
2456 	gboolean ret;
2457 	guint i;
2458 	g_autofree gchar *filename = NULL;
2459 	g_autoptr(AsApp) app = NULL;
2460 	g_autoptr(GPtrArray) probs = NULL;
2461 
2462 	/* open file */
2463 	app = as_app_new ();
2464 	filename = as_test_get_filename ("broken.metainfo.xml");
2465 	ret = as_app_parse_file (app, filename, AS_APP_PARSE_FLAG_NONE, &error);
2466 	g_assert_no_error (error);
2467 	g_assert (ret);
2468 
2469 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NONE, &error);
2470 	g_assert_no_error (error);
2471 	g_assert (probs != NULL);
2472 	for (i = 0; i < probs->len; i++) {
2473 		problem = g_ptr_array_index (probs, i);
2474 		g_debug ("%s", as_problem_get_message (problem));
2475 	}
2476 	g_assert_cmpint (probs->len, ==, 6);
2477 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2478 				    "<name> is not present");
2479 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2480 				    "<summary> is not present");
2481 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2482 				    "<url> is not present");
2483 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2484 				    "<extends> is not present");
2485 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2486 				    "<metadata_license> is not present");
2487 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2488 				    "<pkgname> not allowed in metainfo");
2489 }
2490 
2491 static void
as_test_store_local_appdata_func(void)2492 as_test_store_local_appdata_func (void)
2493 {
2494 	AsApp *app;
2495 	AsFormat *format;
2496 	GError *error = NULL;
2497 	gboolean ret;
2498 	g_autofree gchar *filename = NULL;
2499 	g_autofree gchar *filename_full = NULL;
2500 	g_autofree gchar *canonical_filename;
2501 	g_autoptr(AsStore) store = NULL;
2502 
2503 	/* this are the warnings expected */
2504 #ifdef _WIN32
2505 	g_test_expect_message (G_LOG_DOMAIN,
2506 			       G_LOG_LEVEL_WARNING,
2507 			       "ignoring description '*' from *\\broken.appdata.xml: Unknown tag '_p'");
2508 #else
2509 	g_test_expect_message (G_LOG_DOMAIN,
2510 			       G_LOG_LEVEL_WARNING,
2511 			       "ignoring description '*' from */broken.appdata.xml: Unknown tag '_p'");
2512 #endif
2513 
2514 	/* open test store */
2515 #ifdef _WIN32
2516 	g_setenv ("XDG_DATA_DIRS", "/usr/share/", TRUE);
2517 #endif
2518 	store = as_store_new ();
2519 	filename = as_test_get_filename (".");
2520 	as_store_set_destdir (store, filename);
2521 	ret = as_store_load (store, AS_STORE_LOAD_FLAG_APPDATA, NULL, &error);
2522 	g_assert_no_error (error);
2523 	g_assert (ret);
2524 	g_assert_cmpint (as_store_get_size (store), ==, 1);
2525 
2526 	/* make sure app is valid */
2527 	app = as_store_get_app_by_id (store, "broken.desktop");
2528 	g_assert (app != NULL);
2529 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "Broken");
2530 
2531 	/* check format */
2532 	format = as_app_get_format_by_kind (app, AS_FORMAT_KIND_APPDATA);
2533 	g_assert (format != NULL);
2534 	filename_full = g_build_filename (filename,
2535 					  "usr/share/appdata/broken.appdata.xml",
2536 					  NULL);
2537 	canonical_filename = g_canonicalize_filename (filename_full, NULL);
2538 	g_assert_cmpstr (as_format_get_filename (format), ==, canonical_filename);
2539 }
2540 
2541 static void
as_test_store_validate_func(void)2542 as_test_store_validate_func (void)
2543 {
2544 	GError *error = NULL;
2545 	gboolean ret;
2546 	g_autofree gchar *filename = NULL;
2547 	g_autoptr(AsStore) store = NULL;
2548 	g_autoptr(GFile) file = NULL;
2549 	g_autoptr(GPtrArray) probs = NULL;
2550 
2551 	/* open file */
2552 	store = as_store_new ();
2553 	filename = as_test_get_filename ("validate.xml.gz");
2554 	file = g_file_new_for_path (filename);
2555 	ret = as_store_from_file (store, file, NULL, NULL, &error);
2556 	g_assert_no_error (error);
2557 	g_assert (ret);
2558 	g_assert_cmpint (as_store_get_size (store), ==, 1);
2559 
2560 	probs = as_store_validate (store, AS_APP_VALIDATE_FLAG_NONE, &error);
2561 	g_assert_no_error (error);
2562 	g_assert (probs != NULL);
2563 	g_assert_cmpint (probs->len, ==, 4);
2564 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2565 				    "metadata version is v0.1 and "
2566 				    "<screenshots> only introduced in v0.4");
2567 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2568 				    "metadata version is v0.1 and "
2569 				    "<compulsory_for_desktop> only introduced in v0.4");
2570 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2571 				    "metadata version is v0.1 and "
2572 				    "<project_group> only introduced in v0.4");
2573 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2574 				    "metadata version is v0.1 and "
2575 				    "<description> markup was introduced in v0.6");
2576 }
2577 
2578 static void
_as_app_add_format_kind(AsApp * app,AsFormatKind kind)2579 _as_app_add_format_kind (AsApp *app, AsFormatKind kind)
2580 {
2581 	g_autoptr(AsFormat) format = as_format_new ();
2582 	as_format_set_kind (format, kind);
2583 	as_app_add_format (app, format);
2584 }
2585 
2586 static void
as_test_app_validate_style_func(void)2587 as_test_app_validate_style_func (void)
2588 {
2589 	AsProblem *problem;
2590 	GError *error = NULL;
2591 	guint i;
2592 	g_autoptr(AsApp) app = NULL;
2593 	g_autoptr(GPtrArray) probs = NULL;
2594 
2595 	app = as_app_new ();
2596 	as_app_add_url (app, AS_URL_KIND_UNKNOWN, "dave.com");
2597 	as_app_set_id (app, "dave.exe");
2598 	as_app_set_kind (app, AS_APP_KIND_DESKTOP);
2599 	_as_app_add_format_kind (app, AS_FORMAT_KIND_APPDATA);
2600 	as_app_set_metadata_license (app, "BSD");
2601 	as_app_set_project_license (app, "GPL-2.0+");
2602 	as_app_set_name (app, "C", "Test app name that is very long indeed although Rob forced me to relax the requirements.");
2603 	as_app_set_comment (app, "C", "Awesome");
2604 	as_app_set_update_contact (app, "someone_who_cares@upstream_project.org");
2605 
2606 	probs = as_app_validate (app, AS_APP_VALIDATE_FLAG_NONE, &error);
2607 	g_assert_no_error (error);
2608 	g_assert (probs != NULL);
2609 	for (i = 0; i < probs->len; i++) {
2610 		problem = g_ptr_array_index (probs, i);
2611 		g_debug ("%s", as_problem_get_message (problem));
2612 	}
2613 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2614 				    "<update_contact> is still set to a dummy value");
2615 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2616 				    "<url> type invalid");
2617 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2618 				    "<url> does not start with 'http://'");
2619 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_INVALID,
2620 				    "<metadata_license> is not valid");
2621 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2622 				    "<name> is too long");
2623 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2624 				    "<name> cannot end in '.'");
2625 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2626 				    "<summary> is too short");
2627 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_STYLE_INCORRECT,
2628 				    "Not enough <screenshot> tags");
2629 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2630 				    "<url> is not present");
2631 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2632 				    "<content_rating> required");
2633 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2634 				    "<release> required");
2635 	as_test_app_validate_check (probs, AS_PROBLEM_KIND_TAG_MISSING,
2636 				    "<description> required");
2637 	g_assert_cmpint (probs->len, ==, 12);
2638 }
2639 
2640 static void
as_test_app_parse_file_desktop_func(void)2641 as_test_app_parse_file_desktop_func (void)
2642 {
2643 	AsFormat *format;
2644 	AsIcon *ic;
2645 	GError *error = NULL;
2646 	gboolean ret;
2647 	g_autofree gchar *filename = NULL;
2648 	g_autoptr(AsApp) app = NULL;
2649 
2650 	/* create an AsApp from a desktop file */
2651 	app = as_app_new ();
2652 	filename = as_test_get_filename ("example.desktop");
2653 	ret = as_app_parse_file (app,
2654 				 filename,
2655 				 AS_APP_PARSE_FLAG_ALLOW_VETO,
2656 				 &error);
2657 	g_assert_no_error (error);
2658 	g_assert (ret);
2659 
2660 	/* test things we found */
2661 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "Color Profile Viewer");
2662 	g_assert_cmpstr (as_app_get_name (app, "pl"), ==, "Podgląd profilu kolorów");
2663 	g_assert_cmpstr (as_app_get_comment (app, "C"), ==,
2664 		"Inspect and compare installed color profiles");
2665 	g_assert_cmpstr (as_app_get_comment (app, "pl"), ==,
2666 		"Badanie i porównywanie zainstalowanych profilów kolorów");
2667 	g_assert_cmpint (as_app_get_vetos(app)->len, ==, 1);
2668 	g_assert_cmpstr (as_app_get_project_group (app), ==, NULL);
2669 	g_assert_cmpint (as_app_get_categories(app)->len, ==, 1);
2670 	g_assert_cmpint (as_app_get_keywords(app, NULL)->len, ==, 2);
2671 	g_assert_cmpint (as_app_get_keywords(app, "pl")->len, ==, 1);
2672 	g_assert (as_app_has_category (app, "System"));
2673 	g_assert (!as_app_has_category (app, "NotGoingToExist"));
2674 
2675 	/* check format */
2676 	g_assert_cmpint (as_app_get_formats(app)->len, ==, 1);
2677 	format = as_app_get_format_by_kind (app, AS_FORMAT_KIND_DESKTOP);
2678 	g_assert (format != NULL);
2679 	g_assert_cmpstr (as_format_get_filename (format), ==, filename);
2680 
2681 	/* check icons */
2682 	g_assert_cmpint (as_app_get_icons(app)->len, ==, 1);
2683 	ic = as_app_get_icon_default (app);
2684 	g_assert (ic != NULL);
2685 	g_assert_cmpstr (as_icon_get_name (ic), ==, "audio-input-microphone");
2686 	g_assert_cmpint (as_icon_get_kind (ic), ==, AS_ICON_KIND_STOCK);
2687 	g_assert_cmpint (as_icon_get_width (ic), ==, 0);
2688 	g_assert_cmpint (as_icon_get_height (ic), ==, 0);
2689 
2690 	/* reparse with heuristics */
2691 	ret = as_app_parse_file (app,
2692 				 filename,
2693 				 AS_APP_PARSE_FLAG_ALLOW_VETO |
2694 				 AS_APP_PARSE_FLAG_USE_HEURISTICS,
2695 				 &error);
2696 	g_assert_no_error (error);
2697 	g_assert (ret);
2698 	g_assert_cmpstr (as_app_get_project_group (app), ==, "GNOME");
2699 	g_free (filename);
2700 
2701 	/* reparse with invalid file */
2702 	filename = as_test_get_filename ("settings-panel.desktop");
2703 	ret = as_app_parse_file (app, filename, 0, &error);
2704 	g_assert_error (error, AS_APP_ERROR, AS_APP_ERROR_INVALID_TYPE);
2705 	g_assert (!ret);
2706 	g_clear_error (&error);
2707 }
2708 
2709 static void
as_test_app_no_markup_func(void)2710 as_test_app_no_markup_func (void)
2711 {
2712 	GError *error = NULL;
2713 	AsNode *n;
2714 	AsNode *root;
2715 	GString *xml;
2716 	gboolean ret;
2717 	const gchar *src =
2718 		"<component type=\"desktop\">\n"
2719 		"<id>org.gnome.Software.desktop</id>\n"
2720 		"<description>Software is awesome:\n\n * Bada\n * Boom!</description>\n"
2721 		"<launchable type=\"desktop-id\">org.gnome.Software.desktop</launchable>\n"
2722 		"</component>\n";
2723 	g_autoptr(AsNodeContext) ctx = NULL;
2724 	g_autoptr(AsApp) app = NULL;
2725 
2726 	app = as_app_new ();
2727 
2728 	/* to object */
2729 	root = as_node_from_xml (src,
2730 				 AS_NODE_FROM_XML_FLAG_LITERAL_TEXT,
2731 				 &error);
2732 	g_assert_no_error (error);
2733 	g_assert (root != NULL);
2734 	n = as_node_find (root, "component");
2735 	g_assert (n != NULL);
2736 	ctx = as_node_context_new ();
2737 	ret = as_app_node_parse (app, n, ctx, &error);
2738 	g_assert_no_error (error);
2739 	g_assert (ret);
2740 
2741 	/* verify */
2742 	g_assert_cmpstr (as_app_get_id (app), ==, "org.gnome.Software.desktop");
2743 	g_assert_cmpstr (as_app_get_description (app, "C"), ==,
2744 		"Software is awesome:\n\n * Bada\n * Boom!");
2745 	as_node_unref (root);
2746 
2747 	/* back to node */
2748 	root = as_node_new ();
2749 	as_node_context_set_version (ctx, 0.4);
2750 	n = as_app_node_insert (app, root, ctx);
2751 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
2752 	ret = as_test_compare_lines (xml->str, src, &error);
2753 	g_assert_no_error (error);
2754 	g_assert (ret);
2755 	g_string_free (xml, TRUE);
2756 	as_node_unref (root);
2757 }
2758 
2759 static void
as_test_node_reflow_text_func(void)2760 as_test_node_reflow_text_func (void)
2761 {
2762 	AsRefString *tmp;
2763 
2764 	/* plain text */
2765 	tmp = as_node_reflow_text ("Dave", -1);
2766 	g_assert_cmpstr (tmp, ==, "Dave");
2767 	as_ref_string_unref (tmp);
2768 
2769 	/* stripping */
2770 	tmp = as_node_reflow_text ("    Dave    ", -1);
2771 	g_assert_cmpstr (tmp, ==, "Dave");
2772 	as_ref_string_unref (tmp);
2773 
2774 	/* paragraph */
2775 	tmp = as_node_reflow_text ("Dave\n\nSoftware", -1);
2776 	g_assert_cmpstr (tmp, ==, "Dave\n\nSoftware");
2777 	as_ref_string_unref (tmp);
2778 
2779 	/* pathological */
2780 	tmp = as_node_reflow_text (
2781 		"\n"
2782 		"  Dave: \n"
2783 		"  Software is \n"
2784 		"  awesome.\n\n\n"
2785 		"  Okay!\n", -1);
2786 	g_assert_cmpstr (tmp, ==, "Dave: Software is awesome.\n\nOkay!");
2787 	as_ref_string_unref (tmp);
2788 }
2789 
2790 static void
as_test_node_sort_func(void)2791 as_test_node_sort_func (void)
2792 {
2793 	g_autoptr(GError) error = NULL;
2794 	g_autoptr(AsNode) root = NULL;
2795 	g_autoptr(GString) str = NULL;
2796 
2797 	root = as_node_from_xml ("<d>ddd</d><c>ccc</c><b>bbb</b><a>aaa</a>", 0, &error);
2798 	g_assert_no_error (error);
2799 	g_assert (root != NULL);
2800 
2801 	/* verify that the tags are sorted */
2802 	str = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_SORT_CHILDREN);
2803 	g_assert_cmpstr (str->str, ==, "<a>aaa</a><b>bbb</b><c>ccc</c><d>ddd</d>");
2804 }
2805 
2806 static void
as_test_node_func(void)2807 as_test_node_func (void)
2808 {
2809 	AsNode *n1;
2810 	AsNode *n2;
2811 	g_autoptr(AsNode) root = NULL;
2812 
2813 	/* create a simple tree */
2814 	root = as_node_new ();
2815 	n1 = as_node_insert (root, "apps", NULL, 0,
2816 			     "version", "2",
2817 			     NULL);
2818 	g_assert (n1 != NULL);
2819 	g_assert_cmpstr (as_node_get_name (n1), ==, "apps");
2820 	g_assert_cmpstr (as_node_get_data (n1), ==, NULL);
2821 	g_assert_cmpstr (as_node_get_attribute (n1, "version"), ==, "2");
2822 	g_assert_cmpint (as_node_get_attribute_as_int (n1, "version"), ==, 2);
2823 	g_assert_cmpstr (as_node_get_attribute (n1, "xxx"), ==, NULL);
2824 	n2 = as_node_insert (n1, "id", "hal", 0, NULL);
2825 	g_assert (n2 != NULL);
2826 	g_assert_cmpint (as_node_get_tag (n2), ==, AS_TAG_ID);
2827 	g_assert_cmpstr (as_node_get_data (n2), ==, "hal");
2828 	g_assert_cmpstr (as_node_get_attribute (n2, "xxx"), ==, NULL);
2829 
2830 	/* remove an attribute */
2831 	as_node_remove_attribute (n1, "version");
2832 	g_assert_cmpstr (as_node_get_attribute (n1, "version"), ==, NULL);
2833 
2834 	/* replace some node data */
2835 	as_node_set_data (n2, "udev", 0);
2836 	g_assert_cmpstr (as_node_get_data (n2), ==, "udev");
2837 	as_node_add_attribute (n2, "enabled", "true");
2838 	g_assert_cmpstr (as_node_get_attribute (n2, "enabled"), ==, "true");
2839 
2840 	/* find the n2 node */
2841 	n2 = as_node_find (root, "apps/id");
2842 	g_assert (n2 != NULL);
2843 	g_assert_cmpint (as_node_get_tag (n2), ==, AS_TAG_ID);
2844 
2845 	/* don't find invalid nodes */
2846 	n2 = as_node_find (root, "apps/id/xxx");
2847 	g_assert (n2 == NULL);
2848 	n2 = as_node_find (root, "apps/xxx");
2849 	g_assert (n2 == NULL);
2850 	n2 = as_node_find (root, "apps//id");
2851 	g_assert (n2 == NULL);
2852 }
2853 
2854 static void
as_test_node_xml_func(void)2855 as_test_node_xml_func (void)
2856 {
2857 	const gchar *valid = "<!--\n"
2858 			     "  this documents foo\n"
2859 			     "-->"
2860 			     "<foo>"
2861 			     "<!-- this documents bar -->"
2862 			     "<bar key=\"value\">baz</bar>"
2863 			     "</foo>";
2864 	GError *error = NULL;
2865 	AsNode *n2;
2866 	AsNode *root;
2867 	GString *xml;
2868 	GHashTable *hashtable;
2869 
2870 	/* invalid XML */
2871 	root = as_node_from_xml ("<moo>", 0, &error);
2872 	g_assert (root == NULL);
2873 	g_assert_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED);
2874 	g_clear_error (&error);
2875 	root = as_node_from_xml ("<foo></bar>", 0, &error);
2876 	g_assert (root == NULL);
2877 	g_assert_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED);
2878 	g_clear_error (&error);
2879 
2880 	/* valid XML */
2881 	root = as_node_from_xml (valid, 0, &error);
2882 	g_assert_no_error (error);
2883 	g_assert (root != NULL);
2884 
2885 	n2 = as_node_find (root, "foo/bar");
2886 	g_assert (n2 != NULL);
2887 	g_assert_cmpstr (as_node_get_data (n2), ==, "baz");
2888 	g_assert_cmpstr (as_node_get_comment (n2), ==, NULL);
2889 	g_assert_cmpstr (as_node_get_attribute (n2, "key"), ==, "value");
2890 
2891 	/* convert back */
2892 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
2893 	g_assert (xml != NULL);
2894 	g_assert_cmpstr (xml->str, ==, "<foo><bar key=\"value\">baz</bar></foo>");
2895 	g_string_free (xml, TRUE);
2896 
2897 	/* with newlines */
2898 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
2899 	g_assert (xml != NULL);
2900 	g_assert_cmpstr (xml->str, ==,
2901 		"<foo>\n<bar key=\"value\">baz</bar>\n</foo>\n");
2902 	g_string_free (xml, TRUE);
2903 
2904 	/* fully formatted */
2905 	xml = as_node_to_xml (root,
2906 			      AS_NODE_TO_XML_FLAG_ADD_HEADER |
2907 			      AS_NODE_TO_XML_FLAG_FORMAT_INDENT |
2908 			      AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
2909 	g_assert (xml != NULL);
2910 	g_assert_cmpstr (xml->str, ==,
2911 		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2912 		"<foo>\n  <bar key=\"value\">baz</bar>\n</foo>\n");
2913 	g_string_free (xml, TRUE);
2914 	as_node_unref (root);
2915 
2916 	/* convert all the children to XML */
2917 	root = as_node_from_xml ("<p>One</p><p>Two</p>", 0, &error);
2918 	g_assert_no_error (error);
2919 	g_assert (root != NULL);
2920 	g_assert_cmpint (g_node_n_nodes (root, G_TRAVERSE_ALL), ==, 3);
2921 	xml = as_node_to_xml (root->children, AS_NODE_TO_XML_FLAG_INCLUDE_SIBLINGS);
2922 	g_assert (xml != NULL);
2923 	g_assert_cmpstr (xml->str, ==, "<p>One</p><p>Two</p>");
2924 	g_string_free (xml, TRUE);
2925 	as_node_unref (root);
2926 
2927 	/* keep comments */
2928 	root = as_node_from_xml (valid,
2929 				 AS_NODE_FROM_XML_FLAG_KEEP_COMMENTS,
2930 				 &error);
2931 	g_assert_no_error (error);
2932 	g_assert (root != NULL);
2933 	n2 = as_node_find (root, "foo/bar");
2934 	g_assert (n2 != NULL);
2935 	g_assert_cmpstr (as_node_get_comment (n2), ==, "this documents bar");
2936 	n2 = as_node_find (root, "foo");
2937 	g_assert (n2 != NULL);
2938 	g_assert_cmpstr (as_node_get_comment (n2), ==, "this documents foo");
2939 	as_node_unref (root);
2940 
2941 	/* keep comment formatting */
2942 	root = as_node_from_xml (valid,
2943 				 AS_NODE_FROM_XML_FLAG_KEEP_COMMENTS |
2944 				 AS_NODE_FROM_XML_FLAG_LITERAL_TEXT,
2945 				 &error);
2946 	g_assert_no_error (error);
2947 	g_assert (root != NULL);
2948 	n2 = as_node_find (root, "foo/bar");
2949 	g_assert (n2 != NULL);
2950 	g_assert_cmpstr (as_node_get_comment (n2), ==, " this documents bar ");
2951 	n2 = as_node_find (root, "foo");
2952 	g_assert (n2 != NULL);
2953 	g_assert_cmpstr (as_node_get_comment (n2), ==, "\n  this documents foo\n");
2954 
2955 	/* check comments were preserved */
2956 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
2957 	g_assert (xml != NULL);
2958 	g_assert_cmpstr (xml->str, ==, valid);
2959 	g_string_free (xml, TRUE);
2960 	as_node_unref (root);
2961 
2962 	/* check comments are appended together */
2963 	root = as_node_from_xml ("<!-- 1st -->\n<!-- 2nd -->\n<foo/>\n",
2964 				 AS_NODE_FROM_XML_FLAG_KEEP_COMMENTS |
2965 				 AS_NODE_FROM_XML_FLAG_LITERAL_TEXT,
2966 				 &error);
2967 	g_assert_no_error (error);
2968 	g_assert (root != NULL);
2969 	n2 = as_node_find (root, "foo");
2970 	g_assert (n2 != NULL);
2971 	g_assert_cmpstr (as_node_get_comment (n2), ==, " 1st <&> 2nd ");
2972 
2973 	/* check comments were output as two blocks */
2974 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
2975 	g_assert (xml != NULL);
2976 	g_assert_cmpstr (xml->str, ==, "<!-- 1st -->\n<!-- 2nd -->\n<foo/>\n");
2977 	g_string_free (xml, TRUE);
2978 	as_node_unref (root);
2979 
2980 	/* invalid child of ul */
2981 	root = as_node_from_xml ("<ul><ul></ul></ul>", 0, &error);
2982 	g_assert_no_error (error);
2983 	g_assert (root != NULL);
2984 	hashtable = as_node_get_localized_unwrap (root, &error);
2985 	g_assert_error (error, AS_NODE_ERROR, AS_NODE_ERROR_INVALID_MARKUP);
2986 	g_assert_cmpstr (error->message, ==, "Tag ul in ul invalid");
2987 	g_clear_error (&error);
2988 	g_assert (hashtable == NULL);
2989 }
2990 
2991 static void
as_test_node_hash_func(void)2992 as_test_node_hash_func (void)
2993 {
2994 	GHashTable *hash;
2995 	AsNode *n1;
2996 	AsNode *root;
2997 	GString *xml;
2998 
2999 	/* test un-swapped hash */
3000 	root = as_node_new ();
3001 	n1 = as_node_insert (root, "app", NULL, 0, NULL);
3002 	hash = g_hash_table_new (g_str_hash, g_str_equal);
3003 	g_hash_table_insert (hash, (gpointer) "a", (gpointer) "1");
3004 	g_hash_table_insert (hash, (gpointer) "b", (gpointer) "2");
3005 	as_node_insert_hash (n1, "md1", "key", hash, 0);
3006 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
3007 	g_assert (xml != NULL);
3008 	g_assert_cmpstr (xml->str, ==,
3009 		"<app><md1 key=\"a\">1</md1><md1 key=\"b\">2</md1></app>");
3010 	g_string_free (xml, TRUE);
3011 	g_hash_table_unref (hash);
3012 	as_node_unref (root);
3013 
3014 	/* test swapped hash */
3015 	root = as_node_new ();
3016 	n1 = as_node_insert (root, "app", NULL, AS_NODE_INSERT_FLAG_NONE, NULL);
3017 	hash = g_hash_table_new (g_str_hash, g_str_equal);
3018 	g_hash_table_insert (hash, (gpointer) "a", (gpointer) "1");
3019 	g_hash_table_insert (hash, (gpointer) "b", (gpointer) "2");
3020 	as_node_insert_hash (n1, "md1", "key", hash, AS_NODE_INSERT_FLAG_SWAPPED);
3021 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
3022 	g_assert (xml != NULL);
3023 	g_assert_cmpstr (xml->str, ==,
3024 		"<app><md1 key=\"1\">a</md1><md1 key=\"2\">b</md1></app>");
3025 	g_string_free (xml, TRUE);
3026 	g_hash_table_unref (hash);
3027 	as_node_unref (root);
3028 }
3029 
3030 static void
as_test_node_localized_func(void)3031 as_test_node_localized_func (void)
3032 {
3033 	GHashTable *hash;
3034 	AsNode *n1;
3035 	AsNode *root;
3036 	GString *xml;
3037 
3038 	/* writing localized values */
3039 	root = as_node_new ();
3040 	n1 = as_node_insert (root, "app", NULL, 0, NULL);
3041 	hash = g_hash_table_new (g_str_hash, g_str_equal);
3042 	g_hash_table_insert (hash, (gpointer) "C", (gpointer) "color");
3043 	g_hash_table_insert (hash, (gpointer) "en_XX", (gpointer) "colour");
3044 	as_node_insert_localized (n1, "name", hash, AS_NODE_INSERT_FLAG_NONE);
3045 	xml = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
3046 	g_assert (xml != NULL);
3047 	g_assert_cmpstr (xml->str, ==,
3048 		"<app><name>color</name>"
3049 		"<name xml:lang=\"en_XX\">colour</name></app>");
3050 	g_string_free (xml, TRUE);
3051 	g_hash_table_unref (hash);
3052 
3053 	/* get the best locale */
3054 	g_assert_cmpstr (as_node_get_localized_best (n1, "name"), ==, "color");
3055 
3056 	/* get something that isn't there */
3057 	hash = as_node_get_localized (n1, "comment");
3058 	g_assert (hash == NULL);
3059 
3060 	/* read them back */
3061 	hash = as_node_get_localized (n1, "name");
3062 	g_assert (hash != NULL);
3063 	g_assert_cmpint (g_hash_table_size (hash), ==, 2);
3064 	g_assert_cmpstr (g_hash_table_lookup (hash, "C"), ==, "color");
3065 	g_assert_cmpstr (g_hash_table_lookup (hash, "en_XX"), ==, "colour");
3066 	g_hash_table_unref (hash);
3067 
3068 	as_node_unref (root);
3069 }
3070 
3071 static void
as_test_node_localized_wrap_func(void)3072 as_test_node_localized_wrap_func (void)
3073 {
3074 	GError *error = NULL;
3075 	AsNode *n1;
3076 	const gchar *xml =
3077 		"<description>"
3078 		" <p>Hi</p>"
3079 		" <p xml:lang=\"pl\">Czesc</p>"
3080 		" <ul>"
3081 		"  <li>First</li>"
3082 		"  <li xml:lang=\"pl\">Pierwszy</li>"
3083 		"  <li xml:lang=\"en_GB\">Hi</li>"
3084 		" </ul>"
3085 		"</description>";
3086 	g_autoptr(GHashTable) hash = NULL;
3087 	g_autoptr(AsNode) root = NULL;
3088 
3089 	root = as_node_from_xml (xml, 0, &error);
3090 	g_assert_no_error (error);
3091 	g_assert (root != NULL);
3092 
3093 	/* unwrap the locale data */
3094 	n1 = as_node_find (root, "description");
3095 	g_assert (n1 != NULL);
3096 	hash = as_node_get_localized_unwrap (n1, &error);
3097 	g_assert_no_error (error);
3098 	g_assert (hash != NULL);
3099 	g_assert_cmpint (g_hash_table_size (hash), ==, 3);
3100 	g_assert_cmpstr (g_hash_table_lookup (hash, "C"), ==,
3101 		"<p>Hi</p><ul><li>First</li></ul>");
3102 	g_assert_cmpstr (g_hash_table_lookup (hash, "pl"), ==,
3103 		"<p>Czesc</p><ul><li>Pierwszy</li></ul>");
3104 	g_assert_cmpstr (g_hash_table_lookup (hash, "en_GB"), ==,
3105 		"<ul><li>Hi</li></ul>");
3106 }
3107 
3108 static void
as_test_node_intltool_func(void)3109 as_test_node_intltool_func (void)
3110 {
3111 	AsNode *n;
3112 	g_autoptr(AsNode) root = NULL;
3113 	g_autoptr(GString) str = NULL;
3114 
3115 	root = as_node_new ();
3116 	n = as_node_insert (root, "description", NULL, AS_NODE_INSERT_FLAG_NONE, NULL);
3117 	as_node_insert (n, "name", "Hello",
3118 			AS_NODE_INSERT_FLAG_MARK_TRANSLATABLE, NULL);
3119 
3120 	/* verify that the tags get prefixed with '_' */
3121 	str = as_node_to_xml (root, AS_NODE_TO_XML_FLAG_NONE);
3122 	g_assert_cmpstr (str->str, ==, "<description><_name>Hello</_name></description>");
3123 }
3124 
3125 static void
as_test_node_localized_wrap2_func(void)3126 as_test_node_localized_wrap2_func (void)
3127 {
3128 	GError *error = NULL;
3129 	AsNode *n1;
3130 	const gchar *xml =
3131 		"<description>"
3132 		" <p>Hi</p>"
3133 		" <p xml:lang=\"pl\">Czesc</p>"
3134 		" <ul>"
3135 		"  <li>First</li>"
3136 		"  <li>Second</li>"
3137 		" </ul>"
3138 		" <ul xml:lang=\"pl\">"
3139 		"  <li>Pierwszy</li>"
3140 		"  <li>Secondski</li>"
3141 		" </ul>"
3142 		"</description>";
3143 	g_autoptr(GHashTable) hash = NULL;
3144 	g_autoptr(AsNode) root = NULL;
3145 
3146 	root = as_node_from_xml (xml, 0, &error);
3147 	g_assert_no_error (error);
3148 	g_assert (root != NULL);
3149 
3150 	/* unwrap the locale data */
3151 	n1 = as_node_find (root, "description");
3152 	g_assert (n1 != NULL);
3153 	hash = as_node_get_localized_unwrap (n1, &error);
3154 	g_assert_no_error (error);
3155 	g_assert (hash != NULL);
3156 	g_assert_cmpint (g_hash_table_size (hash), ==, 2);
3157 	g_assert_cmpstr (g_hash_table_lookup (hash, "C"), ==,
3158 		"<p>Hi</p><ul><li>First</li><li>Second</li></ul>");
3159 	g_assert_cmpstr (g_hash_table_lookup (hash, "pl"), ==,
3160 		"<p>Czesc</p><ul><li>Pierwszy</li><li>Secondski</li></ul>");
3161 
3162 	/* find the Polish first paragraph */
3163 	n1 = as_node_find_with_attribute (root, "description/p", "xml:lang", "pl");
3164 	g_assert (n1 != NULL);
3165 	g_assert_cmpstr (as_node_get_data (n1), ==, "Czesc");
3166 }
3167 
3168 static void
as_test_app_subsume_func(void)3169 as_test_app_subsume_func (void)
3170 {
3171 	AsIcon *ic;
3172 	GList *list;
3173 	g_autoptr(AsApp) app = NULL;
3174 	g_autoptr(AsApp) donor = NULL;
3175 	g_autoptr(AsIcon) icon = NULL;
3176 	g_autoptr(AsIcon) icon2 = NULL;
3177 	g_autoptr(AsScreenshot) ss = NULL;
3178 
3179 	donor = as_app_new ();
3180 	icon = as_icon_new ();
3181 	as_icon_set_name (icon, "some-custom-icon");
3182 	as_icon_set_kind (icon, AS_ICON_KIND_CACHED);
3183 	as_app_add_icon (donor, icon);
3184 	icon2 = as_icon_new ();
3185 	as_icon_set_name (icon2, "gtk-find");
3186 	as_icon_set_kind (icon2, AS_ICON_KIND_STOCK);
3187 	as_app_add_icon (donor, icon2);
3188 	as_app_set_state (donor, AS_APP_STATE_INSTALLED);
3189 	as_app_add_pkgname (donor, "hal");
3190 	as_app_add_language (donor, -1, "en_GB");
3191 	as_app_add_metadata (donor, "donor", "true");
3192 	as_app_add_metadata (donor, "overwrite", "1111");
3193 	as_app_add_keyword (donor, "C", "klass");
3194 	as_app_add_keyword (donor, "pl", "klaski");
3195 	ss = as_screenshot_new ();
3196 	as_app_add_screenshot (donor, ss);
3197 
3198 	/* copy all useful properties */
3199 	app = as_app_new ();
3200 	as_app_add_metadata (app, "overwrite", "2222");
3201 	as_app_add_metadata (app, "recipient", "true");
3202 	as_app_subsume_full (app, donor,
3203 			     AS_APP_SUBSUME_FLAG_NO_OVERWRITE |
3204 			     AS_APP_SUBSUME_FLAG_DEDUPE);
3205 	as_app_add_screenshot (app, ss);
3206 
3207 	g_assert_cmpstr (as_app_get_metadata_item (app, "donor"), ==, "true");
3208 	g_assert_cmpstr (as_app_get_metadata_item (app, "overwrite"), ==, "2222");
3209 	g_assert_cmpstr (as_app_get_metadata_item (donor, "recipient"), ==, NULL);
3210 	g_assert_cmpint (as_app_get_pkgnames(app)->len, ==, 1);
3211 	g_assert_cmpint (as_app_get_state (app), ==, AS_APP_STATE_INSTALLED);
3212 	g_assert_cmpint (as_app_get_keywords(app, "C")->len, ==, 1);
3213 	g_assert_cmpint (as_app_get_keywords(app, "pl")->len, ==, 1);
3214 	list = as_app_get_languages (app);
3215 	g_assert_cmpint (g_list_length (list), ==, 1);
3216 	g_list_free (list);
3217 
3218 	/* check icon */
3219 	g_assert_cmpint (as_app_get_icons(app)->len, ==, 2);
3220 	ic = as_app_get_icon_default (app);
3221 	g_assert (ic != NULL);
3222 	g_assert_cmpstr (as_icon_get_name (ic), ==, "gtk-find");
3223 	g_assert_cmpint (as_icon_get_kind (ic), ==, AS_ICON_KIND_STOCK);
3224 	g_assert_cmpint (as_icon_get_width (ic), ==, 0);
3225 	g_assert_cmpint (as_icon_get_height (ic), ==, 0);
3226 
3227 	/* test both ways */
3228 	as_app_subsume_full (app, donor,
3229 			     AS_APP_SUBSUME_FLAG_BOTH_WAYS |
3230 			     AS_APP_SUBSUME_FLAG_METADATA);
3231 	g_assert_cmpstr (as_app_get_metadata_item (app, "donor"), ==, "true");
3232 	g_assert_cmpstr (as_app_get_metadata_item (app, "recipient"), ==, "true");
3233 	g_assert_cmpstr (as_app_get_metadata_item (donor, "donor"), ==, "true");
3234 	g_assert_cmpstr (as_app_get_metadata_item (donor, "recipient"), ==, "true");
3235 	g_assert_cmpint (as_app_get_screenshots(app)->len, ==, 1);
3236 }
3237 
3238 static void
as_test_app_screenshot_func(void)3239 as_test_app_screenshot_func (void)
3240 {
3241 	AsScreenshot *ss;
3242 	GPtrArray *screenshots;
3243 	g_autoptr(AsApp) app = as_app_new ();
3244 	g_autoptr(AsScreenshot) ss1 = as_screenshot_new ();
3245 	g_autoptr(AsScreenshot) ss2 = as_screenshot_new ();
3246 
3247 	as_screenshot_set_kind (ss1, AS_SCREENSHOT_KIND_DEFAULT);
3248 	as_screenshot_set_caption (ss1, NULL, "bbb");
3249 	as_app_add_screenshot (app, ss1);
3250 
3251 	as_screenshot_set_kind (ss2, AS_SCREENSHOT_KIND_NORMAL);
3252 	as_screenshot_set_caption (ss2, NULL, "aaa");
3253 	as_app_add_screenshot (app, ss2);
3254 
3255 	screenshots = as_app_get_screenshots (app);
3256 	ss = g_ptr_array_index (screenshots, 0);
3257 	g_assert (ss == ss1);
3258 	g_assert_cmpint (as_screenshot_get_kind (ss), ==, AS_SCREENSHOT_KIND_DEFAULT);
3259 	ss = g_ptr_array_index (screenshots, 1);
3260 	g_assert (ss == ss2);
3261 	g_assert_cmpint (as_screenshot_get_kind (ss), ==, AS_SCREENSHOT_KIND_NORMAL);
3262 }
3263 
3264 static void
as_test_app_search_func(void)3265 as_test_app_search_func (void)
3266 {
3267 	const gchar *all[] = { "gnome", "install", "software", NULL };
3268 	const gchar *none[] = { "gnome", "xxx", "software", NULL };
3269 	const gchar *mime[] = { "application/vnd.oasis.opendocument.text", NULL };
3270 	g_auto(GStrv) tokens = NULL;
3271 	g_autoptr(AsApp) app = NULL;
3272 	g_autoptr(GHashTable) search_blacklist = NULL;
3273 	g_autoptr(AsStemmer) stemmer = as_stemmer_new ();
3274 
3275 	app = as_app_new ();
3276 	as_app_set_stemmer (app, stemmer);
3277 	as_app_set_id (app, "org.gnome.Software.desktop");
3278 	as_app_add_pkgname (app, "gnome-software");
3279 	as_app_set_name (app, NULL, "GNOME Software X-Plane");
3280 	as_app_set_comment (app, NULL, "Install and remove software");
3281 	as_app_add_mimetype (app, "application/vnd.oasis.opendocument.text");
3282 	as_app_add_keyword (app, NULL, "awesome");
3283 	as_app_add_keyword (app, NULL, "c++");
3284 	as_app_add_keyword (app, NULL, "d-feet");
3285 
3286 	search_blacklist = g_hash_table_new (g_str_hash, g_str_equal);
3287 	g_hash_table_insert (search_blacklist,
3288 			     (gpointer) "and",
3289 			     GUINT_TO_POINTER (1));
3290 	as_app_set_search_blacklist (app, search_blacklist);
3291 
3292 	g_assert_cmpint (as_app_search_matches (app, "software"), ==, 352);
3293 	g_assert_cmpint (as_app_search_matches (app, "soft"), ==, 88);
3294 	g_assert_cmpint (as_app_search_matches (app, "install"), ==, 32);
3295 	g_assert_cmpint (as_app_search_matches (app, "awesome"), ==, 128);
3296 	g_assert_cmpint (as_app_search_matches (app, "c++"), ==, 128);
3297 	g_assert_cmpint (as_app_search_matches (app, "d-feet"), ==, 128);
3298 	g_assert_cmpint (as_app_search_matches_all (app, (gchar**) all), ==, 352);
3299 	g_assert_cmpint (as_app_search_matches_all (app, (gchar**) none), ==, 0);
3300 	g_assert_cmpint (as_app_search_matches_all (app, (gchar**) mime), ==, 4);
3301 
3302 	/* test searching for all tokenized tokens */
3303 	tokens = as_utils_search_tokenize ("org.gnome.Software");
3304 	g_assert_cmpstr (tokens[0], ==, "org.gnome.software");
3305 	g_assert_cmpstr (tokens[1], ==, NULL);
3306 	g_assert_cmpint (as_app_search_matches_all (app, tokens), ==, 256);
3307 
3308 	/* test tokenization of hyphenated name */
3309 	g_assert_cmpint (as_app_search_matches (app, "x-plane"), ==, 64);
3310 	g_assert_cmpint (as_app_search_matches (app, "plane"), ==, 64);
3311 
3312 	/* do not add short or common keywords */
3313 	g_assert_cmpint (as_app_search_matches (app, "and"), ==, 0);
3314 }
3315 
3316 /* load and save embedded icons */
3317 static void
as_test_store_embedded_func(void)3318 as_test_store_embedded_func (void)
3319 {
3320 	AsApp *app;
3321 	AsIcon *icon;
3322 	gboolean ret;
3323 	g_autoptr(GError) error = NULL;
3324 	g_autoptr(AsStore) store = NULL;
3325 	g_autoptr(GString) xml = NULL;
3326 	const gchar *xml_src =
3327 "<components origin=\"origin\" version=\"0.6\">"
3328 "<component type=\"desktop\">"
3329 "<id>eog.desktop</id>"
3330 "<pkgname>eog</pkgname>"
3331 "<name>Image Viewer</name>"
3332 "<icon type=\"embedded\" height=\"32\" width=\"32\">"
3333 "<name>eog.png</name>"
3334 "<filecontent>\n"
3335 "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJ\n"
3336 "TUUH1gsaCxQZBldDDAAACLxJREFUWIW9lmtsHNUVx/8zd3Zm9uFd73ptZ/3Gid+OoUlwyAscSJw4\n"
3337 "tIEKCGCQUPuBIlUIhbbEwIfuh0oRUYtKUEEIVQIJSpomPJKACYKQENNg7BiDE8dJnDi7drzrxz5m\n"
3338 "d3a9O3Nnbj8YaOo6qSFSj3Q0V3Nnzv93z9x7znD4kbZzZ4dbM8QWSbBsAoc2XdeLJFH8OJ2m9/j9\n"
3339 "/vRC4wgLfdDv9zsIobcKgqWVF8idAhHKljU20aol1daCggJOFCUcP3709u7uE88CePa6AZ5/frs1\n"
3340 "lbKvAi+0ihbxpzyPqsaGFXp1dY2tsHARJ8syKKWiruvQdQpKDSxf3iz29Pa0/xAA7rvBK688apmY\n"
3341 "KGwmhGwURHErGGtoaGjUa2vqrIsW+Xir1QpKDVCqg1INuk6vCMNgmgxOZy5eevnFbEJJVfr9/vEF\n"
3342 "ZcDv91fabMIrcQVrG5fWmA31jXJxcQlvs9lAqSF+JxaPxwAwMPbvl1NpFUpCQSw+CSWRwrIbb8aN\n"
3343 "TU3m5593tQJ4bUEAVru4b9u2B28qKy3nDGN2hbquIR6PgX2vNiucyWagJOKIK9NQEgnwAoMgJsCL\n"
3344 "Scg5NoTCY7ihcom192TPPQsGoLpWU1ZaziUScRiG8R+Tmp5FXFEQT0SgKHGAmaCaBqaZ4OUoBi8M\n"
3345 "YvCby5gIq8ikDciyFdVV1Uil1Na2trb8zs7Oqf8JIFgs/el0ajXH8aA0i0QyjpgShZKIgeoUpm4A\n"
3346 "1AAhFAwzWFzajO7+Xrz9eidWr1qN9m13o7ysHA6HA6qqIhAM4Msve8Tg6Fjg9g0tuySLdWdnZ2f2\n"
3347 "agCk5bY1zqKikjvcbjfp+uIYdKrA4UzDV8QhEkhh1eoNWPqT5XC5FqFz7xF83H0MqVQKT+/oAC/I\n"
3348 "6Ds1gk9OHkXXmc/x1UAYmmZBbVUl2u+/zzIdibSMBC7dUVpbeiA4HJy3NvCUJx/2f91HRVGCy5UD\n"
3349 "XzGPgkJAsKhIJROwOexIj53AzGfbMTxyBDdUlGPbvfdi7579EJ1leLj9fjze/hhEyxREWwRTioLR\n"
3350 "uIAXXjsY3/qzreamjRtXCTo52NbWJs0L4H/GPzQ6GkwzMHhyvVBiJpRoCn2fKpgcTaJ7910IvfdL\n"
3351 "HB4ahc23FCubm3Hi3V3YuNyHG4sBqps4/OFHICQMrzeNbGoKlaUFiMUVe8dfPn1h2bLlRm1t7cqM\n"
3352 "ln5mXgAAMBn7YGpyAnmeAsTjJoa+pLh1wzY8+rtfw5Xph5Ar4mCPiDs3b0H/P/+OW9dvxqI8J47v\n"
3353 "2op3//oq0lNhWKRJ2B0RuOwmBGRQfUOpoWtJ/uV9PW9sWH8HCBF+09LS4p0XQNP1d86eOzuT68oF\n"
3354 "pYAgisj15IIXZNjK1uPQZyZqapsQHDmHClmD21WAvjd+j4r6tXhsx5PY8vO74c2sh6bH4HAlEY+M\n"
3355 "4aal1VKhzWj6OiR0XQiMRevr6uwgeGheAEnIHhkY6CeECHDluEDsFO/v24vXX3wJB4cbMcSWoqKi\n"
3356 "AuGRYdg8DbjwzVe47NgIx+0dIISDr6QIMnFDFGTkejkEg2dRXVnGWZBesf2B5iWnR+K9xSUl4MC2\n"
3357 "zgvQ0fGcks1qQ6mUijxPPiwOAkflIARbBr/a8QTGYxnIshXBVCGK1z4MX8ujcC6ux7Gut3DondfR\n"
3358 "dfwAbMUJmGoRIpclTE7E4HLYUFNVITYt9qw8P8EGRNECgGuYC/B9MzKovj84GqgvKS4Vhi+JYFYD\n"
3359 "jFogyTISiQQMg0KwyNB1Cosgoq6pCYK9DjwkqIkM5GQ+il0SnPUueHK9IIRH6/p1lsnpqDuWESZ1\n"
3360 "XQeAvKsCUGq8f/rUwFPVVdWCRbBAz4gQigPYv+dVSKIF09PT4J1ZdPd0Y3FZPjwuO0TeDlm2wuuW\n"
3361 "QAgBADDGYDIGMAabLYe/1H/O5+QzBZFIEgAiVwUwTfLV2NioaRizxzEUzYNsNwBJg8frxsTEBDgp\n"
3362 "D26PF+Vl5ZBEAoHnwX3bTxkAZppgAEzTRFY3IYgyhi+OuvPk+NKp6RkA7PS8ewAA/H6/yTgcmZqa\n"
3363 "gMedD6b54OSbUeq9BWtWrcN4KAQzHQMnyNB0A1nNgGEyGObsig2DAeDAgQM4gtSMjoHB8ywYjk/Y\n"
3364 "eWXF9NQ0GLgDV80AAGiZ7L7h4XOtzc23WFfcdDO4b5fnXO/EewcOwJaK4mRfH3JzVsHrsoMaJqyS\n"
3365 "BaJFAGMmpqNRBIJjdGBomI5enuSn4vR8NJY4I1vT9yaTyRQMvHlNANMkHw2eOU1Wr177vTgA5OTk\n"
3366 "YEtbGw59cAhp9SN48grRVL8YIm9CUeJmODSqhcNholMEZij6VM1+9pLquxweu1BeaZt8SlVVAOxP\n"
3367 "R48em54LwM298dxzfzj/yCO/WMLzs1+HEAGEEFBKsePpDoRC47BaraBSsZmb5ws5nTmnrTbHUBau\n"
3368 "s4l0VguEEkYoqhKXNtxSZJ14MDMzwxsmxnjGLZmvK/7XP6Fh0L/1njy5Y+2adZKqJhEKBdiFi8Pq\n"
3369 "xYsXpSJf/sj4+LhDTaWLHRjnI8GQ7RJ1mHGWl8kwryhz0+W5XKRpsaCulKzMrabSAPixhrqyktLx\n"
3370 "VzOb20mXoRt3PfkPRK+agd27H5cymYI9OjU3CYQfN0z2vka1w+mkdnzXrl3JtrY2KavPPA1wv5Uk\n"
3371 "yS5KIgQigOMAxgBqUGhZDdlsNgWwP0oW685Wz5FYfX2NdSZjaoGLZ6IGjNYn38TAvAALtU2bNnk0\n"
3372 "qj2A2fLaiNkiEwFwCuAOiIK45/Dhw1EAeKFdOLvIa6uorLtZVNQ0G/ymV2VU3/LEW+j60QA/xHbf\n"
3373 "h3wmksFKn8NbWN6IGUPA170nUpRqbf8XAAD48wNYyRHyyZIim91b0gCNy0HvF0dAriMmd4XzVziZ\n"
3374 "4wIA8uEphNdV8X1qRr9LZnHRoFlElMTla2VgrgB3Fb/W3Nw42L6ZrClzs7d5ngtrmvHQQgEWInYt\n"
3375 "xxVXYLZ16ADU690D3JzxXLG581caBWBep/71278AZpn8hFce4VcAAAAASUVORK5CYII=\n"
3376 "</filecontent>"
3377 "</icon>"
3378 "<launchable type=\"desktop-id\">eog.desktop</launchable>"
3379 "</component>"
3380 "</components>";
3381 
3382 	/* load AppStream file with embedded icon */
3383 	store = as_store_new ();
3384 	as_store_set_origin (store, "origin");
3385 	ret = as_store_from_xml (store, xml_src, "/tmp/origin", &error);
3386 	g_assert_no_error (error);
3387 	g_assert (ret);
3388 
3389 	/* check the icon was parsed */
3390 	g_assert_cmpint (as_store_get_size (store), ==, 1);
3391 	app = as_store_get_app_by_id (store, "eog.desktop");
3392 	g_assert (app != NULL);
3393 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
3394 	icon = as_app_get_icon_default (app);
3395 	g_assert (icon != NULL);
3396 	g_assert_cmpint (as_icon_get_kind (icon), ==, AS_ICON_KIND_EMBEDDED);
3397 	g_assert_cmpstr (as_icon_get_name (icon), ==, "eog.png");
3398 	g_assert_cmpstr (as_icon_get_prefix (icon), ==, "/tmp/origin/icons");
3399 
3400 	/* convert back to a file */
3401 	xml = as_store_to_xml (store, AS_NODE_TO_XML_FLAG_NONE);
3402 	ret = as_test_compare_lines (xml->str, xml_src, &error);
3403 	g_assert_no_error (error);
3404 	g_assert (ret);
3405 
3406 	/* strip out the embedded icons */
3407 	ret = as_store_convert_icons (store, AS_ICON_KIND_CACHED, &error);
3408 	g_assert_no_error (error);
3409 	g_assert (ret);
3410 
3411 	/* check exists */
3412 	g_assert (g_file_test ("/tmp/origin/icons/32x32/eog.png", G_FILE_TEST_EXISTS));
3413 }
3414 
3415 static void
store_changed_cb(AsStore * store,guint * cnt)3416 store_changed_cb (AsStore *store, guint *cnt)
3417 {
3418 	as_test_loop_quit ();
3419 	(*cnt)++;
3420 	g_debug ("changed callback, now #%u", *cnt);
3421 }
3422 
3423 static void
store_app_changed_cb(AsStore * store,AsApp * app,guint * cnt)3424 store_app_changed_cb (AsStore *store, AsApp *app, guint *cnt)
3425 {
3426 	(*cnt)++;
3427 }
3428 
3429 /* automatically reload changed directories */
3430 static void
as_test_store_auto_reload_dir_func(void)3431 as_test_store_auto_reload_dir_func (void)
3432 {
3433 	AsApp *app;
3434 	gboolean ret;
3435 	guint cnt = 0;
3436 	guint cnt_added = 0;
3437 	guint cnt_removed = 0;
3438 	g_autoptr(GError) error = NULL;
3439 	g_autoptr(AsStore) store = NULL;
3440 
3441 	/* add this file to a store */
3442 	store = as_store_new ();
3443 	g_signal_connect (store, "changed",
3444 			  G_CALLBACK (store_changed_cb), &cnt);
3445 	g_signal_connect (store, "app-added",
3446 			  G_CALLBACK (store_app_changed_cb), &cnt_added);
3447 	g_signal_connect (store, "app-removed",
3448 			  G_CALLBACK (store_app_changed_cb), &cnt_removed);
3449 	as_store_set_watch_flags (store, AS_STORE_WATCH_FLAG_ADDED |
3450 					   AS_STORE_WATCH_FLAG_REMOVED);
3451 
3452 	as_store_set_destdir (store, "/tmp/repo-tmp");
3453 	g_mkdir_with_parents ("/tmp/repo-tmp/usr/share/app-info/xmls", 0700);
3454 	g_unlink ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml");
3455 
3456 	/* load store */
3457 	ret = as_store_load (store, AS_STORE_LOAD_FLAG_APP_INFO_SYSTEM, NULL, &error);
3458 	g_assert_no_error (error);
3459 	g_assert (ret);
3460 	g_assert_cmpint (cnt, ==, 1);
3461 	g_assert_cmpint (cnt_added, ==, 0);
3462 	g_assert_cmpint (cnt_removed, ==, 0);
3463 
3464 	/* create file */
3465 	ret = g_file_set_contents ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml",
3466 				   "<components version=\"0.6\">"
3467 				   "<component type=\"desktop\">"
3468 				   "<id>test.desktop</id>"
3469 				   "</component>"
3470 				   "</components>",
3471 				   -1, &error);
3472 	g_assert_no_error (error);
3473 	g_assert (ret);
3474 
3475 	as_test_loop_run_with_timeout (2000);
3476 	g_assert_cmpint (cnt, ==, 2);
3477 	g_assert_cmpint (cnt_added, ==, 1);
3478 	g_assert_cmpint (cnt_removed, ==, 0);
3479 
3480 	/* verify */
3481 	app = as_store_get_app_by_id (store, "test.desktop");
3482 	g_assert (app != NULL);
3483 
3484 	/* remove file */
3485 	g_unlink ("/tmp/repo-tmp/usr/share/app-info/xmls/foo.xml");
3486 	as_test_loop_run_with_timeout (2000);
3487 	g_assert_cmpint (cnt, ==, 3);
3488 	g_assert_cmpint (cnt_added, ==, 1);
3489 	g_assert_cmpint (cnt_removed, ==, 1);
3490 	app = as_store_get_app_by_id (store, "test.desktop");
3491 	g_assert (app == NULL);
3492 }
3493 
3494 /* automatically reload changed files */
3495 static void
as_test_store_auto_reload_file_func(void)3496 as_test_store_auto_reload_file_func (void)
3497 {
3498 	AsApp *app;
3499 	AsFormat *format;
3500 	AsRelease *rel;
3501 	gboolean ret;
3502 	guint cnt = 0;
3503 	guint cnt_added = 0;
3504 	g_autoptr(GError) error = NULL;
3505 	g_autoptr(AsStore) store = NULL;
3506 	g_autoptr(GFile) file = NULL;
3507 
3508 	/* set initial file */
3509 	ret = g_file_set_contents ("/tmp/foo.xml",
3510 				   "<components version=\"0.6\">"
3511 				   "<component type=\"desktop\">"
3512 				   "<id>test.desktop</id>"
3513 				   "<releases>"
3514 				   "<release version=\"0.1.2\" timestamp=\"123\">"
3515 				   "</release>"
3516 				   "</releases>"
3517 				   "</component>"
3518 				   "</components>",
3519 				   -1, &error);
3520 	g_assert_no_error (error);
3521 	g_assert (ret);
3522 
3523 	/* add this file to a store */
3524 	store = as_store_new ();
3525 	g_signal_connect (store, "changed",
3526 			  G_CALLBACK (store_changed_cb), &cnt);
3527 	g_signal_connect (store, "app-added",
3528 			  G_CALLBACK (store_app_changed_cb), &cnt_added);
3529 	g_signal_connect (store, "app-removed",
3530 			  G_CALLBACK (store_app_changed_cb), &cnt_added);
3531 	as_store_set_watch_flags (store, AS_STORE_WATCH_FLAG_ADDED |
3532 					   AS_STORE_WATCH_FLAG_REMOVED);
3533 	file = g_file_new_for_path ("/tmp/foo.xml");
3534 	ret = as_store_from_file (store, file, NULL, NULL, &error);
3535 	g_assert_no_error (error);
3536 	g_assert (ret);
3537 	g_assert_cmpint (cnt, ==, 1);
3538 
3539 	/* verify */
3540 	app = as_store_get_app_by_id (store, "test.desktop");
3541 	g_assert (app != NULL);
3542 	rel = as_app_get_release_default (app);
3543 	g_assert_cmpstr (as_release_get_version (rel), ==, "0.1.2");
3544 
3545 	/* check format */
3546 	format = as_app_get_format_by_kind (app, AS_FORMAT_KIND_APPSTREAM);
3547 	g_assert (format != NULL);
3548 	g_assert_cmpstr (as_format_get_filename (format), ==, "/tmp/foo.xml");
3549 
3550 	/* change the file, and ensure we get the callback */
3551 	g_debug ("changing file");
3552 	ret = g_file_set_contents ("/tmp/foo.xml",
3553 				   "<components version=\"0.6\">"
3554 				   "<component type=\"desktop\">"
3555 				   "<id>test.desktop</id>"
3556 				   "<releases>"
3557 				   "<release version=\"0.1.0\" timestamp=\"100\">"
3558 				   "</release>"
3559 				   "</releases>"
3560 				   "</component>"
3561 				   "<component type=\"desktop\">"
3562 				   "<id>baz.desktop</id>"
3563 				   "</component>"
3564 				   "</components>",
3565 				   -1, &error);
3566 	g_assert_no_error (error);
3567 	g_assert (ret);
3568 	as_test_loop_run_with_timeout (2000);
3569 	g_assert_cmpint (cnt, ==, 2);
3570 
3571 	/* verify */
3572 	app = as_store_get_app_by_id (store, "baz.desktop");
3573 	g_assert (app != NULL);
3574 	app = as_store_get_app_by_id (store, "test.desktop");
3575 	g_assert (app != NULL);
3576 	rel = as_app_get_release_default (app);
3577 	g_assert_cmpstr (as_release_get_version (rel), ==, "0.1.0");
3578 
3579 	/* remove file */
3580 	g_unlink ("/tmp/foo.xml");
3581 	as_test_loop_run_with_timeout (2000);
3582 	g_assert_cmpint (cnt, ==, 3);
3583 	app = as_store_get_app_by_id (store, "baz.desktop");
3584 	g_assert (app == NULL);
3585 	app = as_store_get_app_by_id (store, "test.desktop");
3586 	g_assert (app == NULL);
3587 }
3588 
3589 /* get an application from the store ignoring the prefix */
3590 static void
as_test_store_prefix_func(void)3591 as_test_store_prefix_func (void)
3592 {
3593 	g_autoptr (AsStore) store = as_store_new ();
3594 	g_autoptr (AsApp) app = as_app_new ();
3595 	g_autoptr (GPtrArray) apps = NULL;
3596 	AsApp *app_tmp;
3597 
3598 	/* add app */
3599 	as_app_set_id (app, "flatpak-user:org.gnome.Software.desktop");
3600 	as_store_add_app (store, app);
3601 
3602 	app_tmp = as_store_get_app_by_id (store, "org.gnome.Software.desktop");
3603 	g_assert (app_tmp == NULL);
3604 	app_tmp = as_store_get_app_by_id_ignore_prefix (store, "org.gnome.Software.desktop");
3605 	g_assert (app_tmp != NULL);
3606 	g_assert_cmpstr (as_app_get_id (app_tmp), ==,
3607 			 "flatpak-user:org.gnome.Software.desktop");
3608 
3609 	/* there might be multiple apps we want to get */
3610 	apps = as_store_get_apps_by_id (store, "flatpak-user:org.gnome.Software.desktop");
3611 	g_assert (apps != NULL);
3612 	g_assert_cmpint (apps->len, ==, 1);
3613 	app_tmp = g_ptr_array_index (apps, 0);
3614 	g_assert_cmpstr (as_app_get_id (app_tmp), ==,
3615 			 "flatpak-user:org.gnome.Software.desktop");
3616 
3617 	/* exact unique match */
3618 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/*/*/test/*",
3619 						 AS_STORE_SEARCH_FLAG_NONE);
3620 	g_assert (app_tmp == NULL);
3621 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/*/*/test/*",
3622 						 AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
3623 	g_assert (app_tmp == NULL);
3624 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/*/*/org.gnome.Software.desktop/*",
3625 						 AS_STORE_SEARCH_FLAG_NONE);
3626 	g_assert (app_tmp != NULL);
3627 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/*/*/org.gnome.Software.desktop/*",
3628 						 AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
3629 	g_assert (app_tmp != NULL);
3630 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/*/*/*/*",
3631 						 AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
3632 	g_assert (app_tmp != NULL);
3633 }
3634 
3635 static void
as_test_store_wildcard_func(void)3636 as_test_store_wildcard_func (void)
3637 {
3638 	AsApp *app_tmp;
3639 	g_autoptr (AsApp) app1 = as_app_new ();
3640 	g_autoptr (AsApp) app2 = as_app_new ();
3641 	g_autoptr (AsStore) store = as_store_new ();
3642 
3643 	/* package from fedora */
3644 	as_app_set_id (app1, "gimp.desktop");
3645 	as_app_set_origin (app1, "fedora");
3646 	as_app_add_pkgname (app1, "polari");
3647 	_as_app_add_format_kind (app1, AS_FORMAT_KIND_DESKTOP);
3648 	as_store_add_app (store, app1);
3649 
3650 	/* package from updates */
3651 	as_app_set_id (app2, "gimp.desktop");
3652 	as_app_set_origin (app2, "updates");
3653 	as_app_add_pkgname (app2, "polari");
3654 	_as_app_add_format_kind (app2, AS_FORMAT_KIND_DESKTOP);
3655 	as_store_add_app (store, app2);
3656 
3657 	/* check negative match */
3658 	app_tmp = as_store_get_app_by_unique_id (store, "*/*/xxx/*/gimp.desktop/*",
3659 						 AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
3660 	g_assert (app_tmp == NULL);
3661 	app_tmp = as_store_get_app_by_unique_id (store, "*/snap/*/*/gimp.desktop/*",
3662 						 AS_STORE_SEARCH_FLAG_USE_WILDCARDS);
3663 	g_assert (app_tmp == NULL);
3664 }
3665 
3666 /* load a store with a origin and scope encoded in the symlink name */
3667 static void
as_test_store_flatpak_func(void)3668 as_test_store_flatpak_func (void)
3669 {
3670 	AsApp *app;
3671 	AsFormat *format;
3672 	GError *error = NULL;
3673 	gboolean ret;
3674 	g_autofree gchar *filename = NULL;
3675 	g_autofree gchar *filename_root = NULL;
3676 	g_autoptr(AsStore) store = NULL;
3677 	g_autoptr(GFile) file = NULL;
3678 	g_autoptr(GPtrArray) apps = NULL;
3679 
3680 	/* make throws us under a bus, yet again */
3681 	g_setenv ("AS_SELF_TEST_PREFIX_DELIM", "_", TRUE);
3682 
3683 	/* load a symlinked file to the store */
3684 	store = as_store_new ();
3685 	filename_root = as_test_get_filename (".");
3686 	filename = g_build_filename (filename_root, "flatpak_remote-name.xml", NULL);
3687 	if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) {
3688 		g_debug ("not doing symlink test in distcheck as regular file");
3689 		return;
3690 	}
3691 	file = g_file_new_for_path (filename);
3692 	ret = as_store_from_file (store, file, NULL, NULL, &error);
3693 	g_assert_no_error (error);
3694 	g_assert (ret);
3695 
3696 	/* test extraction of symlink data */
3697 	g_assert_cmpstr (as_store_get_origin (store), ==, "flatpak");
3698 	g_assert_cmpint (as_store_get_size (store), ==, 1);
3699 	apps = as_store_dup_apps (store);
3700 	g_assert_cmpint (apps->len, ==, 1);
3701 	app = g_ptr_array_index (apps, 0);
3702 	g_assert_cmpstr (as_app_get_id (app), ==, "flatpak:test.desktop");
3703 	g_assert_cmpstr (as_app_get_unique_id (app), ==, "system/flatpak/remote-name/desktop/test.desktop/master");
3704 	g_assert_cmpstr (as_app_get_id_filename (app), ==, "test");
3705 	g_assert_cmpstr (as_app_get_origin (app), ==, "remote-name");
3706 
3707 	/* check format */
3708 	format = as_app_get_format_by_kind (app, AS_FORMAT_KIND_APPSTREAM);
3709 	g_assert (format != NULL);
3710 	g_assert_cmpstr (as_format_get_filename (format), ==, filename);
3711 
3712 	/* back to normality */
3713 	g_unsetenv ("AS_SELF_TEST_PREFIX_DELIM");
3714 }
3715 
3716 /* demote the .desktop "application" to an addon */
3717 static void
as_test_store_demote_func(void)3718 as_test_store_demote_func (void)
3719 {
3720 	AsApp *app;
3721 	GError *error = NULL;
3722 	gboolean ret;
3723 	g_autofree gchar *filename1 = NULL;
3724 	g_autofree gchar *filename2 = NULL;
3725 	g_autoptr(AsApp) app_appdata = NULL;
3726 	g_autoptr(AsApp) app_desktop = NULL;
3727 	g_autoptr(AsStore) store = NULL;
3728 	g_autoptr(GString) xml = NULL;
3729 
3730 	/* load example desktop file */
3731 	app_desktop = as_app_new ();
3732 	filename1 = as_test_get_filename ("example.desktop");
3733 	ret = as_app_parse_file (app_desktop, filename1,
3734 				 AS_APP_PARSE_FLAG_ALLOW_VETO, &error);
3735 	g_assert_no_error (error);
3736 	g_assert (ret);
3737 	g_assert_cmpint (as_app_get_kind (app_desktop), ==, AS_APP_KIND_DESKTOP);
3738 
3739 	/* load example appdata file */
3740 	app_appdata = as_app_new ();
3741 	filename2 = as_test_get_filename ("example.appdata.xml");
3742 	ret = as_app_parse_file (app_appdata, filename2,
3743 				 AS_APP_PARSE_FLAG_ALLOW_VETO, &error);
3744 	g_assert_no_error (error);
3745 	g_assert (ret);
3746 	g_assert_cmpint (as_app_get_kind (app_appdata), ==, AS_APP_KIND_ADDON);
3747 
3748 	/* add apps */
3749 	store = as_store_new ();
3750 	as_store_set_api_version (store, 0.8);
3751 	as_store_add_app (store, app_desktop);
3752 	as_store_add_app (store, app_appdata);
3753 
3754 	/* check we demoted */
3755 	g_assert_cmpint (as_store_get_size (store), ==, 1);
3756 	app = as_store_get_app_by_id (store, "example.desktop");
3757 	g_assert (app != NULL);
3758 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_ADDON);
3759 	g_assert_cmpint (as_app_get_extends(app)->len, >, 0);
3760 
3761 	/* dump */
3762 	xml = as_store_to_xml (store,
3763 			       AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE |
3764 			       AS_NODE_TO_XML_FLAG_FORMAT_INDENT);
3765 	g_debug ("%s", xml->str);
3766 }
3767 
3768 static void
as_test_store_merges_func(void)3769 as_test_store_merges_func (void)
3770 {
3771 	AsApp *app_tmp;
3772 	g_autoptr(AsApp) app_appdata = NULL;
3773 	g_autoptr(AsApp) app_appinfo = NULL;
3774 	g_autoptr(AsApp) app_desktop = NULL;
3775 	g_autoptr(AsStore) store_all = NULL;
3776 	g_autoptr(AsStore) store_desktop_appdata = NULL;
3777 
3778 	/* test desktop + appdata */
3779 	store_desktop_appdata = as_store_new ();
3780 
3781 	app_desktop = as_app_new ();
3782 	as_app_set_id (app_desktop, "gimp.desktop");
3783 	_as_app_add_format_kind (app_desktop, AS_FORMAT_KIND_DESKTOP);
3784 	as_app_set_name (app_desktop, NULL, "GIMP");
3785 	as_app_set_comment (app_desktop, NULL, "GNU Bla Bla");
3786 	as_app_set_priority (app_desktop, -1);
3787 	as_app_set_state (app_desktop, AS_APP_STATE_INSTALLED);
3788 	as_app_set_scope (app_desktop, AS_APP_SCOPE_SYSTEM);
3789 
3790 	app_appdata = as_app_new ();
3791 	as_app_set_id (app_appdata, "gimp.desktop");
3792 	_as_app_add_format_kind (app_appdata, AS_FORMAT_KIND_APPDATA);
3793 	as_app_set_description (app_appdata, NULL, "<p>Gimp is awesome</p>");
3794 	as_app_add_pkgname (app_appdata, "gimp");
3795 	as_app_set_priority (app_appdata, -1);
3796 	as_app_set_state (app_appdata, AS_APP_STATE_INSTALLED);
3797 	as_app_set_scope (app_desktop, AS_APP_SCOPE_SYSTEM);
3798 
3799 	as_store_add_app (store_desktop_appdata, app_desktop);
3800 	as_store_add_app (store_desktop_appdata, app_appdata);
3801 
3802 	app_tmp = as_store_get_app_by_id (store_desktop_appdata, "gimp.desktop");
3803 	g_assert (app_tmp != NULL);
3804 	g_assert_cmpstr (as_app_get_name (app_tmp, NULL), ==, "GIMP");
3805 	g_assert_cmpstr (as_app_get_comment (app_tmp, NULL), ==, "GNU Bla Bla");
3806 	g_assert_cmpstr (as_app_get_description (app_tmp, NULL), ==, "<p>Gimp is awesome</p>");
3807 	g_assert_cmpstr (as_app_get_pkgname_default (app_tmp), ==, "gimp");
3808 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_DESKTOP) != NULL);
3809 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_APPDATA) != NULL);
3810 	g_assert_cmpint (as_app_get_state (app_tmp), ==, AS_APP_STATE_INSTALLED);
3811 
3812 	/* test desktop + appdata + appstream */
3813 	store_all = as_store_new ();
3814 
3815 	app_appinfo = as_app_new ();
3816 	as_app_set_id (app_appinfo, "gimp.desktop");
3817 	_as_app_add_format_kind (app_appinfo, AS_FORMAT_KIND_APPSTREAM);
3818 	as_app_set_name (app_appinfo, NULL, "GIMP");
3819 	as_app_set_comment (app_appinfo, NULL, "GNU Bla Bla");
3820 	as_app_set_description (app_appinfo, NULL, "<p>Gimp is Distro</p>");
3821 	as_app_add_pkgname (app_appinfo, "gimp");
3822 	as_app_set_priority (app_appinfo, 0);
3823 
3824 	as_store_add_app (store_all, app_appinfo);
3825 	as_store_add_app (store_all, app_desktop);
3826 	as_store_add_app (store_all, app_appdata);
3827 
3828 	/* ensure the AppStream entry 'wins' */
3829 	app_tmp = as_store_get_app_by_id (store_all, "gimp.desktop");
3830 	g_assert (app_tmp != NULL);
3831 	g_assert_cmpstr (as_app_get_name (app_tmp, NULL), ==, "GIMP");
3832 	g_assert_cmpstr (as_app_get_comment (app_tmp, NULL), ==, "GNU Bla Bla");
3833 	g_assert_cmpstr (as_app_get_description (app_tmp, NULL), ==, "<p>Gimp is Distro</p>");
3834 	g_assert_cmpstr (as_app_get_pkgname_default (app_tmp), ==, "gimp");
3835 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_DESKTOP) != NULL);
3836 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_APPDATA) != NULL);
3837 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_APPSTREAM) != NULL);
3838 	g_assert_cmpint (as_app_get_formats(app_tmp)->len, ==, 3);
3839 	g_assert_cmpint (as_app_get_state (app_tmp), ==, AS_APP_STATE_INSTALLED);
3840 }
3841 
3842 static void
as_test_store_merges_local_func(void)3843 as_test_store_merges_local_func (void)
3844 {
3845 	AsApp *app_tmp;
3846 	g_autoptr(AsApp) app_appdata = NULL;
3847 	g_autoptr(AsApp) app_appinfo = NULL;
3848 	g_autoptr(AsApp) app_desktop = NULL;
3849 	g_autoptr(AsStore) store = NULL;
3850 
3851 	/* test desktop + appdata + appstream */
3852 	store = as_store_new ();
3853 	as_store_set_add_flags (store, AS_STORE_ADD_FLAG_PREFER_LOCAL);
3854 
3855 	app_desktop = as_app_new ();
3856 	as_app_set_id (app_desktop, "gimp.desktop");
3857 	_as_app_add_format_kind (app_desktop, AS_FORMAT_KIND_DESKTOP);
3858 	as_app_set_name (app_desktop, NULL, "GIMP");
3859 	as_app_set_comment (app_desktop, NULL, "GNU Bla Bla");
3860 	as_app_set_priority (app_desktop, -1);
3861 	as_app_set_state (app_desktop, AS_APP_STATE_INSTALLED);
3862 
3863 	app_appdata = as_app_new ();
3864 	as_app_set_id (app_appdata, "gimp.desktop");
3865 	_as_app_add_format_kind (app_appdata, AS_FORMAT_KIND_APPDATA);
3866 	as_app_set_description (app_appdata, NULL, "<p>Gimp is awesome</p>");
3867 	as_app_add_pkgname (app_appdata, "gimp");
3868 	as_app_set_priority (app_appdata, -1);
3869 	as_app_set_state (app_appdata, AS_APP_STATE_INSTALLED);
3870 
3871 	app_appinfo = as_app_new ();
3872 	as_app_set_id (app_appinfo, "gimp.desktop");
3873 	_as_app_add_format_kind (app_appinfo, AS_FORMAT_KIND_APPSTREAM);
3874 	as_app_set_name (app_appinfo, NULL, "GIMP");
3875 	as_app_set_comment (app_appinfo, NULL, "Fedora GNU Bla Bla");
3876 	as_app_set_description (app_appinfo, NULL, "<p>Gimp is Distro</p>");
3877 	as_app_add_pkgname (app_appinfo, "gimp");
3878 	as_app_set_priority (app_appinfo, 0);
3879 
3880 	/* this is actually the install order we get at startup */
3881 	as_store_add_app (store, app_appinfo);
3882 	as_store_add_app (store, app_desktop);
3883 	as_store_add_app (store, app_appdata);
3884 
3885 	/* ensure the local entry 'wins' */
3886 	app_tmp = as_store_get_app_by_id (store, "gimp.desktop");
3887 	g_assert (app_tmp != NULL);
3888 	g_assert_cmpstr (as_app_get_name (app_tmp, NULL), ==, "GIMP");
3889 	g_assert_cmpstr (as_app_get_comment (app_tmp, NULL), ==, "GNU Bla Bla");
3890 	g_assert_cmpstr (as_app_get_description (app_tmp, NULL), ==, "<p>Gimp is awesome</p>");
3891 	g_assert_cmpstr (as_app_get_pkgname_default (app_tmp), ==, "gimp");
3892 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_DESKTOP) != NULL);
3893 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_APPDATA) != NULL);
3894 	g_assert (as_app_get_format_by_kind (app_tmp, AS_FORMAT_KIND_APPSTREAM) != NULL);
3895 	g_assert_cmpint (as_app_get_formats(app_tmp)->len, ==, 3);
3896 	g_assert_cmpint (as_app_get_state (app_tmp), ==, AS_APP_STATE_INSTALLED);
3897 }
3898 
3899 static void
as_test_store_empty_func(void)3900 as_test_store_empty_func (void)
3901 {
3902 	gboolean ret;
3903 	g_autoptr(GError) error = NULL;
3904 	g_autoptr(AsStore) store = NULL;
3905 
3906 	store = as_store_new ();
3907 	ret = as_store_from_xml (store, "", NULL, &error);
3908 	g_assert_no_error (error);
3909 	g_assert (ret);
3910 }
3911 
3912 static void
as_test_store_func(void)3913 as_test_store_func (void)
3914 {
3915 	AsApp *app;
3916 	GString *xml;
3917 	gboolean ret;
3918 	g_autoptr(AsStore) store = NULL;
3919 	g_autoptr(GError) error = NULL;
3920 
3921 	/* create a store and add a single app */
3922 	store = as_store_new ();
3923 	g_assert_cmpfloat (as_store_get_api_version (store), <, 1.f);
3924 	g_assert_cmpfloat (as_store_get_api_version (store), >, 0.f);
3925 	app = as_app_new ();
3926 	as_app_set_id (app, "gnome-software.desktop");
3927 	as_app_set_kind (app, AS_APP_KIND_DESKTOP);
3928 	as_store_add_app (store, app);
3929 	g_object_unref (app);
3930 	g_assert_cmpstr (as_store_get_origin (store), ==, NULL);
3931 
3932 	/* check string output */
3933 	as_store_set_api_version (store, 0.6);
3934 	xml = as_store_to_xml (store, 0);
3935 	ret = as_test_compare_lines (xml->str,
3936 				     "<components version=\"0.6\">"
3937 				     "<component type=\"desktop\">"
3938 				     "<id>gnome-software.desktop</id>"
3939 				     "</component>"
3940 				     "</components>",
3941 				     &error);
3942 	g_assert_no_error (error);
3943 	g_assert (ret);
3944 	g_string_free (xml, TRUE);
3945 
3946 	/* add and then remove another app */
3947 	app = as_app_new ();
3948 	as_app_set_id (app, "junk.desktop");
3949 	as_app_set_kind (app, AS_APP_KIND_FONT);
3950 	as_store_add_app (store, app);
3951 	g_object_unref (app);
3952 	as_store_remove_app (store, app);
3953 
3954 	/* check string output */
3955 	as_store_set_api_version (store, 0.6);
3956 	xml = as_store_to_xml (store, 0);
3957 	ret = as_test_compare_lines (xml->str,
3958 				     "<components version=\"0.6\">"
3959 				     "<component type=\"desktop\">"
3960 				     "<id>gnome-software.desktop</id>"
3961 				     "</component>"
3962 				     "</components>",
3963 				     &error);
3964 	g_assert_no_error (error);
3965 	g_assert (ret);
3966 	g_string_free (xml, TRUE);
3967 
3968 	/* add another app and ensure it's sorted */
3969 	app = as_app_new ();
3970 	as_app_set_id (app, "aaa.desktop");
3971 	as_app_set_kind (app, AS_APP_KIND_FONT);
3972 	as_store_add_app (store, app);
3973 	g_object_unref (app);
3974 	xml = as_store_to_xml (store, 0);
3975 	g_assert_cmpstr (xml->str, ==,
3976 		"<components version=\"0.6\">"
3977 		"<component type=\"font\">"
3978 		"<id>aaa.desktop</id>"
3979 		"</component>"
3980 		"<component type=\"desktop\">"
3981 		"<id>gnome-software.desktop</id>"
3982 		"</component>"
3983 		"</components>");
3984 	g_string_free (xml, TRUE);
3985 
3986 	/* empty the store */
3987 	as_store_remove_all (store);
3988 	g_assert_cmpint (as_store_get_size (store), ==, 0);
3989 	g_assert (as_store_get_app_by_id (store, "aaa.desktop") == NULL);
3990 	g_assert (as_store_get_app_by_id (store, "gnome-software.desktop") == NULL);
3991 	xml = as_store_to_xml (store, 0);
3992 	g_assert_cmpstr (xml->str, ==,
3993 		"<components version=\"0.6\"/>");
3994 	g_string_free (xml, TRUE);
3995 }
3996 
3997 static void
as_test_store_unique_func(void)3998 as_test_store_unique_func (void)
3999 {
4000 	AsApp *app;
4001 	g_autoptr(AsApp) app1 = NULL;
4002 	g_autoptr(AsApp) app2 = NULL;
4003 	g_autoptr(AsApp) app3 = NULL;
4004 	g_autoptr(AsBundle) bundle2 = NULL;
4005 	g_autoptr(AsBundle) bundle3 = NULL;
4006 	g_autoptr(AsStore) store = NULL;
4007 	g_autoptr(GPtrArray) apps = NULL;
4008 
4009 	/* create a store and add a single app */
4010 	store = as_store_new ();
4011 	as_store_set_add_flags (store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
4012 	app1 = as_app_new ();
4013 	as_app_set_id (app1, "org.gnome.Software.desktop");
4014 	as_app_set_kind (app1, AS_APP_KIND_DESKTOP);
4015 	as_app_add_pkgname (app1, "gnome-software");
4016 	as_store_add_app (store, app1);
4017 
4018 	/* add a stable bundle */
4019 	app2 = as_app_new ();
4020 	bundle2 = as_bundle_new ();
4021 	as_bundle_set_kind (bundle2, AS_BUNDLE_KIND_FLATPAK);
4022 	as_bundle_set_id (bundle2, "app/org.gnome.Software/i386/3-18");
4023 	as_app_set_id (app2, "org.gnome.Software.desktop");
4024 	as_app_set_kind (app2, AS_APP_KIND_DESKTOP);
4025 	as_app_add_bundle (app2, bundle2);
4026 	as_store_add_app (store, app2);
4027 
4028 	/* add a master bundle */
4029 	app3 = as_app_new ();
4030 	bundle3 = as_bundle_new ();
4031 	as_bundle_set_kind (bundle3, AS_BUNDLE_KIND_FLATPAK);
4032 	as_bundle_set_id (bundle3, "app/org.gnome.Software/i386/master");
4033 	as_app_set_id (app3, "org.gnome.Software.desktop");
4034 	as_app_set_kind (app3, AS_APP_KIND_DESKTOP);
4035 	as_app_add_bundle (app3, bundle3);
4036 	as_store_add_app (store, app3);
4037 
4038 	g_assert_cmpint (as_store_get_size (store), ==, 3);
4039 	apps = as_store_get_apps_by_id (store, "org.gnome.Software.desktop");
4040 	g_assert_cmpint (apps->len, ==, 3);
4041 	app = g_ptr_array_index (apps, 0);
4042 	g_assert_cmpstr (as_app_get_unique_id (app), ==,
4043 			 "*/package/*/desktop/org.gnome.Software.desktop/*");
4044 	app = g_ptr_array_index (apps, 1);
4045 	g_assert_cmpstr (as_app_get_unique_id (app), ==,
4046 			 "*/flatpak/*/desktop/org.gnome.Software.desktop/3-18");
4047 	app = g_ptr_array_index (apps, 2);
4048 	g_assert_cmpstr (as_app_get_unique_id (app), ==,
4049 			 "*/flatpak/*/desktop/org.gnome.Software.desktop/master");
4050 	app = as_store_get_app_by_unique_id (store,
4051 					     "*/flatpak/*/desktop/"
4052 					     "org.gnome.Software.desktop/master",
4053 					     AS_STORE_SEARCH_FLAG_NONE);
4054 	g_assert (app != NULL);
4055 }
4056 
4057 static void
as_test_store_provides_func(void)4058 as_test_store_provides_func (void)
4059 {
4060 	AsApp *app;
4061 	gboolean ret;
4062 	g_autoptr(GError) error = NULL;
4063 	g_autoptr(AsStore) store = NULL;
4064 	g_autoptr(GPtrArray) apps1 = NULL;
4065 	g_autoptr(GPtrArray) apps2 = NULL;
4066 
4067 	/* create a store and add a single app */
4068 	store = as_store_new ();
4069 	ret = as_store_from_xml (store,
4070 		"<components version=\"0.6\">"
4071 		"<component type=\"desktop\">"
4072 		"<id>test.desktop</id>"
4073 		"<provides>"
4074 		"<firmware type=\"flashed\">deadbeef</firmware>"
4075 		"</provides>"
4076 		"</component>"
4077 		"</components>", NULL, &error);
4078 	g_assert_no_error (error);
4079 	g_assert (ret);
4080 
4081 	/* get an appication by the provide value */
4082 	app = as_store_get_app_by_provide (store,
4083 					   AS_PROVIDE_KIND_FIRMWARE_FLASHED,
4084 					   "deadbeef");
4085 	g_assert_cmpstr (as_app_get_id (app), ==, "test.desktop");
4086 	app = as_store_get_app_by_provide (store,
4087 					   AS_PROVIDE_KIND_FIRMWARE_RUNTIME,
4088 					   "deadbeef");
4089 	g_assert (app == NULL);
4090 	app = as_store_get_app_by_provide (store,
4091 					   AS_PROVIDE_KIND_FIRMWARE_FLASHED,
4092 					   "beefdead");
4093 	g_assert (app == NULL);
4094 
4095 	/* arrays of apps */
4096 	apps1 = as_store_get_apps_by_provide (store,
4097 					      AS_PROVIDE_KIND_FIRMWARE_FLASHED,
4098 					      "deadbeef");
4099 	g_assert_cmpint (apps1->len, ==, 1);
4100 	app = g_ptr_array_index (apps1, 0);
4101 	g_assert_cmpstr (as_app_get_id (app), ==, "test.desktop");
4102 	apps2 = as_store_get_apps_by_provide (store,
4103 					      AS_PROVIDE_KIND_FIRMWARE_FLASHED,
4104 					      "beefdead");
4105 	g_assert_cmpint (apps2->len, ==, 0);
4106 }
4107 
4108 static void
as_test_store_versions_func(void)4109 as_test_store_versions_func (void)
4110 {
4111 	AsApp *app;
4112 	AsStore *store;
4113 	GError *error = NULL;
4114 	gboolean ret;
4115 	GString *xml;
4116 
4117 	/* load a file to the store */
4118 	store = as_store_new ();
4119 	ret = as_store_from_xml (store,
4120 		"<components version=\"0.6\">"
4121 		"<component type=\"desktop\">"
4122 		"<id>test.desktop</id>"
4123 		"<description><p>Hello world</p></description>"
4124 		"<architectures><arch>i386</arch></architectures>"
4125 		"<releases>"
4126 		"<release version=\"0.1.2\" timestamp=\"123\">"
4127 		"<description><p>Hello</p></description>"
4128 		"</release>"
4129 		"</releases>"
4130 		"</component>"
4131 		"</components>", NULL, &error);
4132 	g_assert_no_error (error);
4133 	g_assert (ret);
4134 	g_assert_cmpfloat (as_store_get_api_version (store), <, 0.6 + 0.01);
4135 	g_assert_cmpfloat (as_store_get_api_version (store), >, 0.6 - 0.01);
4136 
4137 	/* verify source kind */
4138 	app = as_store_get_app_by_id (store, "test.desktop");
4139 	g_assert (as_app_get_format_by_kind (app, AS_FORMAT_KIND_APPSTREAM) != NULL);
4140 
4141 	/* test with latest features */
4142 	as_store_set_api_version (store, 0.6);
4143 	g_assert_cmpfloat (as_store_get_api_version (store), <, 0.6 + 0.01);
4144 	g_assert_cmpfloat (as_store_get_api_version (store), >, 0.6 - 0.01);
4145 	xml = as_store_to_xml (store, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
4146 	ret = as_test_compare_lines (xml->str,
4147 		"<components version=\"0.6\">\n"
4148 		"<component type=\"desktop\">\n"
4149 		"<id>test.desktop</id>\n"
4150 		"<description><p>Hello world</p></description>\n"
4151 		"<architectures>\n"
4152 		"<arch>i386</arch>\n"
4153 		"</architectures>\n"
4154 		"<releases>\n"
4155 		"<release timestamp=\"123\" version=\"0.1.2\">\n"
4156 		"<description><p>Hello</p></description>\n"
4157 		"</release>\n"
4158 		"</releases>\n"
4159 		"<launchable type=\"desktop-id\">test.desktop</launchable>\n"
4160 		"</component>\n"
4161 		"</components>\n", &error);
4162 	g_assert_no_error (error);
4163 	g_assert (ret);
4164 	g_string_free (xml, TRUE);
4165 	g_object_unref (store);
4166 
4167 	/* load a version 0.6 file to the store */
4168 	store = as_store_new ();
4169 	ret = as_store_from_xml (store,
4170 		"<components version=\"0.6\">"
4171 		"<component type=\"desktop\">"
4172 		"<id>test.desktop</id>"
4173 		"</component>"
4174 		"</components>", NULL, &error);
4175 	g_assert_no_error (error);
4176 	g_assert (ret);
4177 
4178 	/* test latest spec version */
4179 	xml = as_store_to_xml (store, 0);
4180 	g_assert_cmpstr (xml->str, ==,
4181 		"<components version=\"0.6\">"
4182 		"<component type=\"desktop\">"
4183 		"<id>test.desktop</id>"
4184 		"<launchable type=\"desktop-id\">test.desktop</launchable>"
4185 		"</component>"
4186 		"</components>");
4187 	g_string_free (xml, TRUE);
4188 
4189 	g_object_unref (store);
4190 }
4191 
4192 static void
as_test_store_addons_func(void)4193 as_test_store_addons_func (void)
4194 {
4195 	AsApp *app;
4196 	GError *error = NULL;
4197 	GPtrArray *data;
4198 	gboolean ret;
4199 	const gchar *xml =
4200 		"<components version=\"0.7\">"
4201 		"<component type=\"addon\">"
4202 		"<id>eclipse-php.jar</id>"
4203 		"<mimetypes>"
4204 		"<mimetype>xtest</mimetype>"
4205 		"</mimetypes>"
4206 		"<extends>eclipse.desktop</extends>"
4207 		"</component>"
4208 		"<component type=\"desktop\">"
4209 		"<id>eclipse.desktop</id>"
4210 		"<launchable type=\"desktop-id\">eclipse.desktop</launchable>"
4211 		"</component>"
4212 		"</components>";
4213 	g_autoptr(AsStore) store = NULL;
4214 	g_autoptr(GString) str = NULL;
4215 
4216 	/* load a file to the store */
4217 	store = as_store_new ();
4218 	ret = as_store_from_xml (store, xml, NULL, &error);
4219 	g_assert_no_error (error);
4220 	g_assert (ret);
4221 
4222 	/* check the addon references the main application */
4223 	app = as_store_get_app_by_id (store, "eclipse-php.jar");
4224 	g_assert (app != NULL);
4225 	data = as_app_get_extends (app);
4226 	g_assert_cmpint (data->len, ==, 1);
4227 	g_assert_cmpstr (g_ptr_array_index (data, 0), ==, "eclipse.desktop");
4228 
4229 	/* check the main application has a ref to the addon */
4230 	app = as_store_get_app_by_id (store, "eclipse.desktop");
4231 	data = as_app_get_addons (app);
4232 	g_assert_cmpint (data->len, ==, 1);
4233 	app = g_ptr_array_index (data, 0);
4234 	g_assert_cmpstr (as_app_get_id (app), ==, "eclipse-php.jar");
4235 
4236 	/* check we can search for token from the addon */
4237 	g_assert_cmpint (as_app_search_matches (app, "xtest"), >, 0);
4238 	g_assert_cmpint (as_app_search_matches (app, "eclipse-php"), >, 0);
4239 
4240 	/* check it marshals back to the same XML */
4241 	str = as_store_to_xml (store, 0);
4242 	ret = as_test_compare_lines (str->str, xml, &error);
4243 	g_assert_no_error (error);
4244 	g_assert (ret);
4245 }
4246 
4247 /*
4248  * test that we don't save the same translated data as C back to the file
4249  */
4250 static void
as_test_node_no_dup_c_func(void)4251 as_test_node_no_dup_c_func (void)
4252 {
4253 	GError *error = NULL;
4254 	AsNode *n;
4255 	AsNode *root;
4256 	GString *xml;
4257 	gboolean ret;
4258 	const gchar *src =
4259 		"<component type=\"desktop\">"
4260 		"<id>test.desktop</id>"
4261 		"<name>Krita</name>"
4262 		"<name xml:lang=\"pl\">Krita</name>"
4263 		"</component>";
4264 	g_autoptr(AsApp) app = NULL;
4265 	g_autoptr(AsNodeContext) ctx = NULL;
4266 
4267 	/* to object */
4268 	app = as_app_new ();
4269 	root = as_node_from_xml (src, 0, &error);
4270 	g_assert_no_error (error);
4271 	g_assert (root != NULL);
4272 	n = as_node_find (root, "component");
4273 	g_assert (n != NULL);
4274 	ctx = as_node_context_new ();
4275 	ret = as_app_node_parse (app, n, ctx, &error);
4276 	g_assert_no_error (error);
4277 	g_assert (ret);
4278 
4279 	/* verify */
4280 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "Krita");
4281 	g_assert_cmpstr (as_app_get_name (app, "pl"), ==, "Krita");
4282 	as_node_unref (root);
4283 
4284 	/* back to node */
4285 	root = as_node_new ();
4286 	as_node_context_set_version (ctx, 0.4);
4287 	n = as_app_node_insert (app, root, ctx);
4288 	xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
4289 	g_assert_cmpstr (xml->str, ==,
4290 		"<component type=\"desktop\">"
4291 		"<id>test.desktop</id>"
4292 		"<name>Krita</name>"
4293 		"<launchable type=\"desktop-id\">test.desktop</launchable>"
4294 		"</component>");
4295 	g_string_free (xml, TRUE);
4296 	as_node_unref (root);
4297 }
4298 
4299 static void
as_test_store_origin_func(void)4300 as_test_store_origin_func (void)
4301 {
4302 	AsApp *app;
4303 	AsFormat *format;
4304 	GError *error = NULL;
4305 	gboolean ret;
4306 	g_autofree gchar *filename = NULL;
4307 	g_autoptr(AsStore) store = NULL;
4308 	g_autoptr(GFile) file = NULL;
4309 
4310 	/* load a file to the store */
4311 	store = as_store_new ();
4312 	filename = as_test_get_filename ("origin.xml");
4313 	file = g_file_new_for_path (filename);
4314 	ret = as_store_from_file (store, file, NULL, NULL, &error);
4315 	g_assert_no_error (error);
4316 	g_assert (ret);
4317 
4318 	/* test icon path */
4319 	g_assert_cmpstr (as_store_get_origin (store), ==, "fedora-21");
4320 	g_assert_cmpint (as_store_get_size (store), ==, 1);
4321 	app = as_store_get_app_by_id (store, "test.desktop");
4322 	g_assert (app != NULL);
4323 	g_assert_cmpstr (as_app_get_icon_path (app), !=, NULL);
4324 	g_assert (g_str_has_suffix (as_app_get_icon_path (app), "icons"));
4325 	g_assert_cmpstr (as_app_get_origin (app), ==, "fedora-21");
4326 
4327 	/* check format */
4328 	format = as_app_get_format_by_kind (app, AS_FORMAT_KIND_APPSTREAM);
4329 	g_assert (format != NULL);
4330 	g_assert_cmpstr (as_format_get_filename (format), ==, filename);
4331 }
4332 
4333 static void
as_test_store_speed_appstream_func(void)4334 as_test_store_speed_appstream_func (void)
4335 {
4336 	GError *error = NULL;
4337 	gboolean ret;
4338 	guint i;
4339 	guint loops = 10;
4340 	g_autofree gchar *filename = NULL;
4341 	g_autoptr(GFile) file = NULL;
4342 	g_autoptr(GTimer) timer = NULL;
4343 
4344 	filename = as_test_get_filename ("example-v04.xml.gz");
4345 	file = g_file_new_for_path (filename);
4346 	timer = g_timer_new ();
4347 	for (i = 0; i < loops; i++) {
4348 		g_autoptr(AsStore) store = NULL;
4349 		store = as_store_new ();
4350 		as_store_set_add_flags (store, AS_STORE_ADD_FLAG_ONLY_NATIVE_LANGS);
4351 		ret = as_store_from_file (store, file, NULL, NULL, &error);
4352 		g_assert_no_error (error);
4353 		g_assert (ret);
4354 		g_assert_cmpint (as_store_get_apps (store)->len, >=, 1415);
4355 		g_assert (as_store_get_app_by_id (store, "org.gnome.Software.desktop") != NULL);
4356 		g_assert (as_store_get_app_by_pkgname (store, "gnome-software") != NULL);
4357 	}
4358 	g_print ("%.0f ms: ", g_timer_elapsed (timer, NULL) * 1000 / loops);
4359 }
4360 
4361 static void
as_test_store_speed_search_func(void)4362 as_test_store_speed_search_func (void)
4363 {
4364 	AsApp *app;
4365 	GPtrArray *apps;
4366 	GError *error = NULL;
4367 	gboolean ret;
4368 	guint i;
4369 	guint j;
4370 	guint loops = 1000;
4371 	g_autofree gchar *filename = NULL;
4372 	g_autoptr(GFile) file = NULL;
4373 	g_autoptr(GTimer) timer = NULL;
4374 	g_autoptr(AsStore) store = NULL;
4375 
4376 	/* run creating a store and tokenizing */
4377 	filename = as_test_get_filename ("example-v04.xml.gz");
4378 	file = g_file_new_for_path (filename);
4379 	store = as_store_new ();
4380 	ret = as_store_from_file (store, file, NULL, NULL, &error);
4381 	g_assert_no_error (error);
4382 	g_assert (ret);
4383 
4384 	/* tokenize and search */
4385 	timer = g_timer_new ();
4386 	apps = as_store_get_apps (store);
4387 	for (j = 0; j < apps->len; j++) {
4388 		app = g_ptr_array_index (apps, j);
4389 		as_app_search_matches (app, "xxx");
4390 	}
4391 	g_print ("cold=%.0fms: ", g_timer_elapsed (timer, NULL) * 1000);
4392 
4393 	/* search again */
4394 	g_timer_reset (timer);
4395 	for (i = 0; i < loops; i++) {
4396 		for (j = 0; j < apps->len; j++) {
4397 			app = g_ptr_array_index (apps, j);
4398 			as_app_search_matches (app, "xxx");
4399 		}
4400 	}
4401 	g_print ("hot=%.2f ms: ", (g_timer_elapsed (timer, NULL) * 1000) / (gdouble) loops);
4402 }
4403 
4404 static void
as_test_store_speed_appdata_func(void)4405 as_test_store_speed_appdata_func (void)
4406 {
4407 	GError *error = NULL;
4408 	gboolean ret;
4409 	guint i;
4410 	guint loops = 10;
4411 	g_autofree gchar *filename = NULL;
4412 	g_autoptr(GTimer) timer = NULL;
4413 
4414 	filename = as_test_get_filename (".");
4415 	timer = g_timer_new ();
4416 	for (i = 0; i < loops; i++) {
4417 		g_autoptr(AsStore) store = NULL;
4418 		store = as_store_new ();
4419 		as_store_set_destdir (store, filename);
4420 		g_test_expect_message (G_LOG_DOMAIN,
4421 				       G_LOG_LEVEL_WARNING,
4422 				       "ignoring description '*' from */broken.appdata.xml: Unknown tag '_p'");
4423 		ret = as_store_load (store, AS_STORE_LOAD_FLAG_APPDATA, NULL, &error);
4424 		g_assert_no_error (error);
4425 		g_assert (ret);
4426 		g_assert_cmpint (as_store_get_apps (store)->len, >, 0);
4427 	}
4428 	g_print ("%.0f ms: ", g_timer_elapsed (timer, NULL) * 1000 / loops);
4429 }
4430 
4431 static void
as_test_store_speed_desktop_func(void)4432 as_test_store_speed_desktop_func (void)
4433 {
4434 	GError *error = NULL;
4435 	gboolean ret;
4436 	guint i;
4437 	guint loops = 10;
4438 	g_autofree gchar *filename = NULL;
4439 	g_autoptr(GTimer) timer = NULL;
4440 
4441 	filename = as_test_get_filename (".");
4442 	timer = g_timer_new ();
4443 	for (i = 0; i < loops; i++) {
4444 		g_autoptr(AsStore) store = NULL;
4445 		store = as_store_new ();
4446 		as_store_set_destdir (store, filename);
4447 		ret = as_store_load (store, AS_STORE_LOAD_FLAG_DESKTOP, NULL, &error);
4448 		g_assert_no_error (error);
4449 		g_assert (ret);
4450 		g_assert_cmpint (as_store_get_apps (store)->len, >, 0);
4451 	}
4452 	g_print ("%.0f ms: ", g_timer_elapsed (timer, NULL) * 1000 / loops);
4453 }
4454 
4455 static void
as_test_utils_appstream_id_func(void)4456 as_test_utils_appstream_id_func (void)
4457 {
4458 	g_autofree gchar *id = NULL;
4459 	g_assert (as_utils_appstream_id_valid ("org.gnome.Software"));
4460 	g_assert (!as_utils_appstream_id_valid ("xml:gravatar@jr.rlabs.io"));
4461 	id = as_utils_appstream_id_build ("gravatar@jr.rlabs.io");
4462 	g_assert_cmpstr (id, ==, "gravatar_jr.rlabs.io");
4463 }
4464 
4465 static void
as_test_utils_guid_func(void)4466 as_test_utils_guid_func (void)
4467 {
4468 #ifndef _WIN32
4469 	g_autofree gchar *guid1 = NULL;
4470 	g_autofree gchar *guid2 = NULL;
4471 
4472 	/* invalid */
4473 	g_assert (!as_utils_guid_is_valid (NULL));
4474 	g_assert (!as_utils_guid_is_valid (""));
4475 	g_assert (!as_utils_guid_is_valid ("1ff60ab2-3905-06a1-b476"));
4476 	g_assert (!as_utils_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b"));
4477 	g_assert (!as_utils_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b"));
4478 
4479 	/* valid */
4480 	g_assert (as_utils_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b"));
4481 
4482 	/* make valid */
4483 	guid1 = as_utils_guid_from_string ("python.org");
4484 	g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d");
4485 	guid2 = as_utils_guid_from_string ("8086:0406");
4486 	g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486");
4487 #endif
4488 }
4489 
4490 static void
as_test_utils_icons_func(void)4491 as_test_utils_icons_func (void)
4492 {
4493 	gchar *tmp;
4494 	GError *error = NULL;
4495 	g_autofree gchar *destdir = NULL;
4496 
4497 	destdir = as_test_get_filename (".");
4498 
4499 	/* full path */
4500 	tmp = as_utils_find_icon_filename (destdir, "/usr/share/pixmaps/test.png", &error);
4501 	g_assert_cmpstr (tmp, !=, NULL);
4502 	g_assert_no_error (error);
4503 	g_free (tmp);
4504 
4505 	/* full pixmaps name */
4506 	tmp = as_utils_find_icon_filename (destdir, "test.png", &error);
4507 	g_assert_cmpstr (tmp, !=, NULL);
4508 	g_assert_no_error (error);
4509 	g_free (tmp);
4510 
4511 	/* pixmaps name */
4512 	tmp = as_utils_find_icon_filename (destdir, "test", &error);
4513 	g_assert_cmpstr (tmp, !=, NULL);
4514 	g_assert_no_error (error);
4515 	g_free (tmp);
4516 
4517 	/* full theme name */
4518 	tmp = as_utils_find_icon_filename (destdir, "test2.png", &error);
4519 	g_assert_cmpstr (tmp, !=, NULL);
4520 	g_assert_no_error (error);
4521 	g_free (tmp);
4522 
4523 	/* theme name */
4524 	tmp = as_utils_find_icon_filename (destdir, "test2", &error);
4525 	g_assert_cmpstr (tmp, !=, NULL);
4526 	g_assert_no_error (error);
4527 	g_free (tmp);
4528 
4529 	/* theme name, HiDPI */
4530 	tmp = as_utils_find_icon_filename_full (destdir, "test3",
4531 						AS_UTILS_FIND_ICON_HI_DPI,
4532 						&error);
4533 	g_assert_cmpstr (tmp, !=, NULL);
4534 	g_assert_no_error (error);
4535 	g_free (tmp);
4536 
4537 	/* full pixmaps invalid */
4538 	tmp = as_utils_find_icon_filename (destdir, "/usr/share/pixmaps/not-going-to-exist.png", &error);
4539 	g_assert_cmpstr (tmp, ==, NULL);
4540 	g_assert_error (error, AS_UTILS_ERROR, AS_UTILS_ERROR_FAILED);
4541 	g_free (tmp);
4542 	g_clear_error (&error);
4543 
4544 	/* all invalid */
4545 	tmp = as_utils_find_icon_filename (destdir, "not-going-to-exist.png", &error);
4546 	g_assert_cmpstr (tmp, ==, NULL);
4547 	g_assert_error (error, AS_UTILS_ERROR, AS_UTILS_ERROR_FAILED);
4548 	g_free (tmp);
4549 	g_clear_error (&error);
4550 }
4551 
4552 static void
as_test_utils_spdx_token_func(void)4553 as_test_utils_spdx_token_func (void)
4554 {
4555 	gchar **tok;
4556 	gchar *tmp;
4557 
4558 	/* simple */
4559 	tok = as_utils_spdx_license_tokenize ("LGPL-2.0+");
4560 	tmp = g_strjoinv ("  ", tok);
4561 	g_assert_cmpstr (tmp, ==, "@LGPL-2.0+");
4562 	g_strfreev (tok);
4563 	g_free (tmp);
4564 
4565 	/* empty */
4566 	tok = as_utils_spdx_license_tokenize ("");
4567 	tmp = g_strjoinv ("  ", tok);
4568 	g_assert_cmpstr (tmp, ==, "");
4569 	g_strfreev (tok);
4570 	g_free (tmp);
4571 
4572 	/* invalid */
4573 	tok = as_utils_spdx_license_tokenize (NULL);
4574 	g_assert (tok == NULL);
4575 
4576 	/* random */
4577 	tok = as_utils_spdx_license_tokenize ("Public Domain");
4578 	tmp = g_strjoinv ("  ", tok);
4579 	g_assert_cmpstr (tmp, ==, "Public Domain");
4580 	g_strfreev (tok);
4581 	g_free (tmp);
4582 
4583 	/* multiple licences */
4584 	tok = as_utils_spdx_license_tokenize ("LGPL-2.0+ AND GPL-2.0 AND LGPL-3.0");
4585 	tmp = g_strjoinv ("  ", tok);
4586 	g_assert_cmpstr (tmp, ==, "@LGPL-2.0+  &  @GPL-2.0  &  @LGPL-3.0");
4587 	g_strfreev (tok);
4588 	g_free (tmp);
4589 
4590 	/* multiple licences, using the new style */
4591 	tok = as_utils_spdx_license_tokenize ("LGPL-2.0-or-later AND GPL-2.0-only");
4592 	tmp = g_strjoinv ("  ", tok);
4593 	g_assert_cmpstr (tmp, ==, "@LGPL-2.0+  &  @GPL-2.0");
4594 	g_strfreev (tok);
4595 	g_free (tmp);
4596 
4597 	/* multiple licences, deprecated 'and' & 'or' */
4598 	tok = as_utils_spdx_license_tokenize ("LGPL-2.0+ and GPL-2.0 or LGPL-3.0");
4599 	tmp = g_strjoinv ("  ", tok);
4600 	g_assert_cmpstr (tmp, ==, "@LGPL-2.0+  &  @GPL-2.0  |  @LGPL-3.0");
4601 	g_strfreev (tok);
4602 	g_free (tmp);
4603 
4604 	/* brackets */
4605 	tok = as_utils_spdx_license_tokenize ("LGPL-2.0+ and (GPL-2.0 or GPL-2.0+) and MIT");
4606 	tmp = g_strjoinv ("  ", tok);
4607 	g_assert_cmpstr (tmp, ==, "@LGPL-2.0+  &  (  @GPL-2.0  |  @GPL-2.0+  )  &  @MIT");
4608 	g_strfreev (tok);
4609 	g_free (tmp);
4610 
4611 	/* detokenisation */
4612 	tok = as_utils_spdx_license_tokenize ("LGPLv2+ and (QPL or GPLv2) and MIT");
4613 	tmp = as_utils_spdx_license_detokenize (tok);
4614 	g_assert_cmpstr (tmp, ==, "LGPLv2+ AND (QPL OR GPLv2) AND MIT");
4615 	g_strfreev (tok);
4616 	g_free (tmp);
4617 
4618 	/* "+" operator */
4619 	tok = as_utils_spdx_license_tokenize ("CC-BY-SA-3.0+ AND Zlib");
4620 	tmp = g_strjoinv ("  ", tok);
4621 	g_assert_cmpstr (tmp, ==, "@CC-BY-SA-3.0  +  &  @Zlib");
4622 	g_free (tmp);
4623 	tmp = as_utils_spdx_license_detokenize (tok);
4624 	g_assert_cmpstr (tmp, ==, "CC-BY-SA-3.0+ AND Zlib");
4625 	g_strfreev (tok);
4626 	g_free (tmp);
4627 
4628 	/* detokenisation literals */
4629 	tok = as_utils_spdx_license_tokenize ("Public Domain");
4630 	tmp = as_utils_spdx_license_detokenize (tok);
4631 	g_assert_cmpstr (tmp, ==, "Public Domain");
4632 	g_strfreev (tok);
4633 	g_free (tmp);
4634 
4635 	/* invalid tokens */
4636 	tmp = as_utils_spdx_license_detokenize (NULL);
4637 	g_assert (tmp == NULL);
4638 
4639 	/* leading brackets */
4640 	tok = as_utils_spdx_license_tokenize ("(MPLv1.1 or LGPLv3+) and LGPLv3");
4641 	tmp = g_strjoinv ("  ", tok);
4642 	g_assert_cmpstr (tmp, ==, "(  MPLv1.1  |  LGPLv3+  )  &  LGPLv3");
4643 	g_strfreev (tok);
4644 	g_free (tmp);
4645 
4646 	/*  trailing brackets */
4647 	tok = as_utils_spdx_license_tokenize ("MPLv1.1 and (LGPLv3 or GPLv3)");
4648 	tmp = g_strjoinv ("  ", tok);
4649 	g_assert_cmpstr (tmp, ==, "MPLv1.1  &  (  LGPLv3  |  GPLv3  )");
4650 	g_strfreev (tok);
4651 	g_free (tmp);
4652 
4653 	/*  deprecated names */
4654 	tok = as_utils_spdx_license_tokenize ("CC0 and (CC0 or CC0)");
4655 	tmp = g_strjoinv ("  ", tok);
4656 	g_assert_cmpstr (tmp, ==, "@CC0-1.0  &  (  @CC0-1.0  |  @CC0-1.0  )");
4657 	g_strfreev (tok);
4658 	g_free (tmp);
4659 
4660 	/* SPDX strings */
4661 	g_assert (as_utils_is_spdx_license ("CC0"));
4662 	g_assert (as_utils_is_spdx_license ("LicenseRef-proprietary"));
4663 	g_assert (as_utils_is_spdx_license ("CC0 and GFDL-1.3"));
4664 	g_assert (as_utils_is_spdx_license ("CC0 AND GFDL-1.3"));
4665 	g_assert (as_utils_is_spdx_license ("CC-BY-SA-3.0+"));
4666 	g_assert (as_utils_is_spdx_license ("CC-BY-SA-3.0+ AND Zlib"));
4667 	g_assert (as_utils_is_spdx_license ("NOASSERTION"));
4668 	g_assert (!as_utils_is_spdx_license ("CC0 dave"));
4669 	g_assert (!as_utils_is_spdx_license (""));
4670 	g_assert (!as_utils_is_spdx_license (NULL));
4671 
4672 	/* importing non-SPDX formats */
4673 	tmp = as_utils_license_to_spdx ("CC0 and (Public Domain and GPLv3+ with exceptions)");
4674 	g_assert_cmpstr (tmp, ==, "CC0-1.0 AND (LicenseRef-public-domain AND GPL-3.0+)");
4675 	g_free (tmp);
4676 }
4677 
4678 static void
as_test_utils_markup_import_func(void)4679 as_test_utils_markup_import_func (void)
4680 {
4681 	guint i;
4682 	struct {
4683 		const gchar *old;
4684 		const gchar *new;
4685 	} table[] = {
4686 		{ "",			NULL },
4687 		{ "dave",		"<p>dave</p>" },
4688 		{ "dave!\ndave?",	"<p>dave! dave?</p>" },
4689 		{ "dave!\n\ndave?",	"<p>dave!</p><p>dave?</p>" },
4690 		{ NULL,			NULL }
4691 	};
4692 	for (i = 0; table[i].old != NULL; i++) {
4693 		g_autofree gchar *new = NULL;
4694 		g_autoptr(GError) error = NULL;
4695 		new = as_markup_import (table[i].old,
4696 					AS_MARKUP_CONVERT_FORMAT_SIMPLE,
4697 					&error);
4698 		g_assert_no_error (error);
4699 		g_assert_cmpstr (new, ==, table[i].new);
4700 	}
4701 }
4702 
4703 static void
as_test_utils_func(void)4704 as_test_utils_func (void)
4705 {
4706 	gboolean ret;
4707 	gchar *tmp;
4708 	gchar **tokens;
4709 	GError *error = NULL;
4710 
4711 	/* as_utils_is_stock_icon_name */
4712 	g_assert (!as_utils_is_stock_icon_name (NULL));
4713 	g_assert (!as_utils_is_stock_icon_name (""));
4714 	g_assert (!as_utils_is_stock_icon_name ("indigo-blue"));
4715 	g_assert (as_utils_is_stock_icon_name ("accessories-calculator"));
4716 	g_assert (as_utils_is_stock_icon_name ("insert-image"));
4717 	g_assert (as_utils_is_stock_icon_name ("zoom-out"));
4718 
4719 	/* environments */
4720 	g_assert (as_utils_is_environment_id ("GNOME"));
4721 	g_assert (!as_utils_is_environment_id ("RandomDE"));
4722 
4723 	/* categories */
4724 	g_assert (as_utils_is_category_id ("AudioVideoEditing"));
4725 	g_assert (!as_utils_is_category_id ("SpellEditing"));
4726 
4727 	/* valid description markup */
4728 	tmp = as_markup_convert_simple ("<p>Hello world!</p>", &error);
4729 	g_assert_no_error (error);
4730 	g_assert_cmpstr (tmp, ==, "Hello world!");
4731 	g_free (tmp);
4732 	tmp = as_markup_convert_simple ("<p>Hello world</p><p></p>"
4733 					"<ul><li>Item</li></ul>",
4734 					&error);
4735 	g_assert_no_error (error);
4736 	g_assert_cmpstr (tmp, ==, "Hello world\n • Item");
4737 	g_free (tmp);
4738 
4739 	/* valid description markup */
4740 	tmp = as_markup_convert ("<p>Hello world with a very long line that"
4741 				 " probably needs splitting at least once in"
4742 				 " the right place.</p>"
4743 				 "<ul><li>"
4744 				 "This is an overly long item that needs to be"
4745 				 " broken into multiple lines that only has one"
4746 				 " initial bullet point."
4747 				 "</li></ul>",
4748 				 AS_MARKUP_CONVERT_FORMAT_MARKDOWN, &error);
4749 	g_assert_no_error (error);
4750 	g_assert_cmpstr (tmp, ==,
4751 			 "Hello world with a very long line that probably"
4752 			 " needs splitting at least once\n"
4753 			 "in the right place.\n"
4754 			 " * This is an overly long item that needs to be"
4755 			 " broken into multiple lines that\n"
4756 			 "   only has one initial bullet point.");
4757 	g_free (tmp);
4758 
4759 	/* valid description markup */
4760 	tmp = as_markup_convert_simple ("bare text", &error);
4761 	g_assert_no_error (error);
4762 	g_assert_cmpstr (tmp, ==, "bare text");
4763 	g_free (tmp);
4764 
4765 	/* invalid XML */
4766 	tmp = as_markup_convert_simple ("<p>Hello world</dave>", &error);
4767 	g_assert_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED);
4768 	g_assert_cmpstr (tmp, ==, NULL);
4769 	g_clear_error (&error);
4770 
4771 	/* validate */
4772 	ret = as_markup_validate ("<p>hello</p>", &error);
4773 	g_assert_no_error (error);
4774 	g_assert (ret);
4775 	ret = as_markup_validate ("<ol><li>hello</ol>", &error);
4776 	g_assert_error (error, AS_NODE_ERROR, AS_NODE_ERROR_FAILED);
4777 	g_assert (!ret);
4778 	g_clear_error (&error);
4779 
4780 	/* passthrough */
4781 	tmp = as_markup_convert ("<p>pa&amp;ra</p><ul><li>one</li><li>two</li></ul>",
4782 				 AS_MARKUP_CONVERT_FORMAT_APPSTREAM,
4783 				 &error);
4784 	g_assert_no_error (error);
4785 	g_assert_cmpstr (tmp, ==, "<p>pa&amp;ra</p><ul><li>one</li><li>two</li></ul>");
4786 	g_free (tmp);
4787 
4788 	/* ignore errors */
4789 	tmp = as_markup_convert_full ("<p>para</p><ol><li>one</li></ol><li>two</li>",
4790 				      AS_MARKUP_CONVERT_FORMAT_APPSTREAM,
4791 				      AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS,
4792 				      &error);
4793 	g_assert_no_error (error);
4794 	g_assert_cmpstr (tmp, ==, "<p>para</p><ul><li>one</li></ul>");
4795 	g_free (tmp);
4796 	tmp = as_markup_convert_full ("<p>para</p><ul><li>one</li><li>two</ul>",
4797 				      AS_MARKUP_CONVERT_FORMAT_APPSTREAM,
4798 				      AS_MARKUP_CONVERT_FLAG_IGNORE_ERRORS,
4799 				      &error);
4800 	g_assert_no_error (error);
4801 	g_assert_cmpstr (tmp, ==, "<p>para</p>");
4802 	g_free (tmp);
4803 
4804 	/* valid tokens */
4805 	g_assert (as_utils_search_token_valid ("battery"));
4806 	g_assert (!as_utils_search_token_valid ("<b>"));
4807 
4808 	/* check tokenisation */
4809 	tokens = as_utils_search_tokenize ("a c b");
4810 	g_assert (tokens == NULL);
4811 	tokens = as_utils_search_tokenize ("batteries are (really) stupid");
4812 	g_assert_cmpstr (tokens[0], ==, "batteries");
4813 	g_assert_cmpstr (tokens[1], ==, "are");
4814 	g_assert_cmpstr (tokens[2], ==, "stupid");
4815 	g_assert_cmpstr (tokens[3], ==, NULL);
4816 	g_strfreev (tokens);
4817 }
4818 
4819 static void
as_test_utils_version_func(void)4820 as_test_utils_version_func (void)
4821 {
4822 	guint i;
4823 	struct {
4824 		guint32 val;
4825 		const gchar *ver;
4826 		AsVersionParseFlag flags;
4827 	} version_from_uint32[] = {
4828 		{ 0x0,		"0.0.0.0",	AS_VERSION_PARSE_FLAG_NONE },
4829 		{ 0xff,		"0.0.0.255",	AS_VERSION_PARSE_FLAG_NONE },
4830 		{ 0xff01,	"0.0.255.1",	AS_VERSION_PARSE_FLAG_NONE },
4831 		{ 0xff0001,	"0.255.0.1",	AS_VERSION_PARSE_FLAG_NONE },
4832 		{ 0xff000100,	"255.0.1.0",	AS_VERSION_PARSE_FLAG_NONE },
4833 		{ 0x0,		"0.0.0",	AS_VERSION_PARSE_FLAG_USE_TRIPLET },
4834 		{ 0xff,		"0.0.255",	AS_VERSION_PARSE_FLAG_USE_TRIPLET },
4835 		{ 0xff01,	"0.0.65281",	AS_VERSION_PARSE_FLAG_USE_TRIPLET },
4836 		{ 0xff0001,	"0.255.1",	AS_VERSION_PARSE_FLAG_USE_TRIPLET },
4837 		{ 0xff000100,	"255.0.256",	AS_VERSION_PARSE_FLAG_USE_TRIPLET },
4838 		{ 0,		NULL }
4839 	};
4840 	struct {
4841 		guint16 val;
4842 		const gchar *ver;
4843 		AsVersionParseFlag flags;
4844 	} version_from_uint16[] = {
4845 		{ 0x0,		"0.0",		AS_VERSION_PARSE_FLAG_NONE },
4846 		{ 0xff,		"0.255",	AS_VERSION_PARSE_FLAG_NONE },
4847 		{ 0xff01,	"255.1",	AS_VERSION_PARSE_FLAG_NONE },
4848 		{ 0x0,		"0.0",		AS_VERSION_PARSE_FLAG_USE_BCD },
4849 		{ 0x0110,	"1.10",		AS_VERSION_PARSE_FLAG_USE_BCD },
4850 		{ 0x9999,	"99.99",	AS_VERSION_PARSE_FLAG_USE_BCD },
4851 		{ 0,		NULL }
4852 	};
4853 	struct {
4854 		const gchar *old;
4855 		const gchar *new;
4856 	} version_parse[] = {
4857 		{ "0",		"0" },
4858 		{ "0x1a",	"0.0.26" },
4859 		{ "257",	"0.0.257" },
4860 		{ "1.2.3",	"1.2.3" },
4861 		{ "0xff0001",	"0.255.1" },
4862 		{ "16711681",	"0.255.1" },
4863 		{ "20150915",	"20150915" },
4864 		{ "dave",	"dave" },
4865 		{ "0x1x",	"0x1x" },
4866 		{ NULL,		NULL }
4867 	};
4868 
4869 	/* check version conversion */
4870 	for (i = 0; version_from_uint32[i].ver != NULL; i++) {
4871 		g_autofree gchar *ver = NULL;
4872 		ver = as_utils_version_from_uint32 (version_from_uint32[i].val,
4873 						    version_from_uint32[i].flags);
4874 		g_assert_cmpstr (ver, ==, version_from_uint32[i].ver);
4875 	}
4876 	for (i = 0; version_from_uint16[i].ver != NULL; i++) {
4877 		g_autofree gchar *ver = NULL;
4878 		ver = as_utils_version_from_uint16 (version_from_uint16[i].val,
4879 						    version_from_uint16[i].flags);
4880 		g_assert_cmpstr (ver, ==, version_from_uint16[i].ver);
4881 	}
4882 
4883 	/* check version parsing */
4884 	for (i = 0; version_parse[i].old != NULL; i++) {
4885 		g_autofree gchar *ver = NULL;
4886 		ver = as_utils_version_parse (version_parse[i].old);
4887 		g_assert_cmpstr (ver, ==, version_parse[i].new);
4888 	}
4889 }
4890 
4891 static void
as_test_store_metadata_func(void)4892 as_test_store_metadata_func (void)
4893 {
4894 	GError *error = NULL;
4895 	GPtrArray *apps;
4896 	gboolean ret;
4897 	const gchar *xml =
4898 		"<components version=\"0.6\">"
4899 		"<component type=\"desktop\">"
4900 		"<id>test.desktop</id>"
4901 		"<metadata>"
4902 		"<value key=\"foo\">bar</value>"
4903 		"</metadata>"
4904 		"</component>"
4905 		"<component type=\"desktop\">"
4906 		"<id>tested.desktop</id>"
4907 		"<metadata>"
4908 		"<value key=\"foo\">bar</value>"
4909 		"</metadata>"
4910 		"</component>"
4911 		"</components>";
4912 	g_autoptr(AsStore) store = NULL;
4913 
4914 	store = as_store_new ();
4915 	ret = as_store_from_xml (store, xml, NULL, &error);
4916 	g_assert_no_error (error);
4917 	g_assert (ret);
4918 
4919 	apps = as_store_get_apps_by_metadata (store, "foo", "bar");
4920 	g_assert_cmpint (apps->len, ==, 2);
4921 	g_ptr_array_unref (apps);
4922 }
4923 
4924 static void
as_test_store_metadata_index_func(void)4925 as_test_store_metadata_index_func (void)
4926 {
4927 	GPtrArray *apps;
4928 	const guint repeats = 500;
4929 	guint i;
4930 	g_autoptr(AsStore) store = NULL;
4931 	g_autoptr(GTimer) timer = NULL;
4932 
4933 	/* create lots of applications in the store */
4934 	store = as_store_new ();
4935 	as_store_add_metadata_index (store, "X-CacheID");
4936 	for (i = 0; i < repeats; i++) {
4937 		g_autofree gchar *id = g_strdup_printf ("app-%05u", i);
4938 		g_autoptr(AsApp) app = as_app_new ();
4939 		as_app_set_id (app, id);
4940 		as_app_add_metadata (app, "X-CacheID", "dave.i386");
4941 		as_app_add_metadata (app, "baz", "dave");
4942 		as_store_add_app (store, app);
4943 	}
4944 
4945 	/* find out how long this takes with an index */
4946 	timer = g_timer_new ();
4947 	for (i = 0; i < repeats; i++) {
4948 		apps = as_store_get_apps_by_metadata (store, "X-CacheID", "dave.i386");
4949 		g_assert_cmpint (apps->len, ==, repeats);
4950 		g_ptr_array_unref (apps);
4951 		apps = as_store_get_apps_by_metadata (store, "X-CacheID", "notgoingtoexist");
4952 		g_assert_cmpint (apps->len, ==, 0);
4953 		g_ptr_array_unref (apps);
4954 	}
4955 	g_assert_cmpfloat (g_timer_elapsed (timer, NULL), <, 0.5);
4956 	g_print ("%.0fms: ", g_timer_elapsed (timer, NULL) * 1000);
4957 }
4958 
4959 static void
as_test_yaml_broken_func(void)4960 as_test_yaml_broken_func (void)
4961 {
4962 #ifdef AS_BUILD_DEP11
4963 	g_autoptr(AsYaml) node = NULL;
4964 	g_autoptr(GError) error1 = NULL;
4965 	g_autoptr(GError) error2 = NULL;
4966 	node = as_yaml_from_data ("s---\n"
4967 				  "File: DEP-11\n",
4968 				  -1,
4969 				  AS_YAML_FROM_FLAG_NONE,
4970 				  &error1);
4971 	g_assert_error (error1, AS_NODE_ERROR, AS_NODE_ERROR_INVALID_MARKUP);
4972 	g_assert (node == NULL);
4973 	node = as_yaml_from_data ("---\n"
4974 				  "%File: DEP-11\n",
4975 				  -1,
4976 				  AS_YAML_FROM_FLAG_NONE,
4977 				  &error2);
4978 	g_assert_error (error2, AS_NODE_ERROR, AS_NODE_ERROR_INVALID_MARKUP);
4979 	g_assert_cmpstr (error2->message, ==,
4980 			 "scanner error: while scanning a directive at ln:2 col:1, "
4981 			 "found unexpected non-alphabetical character at ln:2 col:6");
4982 	g_assert (node == NULL);
4983 #else
4984 	g_test_skip ("Compiled without YAML (DEP-11) support");
4985 #endif
4986 }
4987 
4988 static void
as_test_yaml_func(void)4989 as_test_yaml_func (void)
4990 {
4991 #ifdef AS_BUILD_DEP11
4992 	AsYaml *node;
4993 	GError *error = NULL;
4994 	GString *str;
4995 	const gchar *expected;
4996 	g_autofree gchar *filename = NULL;
4997 	g_autoptr(GFile) file = NULL;
4998 	gboolean ret;
4999 
5000 	/* simple header */
5001 	node = as_yaml_from_data (
5002 		"File: DEP-11\n"
5003 		"Origin: aequorea\n"
5004 		"Version: '0.6'\n",
5005 		-1,
5006 		AS_YAML_FROM_FLAG_NONE,
5007 		&error);
5008 	g_assert_no_error (error);
5009 	g_assert (node != NULL);
5010 	str = as_yaml_to_string (node);
5011 	expected =
5012 		"[MAP]{\n"
5013 		" [KVL]File=DEP-11\n"
5014 		" [KVL]Origin=aequorea\n"
5015 		" [KVL]Version=0.6\n";
5016 	if (g_strcmp0 (str->str, expected) != 0)
5017 		g_warning ("Expected:\n%s\nGot:\n%s", expected, str->str);
5018 	g_assert_cmpstr (str->str, ==, expected);
5019 	g_string_free (str, TRUE);
5020 	as_yaml_unref (node);
5021 
5022 	/* simple list */
5023 	node = as_yaml_from_data (
5024 		"---\n"
5025 		"Mimetypes:\n"
5026 		"  - text/html\n"
5027 		"  - text/xml\n"
5028 		"  - application/xhtml+xml\n"
5029 		"Kudos:\n"
5030 		"  - AppMenu\n"
5031 		"  - SearchProvider\n"
5032 		"  - Notifications\n",
5033 		-1,
5034 		AS_YAML_FROM_FLAG_NONE,
5035 		&error);
5036 	g_assert_no_error (error);
5037 	g_assert (node != NULL);
5038 	str = as_yaml_to_string (node);
5039 	expected =
5040 		"[MAP]{\n"
5041 		" [SEQ]Mimetypes\n"
5042 		"  [KEY]text/html\n"
5043 		"  [KEY]text/xml\n"
5044 		"  [KEY]application/xhtml+xml\n"
5045 		" [SEQ]Kudos\n"
5046 		"  [KEY]AppMenu\n"
5047 		"  [KEY]SearchProvider\n"
5048 		"  [KEY]Notifications\n";
5049 	if (g_strcmp0 (str->str, expected) != 0)
5050 		g_warning ("Expected:\n%s\nGot:\n%s", expected, str->str);
5051 	g_assert_cmpstr (str->str, ==, expected);
5052 	g_string_free (str, TRUE);
5053 	as_yaml_unref (node);
5054 
5055 	/* dummy application */
5056 	filename = as_test_get_filename ("usr/share/app-info/yaml/aequorea.yml");
5057 	g_assert (filename != NULL);
5058 	file = g_file_new_for_path (filename);
5059 	node = as_yaml_from_file (file, AS_YAML_FROM_FLAG_NONE, NULL, &error);
5060 	g_assert_no_error (error);
5061 	g_assert (node != NULL);
5062 	str = as_yaml_to_string (node);
5063 	expected =
5064 		"[MAP]{\n"
5065 		" [KVL]File=DEP-11\n"
5066 		" [KVL]Origin=aequorea\n"
5067 		" [KVL]Version=0.6\n"
5068 		"[MAP]{\n"
5069 		" [KVL]Type=desktop-app\n"
5070 		" [KVL]ID=iceweasel.desktop\n"
5071 		" [MAP]Name\n"
5072 		"  [KVL]C=Iceweasel\n"
5073 		" [KVL]Package=iceweasel\n"
5074 		" [MAP]Icon\n"
5075 		"  [SEQ]cached\n"
5076 		"   [MAP]{\n"
5077 		"    [KVL]name=iceweasel.png\n"
5078 		"    [KVL]width=64\n"
5079 		"    [KVL]height=64\n"
5080 		" [MAP]Keywords\n"
5081 		"  [SEQ]C\n"
5082 		"   [KEY]browser\n"
5083 		" [SEQ]Screenshots\n"
5084 		"  [MAP]{\n"
5085 		"   [KVL]default=true\n"
5086 		"   [MAP]source-image\n"
5087 		"    [KVL]height=770\n"
5088 		"    [KVL]url=http://localhost/source/screenshot.png\n"
5089 		"    [KVL]width=1026\n"
5090 		"   [SEQ]thumbnails\n"
5091 		"    [MAP]{\n"
5092 		"     [KVL]height=423\n"
5093 		"     [KVL]url=http://localhost/752x423/screenshot.png\n"
5094 		"     [KVL]width=752\n"
5095 		"[MAP]{\n"
5096 		" [KVL]Type=desktop-app\n"
5097 		" [KVL]ID=dave.desktop\n"
5098 		" [MAP]Name\n"
5099 		"  [KVL]C=dave\n";
5100 	ret = as_test_compare_lines (str->str, expected, &error);
5101 	g_assert_no_error (error);
5102 	g_assert (ret);
5103 	g_string_free (str, TRUE);
5104 	as_yaml_unref (node);
5105 #else
5106 	g_test_skip ("Compiled without YAML (DEP-11) support");
5107 #endif
5108 }
5109 
5110 static void
as_test_store_yaml_func(void)5111 as_test_store_yaml_func (void)
5112 {
5113 #ifdef AS_BUILD_DEP11
5114 	AsApp *app;
5115 	GError *error = NULL;
5116 	gboolean ret;
5117 	g_autofree gchar *filename = NULL;
5118 	g_autoptr(AsStore) store = NULL;
5119 	g_autoptr(GFile) file = NULL;
5120 	g_autoptr(GString) str = NULL;
5121 	const gchar *xml =
5122 		"<components origin=\"aequorea\" version=\"0.6\">\n"
5123 		"<component type=\"desktop\">\n"
5124 		"<id>dave.desktop</id>\n"
5125 		"<name>dave</name>\n"
5126 		"</component>\n"
5127 		"<component type=\"desktop\">\n"
5128 		"<id>iceweasel.desktop</id>\n"
5129 		"<pkgname>iceweasel</pkgname>\n"
5130 		"<name>Iceweasel</name>\n"
5131 		"<icon type=\"cached\" height=\"64\" width=\"64\">iceweasel.png</icon>\n"
5132 		"<keywords>\n"
5133 		"<keyword>browser</keyword>\n"
5134 		"</keywords>\n"
5135 		"<screenshots>\n"
5136 		"<screenshot type=\"default\">\n"
5137 		"<image type=\"source\" height=\"770\" width=\"1026\">http://localhost/source/screenshot.png</image>\n"
5138 		"<image type=\"thumbnail\" height=\"423\" width=\"752\">http://localhost/752x423/screenshot.png</image>\n"
5139 		"</screenshot>\n"
5140 		"</screenshots>\n"
5141 		"</component>\n"
5142 		"</components>\n";
5143 
5144 	/* load store */
5145 	store = as_store_new ();
5146 	filename = as_test_get_filename ("usr/share/app-info/yaml/aequorea.yml");
5147 	g_assert (filename != NULL);
5148 	file = g_file_new_for_path (filename);
5149 	ret = as_store_from_file (store, file, NULL, NULL, &error);
5150 	g_assert_no_error (error);
5151 	g_assert (ret);
5152 
5153 	/* test it matches expected XML */
5154 	str = as_store_to_xml (store, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
5155 	ret = as_test_compare_lines (str->str, xml, &error);
5156 	g_assert_no_error (error);
5157 	g_assert (ret);
5158 
5159 	/* test store properties */
5160 	g_assert_cmpstr (as_store_get_origin (store), ==, "aequorea");
5161 	g_assert_cmpfloat (as_store_get_api_version (store), <, 0.6 + 0.01);
5162 	g_assert_cmpfloat (as_store_get_api_version (store), >, 0.6 - 0.01);
5163 	g_assert_cmpint (as_store_get_size (store), ==, 2);
5164 	g_assert (as_store_get_app_by_id (store, "iceweasel.desktop") != NULL);
5165 	g_assert (as_store_get_app_by_id (store, "dave.desktop") != NULL);
5166 
5167 	/* test application properties */
5168 	app = as_store_get_app_by_id (store, "iceweasel.desktop");
5169 	g_assert_cmpint (as_app_get_kind (app), ==, AS_APP_KIND_DESKTOP);
5170 	g_assert_cmpstr (as_app_get_pkgname_default (app), ==, "iceweasel");
5171 	g_assert_cmpstr (as_app_get_name (app, "C"), ==, "Iceweasel");
5172 	g_assert_cmpstr (as_app_get_origin (app), ==, "aequorea");
5173 #else
5174 	g_test_skip ("Compiled without YAML (DEP-11) support");
5175 #endif
5176 }
5177 
5178 static void
as_test_store_speed_yaml_func(void)5179 as_test_store_speed_yaml_func (void)
5180 {
5181 #ifdef AS_BUILD_DEP11
5182 	GError *error = NULL;
5183 	gboolean ret;
5184 	guint i;
5185 	guint loops = 10;
5186 	g_autofree gchar *filename = NULL;
5187 	g_autoptr(GFile) file = NULL;
5188 	g_autoptr(GTimer) timer = NULL;
5189 
5190 	filename = as_test_get_filename ("example-v06.yml.gz");
5191 	g_assert (filename != NULL);
5192 	file = g_file_new_for_path (filename);
5193 	timer = g_timer_new ();
5194 	for (i = 0; i < loops; i++) {
5195 		g_autoptr(AsStore) store = NULL;
5196 		store = as_store_new ();
5197 		ret = as_store_from_file (store, file, NULL, NULL, &error);
5198 		g_assert_no_error (error);
5199 		g_assert (ret);
5200 
5201 		/* test store properties */
5202 		g_assert_cmpstr (as_store_get_origin (store), ==, "bartholomea");
5203 		g_assert_cmpfloat (as_store_get_api_version (store), <, 0.6 + 0.01);
5204 		g_assert_cmpfloat (as_store_get_api_version (store), >, 0.6 - 0.01);
5205 		g_assert_cmpint (as_store_get_size (store), ==, 85);
5206 		g_assert (as_store_get_app_by_id (store, "blobwars.desktop") != NULL);
5207 	}
5208 	g_print ("%.0f ms: ", g_timer_elapsed (timer, NULL) * 1000 / loops);
5209 #else
5210 	g_test_skip ("Compiled without YAML (DEP-11) support");
5211 #endif
5212 }
5213 
5214 static void
as_test_utils_vercmp_func(void)5215 as_test_utils_vercmp_func (void)
5216 {
5217 	/* same */
5218 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3"), ==, 0);
5219 	g_assert_cmpint (as_utils_vercmp ("001.002.003", "001.002.003"), ==, 0);
5220 
5221 	/* same, not dotted decimal */
5222 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "0x1020003"), ==, 0);
5223 	g_assert_cmpint (as_utils_vercmp ("0x10203", "0x10203"), ==, 0);
5224 
5225 	/* upgrade and downgrade */
5226 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.4"), <, 0);
5227 	g_assert_cmpint (as_utils_vercmp ("001.002.000", "001.002.009"), <, 0);
5228 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.2"), >, 0);
5229 	g_assert_cmpint (as_utils_vercmp ("001.002.009", "001.002.000"), >, 0);
5230 
5231 	/* unequal depth */
5232 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3.1"), <, 0);
5233 	g_assert_cmpint (as_utils_vercmp ("1.2.3.1", "1.2.4"), <, 0);
5234 
5235 	/* mixed-alpha-numeric */
5236 	g_assert_cmpint (as_utils_vercmp ("1.2.3a", "1.2.3a"), ==, 0);
5237 	g_assert_cmpint (as_utils_vercmp ("1.2.3a", "1.2.3b"), <, 0);
5238 	g_assert_cmpint (as_utils_vercmp ("1.2.3b", "1.2.3a"), >, 0);
5239 
5240 	/* alpha version append */
5241 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3a"), <, 0);
5242 	g_assert_cmpint (as_utils_vercmp ("1.2.3a", "1.2.3"), >, 0);
5243 
5244 	/* alpha only */
5245 	g_assert_cmpint (as_utils_vercmp ("alpha", "alpha"), ==, 0);
5246 	g_assert_cmpint (as_utils_vercmp ("alpha", "beta"), <, 0);
5247 	g_assert_cmpint (as_utils_vercmp ("beta", "alpha"), >, 0);
5248 
5249 	/* alpha-compare */
5250 	g_assert_cmpint (as_utils_vercmp ("1.2a.3", "1.2a.3"), ==, 0);
5251 	g_assert_cmpint (as_utils_vercmp ("1.2a.3", "1.2b.3"), <, 0);
5252 	g_assert_cmpint (as_utils_vercmp ("1.2b.3", "1.2a.3"), >, 0);
5253 
5254 	/* tilde is all-powerful */
5255 	g_assert_cmpint (as_utils_vercmp ("1.2.3~rc1", "1.2.3~rc1"), ==, 0);
5256 	g_assert_cmpint (as_utils_vercmp ("1.2.3~rc1", "1.2.3"), <, 0);
5257 	g_assert_cmpint (as_utils_vercmp ("1.2.3", "1.2.3~rc1"), >, 0);
5258 	g_assert_cmpint (as_utils_vercmp ("1.2.3~rc2", "1.2.3~rc1"), >, 0);
5259 
5260 	/* invalid */
5261 	g_assert_cmpint (as_utils_vercmp ("1", NULL), ==, G_MAXINT);
5262 	g_assert_cmpint (as_utils_vercmp (NULL, "1"), ==, G_MAXINT);
5263 	g_assert_cmpint (as_utils_vercmp (NULL, NULL), ==, G_MAXINT);
5264 
5265 	/* full version gets some more checks right */
5266 	g_assert_cmpint (as_utils_vercmp_full ("0.9", "1", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5267 	g_assert_cmpint (as_utils_vercmp_full ("9", "9a", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5268 	g_assert_cmpint (as_utils_vercmp_full ("9a", "10", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5269 	g_assert_cmpint (as_utils_vercmp_full ("9+", "10", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5270 	g_assert_cmpint (as_utils_vercmp_full ("9half", "10", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5271 	g_assert_cmpint (as_utils_vercmp_full ("9.5", "10", AS_VERSION_COMPARE_FLAG_NONE), <, 0);
5272 }
5273 
5274 static void
as_test_utils_install_filename_func(void)5275 as_test_utils_install_filename_func (void)
5276 {
5277 	gboolean ret;
5278 	GError *error = NULL;
5279 	g_autofree gchar *filename1 = NULL;
5280 	g_autofree gchar *filename2 = NULL;
5281 	g_autofree gchar *filename3 = NULL;
5282 	g_autofree gchar *filename4 = NULL;
5283 
5284 	/* appdata to shared */
5285 	filename1 = as_test_get_filename ("broken.appdata.xml");
5286 	ret = as_utils_install_filename	(AS_UTILS_LOCATION_SHARED,
5287 					 filename1, NULL,
5288 					 "/tmp/destdir/",
5289 					 &error);
5290 	g_assert_no_error (error);
5291 	g_assert (ret);
5292 	g_assert (g_file_test ("/tmp/destdir/usr/share/appdata/broken.appdata.xml", G_FILE_TEST_EXISTS));
5293 
5294 	/* metainfo to cache */
5295 	filename2 = as_test_get_filename ("example.metainfo.xml");
5296 	ret = as_utils_install_filename	(AS_UTILS_LOCATION_CACHE,
5297 					 filename2, NULL,
5298 					 "/tmp/destdir/",
5299 					 &error);
5300 	g_assert_error (error, AS_UTILS_ERROR, AS_UTILS_ERROR_INVALID_TYPE);
5301 	g_assert (!ret);
5302 	g_assert (!g_file_test ("/tmp/destdir/var/cache/appdata/example.metainfo.xml", G_FILE_TEST_EXISTS));
5303 	g_clear_error (&error);
5304 
5305 	/* appstream to cache */
5306 	filename3 = as_test_get_filename ("origin.xml");
5307 	ret = as_utils_install_filename	(AS_UTILS_LOCATION_CACHE,
5308 					 filename3, NULL,
5309 					 "/tmp/destdir/",
5310 					 &error);
5311 	g_assert_no_error (error);
5312 	g_assert (ret);
5313 	g_assert (g_file_test ("/tmp/destdir/var/cache/app-info/xmls/origin.xml", G_FILE_TEST_EXISTS));
5314 
5315 	/* icons to cache, override origin */
5316 	filename4 = as_test_get_filename ("origin-icons.tar.gz");
5317 	ret = as_utils_install_filename	(AS_UTILS_LOCATION_CACHE,
5318 					 filename4, "neworigin",
5319 					 "/tmp/destdir/",
5320 					 &error);
5321 	g_assert_no_error (error);
5322 	g_assert (ret);
5323 	g_assert (g_file_test ("/tmp/destdir/var/cache/app-info/icons/neworigin/64x64/org.gnome.Software.png", G_FILE_TEST_EXISTS));
5324 
5325 	/* icons to shared */
5326 	ret = as_utils_install_filename	(AS_UTILS_LOCATION_SHARED,
5327 					 filename4, NULL,
5328 					 "/tmp/destdir/",
5329 					 &error);
5330 	g_assert_no_error (error);
5331 	g_assert (ret);
5332 	g_assert (g_file_test ("/tmp/destdir/usr/share/app-info/icons/origin/64x64/org.gnome.Software.png", G_FILE_TEST_EXISTS));
5333 }
5334 
5335 static void
as_test_utils_string_replace_func(void)5336 as_test_utils_string_replace_func (void)
5337 {
5338 	guint i;
5339 	struct {
5340 		const gchar *str;
5341 		const gchar *search;
5342 		const gchar *replace;
5343 		const gchar *result;
5344 	} table[] = {
5345 		{ "",		"",		"",		"" },
5346 		{ "one",	"one",		"two",		"two" },
5347 		{ "one",	"one",		"1",		"1" },
5348 		{ "one",	"one",		"onlyme",	"onlyme" },
5349 		{ "we few ppl",	" few ",	"",		"weppl" },
5350 		{ "bee&",	"&",		"&amp;",	"bee&amp;" },
5351 		{ NULL,		NULL,		NULL,		NULL }
5352 	};
5353 	for (i = 0; table[i].str != NULL; i++) {
5354 		g_autoptr(GString) str = g_string_new (table[i].str);
5355 		as_utils_string_replace (str,
5356 					 table[i].search,
5357 					 table[i].replace);
5358 		g_assert_cmpstr (str->str, ==, table[i].result);
5359 	}
5360 }
5361 
5362 static void
as_test_utils_locale_compat_func(void)5363 as_test_utils_locale_compat_func (void)
5364 {
5365 	/* empty */
5366 	g_assert (as_utils_locale_is_compatible (NULL, NULL));
5367 
5368 	/* same */
5369 	g_assert (as_utils_locale_is_compatible ("en_GB", "en_GB"));
5370 
5371 	/* forward and reverse compatible */
5372 	g_assert (as_utils_locale_is_compatible ("en_GB", "en"));
5373 	g_assert (as_utils_locale_is_compatible ("en", "en_GB"));
5374 
5375 	/* different language and locale */
5376 	g_assert (!as_utils_locale_is_compatible ("en_GB", "fr_FR"));
5377 
5378 	/* politics */
5379 	g_assert (!as_utils_locale_is_compatible ("zh_CN", "zh_TW"));
5380 
5381 	/* never going to match system locale or language */
5382 	g_assert (!as_utils_locale_is_compatible ("xx_XX", NULL));
5383 	g_assert (!as_utils_locale_is_compatible (NULL, "xx_XX"));
5384 }
5385 
5386 static void
as_test_markup_import_html(void)5387 as_test_markup_import_html (void)
5388 {
5389 	const gchar *input;
5390 	g_autofree gchar *out_complex = NULL;
5391 	g_autofree gchar *out_list = NULL;
5392 	g_autofree gchar *out_simple = NULL;
5393 	g_autoptr(GError) error = NULL;
5394 	guint i;
5395 	struct {
5396 		const gchar *html;
5397 		const gchar *markup;
5398 	} table[] = {
5399 		{ "",					"" },
5400 		{ "dave",				"<p>dave</p>" },
5401 		{ "&trade;",				"<p>™</p>" },
5402 		{ "<p>paul</p>",			"<p>paul</p>" },
5403 		{ "<p>tim</p><p>baz</p>",		"<p>tim</p>\n<p>baz</p>" },
5404 		{ "<ul><li>1</li></ul>",		"<ul><li>1</li></ul>" },
5405 		{ "<ul><li>1</li><li>2</li></ul>",	"<ul><li>1</li><li>2</li></ul>" },
5406 		{ "<p>foo<i>awesome</i></p>",		"<p>fooawesome</p>" },
5407 		{ "a<img src=\"moo.png\">b",		"<p>ab</p>" },
5408 		{ "<h2>title</h2>content",		"<p>content</p>" },
5409 		{ "para1<br><br>para2",			"<p>para1</p>\n<p>para2</p>" },
5410 		{ "para1<h1>ignore</h1>para2",		"<p>para1</p>\n<p>para2</p>" },
5411 		{ NULL,				NULL}
5412 	};
5413 	for (i = 0; table[i].html != NULL; i++) {
5414 		g_autofree gchar *tmp = NULL;
5415 		g_autoptr(GError) error_local = NULL;
5416 		tmp = as_markup_import (table[i].html,
5417 					AS_MARKUP_CONVERT_FORMAT_HTML,
5418 					&error_local);
5419 		g_assert_no_error (error_local);
5420 		g_assert_cmpstr (tmp, ==, table[i].markup);
5421 	}
5422 
5423 	/* simple, from meta */
5424 	input = "This game is simply awesome&trade; in every way!";
5425 	out_simple = as_markup_import (input, AS_MARKUP_CONVERT_FORMAT_HTML, &error);
5426 	g_assert_no_error (error);
5427 	g_assert_cmpstr (out_simple, ==, "<p>This game is simply awesome™ in every way!</p>");
5428 
5429 	/* complex non-compliant HTML, from div */
5430 	input = "  <h1>header</h1>"
5431 		"  <p>First line of the <i>description</i> is okay...</p>"
5432 		"  <img src=\"moo.png\">"
5433 		"  <img src=\"png\">"
5434 		"  <p>Second <strong>line</strong> is <a href=\"#moo\">even</a> better!</p>";
5435 	out_complex = as_markup_import (input, AS_MARKUP_CONVERT_FORMAT_HTML, &error);
5436 	g_assert_no_error (error);
5437 	g_assert_cmpstr (out_complex, ==, "<p>First line of the description is okay...</p>\n"
5438 					  "<p>Second line is even better!</p>");
5439 
5440 	/* complex list */
5441 	input = "  <ul>"
5442 		"  <li>First line of the list</li>"
5443 		"  <li>Second line of the list</li>"
5444 		"  </ul>";
5445 	out_list = as_markup_import (input, AS_MARKUP_CONVERT_FORMAT_HTML, &error);
5446 	g_assert_no_error (error);
5447 	g_assert_cmpstr (out_list, ==, "<ul><li>First line of the list</li><li>Second line of the list</li></ul>");
5448 }
5449 
5450 static void
as_test_utils_unique_id_func(void)5451 as_test_utils_unique_id_func (void)
5452 {
5453 	const guint loops = 100000;
5454 	guint i;
5455 	gdouble duration_ns;
5456 	g_autoptr(GTimer) timer = g_timer_new ();
5457 
5458 	/* pathological cases */
5459 	g_assert (!as_utils_unique_id_equal ("foo", "bar"));
5460 	g_assert (!as_utils_unique_id_equal ("foo/bar/baz", "foo/bar"));
5461 
5462 	for (i = 0; i < loops; i++) {
5463 		g_assert (as_utils_unique_id_equal ("aa/bb/cc/dd/ee/ff",
5464 						    "aa/bb/cc/dd/ee/ff"));
5465 		g_assert (as_utils_unique_id_equal ("aa/bb/cc/dd/ee/ff",
5466 						    "aa/*/cc/dd/ee/ff"));
5467 		g_assert (as_utils_unique_id_equal ("user/flatpak/utopia/desktop/gimp.desktop/master",
5468 						    "*/*/*/*/*/*"));
5469 		g_assert (!as_utils_unique_id_equal ("zz/zz/zz/zz/zz/zz",
5470 						     "aa/bb/cc/dd/ee/ff"));
5471 		g_assert (!as_utils_unique_id_equal ("user/*/*/shell-extension/gmail_notify@jablona123.pl.shell-extension/*",
5472 						     "*/*/*/desktop/org.gnome.accerciser.desktop/*"));
5473 	}
5474 	duration_ns = g_timer_elapsed (timer, NULL) * 1000000000.f;
5475 	g_print ("%.0f ns: ", duration_ns / (loops * 4));
5476 
5477 	/* allow ignoring using bitfields */
5478 	g_assert (as_utils_unique_id_match ("aa/bb/cc/dd/ee/ff",
5479 					    "aa/bb/cc/dd/ee/XXXXXXXXXXXXX",
5480 					    AS_UNIQUE_ID_MATCH_FLAG_SCOPE |
5481 					    AS_UNIQUE_ID_MATCH_FLAG_BUNDLE_KIND |
5482 					    AS_UNIQUE_ID_MATCH_FLAG_ORIGIN |
5483 					    AS_UNIQUE_ID_MATCH_FLAG_KIND |
5484 					    AS_UNIQUE_ID_MATCH_FLAG_ID));
5485 	g_assert (as_utils_unique_id_match ("XXXXXXXXXXXXX/bb/cc/dd/ee/ff",
5486 					    "aa/bb/cc/dd/ee/ff",
5487 					    AS_UNIQUE_ID_MATCH_FLAG_BUNDLE_KIND |
5488 					    AS_UNIQUE_ID_MATCH_FLAG_ORIGIN |
5489 					    AS_UNIQUE_ID_MATCH_FLAG_KIND |
5490 					    AS_UNIQUE_ID_MATCH_FLAG_ID |
5491 					    AS_UNIQUE_ID_MATCH_FLAG_BRANCH));
5492 }
5493 
5494 static void
as_test_store_merge_func(void)5495 as_test_store_merge_func (void)
5496 {
5497 	g_autoptr (AsApp) app1 = NULL;
5498 	g_autoptr (AsApp) app2 = NULL;
5499 	g_autoptr (AsApp) app_merge = NULL;
5500 	g_autoptr (AsStore) store = NULL;
5501 	g_autoptr (AsFormat) format = NULL;
5502 
5503 	store = as_store_new ();
5504 	as_store_set_add_flags (store,
5505 				AS_STORE_ADD_FLAG_USE_UNIQUE_ID |
5506 				AS_STORE_ADD_FLAG_USE_MERGE_HEURISTIC);
5507 
5508 	/* add app */
5509 	app1 = as_app_new ();
5510 	as_app_set_id (app1, "org.gnome.Software.desktop");
5511 	as_app_set_branch (app1, "master");
5512 	_as_app_add_format_kind (app1, AS_FORMAT_KIND_APPDATA);
5513 	as_app_add_pkgname (app1, "gnome-software");
5514 	g_assert_cmpstr (as_app_get_unique_id (app1), ==,
5515 			 "*/package/*/*/org.gnome.Software.desktop/master");
5516 	as_store_add_app (store, app1);
5517 
5518 	/* add merge component */
5519 	app_merge = as_app_new ();
5520 	as_app_set_kind (app_merge, AS_APP_KIND_DESKTOP);
5521 	as_app_set_id (app_merge, "org.gnome.Software.desktop");
5522 	_as_app_add_format_kind (app_merge, AS_FORMAT_KIND_APPSTREAM);
5523 	as_app_set_origin (app_merge, "utopia");
5524 	as_app_set_scope (app_merge, AS_APP_SCOPE_USER);
5525 	as_app_add_category (app_merge, "special");
5526 	format = as_format_new ();
5527 	as_format_set_filename (format, "DO-NOT-SUBSUME.xml");
5528 	as_app_add_format (app_merge, format);
5529 	as_store_add_app (store, app_merge);
5530 	g_assert_cmpstr (as_app_get_unique_id (app_merge), ==,
5531 			 "*/*/*/desktop/org.gnome.Software.desktop/*");
5532 
5533 	/* add app */
5534 	app2 = as_app_new ();
5535 	as_app_set_id (app2, "org.gnome.Software.desktop");
5536 	as_app_set_branch (app2, "stable");
5537 	_as_app_add_format_kind (app2, AS_FORMAT_KIND_APPSTREAM);
5538 	as_app_add_pkgname (app2, "gnome-software");
5539 	g_assert_cmpstr (as_app_get_unique_id (app2), ==,
5540 			 "*/package/*/*/org.gnome.Software.desktop/stable");
5541 	as_store_add_app (store, app2);
5542 
5543 	/* verify that both apps have the category */
5544 	g_assert (as_app_has_category (app1, "special"));
5545 	g_assert (as_app_has_category (app2, "special"));
5546 
5547 	/* verify we didn't inherit the private bits */
5548 	g_assert (as_app_get_format_by_kind (app1, AS_FORMAT_KIND_UNKNOWN) == NULL);
5549 	g_assert (as_app_get_format_by_kind (app2, AS_FORMAT_KIND_UNKNOWN) == NULL);
5550 }
5551 
5552 static void
as_test_store_merge_replace_func(void)5553 as_test_store_merge_replace_func (void)
5554 {
5555 	g_autoptr (AsApp) app1 = NULL;
5556 	g_autoptr (AsApp) app2 = NULL;
5557 	g_autoptr (AsApp) app_merge = NULL;
5558 	g_autoptr (AsStore) store = NULL;
5559 
5560 	store = as_store_new ();
5561 	as_store_set_add_flags (store, AS_STORE_ADD_FLAG_USE_UNIQUE_ID);
5562 
5563 	/* add app */
5564 	app1 = as_app_new ();
5565 	as_app_set_id (app1, "org.gnome.Software.desktop");
5566 	as_app_set_branch (app1, "master");
5567 	_as_app_add_format_kind (app1, AS_FORMAT_KIND_APPDATA);
5568 	as_app_add_pkgname (app1, "gnome-software");
5569 	as_app_add_category (app1, "Family");
5570 	as_store_add_app (store, app1);
5571 
5572 	/* add merge component */
5573 	app_merge = as_app_new ();
5574 	as_app_set_kind (app_merge, AS_APP_KIND_DESKTOP);
5575 	as_app_set_id (app_merge, "org.gnome.Software.desktop");
5576 	_as_app_add_format_kind (app_merge, AS_FORMAT_KIND_APPSTREAM);
5577 	as_app_set_origin (app_merge, "utopia");
5578 	as_app_set_scope (app_merge, AS_APP_SCOPE_USER);
5579 	as_app_set_merge_kind (app_merge, AS_APP_MERGE_KIND_REPLACE);
5580 	as_app_add_category (app_merge, "Horror");
5581 	as_store_add_app (store, app_merge);
5582 	g_assert_cmpstr (as_app_get_unique_id (app_merge), ==,
5583 			 "*/*/*/desktop/org.gnome.Software.desktop/*");
5584 
5585 	/* add app */
5586 	app2 = as_app_new ();
5587 	as_app_set_id (app2, "org.gnome.Software.desktop");
5588 	as_app_set_branch (app2, "stable");
5589 	_as_app_add_format_kind (app2, AS_FORMAT_KIND_APPSTREAM);
5590 	as_app_add_pkgname (app2, "gnome-software");
5591 	as_app_add_category (app2, "Family");
5592 	as_store_add_app (store, app2);
5593 
5594 	/* verify that both apps have the category */
5595 	g_assert (as_app_has_category (app1, "Horror"));
5596 	g_assert (as_app_has_category (app2, "Horror"));
5597 
5598 	/* verify we replaced rather than appended */
5599 	g_assert (!as_app_has_category (app1, "Family"));
5600 	g_assert (!as_app_has_category (app2, "Family"));
5601 }
5602 
5603 static void
as_test_store_merge_then_replace_func(void)5604 as_test_store_merge_then_replace_func (void)
5605 {
5606 	g_autoptr (AsApp) app1 = NULL;
5607 	g_autoptr (AsApp) app2 = NULL;
5608 	g_autoptr (AsApp) app3 = NULL;
5609 	g_autoptr (AsStore) store = NULL;
5610 
5611 	store = as_store_new ();
5612 
5613 	/* this test case checks that a memory error using app names as keys is fixed */
5614 
5615 	/* add app */
5616 	app1 = as_app_new ();
5617 	as_app_set_id (app1, "org.gnome.Software.desktop");
5618 	_as_app_add_format_kind (app1, AS_FORMAT_KIND_DESKTOP);
5619 	as_app_set_priority (app1, 0);
5620 	as_store_add_app (store, app1);
5621 	g_clear_object (&app1);
5622 
5623 	/* add app that merges with the first */
5624 	app2 = as_app_new ();
5625 	as_app_set_id (app2, "org.gnome.Software.desktop");
5626 	_as_app_add_format_kind (app2, AS_FORMAT_KIND_DESKTOP);
5627 	as_app_set_priority (app2, 0);
5628 	as_store_add_app (store, app2);
5629 	g_clear_object (&app2);
5630 
5631 	/* add app that replaces the second */
5632 	app3 = as_app_new ();
5633 	as_app_set_id (app3, "org.gnome.Software.desktop");
5634 	_as_app_add_format_kind (app3, AS_FORMAT_KIND_DESKTOP);
5635 	as_app_set_priority (app3, 1);
5636 	as_store_add_app (store, app3);
5637 	g_clear_object (&app3);
5638 }
5639 
5640 /* shows the unique-id globbing functions at work */
5641 static void
as_test_utils_unique_id_hash_func(void)5642 as_test_utils_unique_id_hash_func (void)
5643 {
5644 	AsApp *found;
5645 	g_autoptr(AsApp) app1 = NULL;
5646 	g_autoptr(AsApp) app2 = NULL;
5647 	g_autoptr(GHashTable) hash = NULL;
5648 
5649 	/* create new couple of apps */
5650 	app1 = as_app_new ();
5651 	as_app_set_id (app1, "org.gnome.Software.desktop");
5652 	as_app_set_branch (app1, "master");
5653 	g_assert_cmpstr (as_app_get_unique_id (app1), ==,
5654 			 "*/*/*/*/org.gnome.Software.desktop/master");
5655 	app2 = as_app_new ();
5656 	as_app_set_id (app2, "org.gnome.Software.desktop");
5657 	as_app_set_branch (app2, "stable");
5658 	g_assert_cmpstr (as_app_get_unique_id (app2), ==,
5659 			 "*/*/*/*/org.gnome.Software.desktop/stable");
5660 
5661 	/* add to hash table using the unique ID as a key */
5662 	hash = g_hash_table_new ((GHashFunc) as_utils_unique_id_hash,
5663 				 (GEqualFunc) as_utils_unique_id_equal);
5664 	g_hash_table_insert (hash, (gpointer) as_app_get_unique_id (app1), app1);
5665 	g_hash_table_insert (hash, (gpointer) as_app_get_unique_id (app2), app2);
5666 
5667 	/* get with exact key */
5668 	found = g_hash_table_lookup (hash, "*/*/*/*/org.gnome.Software.desktop/master");
5669 	g_assert (found != NULL);
5670 	found = g_hash_table_lookup (hash, "*/*/*/*/org.gnome.Software.desktop/stable");
5671 	g_assert (found != NULL);
5672 
5673 	/* get with more details specified */
5674 	found = g_hash_table_lookup (hash, "system/*/*/*/org.gnome.Software.desktop/master");
5675 	g_assert (found != NULL);
5676 	found = g_hash_table_lookup (hash, "system/*/*/*/org.gnome.Software.desktop/stable");
5677 	g_assert (found != NULL);
5678 
5679 	/* get with less details specified */
5680 	found = g_hash_table_lookup (hash, "*/*/*/*/org.gnome.Software.desktop/*");
5681 	g_assert (found != NULL);
5682 
5683 	/* different key */
5684 	found = g_hash_table_lookup (hash, "*/*/*/*/gimp.desktop/*");
5685 	g_assert (found == NULL);
5686 
5687 	/* different branch */
5688 	found = g_hash_table_lookup (hash, "*/*/*/*/org.gnome.Software.desktop/obsolete");
5689 	g_assert (found == NULL);
5690 
5691 	/* check hash function */
5692 	g_assert_cmpint (as_utils_unique_id_hash ("*/*/*/*/gimp.desktop/master"), ==,
5693 			 as_utils_unique_id_hash ("system/*/*/*/gimp.desktop/stable"));
5694 }
5695 
5696 /* shows the as_utils_unique_id_*_safe functions are safe with bare text */
5697 static void
as_test_utils_unique_id_hash_safe_func(void)5698 as_test_utils_unique_id_hash_safe_func (void)
5699 {
5700 	AsApp *found;
5701 	g_autoptr(AsApp) app = NULL;
5702 	g_autoptr(GHashTable) hash = NULL;
5703 
5704 	/* create new app */
5705 	app = as_app_new ();
5706 	as_app_set_id (app, "org.gnome.Software.desktop");
5707 
5708 	/* add to hash table using the unique ID as a key */
5709 	hash = g_hash_table_new ((GHashFunc) as_utils_unique_id_hash,
5710 				 (GEqualFunc) as_utils_unique_id_equal);
5711 	g_hash_table_insert (hash, (gpointer) "dave", app);
5712 
5713 	/* get with exact key */
5714 	found = g_hash_table_lookup (hash, "dave");
5715 	g_assert (found != NULL);
5716 
5717 	/* different key */
5718 	found = g_hash_table_lookup (hash, "frank");
5719 	g_assert (found == NULL);
5720 }
5721 
5722 static void
as_test_app_parse_data_func(void)5723 as_test_app_parse_data_func (void)
5724 {
5725 	const gchar *data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
5726 			    "<component>\n</component>\n     ";
5727 	gboolean ret;
5728 	g_autoptr(GBytes) blob = NULL;
5729 	g_autoptr(AsApp) app = as_app_new ();
5730 	g_autoptr(GError) error = NULL;
5731 
5732 	blob = g_bytes_new (data, strlen (data));
5733 	ret = as_app_parse_data (app, blob, AS_APP_PARSE_FLAG_NONE, &error);
5734 	g_assert_no_error (error);
5735 	g_assert (ret);
5736 }
5737 
5738 static void
as_test_ref_string_func(void)5739 as_test_ref_string_func (void)
5740 {
5741 	AsRefString *rstr;
5742 
5743 	/* basic refcounting */
5744 	rstr = as_ref_string_new ("test");
5745 	g_assert (rstr != NULL);
5746 	g_assert_cmpstr (rstr, ==, "test");
5747 	g_assert (as_ref_string_ref (rstr) != NULL);
5748 	g_assert (as_ref_string_unref (rstr) != NULL);
5749 	g_assert (as_ref_string_unref (rstr) == NULL);
5750 }
5751 
5752 int
main(int argc,char ** argv)5753 main (int argc, char **argv)
5754 {
5755 	g_test_init (&argc, &argv, NULL);
5756 
5757 	/* only critical and error are fatal */
5758 	g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
5759 
5760 	/* tests go here */
5761 	g_test_add_func ("/AppStream/ref-string", as_test_ref_string_func);
5762 	g_test_add_func ("/AppStream/utils{unique_id-hash}", as_test_utils_unique_id_hash_func);
5763 	g_test_add_func ("/AppStream/utils{unique_id-hash2}", as_test_utils_unique_id_hash_safe_func);
5764 	g_test_add_func ("/AppStream/utils{unique_id}", as_test_utils_unique_id_func);
5765 	g_test_add_func ("/AppStream/utils{locale-compat}", as_test_utils_locale_compat_func);
5766 	g_test_add_func ("/AppStream/utils{string-replace}", as_test_utils_string_replace_func);
5767 	g_test_add_func ("/AppStream/tag", as_test_tag_func);
5768 	g_test_add_func ("/AppStream/launchable", as_test_launchable_func);
5769 	g_test_add_func ("/AppStream/provide", as_test_provide_func);
5770 	g_test_add_func ("/AppStream/require", as_test_require_func);
5771 	g_test_add_func ("/AppStream/checksum", as_test_checksum_func);
5772 	g_test_add_func ("/AppStream/content_rating", as_test_content_rating_func);
5773 	g_test_add_func ("/AppStream/content_rating/empty", as_test_content_rating_empty);
5774 	g_test_add_func ("/AppStream/content_rating/mappings", as_test_content_rating_mappings);
5775 	g_test_add_func ("/AppStream/content_rating/from-locale", as_test_content_rating_from_locale);
5776 	g_test_add_func ("/AppStream/release", as_test_release_func);
5777 	g_test_add_func ("/AppStream/release{date}", as_test_release_date_func);
5778 	g_test_add_func ("/AppStream/release{appdata}", as_test_release_appdata_func);
5779 	g_test_add_func ("/AppStream/release{appstream}", as_test_release_appstream_func);
5780 	g_test_add_func ("/AppStream/icon", as_test_icon_func);
5781 	g_test_add_func ("/AppStream/icon{scale}", as_test_icon_scale_func);
5782 	g_test_add_func ("/AppStream/icon{embedded}", as_test_icon_embedded_func);
5783 	g_test_add_func ("/AppStream/bundle", as_test_bundle_func);
5784 	g_test_add_func ("/AppStream/review", as_test_review_func);
5785 	g_test_add_func ("/AppStream/agreement", as_test_agreement_func);
5786 	g_test_add_func ("/AppStream/translation", as_test_translation_func);
5787 	g_test_add_func ("/AppStream/suggest", as_test_suggest_func);
5788 	g_test_add_func ("/AppStream/image", as_test_image_func);
5789 	g_test_add_func ("/AppStream/image{resize}", as_test_image_resize_func);
5790 	g_test_add_func ("/AppStream/image{alpha}", as_test_image_alpha_func);
5791 	g_test_add_func ("/AppStream/screenshot", as_test_screenshot_func);
5792 	g_test_add_func ("/AppStream/app", as_test_app_func);
5793 	g_test_add_func ("/AppStream/app{launchable:fallback}", as_test_app_launchable_fallback_func);
5794 	g_test_add_func ("/AppStream/app{builder:gettext}", as_test_app_builder_gettext_func);
5795 	g_test_add_func ("/AppStream/app{builder:gettext-nodomain}", as_test_app_builder_gettext_nodomain_func);
5796 	g_test_add_func ("/AppStream/app{builder:qt}", as_test_app_builder_qt_func);
5797 	g_test_add_func ("/AppStream/app{builder:qt-subdir}", as_test_app_builder_qt_subdir_func);
5798 	g_test_add_func ("/AppStream/app{translated}", as_test_app_translated_func);
5799 	g_test_add_func ("/AppStream/app{validate-style}", as_test_app_validate_style_func);
5800 	g_test_add_func ("/AppStream/app{validate-appdata-good}", as_test_app_validate_appdata_good_func);
5801 	g_test_add_func ("/AppStream/app{validate-metainfo-good}", as_test_app_validate_metainfo_good_func);
5802 	g_test_add_func ("/AppStream/app{validate-file-bad}", as_test_app_validate_file_bad_func);
5803 	g_test_add_func ("/AppStream/app{validate-meta-bad}", as_test_app_validate_meta_bad_func);
5804 	g_test_add_func ("/AppStream/app{validate-intltool}", as_test_app_validate_intltool_func);
5805 	g_test_add_func ("/AppStream/app{parse-data}", as_test_app_parse_data_func);
5806 	g_test_add_func ("/AppStream/app{parse-file:desktop}", as_test_app_parse_file_desktop_func);
5807 	g_test_add_func ("/AppStream/app{no-markup}", as_test_app_no_markup_func);
5808 	g_test_add_func ("/AppStream/app{subsume}", as_test_app_subsume_func);
5809 	g_test_add_func ("/AppStream/app{search}", as_test_app_search_func);
5810 	g_test_add_func ("/AppStream/app{screenshot}", as_test_app_screenshot_func);
5811 	g_test_add_func ("/AppStream/markup{import-html}", as_test_markup_import_html);
5812 	g_test_add_func ("/AppStream/node", as_test_node_func);
5813 	g_test_add_func ("/AppStream/node{reflow}", as_test_node_reflow_text_func);
5814 	g_test_add_func ("/AppStream/node{xml}", as_test_node_xml_func);
5815 	g_test_add_func ("/AppStream/node{hash}", as_test_node_hash_func);
5816 	g_test_add_func ("/AppStream/node{no-dup-c}", as_test_node_no_dup_c_func);
5817 	g_test_add_func ("/AppStream/node{localized}", as_test_node_localized_func);
5818 	g_test_add_func ("/AppStream/node{localized-wrap}", as_test_node_localized_wrap_func);
5819 	g_test_add_func ("/AppStream/node{localized-wrap2}", as_test_node_localized_wrap2_func);
5820 	g_test_add_func ("/AppStream/node{intltool}", as_test_node_intltool_func);
5821 	g_test_add_func ("/AppStream/node{sort}", as_test_node_sort_func);
5822 	g_test_add_func ("/AppStream/utils", as_test_utils_func);
5823 	g_test_add_func ("/AppStream/utils{markup-import}", as_test_utils_markup_import_func);
5824 	g_test_add_func ("/AppStream/utils{version}", as_test_utils_version_func);
5825 	g_test_add_func ("/AppStream/utils{guid}", as_test_utils_guid_func);
5826 	g_test_add_func ("/AppStream/utils{appstream-id}", as_test_utils_appstream_id_func);
5827 	g_test_add_func ("/AppStream/utils{icons}", as_test_utils_icons_func);
5828 	g_test_add_func ("/AppStream/utils{spdx-token}", as_test_utils_spdx_token_func);
5829 	g_test_add_func ("/AppStream/utils{install-filename}", as_test_utils_install_filename_func);
5830 	g_test_add_func ("/AppStream/utils{vercmp}", as_test_utils_vercmp_func);
5831 	if (g_test_slow ()) {
5832 		g_test_add_func ("/AppStream/monitor{dir}", as_test_monitor_dir_func);
5833 		g_test_add_func ("/AppStream/monitor{file}", as_test_monitor_file_func);
5834 	}
5835 	g_test_add_func ("/AppStream/yaml", as_test_yaml_func);
5836 	g_test_add_func ("/AppStream/yaml{broken}", as_test_yaml_broken_func);
5837 	g_test_add_func ("/AppStream/store", as_test_store_func);
5838 	g_test_add_func ("/AppStream/store{unique}", as_test_store_unique_func);
5839 	g_test_add_func ("/AppStream/store{merge}", as_test_store_merge_func);
5840 	g_test_add_func ("/AppStream/store{merge-replace}", as_test_store_merge_replace_func);
5841 	g_test_add_func ("/AppStream/store{merge-then-replace}", as_test_store_merge_then_replace_func);
5842 	g_test_add_func ("/AppStream/store{empty}", as_test_store_empty_func);
5843 	if (g_test_slow ()) {
5844 		g_test_add_func ("/AppStream/store{auto-reload-dir}", as_test_store_auto_reload_dir_func);
5845 		g_test_add_func ("/AppStream/store{auto-reload-file}", as_test_store_auto_reload_file_func);
5846 	}
5847 	g_test_add_func ("/AppStream/store{flatpak}", as_test_store_flatpak_func);
5848 	g_test_add_func ("/AppStream/store{prefix}", as_test_store_prefix_func);
5849 	g_test_add_func ("/AppStream/store{wildcard}", as_test_store_wildcard_func);
5850 	g_test_add_func ("/AppStream/store{demote}", as_test_store_demote_func);
5851 	g_test_add_func ("/AppStream/store{merges}", as_test_store_merges_func);
5852 	g_test_add_func ("/AppStream/store{merges-local}", as_test_store_merges_local_func);
5853 	g_test_add_func ("/AppStream/store{addons}", as_test_store_addons_func);
5854 	g_test_add_func ("/AppStream/store{versions}", as_test_store_versions_func);
5855 	g_test_add_func ("/AppStream/store{origin}", as_test_store_origin_func);
5856 	g_test_add_func ("/AppStream/store{yaml}", as_test_store_yaml_func);
5857 	g_test_add_func ("/AppStream/store{metadata}", as_test_store_metadata_func);
5858 	g_test_add_func ("/AppStream/store{metadata-index}", as_test_store_metadata_index_func);
5859 	g_test_add_func ("/AppStream/store{validate}", as_test_store_validate_func);
5860 	g_test_add_func ("/AppStream/store{embedded}", as_test_store_embedded_func);
5861 	g_test_add_func ("/AppStream/store{provides}", as_test_store_provides_func);
5862 	g_test_add_func ("/AppStream/store{local-appdata}", as_test_store_local_appdata_func);
5863 	if (g_test_slow ()) {
5864 		g_test_add_func ("/AppStream/store{speed-appstream}", as_test_store_speed_appstream_func);
5865 		g_test_add_func ("/AppStream/store{speed-search}", as_test_store_speed_search_func);
5866 		g_test_add_func ("/AppStream/store{speed-appdata}", as_test_store_speed_appdata_func);
5867 		g_test_add_func ("/AppStream/store{speed-desktop}", as_test_store_speed_desktop_func);
5868 		g_test_add_func ("/AppStream/store{speed-yaml}", as_test_store_speed_yaml_func);
5869 	}
5870 
5871 	return g_test_run ();
5872 }
5873