[libgdata] picasaweb: Implement GDataCommentable on GDataPicasaWebFile



commit 8d97202d21f026046f8c316dccd7857f11eb0e90
Author: Philip Withnall <philip tecnocode co uk>
Date:   Sat Jul 9 15:12:24 2011 +0100

    picasaweb: Implement GDataCommentable on GDataPicasaWebFile
    
    This adds support for comments to GDataPicasaWebFile, including a GDataComment
    subclass, GDataPicasaWebComment, and test cases.
    
    This adds the following API:
     â GDataPicasaWebComment
    
    Helps: bgo#598752

 Makefile.am                                        |    4 +-
 docs/reference/gdata-docs.xml                      |    1 +
 docs/reference/gdata-sections.txt                  |   18 +
 gdata/gdata.h                                      |    1 +
 gdata/gdata.symbols                                |    2 +
 gdata/services/picasaweb/gdata-picasaweb-comment.c |  114 +++++
 gdata/services/picasaweb/gdata-picasaweb-comment.h |   69 +++
 gdata/services/picasaweb/gdata-picasaweb-file.c    |   78 +++-
 gdata/tests/picasaweb.c                            |  495 ++++++++++++++++++++
 9 files changed, 779 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 70f98db..1653a84 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -264,7 +264,8 @@ gdata_picasaweb_headers = \
 	gdata/services/picasaweb/gdata-picasaweb-file.h		\
 	gdata/services/picasaweb/gdata-picasaweb-album.h	\
 	gdata/services/picasaweb/gdata-picasaweb-user.h		\
-	gdata/services/picasaweb/gdata-picasaweb-feed.h
+	gdata/services/picasaweb/gdata-picasaweb-feed.h		\
+	gdata/services/picasaweb/gdata-picasaweb-comment.h
 gdatapicasawebinclude_HEADERS = \
 	$(gdata_picasaweb_headers)				\
 	gdata/services/picasaweb/gdata-picasaweb-enums.h
@@ -374,6 +375,7 @@ gdata_sources = \
 	gdata/services/picasaweb/gdata-picasaweb-service.c	\
 	gdata/services/picasaweb/gdata-picasaweb-user.c		\
 	gdata/services/picasaweb/gdata-picasaweb-feed.c		\
+	gdata/services/picasaweb/gdata-picasaweb-comment.c	\
 	\
 	gdata/services/youtube/gdata-youtube-service.c		\
 	gdata/services/youtube/gdata-youtube-video.c		\
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index 2a68183..543a20d 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -168,6 +168,7 @@
 			<xi:include href="xml/gdata-picasaweb-album.xml"/>
 			<xi:include href="xml/gdata-picasaweb-file.xml"/>
 			<xi:include href="xml/gdata-picasaweb-user.xml"/>
+			<xi:include href="xml/gdata-picasaweb-comment.xml"/>
 		</chapter>
 	</part>
 
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 946fdd2..58ab6ee 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -2325,3 +2325,21 @@ gdata_youtube_comment_get_type
 <SUBSECTION Private>
 GDataYouTubeCommentPrivate
 </SECTION>
+
+<SECTION>
+<FILE>gdata-picasaweb-comment</FILE>
+<TITLE>GDataPicasaWebComment</TITLE>
+GDataPicasaWebComment
+GDataPicasaWebCommentClass
+gdata_picasaweb_comment_new
+<SUBSECTION Standard>
+GDATA_TYPE_PICASAWEB_COMMENT
+GDATA_PICASAWEB_COMMENT
+GDATA_PICASAWEB_COMMENT_CLASS
+GDATA_IS_PICASAWEB_COMMENT
+GDATA_IS_PICASAWEB_COMMENT_CLASS
+GDATA_PICASAWEB_COMMENT_GET_CLASS
+gdata_picasaweb_comment_get_type
+<SUBSECTION Private>
+GDataPicasaWebCommentPrivate
+</SECTION>
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 12d63bd..35316f0 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -109,6 +109,7 @@
 #include <gdata/services/picasaweb/gdata-picasaweb-file.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-enums.h>
 #include <gdata/services/picasaweb/gdata-picasaweb-user.h>
+#include <gdata/services/picasaweb/gdata-picasaweb-comment.h>
 
 /* Google Contacts */
 #include <gdata/services/contacts/gdata-contacts-service.h>
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 1ee3b34..41f88ba 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -927,3 +927,5 @@ gdata_youtube_comment_get_type
 gdata_youtube_comment_new
 gdata_youtube_comment_get_parent_comment_uri
 gdata_youtube_comment_set_parent_comment_uri
