[glib: 2/4] gbookmarkfile: Add copy function




commit 2e8375daa0b36510fb8b89ada857f4885f555aee
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Wed Oct 12 15:44:22 2022 +0200

    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 2b500257c4..77fabc8571 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 4b57d02a28..3988e3653e 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 e401862028..f753420ed9 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 389bc6370d..b96e585030 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, &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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]