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.
This commit is contained in:
Marco Trevisan (Treviño) 2022-10-12 15:44:22 +02:00 committed by Philip Withnall
parent 5f604460ef
commit 2e8375daa0
4 changed files with 215 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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);