+gdata_picasaweb_comment_get_type
+gdata_picasaweb_comment_new
diff --git a/gdata/services/picasaweb/gdata-picasaweb-comment.c b/gdata/services/picasaweb/gdata-picasaweb-comment.c
new file mode 100644
index 0000000..bae1a39
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-comment.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2011 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-picasaweb-comment
+ * @short_description: GData PicasaWeb comment object
+ * @stability: Unstable
+ * @include: gdata/services/picasaweb/gdata-picasaweb-comment.h
+ *
+ * #GDataPicasaWebComment is a subclass of #GDataComment to represent a comment on a #GDataPicasaWebFile. It is returned by the #GDataCommentable
+ * interface implementation on #GDataPicasaWebFile.
+ *
+ * It's possible to query for, add and delete #GDataPicasaWebComment<!-- -->s from #GDataPicasaWebFile<!-- -->s.
+ *
+ * Since: 0.9.2
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "gdata-picasaweb-comment.h"
+
+static void gdata_picasaweb_comment_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static void gdata_picasaweb_comment_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+
+enum {
+	PROP_ETAG = 1,
+};
+
+G_DEFINE_TYPE (GDataPicasaWebComment, gdata_picasaweb_comment, GDATA_TYPE_COMMENT)
+
+static void
+gdata_picasaweb_comment_class_init (GDataPicasaWebCommentClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass);
+
+	gobject_class->get_property = gdata_picasaweb_comment_get_property;
+	gobject_class->set_property = gdata_picasaweb_comment_set_property;
+
+	entry_class->kind_term = "http://schemas.google.com/photos/2007#comment";;
+
+	/* Override the ETag property since ETags don't seem to be supported for PicasaWeb comments. */
+	g_object_class_override_property (gobject_class, PROP_ETAG, "etag");
+}
+
+static void
+gdata_picasaweb_comment_init (GDataPicasaWebComment *self)
+{
+	/* Nothing to see here. */
+}
+
+static void
+gdata_picasaweb_comment_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ETAG:
+			/* Never return an ETag */
+			g_value_set_string (value, NULL);
+			break;
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+gdata_picasaweb_comment_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ETAG:
+			/* Never set an ETag (note that this doesn't stop it being set in GDataEntry due to XML parsing) */
+			break;
+		default:
+			/* We don't have any other property... */
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+/**
+ * gdata_picasaweb_comment_new:
+ * @id: the comment's ID, or %NULL
+ *
+ * Creates a new #GDataPicasaWebComment with the given ID and default properties.
+ *
+ * Return value: a new #GDataPicasaWebComment; unref with g_object_unref()
+ *
+ * Since: 0.9.2
+ */
+GDataPicasaWebComment *
+gdata_picasaweb_comment_new (const gchar *id)
+{
+	return GDATA_PICASAWEB_COMMENT (g_object_new (GDATA_TYPE_PICASAWEB_COMMENT,
+	                                              "id", id,
+	                                              NULL));
+}
diff --git a/gdata/services/picasaweb/gdata-picasaweb-comment.h b/gdata/services/picasaweb/gdata-picasaweb-comment.h
new file mode 100644
index 0000000..b78c857
--- /dev/null
+++ b/gdata/services/picasaweb/gdata-picasaweb-comment.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2011 <philip tecnocode co uk>
+ *
+ * GData Client is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GData Client is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_PICASAWEB_COMMENT_H
+#define GDATA_PICASAWEB_COMMENT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-comment.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_PICASAWEB_COMMENT		(gdata_picasaweb_comment_get_type ())
+#define GDATA_PICASAWEB_COMMENT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_PICASAWEB_COMMENT, GDataPicasaWebComment))
+#define GDATA_PICASAWEB_COMMENT_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_PICASAWEB_COMMENT, GDataPicasaWebCommentClass))
+#define GDATA_IS_PICASAWEB_COMMENT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_PICASAWEB_COMMENT))
+#define GDATA_IS_PICASAWEB_COMMENT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_PICASAWEB_COMMENT))
+#define GDATA_PICASAWEB_COMMENT_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_PICASAWEB_COMMENT, GDataPicasaWebCommentClass))
+
+typedef struct _GDataPicasaWebCommentPrivate	GDataPicasaWebCommentPrivate;
+
+/**
+ * GDataPicasaWebComment:
+ *
+ * All the fields in the #GDataPicasaWebComment structure are private and should never be accessed directly.
+ *
+ * Since: 0.9.2
+ */
+typedef struct {
+	GDataComment parent;
+	GDataPicasaWebCommentPrivate *priv;
+} GDataPicasaWebComment;
+
+/**
+ * GDataPicasaWebCommentClass:
+ *
+ * All the fields in the #GDataPicasaWebCommentClass structure are private and should never be accessed directly.
+ *
+ * Since: 0.9.2
+ */
+typedef struct {
+	/*< private >*/
+	GDataCommentClass parent;
+} GDataPicasaWebCommentClass;
+
+GType gdata_picasaweb_comment_get_type (void) G_GNUC_CONST;
+
+GDataPicasaWebComment *gdata_picasaweb_comment_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+G_END_DECLS
+
+#endif /* !GDATA_PICASAWEB_COMMENT_H */
diff --git a/gdata/services/picasaweb/gdata-picasaweb-file.c b/gdata/services/picasaweb/gdata-picasaweb-file.c
index 7d64421..6d69ccc 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-file.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-file.c
@@ -26,6 +26,10 @@
  *
  * #GDataPicasaWebFile is a subclass of #GDataEntry to represent a file (photo or video) in an album on Google PicasaWeb.
  *
