From 2e8375daa0b36510fb8b89ada857f4885f555aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 12 Oct 2022 15:44:22 +0200 Subject: [PATCH] gbookmarkfile: Add copy function GBookmarkFile has everything for being introspectable, but it lacks a GType, because it can't be copied. So provide a copy function that deeply copies all the bookmark structures. Add tests for this. --- docs/reference/glib/glib-sections.txt.in | 1 + glib/gbookmarkfile.c | 117 +++++++++++++++++++++-- glib/gbookmarkfile.h | 3 + glib/tests/bookmarkfile.c | 102 +++++++++++++++++++- 4 files changed, 215 insertions(+), 8 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in index 2b500257c..77fabc857 100644 --- a/docs/reference/glib/glib-sections.txt.in +++ b/docs/reference/glib/glib-sections.txt.in @@ -2152,6 +2152,7 @@ GBookmarkFile G_BOOKMARK_FILE_ERROR GBookmarkFileError g_bookmark_file_new +g_bookmark_file_copy g_bookmark_file_free g_bookmark_file_load_from_file g_bookmark_file_load_from_data diff --git a/glib/gbookmarkfile.c b/glib/gbookmarkfile.c index 4b57d02a2..3988e3653 100644 --- a/glib/gbookmarkfile.c +++ b/glib/gbookmarkfile.c @@ -287,6 +287,24 @@ bookmark_app_info_free (BookmarkAppInfo *app_info) g_slice_free (BookmarkAppInfo, app_info); } +static BookmarkAppInfo * +bookmark_app_info_copy (BookmarkAppInfo *app_info) +{ + BookmarkAppInfo *copy; + + if (!app_info) + return NULL; + + copy = bookmark_app_info_new (app_info->name); + copy->count = app_info->count; + copy->exec = g_strdup (app_info->exec); + + if (app_info->stamp) + copy->stamp = g_date_time_ref (app_info->stamp); + + return copy; +} + static gchar * bookmark_app_info_dump (BookmarkAppInfo *app_info) { @@ -382,6 +400,37 @@ bookmark_metadata_free (BookmarkMetadata *metadata) g_slice_free (BookmarkMetadata, metadata); } +static BookmarkMetadata * +bookmark_metadata_copy (BookmarkMetadata *metadata) +{ + BookmarkMetadata *copy; + GList *l; + + if (!metadata) + return NULL; + + copy = bookmark_metadata_new (); + copy->is_private = metadata->is_private; + copy->mime_type = g_strdup (metadata->mime_type); + copy->icon_href = g_strdup (metadata->icon_href); + copy->icon_mime = g_strdup (metadata->icon_mime); + + copy->groups = g_list_copy_deep (metadata->groups, (GCopyFunc) g_strdup, NULL); + copy->applications = + g_list_copy_deep (metadata->applications, (GCopyFunc) bookmark_app_info_copy, NULL); + + for (l = copy->applications; l; l = l->next) + { + BookmarkAppInfo *app_info = l->data; + g_hash_table_insert (copy->apps_by_name, app_info->name, app_info); + } + + g_assert (g_hash_table_size (copy->apps_by_name) == + g_hash_table_size (metadata->apps_by_name)); + + return copy; +} + static gchar * bookmark_metadata_dump (BookmarkMetadata *metadata) { @@ -556,6 +605,31 @@ bookmark_item_free (BookmarkItem *item) g_slice_free (BookmarkItem, item); } +static BookmarkItem * +bookmark_item_copy (BookmarkItem *item) +{ + BookmarkItem* copy; + + if (!item) + return NULL; + + copy = bookmark_item_new (item->uri); + + copy->title = g_strdup (item->title); + copy->description = g_strdup (item->description); + + copy->metadata = bookmark_metadata_copy (item->metadata); + + if (item->added) + copy->added = g_date_time_ref (item->added); + if (item->modified) + copy->modified = g_date_time_ref (item->modified); + if (item->visited) + copy->visited = g_date_time_ref (item->visited); + + return copy; +} + static void bookmark_item_touch_modified (BookmarkItem *item) { @@ -709,12 +783,7 @@ g_bookmark_file_clear (GBookmarkFile *bookmark) g_list_free_full (bookmark->items, (GDestroyNotify) bookmark_item_free); bookmark->items = NULL; - if (bookmark->items_by_uri) - { - g_hash_table_destroy (bookmark->items_by_uri); - - bookmark->items_by_uri = NULL; - } + g_clear_pointer (&bookmark->items_by_uri, g_hash_table_unref); } struct _ParseData @@ -1684,6 +1753,42 @@ g_bookmark_file_new (void) return bookmark; } +/** + * g_bookmark_file_copy: + * @bookmark: A #GBookmarkFile + * + * Deeply copies a @bookmark #GBookmarkFile object to a new one. + * + * Returns: (transfer full): the copy of @bookmark. Use + * g_bookmark_free() when finished using it. + * + * Since: 2.76 + */ +GBookmarkFile * +g_bookmark_file_copy (GBookmarkFile *bookmark) +{ + GBookmarkFile *copy; + GList *l; + + g_return_val_if_fail (bookmark != NULL, NULL); + + copy = g_bookmark_file_new (); + copy->title = g_strdup (bookmark->title); + copy->description = g_strdup (bookmark->description); + copy->items = g_list_copy_deep (bookmark->items, (GCopyFunc) bookmark_item_copy, NULL); + + for (l = copy->items; l; l = l->next) + { + BookmarkItem *item = l->data; + g_hash_table_insert (copy->items_by_uri, item->uri, item); + } + + g_assert (g_hash_table_size (copy->items_by_uri) == + g_hash_table_size (bookmark->items_by_uri)); + + return copy; +} + /** * g_bookmark_file_free: * @bookmark: a #GBookmarkFile diff --git a/glib/gbookmarkfile.h b/glib/gbookmarkfile.h index e40186202..f753420ed 100644 --- a/glib/gbookmarkfile.h +++ b/glib/gbookmarkfile.h @@ -84,6 +84,9 @@ GBookmarkFile *g_bookmark_file_new (void); GLIB_AVAILABLE_IN_ALL void g_bookmark_file_free (GBookmarkFile *bookmark); +GLIB_AVAILABLE_IN_2_76 +GBookmarkFile *g_bookmark_file_copy (GBookmarkFile *bookmark); + GLIB_AVAILABLE_IN_ALL gboolean g_bookmark_file_load_from_file (GBookmarkFile *bookmark, const gchar *filename, diff --git a/glib/tests/bookmarkfile.c b/glib/tests/bookmarkfile.c index 389bc6370..b96e58503 100644 --- a/glib/tests/bookmarkfile.c +++ b/glib/tests/bookmarkfile.c @@ -1245,6 +1245,99 @@ test_file (gconstpointer d) g_assert_true (success == (strstr (filename, "fail") == NULL)); } +static void +test_file_copy (gconstpointer d) +{ + const gchar *filename = d; + GBookmarkFile *bookmark_file; + GBookmarkFile *copy; + gboolean success; + gchar *data; + gchar *copy_data; + gsize length; + gsize copy_length; + GError *error = NULL; + + bookmark_file = g_bookmark_file_new (); + g_assert_nonnull (bookmark_file); + + success = test_load (bookmark_file, filename); + g_assert_true (success == (strstr (filename, "fail") == NULL)); + + copy = g_bookmark_file_copy (bookmark_file); + g_assert_nonnull (copy); + + if (g_str_has_suffix (filename, "fail-08.xbel") || + g_str_has_suffix (filename, "fail-06.xbel") || + g_str_has_suffix (filename, "fail-07.xbel") || + g_str_has_suffix (filename, "fail-09.xbel") || + g_str_has_suffix (filename, "fail-10.xbel") || + g_str_has_suffix (filename, "fail-11.xbel") || + g_str_has_suffix (filename, "fail-39.xbel")) + { + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*no registered applications*skipping*"); + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*no registered applications*skipping*"); + } + + data = g_bookmark_file_to_data (bookmark_file, &length, &error); + g_assert_no_error (error); + + copy_data = g_bookmark_file_to_data (copy, ©_length, &error); + g_assert_no_error (error); + + g_test_assert_expected_messages (); + + g_assert_cmpuint (length, ==, copy_length); + g_assert_cmpstr (data, ==, copy_data); + + if (success) + { + GBookmarkFile *modified_copy; + gchar *modified_data; + gchar *modified_copy_data; + gsize modified_length; + gsize modified_copy_length; + + test_modify (bookmark_file); + test_modify (copy); + + modified_data = g_bookmark_file_to_data (bookmark_file, + &modified_length, + &error); + g_assert_no_error (error); + + modified_copy_data = g_bookmark_file_to_data (copy, + &modified_copy_length, + &error); + g_assert_no_error (error); + + g_assert_cmpstr (data, !=, modified_data); + g_assert_cmpstr (copy_data, !=, modified_copy_data); + + g_free (modified_copy_data); + modified_copy = g_bookmark_file_copy (bookmark_file); + modified_copy_data = g_bookmark_file_to_data (modified_copy, + &modified_copy_length, + &error); + g_assert_no_error (error); + + g_assert_cmpuint (modified_length, ==, modified_copy_length); + g_assert_cmpstr (modified_data, ==, modified_copy_data); + + g_free (modified_data); + g_free (modified_copy_data); + g_bookmark_file_free (modified_copy); + } + + g_bookmark_file_free (bookmark_file); + g_bookmark_file_free (copy); + + g_free (data); + g_free (copy_data); +} + int main (int argc, char *argv[]) { @@ -1275,12 +1368,17 @@ main (int argc, char *argv[]) g_assert_no_error (error); while ((name = g_dir_read_name (dir)) != NULL) { + gchar *filename; if (!g_str_has_suffix (name, ".xbel")) continue; + filename = g_test_build_filename (G_TEST_DIST, "bookmarks", name, NULL); + path = g_strdup_printf ("/bookmarks/parse/%s", name); - g_test_add_data_func_full (path, g_test_build_filename (G_TEST_DIST, "bookmarks", name, NULL), - test_file, g_free); + g_test_add_data_func_full (path, filename, test_file, g_free); + g_free (path); + path = g_strdup_printf ("/bookmarks/copy/%s", name); + g_test_add_data_func_full (path, g_strdup (filename), test_file_copy, g_free); g_free (path); } g_dir_close (dir);