/*
* Copyright (C) 2012 Intel Corporation.
* Copyright (C) 2013 Jens Georg <mail@jensge.org>
*
* Author: Jens Georg <jensg@openismus.com>
* Jens Georg <mail@jensge.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <libgupnp-av/gupnp-media-collection.h>
/* Flat DIDL_S playlist */
#define TEST_PARSE_COLLECTION_1 \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
"<DIDL-Lite" \
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" \
" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"" \
" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\"" \
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" \
" xsi:schemaLocation=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" \
" http://www.upnp.org/schemas/av/didl-lite-v2-20060531.xsd" \
" urn:schemas-upnp-org:metadata-1-0/upnp/" \
" http://www.upnp.org/schemas/av/upnp-v2-20060531.xsd\">" \
" <item id=\"\" parentID=\"0\" restricted=\"0\">" \
" <dc:title>Song1</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" <upnp:artist></upnp:artist>" \
" </item>" \
" <item id=\"\" parentID=\"0\" restricted=\"0\">" \
" <dc:title>Song2</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" </item>" \
" <item id=\"\" parentID=\"0\" restricted=\"0\">" \
" <dc:title>Song3</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" </item>" \
"</DIDL-Lite>"
/* Nested DIDL_S playlist */
#define TEST_PARSE_COLLECTION_2 \
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \
"<DIDL-Lite" \
" xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"" \
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" \
" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\"" \
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" \
" xsi:schemaLocation=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" \
" http://www.upnp.org/schemas/av/didl-lite-v2-20060531.xsd" \
" urn:schemas-upnp-org:metadata-1-0/upnp/" \
" http://www.upnp.org/schemas/av/upnp-v2-20060531.xsd\">" \
" <container id=\"1\" parentID=\"0\" restricted=\"0\">" \
" <dc:title>NonFlatCollection</dc:title>" \
" <dc:creator>NonFlatCollection Author</dc:creator>" \
" <item id=\"\" parentID=\"1\" restricted=\"0\">" \
" <dc:title>Song1</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" <upnp:artist></upnp:artist>" \
" </item>" \
" <item id=\"\" parentID=\"1\" restricted=\"0\">" \
" <dc:title>Song2</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" </item>" \
" <item id=\"\" parentID=\"1\" restricted=\"0\">" \
" <dc:title>Song3</dc:title>" \
" <upnp:class>object.item.audioItem</upnp:class>" \
" <res protocolInfo=\"*:*:*:*\" />" \
" </item>" \
" </container>" \
"</DIDL-Lite>"
#define TEST_CREATE_FLAT \
"<DIDL-Lite " \
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" " \
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\" " \
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">" \
"<item restricted=\"1\">" \
"<dc:title>Song1</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song1.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song2</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song2.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song3</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song3.mp3</res>" \
"</item>" \
"</DIDL-Lite>"
#define TEST_CREATE_FULL \
"<DIDL-Lite " \
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" " \
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\" " \
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">" \
"<container>" \
"<dc:title>TestCollection1</dc:title>" \
"<dc:creator>TestCollection1Author</dc:creator>" \
"<item restricted=\"1\">" \
"<dc:title>Song1</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song1.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song2</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song2.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song3</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song3.mp3</res>" \
"</item>" \
"</container>" \
"</DIDL-Lite>"
#define TEST_CREATE_FULL_REPARENT \
"<DIDL-Lite " \
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" " \
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\" " \
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">" \
"<container>" \
"<item restricted=\"1\">" \
"<dc:title>Song1</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song1.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song2</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song2.mp3</res>" \
"</item>" \
"<item restricted=\"1\">" \
"<dc:title>Song3</dc:title>" \
"<upnp:class>object.item.audioItem</upnp:class>" \
"<res>http://example.com/song3.mp3</res>" \
"</item>" \
"<dc:title>TestCollection1</dc:title>" \
"<dc:creator>TestCollection1Author</dc:creator>" \
"</container>" \
"</DIDL-Lite>"
#define TEST_PARSE_NO_XML "This is just some random text"
static void
test_didl_collection_construction (void)
{
GUPnPMediaCollection *collection;
/* Check that a collection created via auxillary function is mutable */
collection = gupnp_media_collection_new ();
g_assert (gupnp_media_collection_get_mutable (collection));
g_object_unref (collection);
/* Check that a collection created via auxillary parse function is
* not mutable */
collection = gupnp_media_collection_new_from_string
(TEST_PARSE_COLLECTION_1);
g_assert (!gupnp_media_collection_get_mutable (collection));
g_object_unref (collection);
/* Check that creating a collection via g_object_new and title/author
* properties set is mutable */
collection = g_object_new (GUPNP_TYPE_MEDIA_COLLECTION,
"title", "test01collection",
"author", "test01author",
NULL);
g_assert (gupnp_media_collection_get_mutable (collection));
g_object_unref (collection);
/* Check that creating a collection via g_object_new and data is not
* mutable */
collection = g_object_new (GUPNP_TYPE_MEDIA_COLLECTION,
"data", TEST_PARSE_COLLECTION_1,
NULL);
g_assert (!gupnp_media_collection_get_mutable (collection));
g_object_unref (collection);
/* Check that creating a collection with all properties set will result
* in a collection that ignored "title" and "author" properties.
*/
collection = g_object_new (GUPNP_TYPE_MEDIA_COLLECTION,
"title", "test01collection",
"author", "test01author",
"data", TEST_PARSE_COLLECTION_1,
NULL);
g_assert (!gupnp_media_collection_get_mutable (collection));
g_assert_cmpstr (gupnp_media_collection_get_author (collection), ==,
NULL);
g_assert_cmpstr (gupnp_media_collection_get_title (collection), ==,
NULL);
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_PARSE_COLLECTION_1);
g_object_unref (collection);
}
static void
test_didl_collection_parse_flat (void)
{
GUPnPMediaCollection *collection;
GList *items, *it;
collection = gupnp_media_collection_new_from_string
(TEST_PARSE_COLLECTION_1);
g_assert_cmpstr (gupnp_media_collection_get_author (collection), ==,
NULL);
g_assert_cmpstr (gupnp_media_collection_get_title (collection), ==,
NULL);
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_PARSE_COLLECTION_1);
it = items = gupnp_media_collection_get_items (collection);
g_assert_cmpint (g_list_length (items), ==, 3);
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song1");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song2");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song3");
g_list_free_full (items, (GDestroyNotify) g_object_unref);
}
static void
test_didl_collection_parse_full (void)
{
GUPnPMediaCollection *collection;
GList *items, *it;
collection = gupnp_media_collection_new_from_string
(TEST_PARSE_COLLECTION_2);
g_assert_cmpstr (gupnp_media_collection_get_author (collection), ==,
"NonFlatCollection Author");
g_assert_cmpstr (gupnp_media_collection_get_title (collection), ==,
"NonFlatCollection");
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_PARSE_COLLECTION_2);
it = items = gupnp_media_collection_get_items (collection);
g_assert_cmpint (g_list_length (items), ==, 3);
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song1");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song2");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song3");
g_list_free_full (items, (GDestroyNotify) g_object_unref);
}
#define ERROR_MESSAGE "Failed to parse DIDL-Lite: No 'DIDL-Lite' node in the DIDL-Lite XML:"
static gboolean
ignore_xml_parse_error (G_GNUC_UNUSED const gchar *log_domain,
G_GNUC_UNUSED GLogLevelFlags log_level,
const gchar *message,
G_GNUC_UNUSED gpointer user_data)
{
if (strncmp (message,
ERROR_MESSAGE,
g_utf8_strlen (ERROR_MESSAGE, -1) - 1) == 0) {
return FALSE;
}
return TRUE;
}
static void
test_didl_collection_parse_invalid (void)
{
GUPnPMediaCollection *collection;
GList *items;
g_test_log_set_fatal_handler (ignore_xml_parse_error, NULL);
collection = gupnp_media_collection_new_from_string (TEST_PARSE_NO_XML);
items = gupnp_media_collection_get_items (collection);
g_assert (items == NULL);
g_object_unref (collection);
}
static void
test_didl_collection_create_flat (void)
{
GUPnPMediaCollection *collection;
GUPnPDIDLLiteItem *item;
GList *items, *it;
GUPnPDIDLLiteResource *res;
collection = gupnp_media_collection_new ();
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song1");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song1.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song2");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song2.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song3");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song3.mp3");
g_object_unref (res);
g_object_unref (item);
it = items = gupnp_media_collection_get_items (collection);
g_assert_cmpint (g_list_length (items), ==, 3);
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song1");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song2");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song3");
g_list_free_full (items, (GDestroyNotify) g_object_unref);
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_CREATE_FLAT);
}
static void
test_didl_collection_create_full (void)
{
GUPnPMediaCollection *collection;
GUPnPDIDLLiteItem *item;
GList *items, *it;
GUPnPDIDLLiteResource *res;
collection = gupnp_media_collection_new ();
gupnp_media_collection_set_title (collection, "TestCollection1");
gupnp_media_collection_set_author (collection, "TestCollection1Author");
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song1");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song1.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song2");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song2.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song3");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song3.mp3");
g_object_unref (res);
g_object_unref (item);
it = items = gupnp_media_collection_get_items (collection);
g_assert_cmpint (g_list_length (items), ==, 3);
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song1");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song2");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song3");
g_list_free_full (items, (GDestroyNotify) g_object_unref);
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_CREATE_FULL);
}
static void
test_didl_collection_create_reparent (void)
{
GUPnPMediaCollection *collection;
GUPnPDIDLLiteItem *item;
GList *items, *it;
GUPnPDIDLLiteResource *res;
collection = gupnp_media_collection_new ();
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song1");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song1.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song2");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song2.mp3");
g_object_unref (res);
g_object_unref (item);
item = gupnp_media_collection_add_item (collection);
gupnp_didl_lite_object_set_title (GUPNP_DIDL_LITE_OBJECT (item),
"Song3");
gupnp_didl_lite_object_set_upnp_class (GUPNP_DIDL_LITE_OBJECT (item),
"object.item.audioItem");
res = gupnp_didl_lite_object_add_resource (GUPNP_DIDL_LITE_OBJECT (item));
gupnp_didl_lite_resource_set_uri (res, "http://example.com/song3.mp3");
g_object_unref (res);
g_object_unref (item);
it = items = gupnp_media_collection_get_items (collection);
/* Force reparenting of the items in the XML */
gupnp_media_collection_set_title (collection, "TestCollection1");
gupnp_media_collection_set_author (collection, "TestCollection1Author");
g_assert_cmpint (g_list_length (items), ==, 3);
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song1");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song2");
it = it->next;
g_assert_cmpstr (gupnp_didl_lite_object_get_title (GUPNP_DIDL_LITE_OBJECT (it->data)), ==,
"Song3");
g_list_free_full (items, (GDestroyNotify) g_object_unref);
g_assert_cmpstr (gupnp_media_collection_get_string (collection), ==,
TEST_CREATE_FULL_REPARENT);
}
int main (int argc, char *argv[])
{
#if !GLIB_CHECK_VERSION (2, 35, 0)
g_type_init ();
#endif
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/didl/collection/construction",
test_didl_collection_construction);
g_test_add_func ("/didl/collection/parse_flat",
test_didl_collection_parse_flat);
g_test_add_func ("/didl/collection/parse_full",
test_didl_collection_parse_full);
g_test_add_func ("/didl/collection/parse_invalid",
test_didl_collection_parse_invalid);
g_test_add_func ("/didl/collection/create_flat",
test_didl_collection_create_flat);
g_test_add_func ("/didl/collection/create_full",
test_didl_collection_create_full);
g_test_add_func ("/didl/collection/create_reparent",
test_didl_collection_create_reparent);
return g_test_run ();
}