[libgdata] Bug 598649 — Download API for PicasaWeb images and thumbnails



commit efc38812b658cf56f4141aa59dd1639b1430adde
Author: Richard Schwarting <rschwart src gnome org>
Date:   Sun Dec 6 17:46:07 2009 +1300

    Bug 598649 â?? Download API for PicasaWeb images and thumbnails
    
    Add download APIs and infrastructure for GDataMedia and GDataThumbnail

 configure.ac                        |   10 ++
 docs/reference/gdata-sections.txt   |    2 +
 gdata/gdata-download-stream.c       |   69 ++++++++
 gdata/gdata-private.h               |    2 +
 gdata/gdata.symbols                 |    2 +
 gdata/media/gdata-media-content.c   |   60 +++++++
 gdata/media/gdata-media-content.h   |    2 +
 gdata/media/gdata-media-thumbnail.c |   59 +++++++
 gdata/media/gdata-media-thumbnail.h |    2 +
 gdata/tests/Makefile.am             |    2 +
 gdata/tests/picasaweb.c             |  296 ++++++++++++++++++++++++++++++++++-
 11 files changed, 505 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 30a0aa8..fca8fc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,6 +59,16 @@ PKG_CHECK_MODULES(GDATA, [$pkg_modules])
 AC_SUBST(GDATA_CFLAGS)
 AC_SUBST(GDATA_LIBS)
 
+# Optional dependencies
+
+PKG_CHECK_MODULES(GDK, gdk-2.0, have_gdk=yes, have_gdk=no)
+if test "x$have_gdk" = "xyes"; then
+	AC_DEFINE(HAVE_GDK, 1, [Defined if GDK+ is installed])
+fi
+
+AC_SUBST(GDK_CFLAGS) # TODO: test how this fairs without gdk-2.0.pc avail
+AC_SUBST(GDK_LIBS)
+
 # GNOME support, which pulls in libsoup-gnome-2.4 to provide transparent proxy support
 AC_MSG_CHECKING(whether to build with GNOME support)
 AC_ARG_ENABLE(gnome, AS_HELP_STRING([--enable-gnome], [Whether to enable GNOME support]),, enable_gnome=yes)
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index fc95a95..282babe 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -1103,6 +1103,7 @@ gdata_media_content_get_expression
 gdata_media_content_get_duration
 gdata_media_content_get_height
 gdata_media_content_get_width
+gdata_media_content_download
 <SUBSECTION Standard>
 gdata_media_content_get_type
 GDATA_MEDIA_CONTENT
@@ -1142,6 +1143,7 @@ gdata_media_thumbnail_get_uri
 gdata_media_thumbnail_get_height
 gdata_media_thumbnail_get_width
 gdata_media_thumbnail_get_time
+gdata_media_thumbnail_download
 <SUBSECTION Standard>
 gdata_media_thumbnail_get_type
 GDATA_MEDIA_THUMBNAIL
diff --git a/gdata/gdata-download-stream.c b/gdata/gdata-download-stream.c
index 4891f2c..ee0137f 100644
--- a/gdata/gdata-download-stream.c
+++ b/gdata/gdata-download-stream.c
@@ -560,3 +560,72 @@ gdata_download_stream_get_content_length (GDataDownloadStream *self)
 	g_return_val_if_fail (GDATA_IS_DOWNLOAD_STREAM (self), -1);
 	return self->priv->content_length;
 }