+ * #GDataPicasaWebFile implements #GDataCommentable, allowing comments on files to be queried using gdata_commentable_query_comments(), new
+ * comments to be added to files using gdata_commentable_insert_comment() and existing comments to be deleted from files using
+ * gdata_commentable_delete_comment().
+ *
  * For more details of Google PicasaWeb's GData API, see the
  * <ulink type="http" url="http://code.google.com/apis/picasaweb/developers_guide_protocol.html";>online documentation</ulink>.
  *
@@ -102,6 +106,10 @@
 #include "media/gdata-media-group.h"
 #include "exif/gdata-exif-tags.h"
 #include "georss/gdata-georss-where.h"
+#include "gd/gdata-gd-feed-link.h"
+#include "gdata-commentable.h"
+#include "gdata-picasaweb-comment.h"
+#include "gdata-picasaweb-service.h"
 
 static GObject *gdata_picasaweb_file_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params);
 static void gdata_picasaweb_file_dispose (GObject *object);
@@ -112,6 +120,11 @@ static void get_xml (GDataParsable *parsable, GString *xml_string);
 static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
 static gchar *get_entry_uri (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
+GDataAuthorizationDomain *get_authorization_domain (GDataCommentable *self) G_GNUC_CONST;
+static gchar *get_query_comments_uri (GDataCommentable *self) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static gchar *get_insert_comment_uri (GDataCommentable *self, GDataComment *comment_) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static gboolean is_comment_deletable (GDataCommentable *self, GDataComment *comment_);
+static void gdata_picasaweb_file_commentable_init (GDataCommentableInterface *iface);
 
 struct _GDataPicasaWebFilePrivate {
 	gchar *file_id;
@@ -146,7 +159,7 @@ enum {
 	PROP_CHECKSUM,
 	PROP_TIMESTAMP,
 	PROP_IS_COMMENTING_ENABLED,
-	PROP_COMMENT_COUNT, /* TODO support comments */
+	PROP_COMMENT_COUNT,
 	PROP_ROTATION,
 	PROP_VIDEO_STATUS,
 	PROP_CREDIT,
@@ -166,7 +179,8 @@ enum {
 	PROP_FILE_ID
 };
 
-G_DEFINE_TYPE (GDataPicasaWebFile, gdata_picasaweb_file, GDATA_TYPE_ENTRY)
+G_DEFINE_TYPE_WITH_CODE (GDataPicasaWebFile, gdata_picasaweb_file, GDATA_TYPE_ENTRY,
+                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMMENTABLE, gdata_picasaweb_file_commentable_init))
 
 static void
 gdata_picasaweb_file_class_init (GDataPicasaWebFileClass *klass)
@@ -625,6 +639,16 @@ gdata_picasaweb_file_class_init (GDataPicasaWebFileClass *klass)
 }
 
 static void
+gdata_picasaweb_file_commentable_init (GDataCommentableInterface *iface)
+{
+	iface->comment_type = GDATA_TYPE_PICASAWEB_COMMENT;
+	iface->get_authorization_domain = get_authorization_domain;
+	iface->get_query_comments_uri = get_query_comments_uri;
+	iface->get_insert_comment_uri = get_insert_comment_uri;
+	iface->is_comment_deletable = is_comment_deletable;
+}
+
+static void
 notify_title_cb (GDataPicasaWebFile *self, GParamSpec *pspec, gpointer user_data)
 {
 	/* Keep the atom:title and media:group/media:title in sync */
@@ -1034,6 +1058,56 @@ get_entry_uri (const gchar *id)
 	return uri;
 }
 
+GDataAuthorizationDomain *
+get_authorization_domain (GDataCommentable *self)
+{
+	return gdata_picasaweb_service_get_primary_authorization_domain ();
+}
+
+static gchar *
+get_query_comments_uri (GDataCommentable *self)
+{
+	GDataLink *_link;
+	SoupURI *uri;
+	GHashTable *query;
+	gchar *output_uri;
+
+	/* Get the feed link of the form: https://picasaweb.google.com/data/feed/api/user/[userID]/albumid/[albumID]/photoid/[photoID] */
+	_link = gdata_entry_look_up_link (GDATA_ENTRY (self), "http://schemas.google.com/g/2005#feed";);
+	g_assert (_link != NULL);
+
+	/* We're going to query the comments belonging to the photo, so add the comment kind. This link isn't available as a normal <link> on
+	 * photos. It's of the form: https://picasaweb.google.com/data/feed/api/user/[userID]/albumid/[albumID]/photoid/[photoID]?kind=comment */
+	uri = soup_uri_new (gdata_link_get_uri (_link));
+	query = soup_form_decode (uri->query);
+
+	g_hash_table_replace (query, g_strdup ("kind"), (gchar*) "comment"); /* libsoup only specifies a destruction function for the key */
+	soup_uri_set_query_from_form (uri, query);
+	output_uri = soup_uri_to_string (uri, FALSE);
+
+	g_hash_table_destroy (query);
+	soup_uri_free (uri);
+
+	return output_uri;
+}
+
+static gchar *
+get_insert_comment_uri (GDataCommentable *self, GDataComment *comment_)
+{
+	GDataLink *_link;
+
+	_link = gdata_entry_look_up_link (GDATA_ENTRY (self), "http://schemas.google.com/g/2005#feed";);
+	g_assert (_link != NULL);
+
+	return g_strdup (gdata_link_get_uri (_link));
+}
+
+static gboolean
+is_comment_deletable (GDataCommentable *self, GDataComment *comment_)
+{
+	return (gdata_entry_look_up_link (GDATA_ENTRY (comment_), GDATA_LINK_EDIT) != NULL) ? TRUE : FALSE;
+}
+
 /**
  * gdata_picasaweb_file_new:
  * @id: (allow-none): the file's ID, or %NULL
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index 28c354c..bed1a8f 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -1168,6 +1168,456 @@ check_authenticated_user_details (GDataPicasaWebUser *user)
 	g_assert_cmpstr (gdata_picasaweb_user_get_thumbnail_uri (user), !=, NULL);
 }
 
+typedef struct {
+	QueryFilesData parent;
+	GDataPicasaWebComment *comment1;
+	GDataPicasaWebComment *comment2;
+	GDataPicasaWebComment *comment3;
+} QueryCommentsData;
+
+static void
+set_up_query_comments (QueryCommentsData *data, gconstpointer service)
+{
+	GDataPicasaWebComment *comment_;
+
+	/* Set up some test albums and files. */
+	set_up_query_files ((QueryFilesData*) data, service);
+
+	/* Insert four test comments on the first test file. */
+	comment_ = gdata_picasaweb_comment_new (NULL);
+	gdata_entry_set_content (GDATA_ENTRY (comment_), "Test comment 1.");
+	data->comment1 = GDATA_PICASAWEB_COMMENT (gdata_commentable_insert_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+	                                                                            GDATA_COMMENT (comment_), NULL, NULL));
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (data->comment1));
+	g_object_unref (comment_);
+
+	comment_ = gdata_picasaweb_comment_new (NULL);
+	gdata_entry_set_content (GDATA_ENTRY (comment_), "Test comment 2.");
+	data->comment2 = GDATA_PICASAWEB_COMMENT (gdata_commentable_insert_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+	                                                                            GDATA_COMMENT (comment_), NULL, NULL));
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (data->comment1));
+	g_object_unref (comment_);
+
+	comment_ = gdata_picasaweb_comment_new (NULL);
+	gdata_entry_set_content (GDATA_ENTRY (comment_), "Test comment 3.");
+	data->comment3 = GDATA_PICASAWEB_COMMENT (gdata_commentable_insert_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+	                                                                            GDATA_COMMENT (comment_), NULL, NULL));
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (data->comment1));
+	g_object_unref (comment_);
+}
+
+static void
+tear_down_query_comments (QueryCommentsData *data, gconstpointer service)
+{
+	/* Delete the test comments. */
+	if (data->comment1 != NULL) {
+		g_assert (gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+		                                            GDATA_COMMENT (data->comment1), NULL, NULL) == TRUE);
+		g_object_unref (data->comment1);
+	}
+
+	if (data->comment2 != NULL) {
+		g_assert (gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+		                                            GDATA_COMMENT (data->comment2), NULL, NULL) == TRUE);
+		g_object_unref (data->comment2);
+	}
+
+	if (data->comment3 != NULL) {
+		g_assert (gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+		                                            GDATA_COMMENT (data->comment3), NULL, NULL) == TRUE);
+		g_object_unref (data->comment3);
+	}
+
+	/* Delete the test files and albums. */
+	tear_down_query_files ((QueryFilesData*) data, service);
+}
+
+static void
+assert_comments_feed (QueryCommentsData *data, GDataFeed *comments_feed)
+{
+	gboolean comment1_seen = FALSE, comment2_seen = FALSE, comment3_seen = FALSE;
+	GList *comments;
+
+	g_assert (GDATA_IS_FEED (comments_feed));
+	g_assert_cmpuint (g_list_length (gdata_feed_get_entries (comments_feed)), >=, 3);
+
+	for (comments = gdata_feed_get_entries (comments_feed); comments != NULL; comments = comments->next) {
+		GList *authors;
+		GDataPicasaWebComment *expected_comment, *actual_comment;
+
+		actual_comment = GDATA_PICASAWEB_COMMENT (comments->data);
+
+		if (strcmp (gdata_entry_get_id (GDATA_ENTRY (data->comment1)), gdata_entry_get_id (GDATA_ENTRY (actual_comment))) == 0) {
+			g_assert (comment1_seen == FALSE);
+			comment1_seen = TRUE;
+			expected_comment = data->comment1;
+		} else if (strcmp (gdata_entry_get_id (GDATA_ENTRY (data->comment2)), gdata_entry_get_id (GDATA_ENTRY (actual_comment))) == 0) {
+			g_assert (comment2_seen == FALSE);
+			comment2_seen = TRUE;
+			expected_comment = data->comment2;
+		} else if (strcmp (gdata_entry_get_id (GDATA_ENTRY (data->comment3)), gdata_entry_get_id (GDATA_ENTRY (actual_comment))) == 0) {
+			g_assert (comment3_seen == FALSE);
+			comment3_seen = TRUE;
+			expected_comment = data->comment3;
+		} else {
+			/* Unknown comment; we'll assume it's been added externally to the test suite. */
+			continue;
+		}
+
+		g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (actual_comment)), ==, gdata_entry_get_title (GDATA_ENTRY (expected_comment)));
+		g_assert_cmpstr (gdata_entry_get_content (GDATA_ENTRY (actual_comment)), ==, gdata_entry_get_content (GDATA_ENTRY (expected_comment)));
+
+		g_assert_cmpuint (g_list_length (gdata_entry_get_authors (GDATA_ENTRY (actual_comment))), >, 0);
+
+		for (authors = gdata_entry_get_authors (GDATA_ENTRY (actual_comment)); authors != NULL; authors = authors->next) {
+			GDataAuthor *author = GDATA_AUTHOR (authors->data);
+
+			/* We can't test these much. */
+			g_assert_cmpstr (gdata_author_get_name (author), !=, NULL);
+			g_assert_cmpstr (gdata_author_get_uri (author), !=, NULL);
+		}
+	}
+}
+
+static void
+test_comment_query (QueryCommentsData *data, gconstpointer service)
+{
+	GDataFeed *comments_feed;
+	GError *error = NULL;
+
+	comments_feed = gdata_commentable_query_comments (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service), NULL, NULL, NULL, NULL,
+	                                                  &error);
+	g_assert_no_error (error);
+	g_clear_error (&error);
+
+	assert_comments_feed (data, comments_feed);
+
+	g_object_unref (comments_feed);
+}
+
+typedef struct {
+	QueryCommentsData parent;
+	GMainLoop *main_loop;
+} QueryCommentsAsyncData;
+
+static void
+set_up_query_comments_async (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	set_up_query_comments ((QueryCommentsData*) data, service);
+	data->main_loop = g_main_loop_new (NULL, FALSE);
+}
+
+static void
+tear_down_query_comments_async (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	g_main_loop_unref (data->main_loop);
+	tear_down_query_comments ((QueryCommentsData*) data, service);
+}
+
+static void
+test_comment_query_async_cb (GDataCommentable *commentable, GAsyncResult *result, QueryCommentsAsyncData *data)
+{
+	GDataFeed *comments_feed;
+	GError *error = NULL;
+
+	comments_feed = gdata_commentable_query_comments_finish (commentable, result, &error);
+	g_assert_no_error (error);
+	g_clear_error (&error);
+
+	assert_comments_feed ((QueryCommentsData*) data, comments_feed);
+
+	g_object_unref (comments_feed);
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_query_async (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	gdata_commentable_query_comments_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service), NULL, NULL, NULL, NULL, NULL,
+	                                        (GAsyncReadyCallback) test_comment_query_async_cb, data);
+
+	g_main_loop_run (data->main_loop);
+}
+
+static void
+test_comment_query_async_cancellation_cb (GDataCommentable *commentable, GAsyncResult *result, QueryCommentsAsyncData *data)
+{
+	GDataFeed *comments_feed;
+	GError *error = NULL;
+
+	comments_feed = gdata_commentable_query_comments_finish (commentable, result, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+	g_assert (comments_feed == NULL);
+	g_clear_error (&error);
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_query_async_cancellation (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	GCancellable *cancellable;
+
+	cancellable = g_cancellable_new ();
+	g_cancellable_cancel (cancellable);
+
+	gdata_commentable_query_comments_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service), NULL, cancellable, NULL, NULL,
+	                                        NULL, (GAsyncReadyCallback) test_comment_query_async_cancellation_cb, data);
+
+	g_main_loop_run (data->main_loop);
+
+	g_object_unref (cancellable);
+}
+
+/* Test that the progress callbacks from gdata_commentable_query_comments_async() are called correctly.
+ * We take a QueryCommentsAsyncData so that we can guarantee the file exists, but we don't use it much as we don't actually care about the specific
+ * file. */
+static void
+test_comment_query_async_progress_closure (QueryCommentsAsyncData *query_data, gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_commentable_query_comments_async (GDATA_COMMENTABLE (query_data->parent.parent.file1), GDATA_SERVICE (service), NULL, NULL,
+	                                        (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                        data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                        (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+typedef struct {
+	QueryFilesData parent;
+	GDataPicasaWebComment *comment;
+	GDataPicasaWebComment *new_comment;
+} InsertCommentData;
+
+static void
+set_up_insert_comment (InsertCommentData *data, gconstpointer service)
+{
+	set_up_query_files ((QueryFilesData*) data, service);
+
+	/* Create a test comment to be inserted. */
+	data->comment = gdata_picasaweb_comment_new (NULL);
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (data->comment));
+
+	gdata_entry_set_content (GDATA_ENTRY (data->comment), "This is a test comment.");
+
+	data->new_comment = NULL;
+}
+
+static void
+tear_down_insert_comment (InsertCommentData *data, gconstpointer service)
+{
+	/* Delete the inserted comment. */
+	if (data->new_comment != NULL) {
+		g_assert (gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service),
+		                                            GDATA_COMMENT (data->new_comment), NULL, NULL) == TRUE);
+		g_object_unref (data->new_comment);
+	}
+
+	if (data->comment != NULL) {
+		g_object_unref (data->comment);
+	}
+
+	tear_down_query_files ((QueryFilesData*) data, service);
+}
+
+static void
+assert_comments_equal (GDataComment *new_comment, GDataPicasaWebComment *original_comment)
+{
+	GList *authors;
+	GDataAuthor *author;
+
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (new_comment));
+	g_assert (GDATA_IS_PICASAWEB_COMMENT (original_comment));
+	g_assert (GDATA_PICASAWEB_COMMENT (new_comment) != original_comment);
+
+	g_assert_cmpstr (gdata_entry_get_content (GDATA_ENTRY (new_comment)), ==, gdata_entry_get_content (GDATA_ENTRY (original_comment)));
+
+	/* Check the author of the new comment. */
+	authors = gdata_entry_get_authors (GDATA_ENTRY (new_comment));
+	g_assert_cmpuint (g_list_length (authors), ==, 1);
+
+	author = GDATA_AUTHOR (authors->data);
+
+	g_assert_cmpstr (gdata_author_get_name (author), ==, "libgdata.picasaweb");
+	g_assert_cmpstr (gdata_author_get_uri (author), ==, "https://picasaweb.google.com/libgdata.picasaweb";);
+}
+
+static void
+test_comment_insert (InsertCommentData *data, gconstpointer service)
+{
+	GDataComment *new_comment;
+	GError *error = NULL;
+
+	new_comment = gdata_commentable_insert_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service), GDATA_COMMENT (data->comment),
+	                                                NULL, &error);
+	g_assert_no_error (error);
+	g_clear_error (&error);
+
+	assert_comments_equal (new_comment, data->comment);
+
+	data->new_comment = GDATA_PICASAWEB_COMMENT (new_comment);
+}
+
+typedef struct {
+	InsertCommentData parent;
+	GMainLoop *main_loop;
+} InsertCommentAsyncData;
+
+static void
+set_up_insert_comment_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+	set_up_insert_comment ((InsertCommentData*) data, service);
+	data->main_loop = g_main_loop_new (NULL, FALSE);
+}
+
+static void
+tear_down_insert_comment_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+	g_main_loop_unref (data->main_loop);
+	tear_down_insert_comment ((InsertCommentData*) data, service);
+}
+
+static void
+test_comment_insert_async_cb (GDataCommentable *commentable, GAsyncResult *result, InsertCommentAsyncData *data)
+{
+	GDataComment *new_comment;
+	GError *error = NULL;
+
+	new_comment = gdata_commentable_insert_comment_finish (commentable, result, &error);
+	g_assert_no_error (error);
+	g_clear_error (&error);
+
+	assert_comments_equal (new_comment, data->parent.comment);
+
+	data->parent.new_comment = GDATA_PICASAWEB_COMMENT (new_comment);
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_insert_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+	gdata_commentable_insert_comment_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service),
+	                                        GDATA_COMMENT (data->parent.comment), NULL, (GAsyncReadyCallback) test_comment_insert_async_cb, data);
+
+	g_main_loop_run (data->main_loop);
+}
+
+static void
+test_comment_insert_async_cancellation_cb (GDataCommentable *commentable, GAsyncResult *result, InsertCommentAsyncData *data)
+{
+	GDataComment *new_comment;
+	GError *error = NULL;
+
+	new_comment = gdata_commentable_insert_comment_finish (commentable, result, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+	g_assert (new_comment == NULL);
+	g_clear_error (&error);
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_insert_async_cancellation (InsertCommentAsyncData *data, gconstpointer service)
+{
+	GCancellable *cancellable;
+
+	cancellable = g_cancellable_new ();
+	g_cancellable_cancel (cancellable);
+
+	gdata_commentable_insert_comment_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service),
+	                                        GDATA_COMMENT (data->parent.comment), cancellable,
+	                                        (GAsyncReadyCallback) test_comment_insert_async_cancellation_cb, data);
+
+	g_main_loop_run (data->main_loop);
+
+	g_object_unref (cancellable);
+}
+
+static void
+test_comment_delete (QueryCommentsData *data, gconstpointer service)
+{
+	gboolean success;
+	GError *error = NULL;
+
+	success = gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.file1), GDATA_SERVICE (service), GDATA_COMMENT (data->comment1),
+	                                            NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success == TRUE);
+	g_clear_error (&error);
+
+	g_object_unref (data->comment1);
+	data->comment1 = NULL;
+}
+
+static void
+test_comment_delete_async_cb (GDataCommentable *commentable, GAsyncResult *result, QueryCommentsAsyncData *data)
+{
+	gboolean success;
+	GError *error = NULL;
+
+	success = gdata_commentable_delete_comment_finish (commentable, result, &error);
+	g_assert_no_error (error);
+	g_assert (success == TRUE);
+	g_clear_error (&error);
+
+	g_object_unref (data->parent.comment1);
+	data->parent.comment1 = NULL;
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_delete_async (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	gdata_commentable_delete_comment_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service),
+	                                        GDATA_COMMENT (data->parent.comment1), NULL, (GAsyncReadyCallback) test_comment_delete_async_cb, data);
+
+	g_main_loop_run (data->main_loop);
+}
+
+static void
+test_comment_delete_async_cancellation_cb (GDataCommentable *commentable, GAsyncResult *result, QueryCommentsAsyncData *data)
+{
+	gboolean success;
+	GError *error = NULL;
+
+	success = gdata_commentable_delete_comment_finish (commentable, result, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+	g_assert (success == FALSE);
+	g_clear_error (&error);
+
+	g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_delete_async_cancellation (QueryCommentsAsyncData *data, gconstpointer service)
+{
+	GCancellable *cancellable;
+
+	cancellable = g_cancellable_new ();
+	g_cancellable_cancel (cancellable);
+	gdata_commentable_delete_comment_async (GDATA_COMMENTABLE (data->parent.parent.file1), GDATA_SERVICE (service),
+	                                        GDATA_COMMENT (data->parent.comment1), cancellable,
+	                                        (GAsyncReadyCallback) test_comment_delete_async_cancellation_cb, data);
+
+	g_main_loop_run (data->main_loop);
+
+	g_object_unref (cancellable);
+}
+
 static void
 test_query_user (gconstpointer service)
 {
@@ -1799,6 +2249,26 @@ test_file_properties_coordinates (void)
 }
 
 static void
+test_comment_get_xml (void)
+{
+	GDataPicasaWebComment *comment_;
+
+	comment_ = gdata_picasaweb_comment_new (NULL);
+	gdata_entry_set_content (GDATA_ENTRY (comment_), "This is a comment with <markup> & stÃff.");
+
+	/* Check the outputted XML is OK */
+	gdata_test_assert_xml (comment_,
+		"<?xml version='1.0' encoding='UTF-8'?>"
+		"<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>"
+			"<title type='text'></title>"
+			"<content type='text'>This is a comment with &lt;markup&gt; &amp; stÃff.</content>"
+			"<category term='http://schemas.google.com/photos/2007#comment' scheme='http://schemas.google.com/g/2005#kind'/>"
+		"</entry>");
+
+	g_object_unref (comment_);
+}
+
+static void
 test_query_etag (void)
 {
 	GDataPicasaWebQuery *query = gdata_picasaweb_query_new (NULL);
@@ -1875,6 +2345,29 @@ main (int argc, char *argv[])
 		g_test_add ("/picasaweb/query/files/single", QueryFilesData, service, set_up_query_files, test_query_files_single,
 		            tear_down_query_files);
 
+		g_test_add ("/picasaweb/comment/query", QueryCommentsData, service, set_up_query_comments, test_comment_query,
+		            tear_down_query_comments);
+		g_test_add ("/picasaweb/comment/query/async", QueryCommentsAsyncData, service, set_up_query_comments_async, test_comment_query_async,
+		            tear_down_query_comments_async);
+		g_test_add ("/picasaweb/comment/query/async/cancellation", QueryCommentsAsyncData, service, set_up_query_comments_async,
+		            test_comment_query_async_cancellation, tear_down_query_comments_async);
+		g_test_add ("/picasaweb/comment/query/progress_closure", QueryCommentsAsyncData, service, set_up_query_comments_async,
+		            test_comment_query_async_progress_closure, tear_down_query_comments_async);
+
+		g_test_add ("/picasaweb/comment/insert", InsertCommentData, service, set_up_insert_comment, test_comment_insert,
+		            tear_down_insert_comment);
+		g_test_add ("/picasaweb/comment/insert/async", InsertCommentAsyncData, service, set_up_insert_comment_async, test_comment_insert_async,
+		            tear_down_insert_comment_async);
+		g_test_add ("/picasaweb/comment/insert/async/cancellation", InsertCommentAsyncData, service, set_up_insert_comment_async,
+		            test_comment_insert_async_cancellation, tear_down_insert_comment_async);
+
+		g_test_add ("/picasaweb/comment/delete", QueryCommentsData, service, set_up_query_comments, test_comment_delete,
+		            tear_down_query_comments);
+		g_test_add ("/picasaweb/comment/delete/async", QueryCommentsAsyncData, service, set_up_query_comments_async, test_comment_delete_async,
+		            tear_down_query_comments_async);
+		g_test_add ("/picasaweb/comment/delete/async/cancellation", QueryCommentsAsyncData, service, set_up_query_comments_async,
+		            test_comment_delete_async_cancellation, tear_down_query_comments_async);
+
 		g_test_add ("/picasaweb/upload/default_album", UploadData, service, setup_upload, test_upload_default_album, teardown_upload);
 		g_test_add ("/picasaweb/upload/default_album/async", UploadAsyncData, service, setup_upload_async, test_upload_default_album_async,
 		            teardown_upload_async);
@@ -1896,6 +2389,8 @@ main (int argc, char *argv[])
 	g_test_add_func ("/picasaweb/file/escaping", test_file_escaping);
 	g_test_add_func ("/picasaweb/file/properties/coordinates", test_file_properties_coordinates);
 
+	g_test_add_func ("/picasaweb/comment/get_xml", test_comment_get_xml);
+
 	g_test_add_func ("/picasaweb/query/etag", test_query_etag);
 
 	retval = g_test_run ();



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