1 /****************************************************************************************
2  * Copyright (c) 2010-2012 Leo Franchi <lfranchi@kde.org>                               *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #include "PlaylistTest.h"
18 
19 #include "Config.h"
20 #include "Playlist.h"
21 
22 #include <QDebug>
23 #include <QtXml/QDomDocument>
24 #include <QVariant>
25 #include <QNetworkReply>
26 #include <QtNetwork/QNetworkReply>
27 
28 using namespace Echonest;
29 
initTestCase()30 void PlaylistTest::initTestCase()
31 {
32     Config::instance()->setAPIKey( "JGJCRKWLXLBZIFAZB" );
33 }
34 
testStatic1()35 void PlaylistTest::testStatic1()
36 {
37     DynamicPlaylist::PlaylistParams p;
38     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "tallest man on earth" ) ) );
39     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "bon iver" ) ) );
40     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "mumford and sons" ) ) );
41     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) );
42     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Results, 10 ) );
43 
44     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
45 
46     qDebug() << reply->url().toString();
47     QVERIFY( reply->url().toString() == QLatin1String( "http://developer.echonest.com/api/v4/playlist/static?api_key=JGJCRKWLXLBZIFAZB&format=xml&artist=tallest+man+on+earth&artist=bon+iver&artist=mumford+and+sons&type=artist-radio&results=10" ) );
48 
49     QEventLoop loop;
50     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
51     loop.exec();
52     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
53 
54     QVERIFY( songs.size() == 10 );
55     Q_FOREACH( const Song& song, songs )
56         QVERIFY( !song.id().isEmpty() );
57 
58 }
59 
testStatic2()60 void PlaylistTest::testStatic2()
61 {
62     DynamicPlaylist::PlaylistParams p;
63     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "tallest man on earth" ) ) );
64     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "bon iver" ) ) );
65     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "mumford and sons" ) ) );
66     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "Florence + The Machine" ) ) );
67     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::ArtistMaxFamiliarity, 0.4 ) );
68     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::MinDanceability, 0.7 ) );
69     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistType ) );
70     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity ) ) ) );
71     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 4 ) );
72 
73     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
74 
75     qDebug() << reply->url().toEncoded();
76     QCOMPARE( QLatin1String( reply->url().toEncoded() ), QLatin1String( "http://developer.echonest.com/api/v4/playlist/static?api_key=JGJCRKWLXLBZIFAZB&format=xml&artist=tallest+man+on+earth&artist=bon+iver&artist=mumford+and+sons&artist=Florence+%252B+The+Machine&artist_max_familiarity=0.4&min_danceability=0.7&type=artist&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity&results=4" ) );
77 
78     QEventLoop loop;
79     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
80     loop.exec();
81     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
82 
83 //     qDebug() << "Got songs;" << songs;
84     QVERIFY( songs.size() > 1 );
85     Q_FOREACH( const Song& song, songs ) {
86         QVERIFY( !song.id().isEmpty() );
87     }
88 
89     p.clear();
90     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Description, QLatin1String( "70s" ) ) );
91     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Description, QLatin1String( "folk^2" ) ) );
92     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::ArtistMinFamiliarity, 0.4 ) );
93     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::MaxTempo, 100 ) );
94     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Mode, 0 ) );
95     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistDescriptionType ) );
96     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Style, QLatin1String( "acoustic" ) ) );
97     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::AudioSummaryInformation | Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity ) ) ) );
98     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 7 ) );
99 
100     reply = DynamicPlaylist::staticPlaylist( p );
101 
102 //     qDebug() << reply->url().toString();
103     QVERIFY( reply->url().toString() == QLatin1String( "http://developer.echonest.com/api/v4/playlist/static?api_key=JGJCRKWLXLBZIFAZB&format=xml&description=70s&description=folk^2&artist_min_familiarity=0.4&max_tempo=100&mode=0&type=artist-description&style=acoustic&bucket=audio_summary&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity&results=7" ) );
104 
105     QEventLoop loop2;
106     loop2.connect( reply, SIGNAL(finished()), SLOT(quit()) );
107     loop2.exec();
108     songs = DynamicPlaylist::parseStaticPlaylist( reply );
109 
110     QVERIFY( songs.size() == 7 );
111     Q_FOREACH( const Song& song, songs ) {
112         QVERIFY( !song.id().isEmpty() );
113 //         qDebug() << song << song.audioSummary();
114         QVERIFY( song.audioSummary().duration() > 0 );
115     }
116 
117 }
118 
119 
testStaticArtistYears()120 void PlaylistTest::testStaticArtistYears()
121 {
122     DynamicPlaylist::PlaylistParams p;
123     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Type, DynamicPlaylist::ArtistDescriptionType ) );
124     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Description, QLatin1String( "rock" ) ) );
125     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::ArtistStartYearBefore, 1970 ) );
126     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::ArtistEndYearBefore, 1980 ) );
127     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity ) ) ) );
128     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 4 ) );
129 
130     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
131 
132     qDebug() << reply->url().toEncoded();
133     QCOMPARE( QLatin1String( reply->url().toEncoded() ), QLatin1String( "http://developer.echonest.com/api/v4/playlist/static?api_key=JGJCRKWLXLBZIFAZB&format=xml&type=artist-description&description=rock&artist_start_year_before=1970&artist_end_year_before=1980&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity&results=4" ) );
134     QEventLoop loop;
135     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
136     loop.exec();
137     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
138 
139 //     qDebug() << "Got songs;" << songs;
140     QCOMPARE( songs.size(), 4 );
141     Q_FOREACH( const Song& song, songs ) {
142         QVERIFY( !song.id().isEmpty() );
143     }
144 
145 }
146 
testStaticWithSongType()147 void PlaylistTest::testStaticWithSongType()
148 {
149     DynamicPlaylist::PlaylistParams p;
150     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "The Beatles" ) ) );
151     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongType, QLatin1String( "live" ) ) );
152     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::AudioSummaryInformation | Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity | Echonest::SongInformation::SongType ) ) ) );
153     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Sort, DynamicPlaylist::SortLivenessAscending ) );
154     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 20 ) );
155 
156     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
157 
158     qDebug() << reply->url().toEncoded();
159 
160     QEventLoop loop;
161     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
162     loop.exec();
163     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
164 
165     Q_FOREACH( const Song& song, songs ) {
166         QVERIFY( song.songTypes().contains( QLatin1String("live" ) ) );
167     }
168 }
169 
testStaticXSPF()170 void PlaylistTest::testStaticXSPF()
171 {
172     DynamicPlaylist::PlaylistParams p;
173     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "balmorhea" ) ) );
174     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "tallest man on earth" ) ) );
175     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "explosions in the sky" ) ) );
176     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::ArtistMaxFamiliarity, 0.4 ) );
177     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Format, QLatin1String( "xspf" ) ) );
178     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::MaxDanceability, 0.5 ) );
179     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistType ) );
180     Echonest::SongInformation info( Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity | Echonest::SongInformation::Tracks );
181     info.setIdSpaces( QStringList() << QLatin1String( "musicbrainz" ) << QLatin1String( "7digital" ) << QLatin1String( "playme" ) );
182     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( info ) )  );
183     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Limit, true ) );
184     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 40 ) );
185 
186     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
187 
188     qDebug() << reply->url().toString();
189     QVERIFY( reply->url().toString() == QLatin1String( "http://developer.echonest.com/api/v4/playlist/static?api_key=JGJCRKWLXLBZIFAZB&artist=balmorhea&artist=tallest+man+on+earth&artist=explosions+in+the+sky&artist_max_familiarity=0.4&format=xspf&max_danceability=0.5&type=artist&bucket=tracks&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity&bucket=id:musicbrainz&bucket=id:7digital&bucket=id:playme&limit=true&results=40" ) );
190 
191     QEventLoop loop;
192     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
193     loop.exec();
194     QByteArray xspf = DynamicPlaylist::parseXSPFPlaylist( reply );
195 
196     // verify it's valid
197     QDomDocument doc;
198     QVERIFY( doc.setContent( xspf ) );
199     QVERIFY( !xspf.isEmpty() );
200 
201 }
202 
203 
testDynamic1()204 void PlaylistTest::testDynamic1()
205 {
206     DynamicPlaylist::PlaylistParams p;
207     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "tallest man on earth" ) ) );
208     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "fleet foxes" ) ) );
209     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "johnny cash" ) ) );
210     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) );
211     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMinHotttnesss, .6 ) );
212     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMaxFamiliarity, .4 ) );
213     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Mood, QLatin1String( "sad" ) ) );
214 
215     DynamicPlaylist playlist;
216     QNetworkReply* reply = playlist.create( p );
217 
218     qDebug() << reply->url().toString();
219     QCOMPARE( reply->url().toString(), QLatin1String( "http://developer.echonest.com/api/v4/playlist/dynamic/create?api_key=JGJCRKWLXLBZIFAZB&format=xml&artist=tallest+man+on+earth&artist=fleet+foxes&artist=johnny+cash&type=artist-radio&artist_min_hotttnesss=0.6&artist_max_familiarity=0.4&mood=sad" ) );
220 
221     QEventLoop loop;
222     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
223     loop.exec();
224     playlist.parseCreate( reply );
225 
226     reply = playlist.next( 1 );
227 
228     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
229     loop.exec();
230 
231     Song song = playlist.parseNext( reply ).first.first();
232 //     qDebug() << "next:" << song;
233 
234     QVERIFY( !song.id().isEmpty() );
235     QVERIFY( !song.title().isEmpty() );
236 
237     reply = playlist.next( 1 );
238 
239     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
240     loop.exec();
241     song = playlist.parseNext( reply ).first.first();
242 
243 //     qDebug() << "next:" << song;
244     QVERIFY( !song.id().isEmpty() );
245     QVERIFY( !song.title().isEmpty() );
246 
247     reply = playlist.next( 1 );
248 
249     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
250     loop.exec();
251     song = playlist.parseNext( reply ).first.first();
252 
253 //     qDebug() << "next:" << song;
254     QVERIFY( !song.id().isEmpty() );
255     QVERIFY( !song.title().isEmpty() );
256 }
257 
testDynamic2()258 void PlaylistTest::testDynamic2()
259 {
260     DynamicPlaylist::PlaylistParams p;
261     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "pink floyd^-1" ) ) );
262     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "the who" ) ) );
263     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "queen" ) ) );
264     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "led zeppelin^2" ) ) );
265     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "-the beatles" ) ) ); //exclude
266     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistType ) );
267     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMinHotttnesss, .7 ) );
268     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMaxFamiliarity, .3 ) );
269     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::MinLoudness, -10 ) );
270     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Mode, 1 ) );
271     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::AudioSummaryInformation | Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity ) ) ) );
272 
273     DynamicPlaylist playlist;
274     QNetworkReply* reply = playlist.create( p );
275 
276     qDebug() << reply->url().toString();
277     QCOMPARE( reply->url().toString(), QLatin1String( "http://developer.echonest.com/api/v4/playlist/dynamic/create?api_key=JGJCRKWLXLBZIFAZB&format=xml&artist=pink+floyd^-1&artist=the+who&artist=queen&artist=led+zeppelin^2&artist=-the+beatles&type=artist&artist_min_hotttnesss=0.7&artist_max_familiarity=0.3&min_loudness=-10&mode=1&bucket=audio_summary&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity" ) );
278 
279     QEventLoop loop;
280     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
281     loop.exec();
282     playlist.parseCreate( reply );
283 
284     reply = playlist.next( 1 );
285     qDebug() << reply->url().toString();
286 
287     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
288     loop.exec();
289     Echonest::Song song = playlist.parseNext( reply ).first.first();
290 
291 //     qDebug() << "next:" << song;
292     QVERIFY( !song.id().isEmpty() );
293     QVERIFY( !song.title().isEmpty() );
294 
295     // GET NEXT
296     reply = playlist.next( 1 );
297     qDebug() << reply->url().toString();
298 
299     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
300     loop.exec();
301     song = playlist.parseNext( reply ).first.first();
302 
303 //     qDebug() << "next:" << song;
304     QVERIFY( !song.id().isEmpty() );
305     QVERIFY( !song.title().isEmpty() );
306 
307     // GET NEXT
308     reply = playlist.next( 1 );
309     qDebug() << reply->url().toString();
310 
311     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
312     loop.exec();
313     song = playlist.parseNext( reply ).first.first();
314 
315 //     qDebug() << "next:" << song;
316     QVERIFY( !song.id().isEmpty() );
317     QVERIFY( !song.title().isEmpty() );
318 
319     // GET NEXT
320     DynamicPlaylist::PlaylistParams steering;
321     steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::TargetEnergy, QLatin1String( ".8" ) ) );
322     steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMinFamiliarity, QLatin1String( ".5" ) ) );
323 
324     reply = playlist.steer( steering );
325     qDebug() << reply->url().toString();
326 
327     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
328     loop.exec();
329     playlist.parseSteer( reply );
330 
331     reply = playlist.next( 1 );
332     qDebug() << reply->url().toString();
333 
334 
335     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
336     loop.exec();
337     song = playlist.parseNext( reply ).first.first();
338 //     qDebug() << "next steered:" << song;
339     QVERIFY( !song.id().isEmpty() );
340     QVERIFY( !song.title().isEmpty() );
341 
342     // GET NEXT
343     steering.clear();
344     steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::TargetLoudness, QLatin1String( ".9" ) ) );
345     //steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::MoreLikeThis, QLatin1String( "last" ) ) ); //BUG: this no longer seems to work
346 
347     reply = playlist.steer( steering );
348     qDebug() << reply->url().toString();
349 
350     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
351     loop.exec();
352     playlist.parseSteer( reply );
353 
354     playlist.next();
355 
356     reply = playlist.next( 1 );
357     qDebug() << reply->url().toString();
358 
359     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
360     loop.exec();
361     song = playlist.parseNext( reply ).first.first();
362 //     qDebug() << "next steered:" << song;
363     QVERIFY( !song.id().isEmpty() );
364     QVERIFY( !song.title().isEmpty() );
365 
366     // GET INFO TODO
367     /*reply = playlist.fetchSessionInfo();
368     qDebug() << "session info URL:" << reply->url().toString();
369     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
370     loop.exec();
371     Echonest::SessionInfo info = playlist.parseSessionInfo( reply );
372     QVERIFY( !info.banned_artists.isEmpty() );
373     QVERIFY( !info.banned_songs.isEmpty() );
374     QVERIFY( !info.banned_songs.at( 0 ).artist_id.isEmpty() );
375     QVERIFY( !info.banned_songs.at( 0 ).artist_name.isEmpty() );
376     QVERIFY( !info.banned_songs.at( 0 ).id.isEmpty() );
377     QVERIFY( !info.banned_songs.at( 0 ).title.isEmpty() );
378     QVERIFY( !info.skipped_songs.isEmpty() );
379     QVERIFY( !info.skipped_songs.at( 0 ).artist_id.isEmpty() );
380     QVERIFY( !info.skipped_songs.at( 0 ).artist_name.isEmpty() );
381     QVERIFY( !info.skipped_songs.at( 0 ).id.isEmpty() );
382     QVERIFY( !info.skipped_songs.at( 0 ).title.isEmpty() );
383     QVERIFY( !info.rated_songs.isEmpty() );
384     QVERIFY( !info.rated_songs.at( 0 ).artist_id.isEmpty() );
385     QVERIFY( !info.rated_songs.at( 0 ).artist_name.isEmpty() );
386     QVERIFY( !info.rated_songs.at( 0 ).id.isEmpty() );
387     QVERIFY( !info.rated_songs.at( 0 ).title.isEmpty() );
388     QVERIFY( !info.history.isEmpty() );
389     QVERIFY( !info.history.at( 0 ).artist_id.isEmpty() );
390     QVERIFY( !info.history.at( 0 ).artist_name.isEmpty() );
391     QVERIFY( !info.history.at( 0 ).id.isEmpty() );
392     QVERIFY( !info.history.at( 0 ).title.isEmpty() );
393     QVERIFY( !info.playlist_type.isEmpty() );
394     QVERIFY( !info.rules.isEmpty() );
395     QVERIFY( !info.session_id.isEmpty() );
396 
397     QVERIFY( !song.id().isEmpty() );
398     QVERIFY( !song.title().isEmpty() );*/
399     QByteArray oldId = playlist.sessionId();
400     // now reset it
401     p.clear();
402     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) );
403     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "pink floyd" ) ) );
404     reply = playlist.create( p );
405     qDebug() << reply->url().toString();
406 
407     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
408     loop.exec();
409     playlist.parseCreate( reply );
410 
411     reply = playlist.next();
412     qDebug() << reply->url().toString();
413 
414     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
415     loop.exec();
416 
417     song = playlist.parseNext( reply ).first.first();
418 //     qDebug() << "new:" << song << song.artistFamiliarity() << song.artistHotttnesss();
419 
420     QVERIFY( !song.id().isEmpty() );
421     QVERIFY( !song.title().isEmpty() );
422     QVERIFY( song.artistHotttnesss() == -1 ); // make sure we are in a new playlist, and we didn't ask for this info so it shouldn't be there
423     QVERIFY( song.artistFamiliarity() == -1 ); // make sure we are in a new playlist, and we didn't ask for this info so it shouldn't be there
424 
425     reply = playlist.deleteSession();
426     qDebug() << reply->url().toString();
427 
428     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
429     loop.exec();
430 
431     playlist.parseDeleteSession(reply);
432     Q_ASSERT(playlist.sessionId().isEmpty());
433 
434 }
435 
testNewDynamicAPI()436 void PlaylistTest::testNewDynamicAPI()
437 {
438     DynamicPlaylist::PlaylistParams p;
439     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "frightened rabbit" ) ) );
440     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "wilco" ) ) );
441     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "the tallest man on earth" ) ) );
442     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "noah and the whale" ) ) );
443     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMaxFamiliarity, QLatin1String( ".4" ) ) );
444     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Key, QLatin1String( "3" ) ) );
445     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) );
446 
447     DynamicPlaylist playlist;
448     QNetworkReply* reply = playlist.create( p );
449 
450 //     qDebug() << reply->url().toString();
451     QCOMPARE( reply->url().toString(), QLatin1String( "http://developer.echonest.com/api/v4/playlist/dynamic/create?api_key=JGJCRKWLXLBZIFAZB&format=xml&artist=frightened+rabbit&artist=wilco&artist=the+tallest+man+on+earth&artist=noah+and+the+whale&artist_max_familiarity=.4&key=3&type=artist-radio" ) );
452 
453     QEventLoop loop;
454     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
455     loop.exec();
456     playlist.parseCreate( reply );
457 
458     reply = playlist.next( 2 );
459 
460 //     qDebug() << reply->url().toString();
461     QCOMPARE( reply->url().toString(), QString( QLatin1String( "http://developer.echonest.com/api/v4/playlist/dynamic/next?api_key=JGJCRKWLXLBZIFAZB&format=xml&session_id=%1&results=2&lookahead=0" ) ).arg( QString::fromLatin1( playlist.sessionId() ) ) );
462     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
463     loop.exec();
464 
465     QPair< SongList, SongList > ret;
466     ret = playlist.parseNext( reply );
467 
468     QCOMPARE( ret.first.size(), 2 );
469     QCOMPARE( ret.second.size(), 0 );
470 
471     QVERIFY( !ret.first.at( 0 ).id().isNull() );
472     QVERIFY( !ret.first.at( 0 ).title().isNull() );
473     QVERIFY( !ret.first.at( 1 ).id().isNull() );
474     QVERIFY( !ret.first.at( 1 ).title().isNull() );
475 
476     DynamicPlaylist::DynamicFeedback feedback;
477     feedback.append( DynamicPlaylist::DynamicFeedbackParamData( DynamicPlaylist::FavoriteArtist, "last" ) );
478     feedback.append( DynamicPlaylist::DynamicFeedbackParamData( DynamicPlaylist::FavoriteSong, "last" ) );
479     reply = playlist.feedback( feedback );
480 
481 //     qDebug() << reply->url().toString();
482     QString u = QString::fromUtf8( "http://developer.echonest.com/api/v4/playlist/dynamic/feedback?api_key=JGJCRKWLXLBZIFAZB&format=xml&session_id=%1&favorite_artist=last&favorite_song=last" );
483     QCOMPARE( reply->url().toString(), u.arg( QString::fromUtf8( playlist.sessionId() ) ) );
484     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
485     loop.exec();
486     playlist.parseFeedback( reply );
487 
488     DynamicPlaylist::PlaylistParams steering;
489     steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::MoreLikeThis, QLatin1String( "SONRAMP13775DE8214^4" ) ) );
490     steering.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Mood, QLatin1String( "happy^2" ) ) );
491 
492     reply = playlist.steer( steering );
493 
494 //     qDebug() << reply->url().toString();
495     u = QString::fromUtf8( "http://developer.echonest.com/api/v4/playlist/dynamic/steer?api_key=JGJCRKWLXLBZIFAZB&format=xml&session_id=%1&more_like_this=SONRAMP13775DE8214^4&mood=happy^2" );
496     QCOMPARE( reply->url().toString(), u.arg( QString::fromUtf8( playlist.sessionId() ) ) );
497     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
498     loop.exec();
499     playlist.parseSteer( reply );
500 
501     reply = playlist.next( 3, 3 );
502 
503 //     qDebug() << reply->url().toString();
504     u = QString::fromUtf8( "http://developer.echonest.com/api/v4/playlist/dynamic/next?api_key=JGJCRKWLXLBZIFAZB&format=xml&session_id=%1&results=3&lookahead=3" );
505     QCOMPARE( reply->url().toString(), u.arg( QString::fromUtf8( playlist.sessionId() ) ) );
506     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
507     loop.exec();
508 
509     ret = playlist.parseNext( reply );
510 
511     QCOMPARE( ret.first.size(), 3 );
512     QCOMPARE( ret.second.size(), 3 );
513 
514     QVERIFY( !ret.first.at( 0 ).id().isNull() );
515     QVERIFY( !ret.first.at( 0 ).title().isNull() );
516     QVERIFY( !ret.first.at( 1 ).id().isNull() );
517     QVERIFY( !ret.first.at( 1 ).title().isNull() );
518     QVERIFY( !ret.first.at( 2 ).id().isNull() );
519     QVERIFY( !ret.first.at( 2 ).title().isNull() );
520     QVERIFY( !ret.second.at( 0 ).id().isNull() );
521     QVERIFY( !ret.second.at( 0 ).title().isNull() );
522     QVERIFY( !ret.second.at( 1 ).id().isNull() );
523     QVERIFY( !ret.second.at( 1 ).title().isNull() );
524     QVERIFY( !ret.second.at( 2 ).id().isNull() );
525     QVERIFY( !ret.second.at( 2 ).title().isNull() );
526 }
527 
testDynamicChainXSPF()528 void PlaylistTest::testDynamicChainXSPF()
529 {
530     DynamicPlaylist::PlaylistParams p;
531     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "pink floyd^-1" ) ) );
532     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "the who" ) ) );
533     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "queen" ) ) );
534     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "led zeppelin^2" ) ) );
535     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "-the beatles" ) ) ); //exclude
536     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistType ) );
537     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMinHotttnesss, .7 ) );
538     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ArtistMaxFamiliarity, .3 ) );
539     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::MinLoudness, -10 ) );
540     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Mode, 1 ) );
541     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::ChainXSPF, true ) );
542     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Format, QLatin1String( "xspf" ) ) );
543     Echonest::SongInformation info( Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity | Echonest::SongInformation::Tracks );
544     info.setIdSpaces( QStringList() << QLatin1String( "musicbrainz" ) << QLatin1String( "7digital" ) << QLatin1String( "playme" ) );
545     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( info ) )  );
546     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Limit, true ) );
547 
548     DynamicPlaylist playlist;
549     QNetworkReply* reply = playlist.create( p );
550 
551     qDebug() << reply->url().toString();
552 //     QVERIFY( reply->url().toString() == QLatin1String( "http://developer.echonest.com/api/v4/playlist/dynamic?api_key=JGJCRKWLXLBZIFAZB&artist=pink+floyd^-1&artist=the+who&artist=queen&artist=led+zeppelin^2&artist=-the+beatles&type=artist&artist_min_hotttnesss=0.7&artist_max_familiarity=0.3&min_loudness=-10&mode=1&chain_xspf=true&format=xspf&bucket=audio_summary&bucket=song_hotttnesss&bucket=artist_hotttnesss&bucket=artist_familiarity" ) );
553 
554     QEventLoop loop;
555     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
556     loop.exec();
557     QByteArray xspf = Echonest::DynamicPlaylist::parseXSPFPlaylist( reply );
558 
559     //     qDebug() << "xspf:" << xspf;    // verify it's valid
560     QDomDocument doc;
561     QVERIFY( doc.setContent( xspf ) );
562     QVERIFY( !xspf.isEmpty() );
563 
564 }
565 
testGenreRadio()566 void PlaylistTest::testGenreRadio()
567 {
568     DynamicPlaylist::PlaylistParams p;
569     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Genre, QLatin1String( "dance pop" ) ) );
570     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::GenreRadioType ) );
571     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::AudioSummaryInformation | Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity | Echonest::SongInformation::SongType ) ) ) );
572     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 20 ) );
573 
574     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
575 
576     qDebug() << reply->url().toEncoded();
577 
578     QEventLoop loop;
579     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
580     loop.exec();
581     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
582     QVERIFY( songs.size() == 20 );
583 
584     /*Q_FOREACH( const Song& song, songs ) {
585         //no usefull test code can be inserted here, because genres are not (yet?) supported in songs (e.g. to check via SongInformation if a song is genre "dance pop")
586         qDebug() << song;
587     }*/
588 }
589 
testAudioSummaryAttributes()590 void PlaylistTest::testAudioSummaryAttributes()
591 {
592     DynamicPlaylist::PlaylistParams p;
593     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Artist, QLatin1String( "The Doors" ) ) );
594     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::MinLiveness, 0.7 ) );
595     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::MaxValence, 0.7 ) );
596     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Sort, DynamicPlaylist::SortValenceDescending ) );
597     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::SongInformation, QVariant::fromValue( Echonest::SongInformation( Echonest::SongInformation::AudioSummaryInformation | Echonest::SongInformation::Hotttnesss | Echonest::SongInformation::ArtistHotttnesss | Echonest::SongInformation::ArtistFamiliarity | Echonest::SongInformation::SongType ) ) ) );
598     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 10 ) );
599 
600     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
601 
602     qDebug() << reply->url().toEncoded();
603 
604     QEventLoop loop;
605     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
606     loop.exec();
607     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
608 
609     Q_FOREACH( const Song& song, songs ) {
610         QVERIFY( song.audioSummary().liveness() >= 0.7 );
611     }
612 }
613 
testGenrePresets()614 void PlaylistTest::testGenrePresets()
615 {
616     DynamicPlaylist::PlaylistParams p;
617     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Genre, QLatin1String( "classic rock" ) ) );
618     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::GenreRadioType ) );
619     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::GenrePreset, DynamicPlaylist::CoreBest ) );
620     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 30 ) );
621 
622     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
623 
624     qDebug() << reply->url().toEncoded();
625 
626     QEventLoop loop;
627     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
628     loop.exec();
629     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
630 
631     QVERIFY( songs.size() == 30 );
632 }
633 
testDistribution()634 void PlaylistTest::testDistribution()
635 {
636     DynamicPlaylist::PlaylistParams p;
637     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Artist, QLatin1String( "the doors" ) ) );
638     p.append( DynamicPlaylist::PlaylistParamData( Echonest::DynamicPlaylist::Type, Echonest::DynamicPlaylist::ArtistRadioType ) );
639     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Results, 50 ) );
640     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::Distribution, QLatin1String( "wandering" ) ) );
641     p.append( DynamicPlaylist::PlaylistParamData( DynamicPlaylist::GenrePreset, DynamicPlaylist::CoreBest ) );
642 
643     QNetworkReply* reply = DynamicPlaylist::staticPlaylist( p );
644 
645     qDebug() << reply->url().toEncoded();
646 
647     QEventLoop loop;
648     loop.connect( reply, SIGNAL(finished()), SLOT(quit()) );
649     loop.exec();
650     SongList songs = DynamicPlaylist::parseStaticPlaylist( reply );
651 
652     Q_FOREACH( const Song& song, songs) {
653         qDebug() << song;
654     }
655 
656     QVERIFY( songs.size() == 50 );
657 }
658 
659 QTEST_MAIN( PlaylistTest )
660 
661 #include "PlaylistTest.moc"
662 
663