+
+/**
+ * _gdata_download_stream_find_destination:
+ * @default_filename: a default filename used if the user selects a directory as the destination
+ * @target_dest_file: the destination file or directory to download to
+ * @actual_dest_file: will be set to reference the actual destination, which might be different from @target_dest_file
+ * @replace_file_if_exists: whether to replace pre-existing files at the download location
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Sets up a download stream for a given destination.
+ *
+ * If @target_dest_file is a directory, then the file will be
+ * downloaded into the directory with the filename specified by
+ * @default_filename.  Otherwise, the file will be downloaded as the
+ * file specified by @target_dest_file.
+ *
+ * @actual_dest_file usually only differs from @target_dest_file when
+ * the latter is set to a directory, and @default_filename must be
+ * used. The @actual_dest_file argument should be a pointer to a %NULL
+ * #GFile.  Regardless, unref the #GFile returned in @actual_dest_file
+ * with g_object_unref(), as it increases the ref count of
+ * @target_dest_file even when they are the same.
+ *
+ * Return value: a #GFileOutputStream, or %NULL; unref with g_object_unref()
+ *
+ * Since: 0.6.0
+ **/
+GFileOutputStream *
+_gdata_download_stream_find_destination (const gchar *default_filename, GFile *target_dest_file, GFile **actual_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error)
+{
+	GFileInfo *target_dest_info;
+	GFileOutputStream *dest_stream;
+
+	g_return_val_if_fail (default_filename != NULL, NULL);
+	g_return_val_if_fail (G_IS_FILE (target_dest_file), NULL);
+	g_return_val_if_fail (actual_dest_file != NULL && *actual_dest_file == NULL, NULL);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	/* handle the case where it exists as a directory, so we want to insert it in there */
+	if (g_file_query_exists (target_dest_file, cancellable)) {
+		target_dest_info = g_file_query_info (target_dest_file, "standard::type", G_FILE_QUERY_INFO_NONE, cancellable, error);
+		if (target_dest_info == NULL)
+			return NULL;
+
+		if (g_file_info_get_file_type (target_dest_info) == G_FILE_TYPE_DIRECTORY)
+			*actual_dest_file = g_file_get_child (target_dest_file, default_filename);
+
+		g_object_unref (target_dest_info);
+	}
+
+	/* handle the general case (where it doesn't exist or it does but isn't a directory) */
+	if (*actual_dest_file == NULL)
+		*actual_dest_file = g_object_ref (target_dest_file);
+
+	/* replace or create, leaving it up to the APIs to get the relevant error message */
+	if (replace_file_if_exists)
+		dest_stream = g_file_replace (*actual_dest_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, error);
+	else
+		dest_stream = g_file_create (*actual_dest_file, G_FILE_CREATE_NONE, cancellable, error);
+
+	if (dest_stream == NULL) {
+		g_object_unref (*actual_dest_file);
+		return NULL;
+	}
+
+	return dest_stream;
+}
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index c8d007e..4114469 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -69,6 +69,8 @@ GDataService *_gdata_documents_service_get_spreadsheet_service (GDataDocumentsSe
 
 #include "gdata-parser.h"
 
+GFileOutputStream *_gdata_download_stream_find_destination (const gchar *default_filename, GFile *target_dest_file, GFile **actual_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT;
+
 G_END_DECLS
 
 #endif /* !GDATA_PRIVATE_H */
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index b41f44f..8902029 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -514,6 +514,7 @@ gdata_media_content_get_expression
 gdata_media_content_get_duration
 gdata_media_content_get_height
 gdata_media_content_get_width
+gdata_media_content_download
 gdata_youtube_content_get_type
 gdata_youtube_content_get_format
 gdata_media_thumbnail_get_type
@@ -521,6 +522,7 @@ gdata_media_thumbnail_get_uri
 gdata_media_thumbnail_get_height
 gdata_media_thumbnail_get_width
 gdata_media_thumbnail_get_time
+gdata_media_thumbnail_download
 gdata_youtube_state_get_type
 gdata_youtube_state_get_name
 gdata_youtube_state_get_reason_code
diff --git a/gdata/media/gdata-media-content.c b/gdata/media/gdata-media-content.c
index f5fc09c..f307137 100644
--- a/gdata/media/gdata-media-content.c
+++ b/gdata/media/gdata-media-content.c
@@ -33,9 +33,11 @@
 #include <libxml/parser.h>
 
 #include "gdata-media-content.h"
+#include "gdata-download-stream.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
 #include "gdata-media-enums.h"
+#include "gdata-private.h"
 
 static void gdata_media_content_finalize (GObject *object);
 static void gdata_media_content_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
@@ -544,3 +546,61 @@ gdata_media_content_get_width (GDataMediaContent *self)
 	g_return_val_if_fail (GDATA_IS_MEDIA_CONTENT (self), 0);
 	return self->priv->width;
 }
+
+/**
+ * gdata_media_content_download:
+ * @self: a #GDataMediaContent
+ * @service: the #GDataService
+ * @default_filename: an optional default filename used if the user selects a directory as the destination
+ * @target_dest_file: the destination file or directory to download to
+ * @replace_file_if_exists: whether to replace already existing files at the download location
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Downloads and returns a #GFile of the content represented by @self.
+ *
+ * If @target_dest_file is a directory, then the file will be
+ * downloaded into this directory with the default filename specified
+ * in @default_filename.
+ *
+ * Return value: the content's data, or %NULL; unref with g_object_unref()
+ *
+ * Since: 0.6.0
+ **/
+GFile *
+gdata_media_content_download (GDataMediaContent *self, GDataService *service, const gchar *default_filename, GFile *target_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error)
+{
+	GFileOutputStream *dest_stream;
+	const gchar *src_uri;
+	GInputStream *src_stream;
+	GFile *actual_file = NULL;
+	GError *child_error = NULL;
+
+	g_return_val_if_fail (GDATA_IS_MEDIA_CONTENT (self), NULL);
+	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (default_filename != NULL, NULL);
+	g_return_val_if_fail (G_IS_FILE (target_dest_file), NULL);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	dest_stream = _gdata_download_stream_find_destination (default_filename, target_dest_file, &actual_file, replace_file_if_exists, cancellable, error);
+	if (dest_stream == NULL)
+		return NULL;
+
+	src_uri = gdata_media_content_get_uri (self);
+
+	/* Synchronously splice the data from the download stream to the file stream (network -> disk) */
+	src_stream = gdata_download_stream_new (GDATA_SERVICE (service), src_uri);
+	g_output_stream_splice (G_OUTPUT_STREAM (dest_stream), src_stream,
+				G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, &child_error);
+	g_object_unref (src_stream);
+	g_object_unref (dest_stream);
+	if (child_error != NULL) {
+		g_object_unref (actual_file);
+		g_propagate_error (error, child_error);
+		return NULL;
+	}
+
+	return actual_file;
+}
+
diff --git a/gdata/media/gdata-media-content.h b/gdata/media/gdata-media-content.h
index 2980054..fff4ade 100644
--- a/gdata/media/gdata-media-content.h
+++ b/gdata/media/gdata-media-content.h
@@ -24,6 +24,7 @@
 #include <glib-object.h>
 
 #include <gdata/gdata-parsable.h>
+#include <gdata/gdata-service.h>
 
 G_BEGIN_DECLS
 
@@ -103,6 +104,7 @@ GDataMediaExpression gdata_media_content_get_expression (GDataMediaContent *self
 gint64 gdata_media_content_get_duration (GDataMediaContent *self);
 guint gdata_media_content_get_height (GDataMediaContent *self);
 guint gdata_media_content_get_width (GDataMediaContent *self);
+GFile *gdata_media_content_download (GDataMediaContent *self, GDataService *service, const gchar *default_filename, GFile *target_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
diff --git a/gdata/media/gdata-media-thumbnail.c b/gdata/media/gdata-media-thumbnail.c
index e1fd657..f0a5dc7 100644
--- a/gdata/media/gdata-media-thumbnail.c
+++ b/gdata/media/gdata-media-thumbnail.c
@@ -34,8 +34,10 @@
 #include <string.h>
 
 #include "gdata-media-thumbnail.h"
+#include "gdata-download-stream.h"
 #include "gdata-parsable.h"
 #include "gdata-parser.h"
+#include "gdata-private.h"
 
 static void gdata_media_thumbnail_finalize (GObject *object);
 static void gdata_media_thumbnail_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
@@ -360,3 +362,60 @@ gdata_media_thumbnail_get_time (GDataMediaThumbnail *self)
 	g_return_val_if_fail (GDATA_IS_MEDIA_THUMBNAIL (self), -1);
 	return self->priv->time;
 }
+
+/**
+ * gdata_media_thumbnail_download:
+ * @self: a #GDataMediaThumbnail
+ * @service: the #GDataService
+ * @default_filename: an optional default filename used if the user selects a directory as the destination
+ * @target_dest_file: the destination file or directory to download to
+ * @replace_file_if_exists: whether to replace already existing files at the download location
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Downloads and returns the thumbnail represented by @self.
+ *
+ * If @target_dest_file is a directory, then the file will be
+ * downloaded into this directory with the default filename specified
+ * in @default_filename.
+ *
+ * Return value: the thumbnail's data, or %NULL; unref with g_object_unref()
+ *
+ * Since: 0.6.0
+ **/
+GFile *
+gdata_media_thumbnail_download (GDataMediaThumbnail *self, GDataService *service, const gchar *default_filename, GFile *target_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error)
+{
+	GFileOutputStream *dest_stream;
+	const gchar *src_uri;
+	GInputStream *src_stream;
+	GFile *actual_file = NULL;
+	GError *child_error = NULL;
+
+	g_return_val_if_fail (GDATA_IS_MEDIA_THUMBNAIL (self), NULL);
+	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (default_filename != NULL, NULL);
+	g_return_val_if_fail (G_IS_FILE (target_dest_file), NULL);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+	dest_stream = _gdata_download_stream_find_destination (default_filename, target_dest_file, &actual_file, replace_file_if_exists, cancellable, error);
+	if (dest_stream == NULL)
+		return NULL;
+
+	src_uri = gdata_media_thumbnail_get_uri (self);
+
+	/* Synchronously splice the data from the download stream to the file stream (network -> disk) */
+	src_stream = gdata_download_stream_new (GDATA_SERVICE (service), src_uri);
+	g_output_stream_splice (G_OUTPUT_STREAM (dest_stream), src_stream,
+				G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, &child_error);
+	g_object_unref (src_stream);
+	g_object_unref (dest_stream);
+	if (child_error != NULL) {
+		g_object_unref (actual_file);
+		g_propagate_error (error, child_error);
+		return NULL;
+	}
+
+	return actual_file;
+}
diff --git a/gdata/media/gdata-media-thumbnail.h b/gdata/media/gdata-media-thumbnail.h
index 90d1074..92f55cf 100644
--- a/gdata/media/gdata-media-thumbnail.h
+++ b/gdata/media/gdata-media-thumbnail.h
@@ -22,6 +22,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gdata/gdata-service.h>
 
 #include <gdata/gdata-parsable.h>
 
@@ -64,6 +65,7 @@ const gchar *gdata_media_thumbnail_get_uri (GDataMediaThumbnail *self);
 guint gdata_media_thumbnail_get_height (GDataMediaThumbnail *self);
 guint gdata_media_thumbnail_get_width (GDataMediaThumbnail *self);
 gint64 gdata_media_thumbnail_get_time (GDataMediaThumbnail *self);
+GFile *gdata_media_thumbnail_download (GDataMediaThumbnail *self, GDataService *service, const gchar *default_filename, GFile *target_dest_file, gboolean replace_file_if_exists, GCancellable *cancellable, GError **error) G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
diff --git a/gdata/tests/Makefile.am b/gdata/tests/Makefile.am
index 248e7f3..9cce5ab 100644
--- a/gdata/tests/Makefile.am
+++ b/gdata/tests/Makefile.am
@@ -3,6 +3,7 @@ include $(top_srcdir)/Makefile.decl
 INCLUDES = \
 	-I$(top_srcdir)/				\
 	-I$(top_srcdir)/gdata				\
+	$(GDK_CFLAGS)  					\
 	-DTEST_FILE_DIR="\"$(top_srcdir)/gdata/tests/\""\
 	$(DISABLE_DEPRECATED)				\
 	$(WARN_CFLAGS)					\
@@ -10,6 +11,7 @@ INCLUDES = \
 
 LIBS = \
 	$(top_builddir)/gdata/libgdata.la	\
+	$(GDK_LIBS)				\
 	$(GDATA_LIBS)
 
 noinst_PROGRAMS = $(TEST_PROGS)
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index 018dafa..f5057ea 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -21,6 +21,12 @@
 #include <glib.h>
 #include <unistd.h>
 #include <string.h>
+#include <config.h>
+
+/* For the thumbnail size tests in test_download_thumbnails() */
+#ifdef HAVE_GDK
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#endif
 
 #include "gdata.h"
 #include "common.h"
@@ -99,6 +105,292 @@ test_authentication_async (void)
 }
 
 static void
+test_download_thumbnails (GDataService *service)
+{
+	GDataFeed *album_feed, *photo_feed;
+	GList *album_entries, *photo_entries, *thumbnails, *node;
+	GDataPicasaWebAlbum *album;
+	GDataPicasaWebFile *photo;
+	GDataPicasaWebQuery *query;
+	GFile *dest_dir, *dest_file, *actual_file;
+	GDataMediaThumbnail *thumbnail;
+	GdkPixbuf *pixbuf;
+	gchar *file_path, *basename;
+	GError *error = NULL;
+
+	/* Acquire album, photo to test */
+	album_feed = gdata_picasaweb_service_query_all_albums (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, NULL, NULL, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_FEED (album_feed));
+
+	album_entries = gdata_feed_get_entries (album_feed);
+	g_assert (album_entries != NULL);
+
+	album = GDATA_PICASAWEB_ALBUM (album_entries->data);
+
+	query = gdata_picasaweb_query_new (NULL);
+	gdata_picasaweb_query_set_image_size (query, "32"); /* we're querying for the smallest size, to save bandwidth here :D */
+	photo_feed = gdata_picasaweb_service_query_files (GDATA_PICASAWEB_SERVICE (service), album, GDATA_QUERY (query), NULL, NULL, NULL, &error);
+	g_object_unref (query);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_FEED (photo_feed));
+
+	photo_entries = gdata_feed_get_entries (photo_feed);
+	g_assert (photo_entries != NULL);
+
+	photo = GDATA_PICASAWEB_FILE (photo_entries->data);
+
+	dest_dir = g_file_new_for_path ("/tmp/gdata.picasaweb.test.dir/");
+	dest_file = g_file_new_for_path ("/tmp/gdata.picasaweb.test.dir/test.jpg");
+
+	/* clean up any pre-existing test output  */
+	if (g_file_query_exists (dest_dir, NULL)) {
+		g_file_trash (dest_dir, NULL, &error); /* TODO does this remove it even with files in it?  hope so */
+		g_assert_no_error (error);
+	}
+
+	thumbnails = gdata_picasaweb_file_get_thumbnails (photo);
+	thumbnail = GDATA_MEDIA_THUMBNAIL (thumbnails->data);
+
+	/* to a directory, non-existent, should succeed, file with "directory"'s name */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "gdata.picasaweb.test.dir");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a "directory", which doesn't actually exist (as a directory), should fail */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* create the directory so we can test on it and in it */
+	g_file_trash (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+	g_file_make_directory (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+
+	/* to a directory, existent, should succeed, making use of the default filename provided */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (actual_file != NULL);
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "thumbnail.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a directory, existent, with inferred file destination already existent, without replace, should fail */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* to a directory, existent, with inferred file destination already existent, with replace, should succeed */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_dir, TRUE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "thumbnail.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a path, non-existent, should succeed */
+	g_assert (g_file_query_exists (dest_file, NULL) == FALSE);
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "test.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a path, existent, without replace, should fail */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* to a path, existent, with replace, should succeed */
+	actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_file, TRUE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "test.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* clean up test file and thumbnail*/
+	g_file_trash (dest_file, NULL, &error);
+	g_assert_no_error (error);
+
+	/* test getting all thumbnails and that they're all the correct size */
+	for (node = thumbnails; node != NULL; node = node->next) {
+		thumbnail = GDATA_MEDIA_THUMBNAIL (node->data);
+		actual_file = gdata_media_thumbnail_download (thumbnail, service, "thumbnail.jpg", dest_file, FALSE, NULL, &error);
+		g_assert_no_error (error);
+		g_assert (g_file_query_exists (actual_file, NULL));
+
+#ifdef HAVE_GDK
+		file_path = g_file_get_path (actual_file);
+		pixbuf = gdk_pixbuf_new_from_file (file_path, &error);
+		g_assert_no_error (error);
+		g_free (file_path);
+
+		/* PicasaWeb reported the height of a thumbnail as a pixel too large once, but otherwise correct */
+		g_assert_cmpint (abs (gdk_pixbuf_get_width (pixbuf) - (gint)gdata_media_thumbnail_get_width (thumbnail)) , <=, 1);
+		g_assert_cmpint (abs (gdk_pixbuf_get_height (pixbuf) - (gint)gdata_media_thumbnail_get_height (thumbnail)) , <=, 1);
+		g_object_unref (pixbuf);
+#endif /* HAVE_GDK */
+
+		g_file_trash (actual_file, NULL, &error);
+		g_assert (g_file_query_exists (actual_file, NULL) == FALSE);
+		g_assert_no_error (error);
+		g_object_unref (actual_file);
+	}
+
+	/* clean up test directory again */
+	g_file_trash (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+
+	g_object_unref (photo_feed);
+	g_object_unref (album_feed);
+	g_object_unref (dest_dir);
+	g_object_unref (dest_file);
+}
+
+static void
+test_download (GDataService *service)
+{
+	GDataFeed *album_feed, *photo_feed;
+	GList *album_entries, *photo_entries, *media_contents;
+	GDataPicasaWebAlbum *album;
+	GDataPicasaWebFile *photo;
+	GDataPicasaWebQuery *query;
+	GDataMediaContent* content;
+	GFile *dest_dir, *dest_file, *actual_file;
+	gchar *basename;
+	GError *error = NULL;
+
+	/*** Acquire a photo to test ***/
+	album_feed = gdata_picasaweb_service_query_all_albums (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, NULL, NULL, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_FEED (album_feed));
+
+	album_entries = gdata_feed_get_entries (album_feed);
+	g_assert (album_entries != NULL);
+
+	album = GDATA_PICASAWEB_ALBUM (album_entries->data);
+
+	query = gdata_picasaweb_query_new (NULL);
+	gdata_picasaweb_query_set_image_size (query, "32"); /* we're querying for the smallest size, to save bandwidth here :D */
+	photo_feed = gdata_picasaweb_service_query_files (GDATA_PICASAWEB_SERVICE (service), album, GDATA_QUERY (query), NULL, NULL, NULL, &error);
+	g_object_unref (query);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_FEED (photo_feed));
+
+	photo_entries = gdata_feed_get_entries (photo_feed);
+	g_assert (photo_entries != NULL);
+
+	photo = GDATA_PICASAWEB_FILE (photo_entries->data);
+
+	dest_dir = g_file_new_for_path ("/tmp/gdata.picasaweb.test.dir/");
+	dest_file = g_file_new_for_path ("/tmp/gdata.picasaweb.test.dir/test.jpg");
+
+	/* clean up any pre-existing test output  */
+	if (g_file_query_exists (dest_dir, NULL)) {
+		g_file_trash (dest_dir, NULL, &error); /* TODO does this remove it even with files in it?  hope so */
+		g_assert_no_error (error);
+	}
+
+	media_contents = gdata_picasaweb_file_get_contents (photo);
+	g_assert_cmpint (g_list_length (media_contents), ==, 1);
+	content = GDATA_MEDIA_CONTENT (media_contents->data);
+
+	/* to a directory, non-existent, should succeed, file with "directory"'s name */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "gdata.picasaweb.test.dir");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a file in a "directory", which already exists as a file, should fail */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* create the directory so we can test on it and in it */
+	g_file_trash (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+	g_file_make_directory (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+
+	/* to a directory, existent, should succeed, using default filename */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (actual_file != NULL);
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "default.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+	/* TODO: test that it exists with default filename? */
+
+	/* to a directory, existent, should fail trying to use the default filename, which already exists */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_dir, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* to a directory, existent, should succeed with default filename, replacing what already exists */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_dir, TRUE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "default.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a path, non-existent, should succeed */
+	g_assert (g_file_query_exists (dest_file, NULL) == FALSE);
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "test.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* to a path, existent, without replace, should fail */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_file, FALSE, NULL, &error);
+	g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+	g_clear_error (&error);
+	g_assert (actual_file == NULL);
+
+	/* to a path, existent, with replace, should succeed */
+	actual_file = gdata_media_content_download (content, service, "default.jpg", dest_file, TRUE, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (g_file_query_exists (actual_file, NULL));
+	basename = g_file_get_basename (actual_file);
+	g_assert_cmpstr (basename, ==, "test.jpg");
+	g_free (basename);
+	g_object_unref (actual_file);
+
+	/* clean up test directory */
+	g_file_trash (dest_dir, NULL, &error);
+	g_assert_no_error (error);
+
+	g_object_unref (photo_feed);
+	g_object_unref (album_feed);
+	g_object_unref (dest_dir);
+	g_object_unref (dest_file);
+}
+
+static void
 test_upload_simple (GDataService *service)
 {
 	GDataPicasaWebFile *photo, *photo_new;
@@ -775,7 +1067,6 @@ main (int argc, char *argv[])
 	g_test_add_func ("/picasaweb/authentication", test_authentication);
 	if (g_test_thorough () == TRUE)
 		g_test_add_func ("/picasaweb/authentication_async", test_authentication_async);
-	g_test_add_data_func ("/picasaweb/upload/photo", service, test_upload_simple);
 	g_test_add_data_func ("/picasaweb/query/all_albums", service, test_query_all_albums);
 	g_test_add_data_func ("/picasaweb/query/user", service, test_query_user);
 	if (g_test_thorough () == TRUE)
@@ -787,6 +1078,9 @@ main (int argc, char *argv[])
 	g_test_add_data_func ("/picasaweb/query/photo_feed", service, test_photo_feed);
 	g_test_add_data_func ("/picasaweb/query/photo_feed_entry", service, test_photo_feed_entry);
 	g_test_add_data_func ("/picasaweb/query/photo", service, test_photo);
+	g_test_add_data_func ("/picasaweb/upload/photo", service, test_upload_simple);
+	g_test_add_data_func ("/picasaweb/download/photo", service, test_download);
+	g_test_add_data_func ("/picasaweb/download/thumbnails", service, test_download_thumbnails);
 	g_test_add_data_func ("/picasaweb/album/new", service, test_album_new);
 
 	retval = g_test_run ();



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