File indexing completed on 2024-04-28 04:48:13

0001 /****************************************************************************************
0002  * Copyright (c) 2013 Konrad Zemek <konrad.zemek@gmail.com>                             *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #include <TestImporterBase.h>
0018 
0019 #include "MetaValues.h"
0020 #include "core/meta/support/MetaConstants.h"
0021 #include "statsyncing/Provider.h"
0022 #include "statsyncing/Track.h"
0023 
0024 #include <QTest>
0025 
0026 
0027 using namespace StatSyncing;
0028 
0029 TestImporterBase::TestImporterBase()
0030 {
0031 }
0032 
0033 ProviderPtr
0034 TestImporterBase::getWritableProvider()
0035 {
0036     return getProvider();
0037 }
0038 
0039 bool
0040 TestImporterBase::hasOddRatings() const
0041 {
0042     return true;
0043 }
0044 
0045 #define skipIfNoSupport( fieldmask, metavalue ) \
0046 { \
0047     if( !( fieldmask & metavalue ) ) \
0048     { \
0049         const QString msg = QString( "Tested provider does not support %1 metadata" ) \
0050                                                 .arg( Meta::nameForField( metavalue ) ); \
0051         QSKIP( msg.toLocal8Bit().constData(), SkipAll ); \
0052     } \
0053 } do {} while(false)
0054 
0055 #define amarokProviderSkipIfNoMysqld( provider ) \
0056     if( QString( provider->prettyName() ) == "Amarok2Test" ) \
0057         if( !QFileInfo( "/usr/bin/mysqld" ).isExecutable() ) \
0058             QSKIP( "/usr/bin/mysqld not executable, skipping Amarok provider tests", \
0059                    SkipAll )
0060 
0061 void
0062 TestImporterBase::titleShouldBeCaseSensitive()
0063 {
0064     ProviderPtr provider( getProvider() );
0065     amarokProviderSkipIfNoMysqld( provider );
0066 
0067     const QString artist = "caseSensitiveTitle";
0068     QVERIFY( provider->artists().contains( artist ) );
0069 
0070     QSet<QString> trackNames;
0071     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0072         trackNames.insert( track->name() );
0073 
0074     QCOMPARE( trackNames.size(), 3 );
0075     QVERIFY( trackNames.contains( "title" ) );
0076     QVERIFY( trackNames.contains( "Title" ) );
0077     QVERIFY( trackNames.contains( "tiTle" ) );
0078 }
0079 
0080 void
0081 TestImporterBase::artistShouldBeCaseSensitive()
0082 {
0083     ProviderPtr provider( getProvider() );
0084     amarokProviderSkipIfNoMysqld( provider );
0085 
0086     const QVector<QString> artists = QVector<QString>()
0087             << "caseSensitiveArtist" << "casesensitiveartist" << "caseSensitiveartist";
0088 
0089     foreach( const QString &artist, artists )
0090     {
0091         const TrackList tracks = provider->artistTracks( artist );
0092         QCOMPARE( tracks.size(), 1 );
0093         QCOMPARE( tracks.front()->artist(), artist );
0094     }
0095 }
0096 
0097 void
0098 TestImporterBase::albumShouldBeCaseSensitive()
0099 {
0100     ProviderPtr provider( getProvider() );
0101     amarokProviderSkipIfNoMysqld( provider );
0102 
0103     const QString artist = "caseSensitiveAlbum";
0104     QVERIFY( provider->artists().contains( artist ) );
0105 
0106     QSet<QString> trackAlbums;
0107     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0108         trackAlbums.insert( track->album() );
0109 
0110     QCOMPARE( trackAlbums.size(), 3 );
0111     QVERIFY( trackAlbums.contains( "album" ) );
0112     QVERIFY( trackAlbums.contains( "Album" ) );
0113     QVERIFY( trackAlbums.contains( "alBum" ) );
0114 }
0115 
0116 void
0117 TestImporterBase::composerShouldBeCaseSensitive()
0118 {
0119     ProviderPtr provider( getProvider() );
0120     amarokProviderSkipIfNoMysqld( provider );
0121     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valComposer );
0122 
0123     const QString artist = "caseSensitiveComposer";
0124     QVERIFY( provider->artists().contains( artist ) );
0125 
0126     QSet<QString> trackComposers;
0127     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0128         trackComposers.insert( track->composer() );
0129 
0130     QCOMPARE( trackComposers.size(), 3 );
0131     QVERIFY( trackComposers.contains( "composer" ) );
0132     QVERIFY( trackComposers.contains( "Composer" ) );
0133     QVERIFY( trackComposers.contains( "comPoser" ) );
0134 }
0135 
0136 void
0137 TestImporterBase::titleShouldSupportUTF()
0138 {
0139     ProviderPtr provider( getProvider() );
0140     amarokProviderSkipIfNoMysqld( provider );
0141 
0142     const QString artist = "utfTitle";
0143     QVERIFY( provider->artists().contains( artist ) );
0144 
0145     const TrackList tracks = provider->artistTracks( artist );
0146     QCOMPARE( tracks.size(), 1 );
0147     QCOMPARE( tracks.front()->name(), QString::fromWCharArray( L"\xF906\xF907\xF908" ) );
0148 }
0149 
0150 void
0151 TestImporterBase::artistShouldSupportUTF()
0152 {
0153     ProviderPtr provider( getProvider() );
0154     amarokProviderSkipIfNoMysqld( provider );
0155 
0156     const QString artist = QString::fromWCharArray( L"utf\xF909\xF90A\xF90B" );
0157     QVERIFY( provider->artists().contains( artist ) );
0158 
0159     const TrackList tracks = provider->artistTracks( artist );
0160     QCOMPARE( tracks.size(), 1 );
0161     QCOMPARE( tracks.front()->artist(), artist );
0162 }
0163 
0164 void
0165 TestImporterBase::albumShouldSupportUTF()
0166 {
0167     ProviderPtr provider( getProvider() );
0168     amarokProviderSkipIfNoMysqld( provider );
0169 
0170     const QString artist = "utfAlbum";
0171     QVERIFY( provider->artists().contains( artist ) );
0172 
0173     const TrackList tracks = provider->artistTracks( artist );
0174     QCOMPARE( tracks.size(), 1 );
0175     QCOMPARE( tracks.front()->album(), QString::fromWCharArray( L"\xF903\xF904\xF905" ) );
0176 }
0177 
0178 void
0179 TestImporterBase::composerShouldSupportUTF()
0180 {
0181     ProviderPtr provider( getProvider() );
0182     amarokProviderSkipIfNoMysqld( provider );
0183     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valComposer );
0184 
0185     const QString artist = "utfComposer";
0186     QVERIFY( provider->artists().contains( artist ) );
0187 
0188     const TrackList tracks = provider->artistTracks( artist );
0189     QCOMPARE( tracks.size(), 1 );
0190     QCOMPARE( tracks.front()->composer(),
0191               QString::fromWCharArray( L"\xF900\xF901\xF902" ) );
0192 }
0193 
0194 void
0195 TestImporterBase::titleShouldSupportMultipleWords()
0196 {
0197     ProviderPtr provider( getProvider() );
0198     amarokProviderSkipIfNoMysqld( provider );
0199 
0200     const QString artist = "multiWordTitle";
0201     QVERIFY( provider->artists().contains( artist ) );
0202 
0203     const TrackList tracks = provider->artistTracks( artist );
0204     QCOMPARE( tracks.size(), 1 );
0205     QCOMPARE( tracks.front()->name(), QString( "ti tl e" ) );
0206 }
0207 
0208 void
0209 TestImporterBase::artistShouldSupportMultipleWords()
0210 {
0211     ProviderPtr provider( getProvider() );
0212     amarokProviderSkipIfNoMysqld( provider );
0213 
0214     const QString artist = "multi Word Artist";
0215     QVERIFY( provider->artists().contains( artist ) );
0216 
0217     const TrackList tracks = provider->artistTracks( artist );
0218     QCOMPARE( tracks.size(), 1 );
0219     QCOMPARE( tracks.front()->artist(), artist );
0220 }
0221 
0222 void
0223 TestImporterBase::albumShouldSupportMultipleWords()
0224 {
0225     ProviderPtr provider( getProvider() );
0226     amarokProviderSkipIfNoMysqld( provider );
0227 
0228     const QString artist = "multiWordAlbum";
0229     QVERIFY( provider->artists().contains( artist ) );
0230 
0231     const TrackList tracks = provider->artistTracks( artist );
0232     QCOMPARE( tracks.size(), 1 );
0233     QCOMPARE( tracks.front()->album(), QString( "al b um" ) );
0234 }
0235 
0236 void
0237 TestImporterBase::composerShouldSupportMultipleWords()
0238 {
0239     ProviderPtr provider( getProvider() );
0240     amarokProviderSkipIfNoMysqld( provider );
0241     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valComposer );
0242 
0243     const QString artist = "multiWordComposer";
0244     QVERIFY( provider->artists().contains( artist ) );
0245 
0246     const TrackList tracks = provider->artistTracks( artist );
0247     QCOMPARE( tracks.size(), 1 );
0248     QCOMPARE( tracks.front()->composer(), QString( "com po ser" ) );
0249 }
0250 
0251 void
0252 TestImporterBase::titleShouldBeWhitespaceTrimmed()
0253 {
0254     ProviderPtr provider( getProvider() );
0255     amarokProviderSkipIfNoMysqld( provider );
0256 
0257     const QString artist = "trimTitle";
0258     QVERIFY( provider->artists().contains( artist ) );
0259 
0260     QSet<QString> trackNames;
0261     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0262         trackNames.insert( track->name() );
0263 
0264     QCOMPARE( trackNames.size(), 3 );
0265     QVERIFY( trackNames.contains( "title1" ) );
0266     QVERIFY( trackNames.contains( "title2" ) );
0267     QVERIFY( trackNames.contains( "title3" ) );
0268 }
0269 
0270 void
0271 TestImporterBase::artistShouldBeWhitespaceTrimmed()
0272 {
0273     ProviderPtr provider( getProvider() );
0274     amarokProviderSkipIfNoMysqld( provider );
0275 
0276     const QString artist = "trimArtist";
0277     QVERIFY( provider->artists().contains( artist ) );
0278 
0279     const TrackList tracks = provider->artistTracks( artist );
0280     QCOMPARE( tracks.size(), 3 );
0281 
0282     foreach( const TrackPtr &track, tracks )
0283         QCOMPARE( track->artist(), artist );
0284 }
0285 
0286 void
0287 TestImporterBase::albumShouldBeWhitespaceTrimmed()
0288 {
0289     ProviderPtr provider( getProvider() );
0290     amarokProviderSkipIfNoMysqld( provider );
0291 
0292     const QString artist = "trimAlbum";
0293     QVERIFY( provider->artists().contains( artist ) );
0294 
0295     const TrackList tracks = provider->artistTracks( artist );
0296     QCOMPARE( tracks.size(), 3 );
0297 
0298     foreach( const TrackPtr &track, tracks )
0299         QCOMPARE( track->album(), QString( "album" ) );
0300 }
0301 
0302 void
0303 TestImporterBase::composerShouldBeWhitespaceTrimmed()
0304 {
0305     ProviderPtr provider( getProvider() );
0306     amarokProviderSkipIfNoMysqld( provider );
0307     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valComposer );
0308 
0309     const QString artist = "trimComposer";
0310     QVERIFY( provider->artists().contains( artist ) );
0311 
0312     const TrackList tracks = provider->artistTracks( artist );
0313     QCOMPARE( tracks.size(), 3 );
0314 
0315     foreach( const TrackPtr &track, tracks )
0316         QCOMPARE( track->composer(), QString( "composer" ) );
0317 }
0318 
0319 void
0320 TestImporterBase::albumShouldBeUnsetIfTagIsUnset()
0321 {
0322     ProviderPtr provider( getProvider() );
0323     amarokProviderSkipIfNoMysqld( provider );
0324 
0325     const QString artist = "albumUnset";
0326     QVERIFY( provider->artists().contains( artist ) );
0327 
0328     const TrackList tracks = provider->artistTracks( artist );
0329     QCOMPARE( tracks.size(), 1 );
0330     QCOMPARE( tracks.front()->album(), QString() );
0331 }
0332 
0333 void
0334 TestImporterBase::composerShouldBeUnsetIfTagIsUnset()
0335 {
0336     ProviderPtr provider( getProvider() );
0337     amarokProviderSkipIfNoMysqld( provider );
0338     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valComposer );
0339 
0340     const QString artist = "composerUnset";
0341     QVERIFY( provider->artists().contains( artist ) );
0342 
0343     const TrackList tracks = provider->artistTracks( artist );
0344     QCOMPARE( tracks.size(), 1 );
0345     QCOMPARE( tracks.front()->composer(), QString() );
0346 }
0347 
0348 void
0349 TestImporterBase::yearShouldBeUnsetIfTagIsUnset()
0350 {
0351     ProviderPtr provider( getProvider() );
0352     amarokProviderSkipIfNoMysqld( provider );
0353     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valYear );
0354 
0355     const QString artist = "yearUnset";
0356     QVERIFY( provider->artists().contains( artist ) );
0357 
0358     const TrackList tracks = provider->artistTracks( artist );
0359     QCOMPARE( tracks.size(), 1 );
0360     QCOMPARE( tracks.front()->year(), 0 );
0361 }
0362 
0363 void
0364 TestImporterBase::trackShouldBeUnsetIfTagIsUnset()
0365 {
0366     ProviderPtr provider( getProvider() );
0367     amarokProviderSkipIfNoMysqld( provider );
0368     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valTrackNr );
0369 
0370     const QString artist = "trackUnset";
0371     QVERIFY( provider->artists().contains( artist ) );
0372 
0373     const TrackList tracks = provider->artistTracks( artist );
0374     QCOMPARE( tracks.size(), 1 );
0375     QCOMPARE( tracks.front()->trackNumber(), 0 );
0376 }
0377 
0378 void
0379 TestImporterBase::discShouldBeUnsetIfTagIsUnset()
0380 {
0381     ProviderPtr provider( getProvider() );
0382     amarokProviderSkipIfNoMysqld( provider );
0383     skipIfNoSupport( provider->reliableTrackMetaData(), Meta::valDiscNr );
0384 
0385     const QString artist = "discUnset";
0386     QVERIFY( provider->artists().contains( artist ) );
0387 
0388     const TrackList tracks = provider->artistTracks( artist );
0389     QCOMPARE( tracks.size(), 1 );
0390     QCOMPARE( tracks.front()->discNumber(), 0 );
0391 }
0392 
0393 void
0394 TestImporterBase::checkStatistics( const QString &artist )
0395 {
0396     ProviderPtr provider( getProvider() );
0397     amarokProviderSkipIfNoMysqld( provider );
0398     QVERIFY( provider->artists().contains( artist ) );
0399 
0400     QMap<QString, TrackPtr> trackForName;
0401     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0402         trackForName.insert( track->name(), track );
0403 
0404     const QString testName( QTest::currentDataTag() );
0405     QCOMPARE( trackForName.size(), 10 );
0406     QVERIFY( trackForName.contains( testName ) );
0407 
0408     const TrackPtr &track = trackForName.value( testName );
0409 
0410     if( reliableStatistics() & Meta::valFirstPlayed )
0411         QTEST( track->firstPlayed(), "firstPlayed" );
0412     if( reliableStatistics() & Meta::valLastPlayed )
0413         QTEST( track->lastPlayed(), "lastPlayed" );
0414     if( reliableStatistics() & Meta::valPlaycount )
0415         QTEST( track->playCount(), "playCount" );
0416 
0417     if( reliableStatistics() & Meta::valRating )
0418     {
0419         QFETCH( int, rating );
0420         if( !hasOddRatings() && (rating & 1) )
0421             ++rating;
0422 
0423         QCOMPARE( track->rating(), rating );
0424     }
0425 }
0426 
0427 void
0428 TestImporterBase::tracksShouldHaveStatistics_data()
0429 {
0430     QTest::addColumn<QDateTime> ( "firstPlayed" );
0431     QTest::addColumn<QDateTime> ( "lastPlayed" );
0432     QTest::addColumn<int>       ( "rating" );
0433     QTest::addColumn<int>       ( "playCount" );
0434 
0435     QVector<QDateTime> d;
0436     for( uint t = 0; t < 20; ++t )
0437         d.push_back( QDateTime::fromSecsSinceEpoch( 1378125780u + t ) );
0438 
0439     QTest::newRow( "title0" ) << d[ 0] << d[ 1] <<  1 << 20;
0440     QTest::newRow( "title1" ) << d[ 2] << d[ 3] <<  2 << 15;
0441     QTest::newRow( "title2" ) << d[ 4] << d[ 5] <<  3 << 14;
0442     QTest::newRow( "title3" ) << d[ 6] << d[ 7] <<  4 << 13;
0443     QTest::newRow( "title4" ) << d[ 8] << d[ 9] <<  5 << 11;
0444     QTest::newRow( "title5" ) << d[10] << d[11] <<  6 << 10;
0445     QTest::newRow( "title6" ) << d[12] << d[13] <<  7 <<  7;
0446     QTest::newRow( "title7" ) << d[14] << d[15] <<  8 <<  5;
0447     QTest::newRow( "title8" ) << d[16] << d[17] <<  9 <<  3;
0448     QTest::newRow( "title9" ) << d[18] << d[19] << 10 <<  2;
0449 }
0450 
0451 void
0452 TestImporterBase::tracksShouldHaveStatistics()
0453 {
0454     checkStatistics( "testStatistics" );
0455 }
0456 
0457 void
0458 TestImporterBase::tracksShouldBehaveNicelyWithNoStatistics_data()
0459 {
0460     QTest::addColumn<QDateTime> ( "firstPlayed" );
0461     QTest::addColumn<QDateTime> ( "lastPlayed" );
0462     QTest::addColumn<int>       ( "rating" );
0463     QTest::addColumn<int>       ( "playCount" );
0464 
0465     QVector<QDateTime> d;
0466     for( uint t = 0; t < 20; ++t )
0467         d.push_back( QDateTime::fromSecsSinceEpoch( 1378125780u + t ) );
0468 
0469     QTest::newRow( "title0" ) << QDateTime() << QDateTime() <<  0 <<  0;
0470     QTest::newRow( "title1" ) << QDateTime() <<       d[ 3] <<  2 << 15;
0471     QTest::newRow( "title2" ) << QDateTime() << QDateTime() <<  3 << 14;
0472     QTest::newRow( "title3" ) << QDateTime() <<       d[ 7] <<  0 << 13;
0473     QTest::newRow( "title4" ) << QDateTime() << QDateTime() <<  5 <<  0;
0474     QTest::newRow( "title5" ) <<       d[10] <<       d[11] <<  6 << 10;
0475     QTest::newRow( "title6" ) <<       d[12] << QDateTime() <<  0 <<  7;
0476     QTest::newRow( "title7" ) <<       d[14] <<       d[15] <<  8 <<  5;
0477     QTest::newRow( "title8" ) <<       d[16] << QDateTime() <<  9 <<  0;
0478     QTest::newRow( "title9" ) <<       d[18] <<       d[19] <<  0 <<  2;
0479 }
0480 
0481 void
0482 TestImporterBase::tracksShouldBehaveNicelyWithNoStatistics()
0483 {
0484     checkStatistics( "testStatisticsNotSet" );
0485 }
0486 
0487 void TestImporterBase::labels( const ProviderPtr &provider, const QString &trackName )
0488 {
0489     m_lbl.clear();
0490 
0491     const QString artist = "testStatistics";
0492 
0493     QVERIFY( provider->artists().contains( artist ) );
0494 
0495     QMap<QString, TrackPtr> trackForName;
0496     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0497     {
0498         QVERIFY( !trackForName.contains( track->name() ) );
0499         trackForName.insert( track->name(), track );
0500     }
0501 
0502     QVERIFY( trackForName.contains( trackName ) );
0503     m_lbl = trackForName.value( trackName )->labels();
0504 }
0505 
0506 void
0507 TestImporterBase::tracksShouldWorkWithSingleLabel()
0508 {
0509     ProviderPtr provider( getProvider() );
0510     amarokProviderSkipIfNoMysqld( provider );
0511     skipIfNoSupport( reliableStatistics(), Meta::valLabel );
0512 
0513     labels( provider, "title0" );
0514 
0515     QCOMPARE( m_lbl.size(), 1 );
0516     QVERIFY( m_lbl.contains( "singleTag" ) );
0517 }
0518 
0519 void
0520 TestImporterBase::tracksShouldWorkWithMultipleLabels()
0521 {
0522     ProviderPtr provider( getProvider() );
0523     amarokProviderSkipIfNoMysqld( provider );
0524     skipIfNoSupport( reliableStatistics(), Meta::valLabel );
0525 
0526     labels( provider, "title1" );
0527 
0528     QCOMPARE( m_lbl.size(), 2 );
0529     QVERIFY( m_lbl.contains( "multiple" ) );
0530     QVERIFY( m_lbl.contains( "tags" ) );
0531 }
0532 
0533 void
0534 TestImporterBase::tracksShouldWorkWithCaseSensitiveLabels()
0535 {
0536     ProviderPtr provider( getProvider() );
0537     amarokProviderSkipIfNoMysqld( provider );
0538     skipIfNoSupport( reliableStatistics(), Meta::valLabel );
0539 
0540     labels( provider, "title2" );
0541 
0542     QCOMPARE( m_lbl.size(), 2 );
0543     QVERIFY( m_lbl.contains( "caseSensitive" ) );
0544     QVERIFY( m_lbl.contains( "casesensitive" ) );
0545 }
0546 
0547 void
0548 TestImporterBase::tracksShouldWorkWithUTFLabels()
0549 {
0550     ProviderPtr provider( getProvider() );
0551     amarokProviderSkipIfNoMysqld( provider );
0552     skipIfNoSupport( reliableStatistics(), Meta::valLabel );
0553 
0554     labels( provider, "title3" );
0555 
0556     QCOMPARE( m_lbl.size(), 1 );
0557     QVERIFY( m_lbl.contains( QString::fromWCharArray( L"\x2622" ) ) );
0558 }
0559 
0560 void
0561 TestImporterBase::providerShouldReturnNoTracksForNonexistentArtist()
0562 {
0563     ProviderPtr provider( getProvider() );
0564     amarokProviderSkipIfNoMysqld( provider );
0565 
0566     const QString artist = "I'mNotHere";
0567     QVERIFY( !provider->artists().contains( artist ) );
0568     QVERIFY( provider->artistTracks( artist ).isEmpty() );
0569 }
0570 
0571 void
0572 TestImporterBase::providerShouldNotBreakOnLittleBobbyTables()
0573 {
0574     ProviderPtr provider( getProvider() );
0575     amarokProviderSkipIfNoMysqld( provider );
0576 
0577     const QString artist = "Robert'); DROP TABLE students;--";
0578     QVERIFY( !provider->artists().contains( artist ) );
0579     QVERIFY( provider->artistTracks( artist ).isEmpty() );
0580 }
0581 
0582 static TrackPtr
0583 trackForName( ProviderPtr &provider, const QString &name, const QString &artist )
0584 {
0585     foreach( const TrackPtr &track, provider->artistTracks( artist ) )
0586         if( track->name() == name )
0587             return track;
0588 
0589     return TrackPtr( nullptr );
0590 }
0591 
0592 static Meta::FieldHash
0593 saveData( const TrackPtr &track )
0594 {
0595     Meta::FieldHash data;
0596     data.insert( Meta::valTitle, track->name() );
0597     data.insert( Meta::valArtist, track->artist() );
0598     data.insert( Meta::valAlbum, track->album() );
0599     data.insert( Meta::valComposer, track->composer() );
0600     data.insert( Meta::valTrackNr, track->trackNumber() );
0601     data.insert( Meta::valDiscNr, track->discNumber() );
0602     data.insert( Meta::valFirstPlayed, track->firstPlayed() );
0603     data.insert( Meta::valLastPlayed, track->lastPlayed() );
0604     data.insert( Meta::valRating, track->rating() );
0605     data.insert( Meta::valPlaycount, track->playCount() );
0606     data.insert( Meta::valLabel, QStringList( track->labels().values() ) );
0607     return data;
0608 }
0609 
0610 static void
0611 verifyEqualExcept( const Meta::FieldHash &lhs, const TrackPtr &track,
0612                    const qint64 except )
0613 {
0614     const QList<qint64> fields = QList<qint64>() << Meta::valTitle << Meta::valArtist
0615                               << Meta::valAlbum << Meta::valComposer << Meta::valTrackNr
0616                               << Meta::valDiscNr << Meta::valFirstPlayed
0617                               << Meta::valLastPlayed << Meta::valRating
0618                               << Meta::valPlaycount << Meta::valLabel;
0619 
0620     const Meta::FieldHash rhs = saveData( track );
0621     foreach( const qint64 field, fields )
0622         if( !( except & field ) )
0623             QCOMPARE( lhs.value( field ), rhs.value( field ) );
0624 }
0625 
0626 void
0627 TestImporterBase::commitAfterSettingAllStatisticsShouldSaveThem_data()
0628 {
0629     QTest::addColumn<QString>( "title" );
0630     QTest::addColumn<QString>( "artist" );
0631     QTest::addColumn<QDateTime>( "newFirstPlayed" );
0632     QTest::addColumn<QDateTime>( "newLastPlayed" );
0633     QTest::addColumn<int>( "newRating" );
0634     QTest::addColumn<int>( "newPlayCount" );
0635     QTest::addColumn<QStringList>( "newLabels" );
0636 
0637     const uint now = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
0638 
0639     QTest::newRow( "Replace all" ) << "title0" << "testStatistics"
0640                                    << QDateTime::fromSecsSinceEpoch( now - 100 )
0641                                    << QDateTime::fromSecsSinceEpoch( now + 100 )
0642                                    << 9 << 25 << ( QStringList() << "teh" << "lab'ls" );
0643 
0644     QTest::newRow( "Add all" ) << "title0" << "testStatisticsNotSet"
0645                                << QDateTime::fromSecsSinceEpoch( now - 100 )
0646                                << QDateTime::fromSecsSinceEpoch(now + 100 )
0647                                << 9 << 25 << ( QStringList() << "teh" << "lab'ls" );
0648 
0649     QTest::newRow( "Add some 1" ) << "title2" << "testStatisticsNotSet"
0650                                   << QDateTime::fromSecsSinceEpoch( now - 100 )
0651                                   << QDateTime::fromSecsSinceEpoch( now + 100 )
0652                                   << 9 << 25 << ( QStringList() << "teh" << "lab'ls" );
0653 
0654     QTest::newRow( "Add some 1" ) << "title4" << "testStatisticsNotSet"
0655                                   << QDateTime::fromSecsSinceEpoch( now - 100 )
0656                                   << QDateTime::fromSecsSinceEpoch( now + 100 )
0657                                   << 9 << 25 << ( QStringList() << "teh" << "lab'ls" );
0658 
0659     QTest::newRow( "Add some 1" ) << "title6" << "testStatisticsNotSet"
0660                                   << QDateTime::fromSecsSinceEpoch( now - 100 )
0661                                   << QDateTime::fromSecsSinceEpoch( now + 100 )
0662                                   << 9 << 25 << ( QStringList() << "teh" << "lab'ls" );
0663 }
0664 
0665 void
0666 TestImporterBase::commitAfterSettingAllStatisticsShouldSaveThem()
0667 {
0668     ProviderPtr provider( getWritableProvider() );
0669     amarokProviderSkipIfNoMysqld( provider );
0670 
0671     QFETCH( QString, title );
0672     QFETCH( QString, artist );
0673     TrackPtr track = trackForName( provider, title, artist );
0674     QVERIFY( track );
0675 
0676     const Meta::FieldHash data = saveData( track );
0677 
0678     if( provider->writableTrackStatsData() & Meta::valFirstPlayed )
0679     {
0680         QFETCH( QDateTime, newFirstPlayed );
0681         track->setFirstPlayed( newFirstPlayed );
0682     }
0683     if( provider->writableTrackStatsData() & Meta::valLastPlayed )
0684     {
0685         QFETCH( QDateTime, newLastPlayed );
0686         track->setLastPlayed( newLastPlayed );
0687     }
0688     if( provider->writableTrackStatsData() & Meta::valRating )
0689     {
0690         QFETCH( int, newRating );
0691         track->setRating( newRating );
0692     }
0693     if( provider->writableTrackStatsData() & Meta::valPlaycount )
0694     {
0695         QFETCH( int, newPlayCount );
0696         track->setPlayCount( newPlayCount );
0697     }
0698     if( provider->writableTrackStatsData() & Meta::valLabel )
0699     {
0700         QFETCH( QStringList, newLabels );
0701         track->setLabels( newLabels.toSet() );
0702     }
0703 
0704     track->commit();
0705     provider->commitTracks();
0706 
0707     track = trackForName( provider, title, artist );
0708     QVERIFY( track );
0709 
0710     if( provider->writableTrackStatsData() & Meta::valFirstPlayed )
0711     {
0712         QFETCH( QDateTime, newFirstPlayed );
0713         QCOMPARE( track->firstPlayed(), newFirstPlayed );
0714     }
0715     if( provider->writableTrackStatsData() & Meta::valLastPlayed )
0716     {
0717         QFETCH( QDateTime, newLastPlayed );
0718         QCOMPARE( track->lastPlayed(), newLastPlayed );
0719     }
0720     if( provider->writableTrackStatsData() & Meta::valRating )
0721     {
0722         QFETCH( int, newRating );
0723         if( !hasOddRatings() && (newRating & 1) )
0724             ++newRating;
0725         QCOMPARE( track->rating(), newRating );
0726     }
0727     if( provider->writableTrackStatsData() & Meta::valPlaycount )
0728     {
0729         QFETCH( int, newPlayCount );
0730         QCOMPARE( track->playCount(), newPlayCount );
0731     }
0732     if( provider->writableTrackStatsData() & Meta::valLabel )
0733     {
0734         QFETCH( QStringList, newLabels );
0735         QCOMPARE( track->labels(), newLabels.toSet() );
0736     }
0737 
0738     verifyEqualExcept( data, track, Meta::valFirstPlayed | Meta::valLastPlayed |
0739                        Meta::valRating | Meta::valPlaycount | Meta::valLabel );
0740 }
0741 
0742 void
0743 TestImporterBase::commitAfterSettingFirstPlayedShouldSaveIt_data()
0744 {
0745      QTest::addColumn<QString>( "title" );
0746      QTest::addColumn<QDateTime>( "newFirstPlayed" );
0747 
0748      const uint now = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
0749 
0750      QTest::newRow( "Add stat 1" ) << "title0" << QDateTime::fromSecsSinceEpoch( now );
0751      QTest::newRow( "Add stat 2" ) << "title1" << QDateTime::fromSecsSinceEpoch( now + 2 );
0752      QTest::newRow( "Add stat 3" ) << "title2" << QDateTime::fromSecsSinceEpoch( now + 3 );
0753 
0754      QTest::newRow( "Replace stat 1" ) << "title5" << QDateTime::fromSecsSinceEpoch( now + 11 );
0755      QTest::newRow( "Replace stat 2" ) << "title6" << QDateTime::fromSecsSinceEpoch( now + 13 );
0756      QTest::newRow( "Replace stat 3" ) << "title7" << QDateTime::fromSecsSinceEpoch( now + 17 );
0757 
0758      QTest::newRow( "Remove stat 1" ) << "title5" << QDateTime();
0759      QTest::newRow( "Remove stat 2" ) << "title6" << QDateTime();
0760      QTest::newRow( "Remove stat 3" ) << "title7" << QDateTime();
0761 }
0762 
0763 void
0764 TestImporterBase::commitAfterSettingFirstPlayedShouldSaveIt()
0765 {
0766     ProviderPtr provider( getWritableProvider() );
0767     amarokProviderSkipIfNoMysqld( provider );
0768     skipIfNoSupport( provider->writableTrackStatsData(), Meta::valFirstPlayed );
0769 
0770     QFETCH( QString, title );
0771     QFETCH( QDateTime, newFirstPlayed );
0772 
0773     TrackPtr track = trackForName( provider, title, "testStatisticsNotSet" );
0774     QVERIFY( track );
0775 
0776     const Meta::FieldHash data = saveData( track );
0777     track->setFirstPlayed( newFirstPlayed );
0778     track->commit();
0779     provider->commitTracks();
0780 
0781     track = trackForName( provider, title, "testStatisticsNotSet" );
0782     QVERIFY( track );
0783     QCOMPARE( track->firstPlayed(), newFirstPlayed );
0784     verifyEqualExcept( data, track, Meta::valFirstPlayed );
0785 }
0786 
0787 void
0788 TestImporterBase::commitAfterSettingLastPlayedShouldSaveIt_data()
0789 {
0790     QTest::addColumn<QString>( "title" );
0791     QTest::addColumn<QDateTime>( "newLastPlayed" );
0792 
0793     const uint now = QDateTime::currentDateTimeUtc().toSecsSinceEpoch();
0794 
0795     QTest::newRow( "Add stat 1" ) << "title0" << QDateTime::fromSecsSinceEpoch( now );
0796     QTest::newRow( "Add stat 2" ) << "title2" << QDateTime::fromSecsSinceEpoch( now + 2 );
0797     QTest::newRow( "Add stat 3" ) << "title4" << QDateTime::fromSecsSinceEpoch( now + 3 );
0798 
0799     QTest::newRow( "Replace stat 1" ) << "title1" << QDateTime::fromSecsSinceEpoch( now + 11 );
0800     QTest::newRow( "Replace stat 2" ) << "title3" << QDateTime::fromSecsSinceEpoch( now + 13 );
0801     QTest::newRow( "Replace stat 3" ) << "title5" << QDateTime::fromSecsSinceEpoch( now + 17 );
0802 
0803     QTest::newRow( "Remove stat 1" ) << "title1" << QDateTime();
0804     QTest::newRow( "Remove stat 2" ) << "title3" << QDateTime();
0805     QTest::newRow( "Remove stat 3" ) << "title5" << QDateTime();
0806 }
0807 
0808 void
0809 TestImporterBase::commitAfterSettingLastPlayedShouldSaveIt()
0810 {
0811     ProviderPtr provider( getWritableProvider() );
0812     amarokProviderSkipIfNoMysqld( provider );
0813     skipIfNoSupport( provider->writableTrackStatsData(), Meta::valLastPlayed );
0814 
0815     QFETCH( QString, title );
0816     QFETCH( QDateTime, newLastPlayed );
0817 
0818     TrackPtr track = trackForName( provider, title, "testStatisticsNotSet" );
0819     QVERIFY( track );
0820 
0821     const Meta::FieldHash data = saveData( track );
0822     track->setLastPlayed( newLastPlayed );
0823     track->commit();
0824     provider->commitTracks();
0825 
0826     track = trackForName( provider, title, "testStatisticsNotSet" );
0827     QVERIFY( track );
0828     QCOMPARE( track->lastPlayed(), newLastPlayed );
0829     verifyEqualExcept( data, track, Meta::valLastPlayed );
0830 }
0831 
0832 void
0833 TestImporterBase::commitAfterSettingRatingShouldSaveIt_data()
0834 {
0835     QTest::addColumn<QString>( "title" );
0836     QTest::addColumn<int>( "newRating" );
0837 
0838     QTest::newRow( "Add stat 1" ) << "title0" << 2;
0839     QTest::newRow( "Add stat 2" ) << "title3" << 3;
0840     QTest::newRow( "Add stat 3" ) << "title6" << 5;
0841 
0842     QTest::newRow( "Replace stat 1" ) << "title1" << 1;
0843     QTest::newRow( "Replace stat 2" ) << "title2" << 3;
0844     QTest::newRow( "Replace stat 3" ) << "title4" << 6;
0845 
0846     QTest::newRow( "Remove stat 1" ) << "title1" << 0;
0847     QTest::newRow( "Remove stat 2" ) << "title2" << 0;
0848     QTest::newRow( "Remove stat 3" ) << "title4" << 0;
0849 }
0850 
0851 void
0852 TestImporterBase::commitAfterSettingRatingShouldSaveIt()
0853 {
0854     ProviderPtr provider( getWritableProvider() );
0855     amarokProviderSkipIfNoMysqld( provider );
0856     skipIfNoSupport( provider->writableTrackStatsData(), Meta::valRating );
0857 
0858     QFETCH( QString, title );
0859     QFETCH( int, newRating );
0860 
0861     TrackPtr track = trackForName( provider, title, "testStatisticsNotSet" );
0862     QVERIFY( track );
0863 
0864     const Meta::FieldHash data = saveData( track );
0865     track->setRating( newRating );
0866     track->commit();
0867     provider->commitTracks();
0868 
0869     if( !hasOddRatings() && (newRating & 1) )
0870         ++newRating;
0871 
0872     track = trackForName( provider, title, "testStatisticsNotSet" );
0873     QVERIFY( track );
0874     QCOMPARE( track->rating(), newRating );
0875     verifyEqualExcept( data, track, Meta::valRating );
0876 }
0877 
0878 void
0879 TestImporterBase::commitAfterSettingPlaycountShouldSaveIt_data()
0880 {
0881     QTest::addColumn<QString>( "title" );
0882     QTest::addColumn<int>( "newPlayCount" );
0883 
0884     QTest::newRow( "Add stat 1" ) << "title0" << 13;
0885     QTest::newRow( "Add stat 2" ) << "title4" << 17;
0886     QTest::newRow( "Add stat 3" ) << "title8" << 23;
0887 
0888     QTest::newRow( "Replace stat 1" ) << "title1" << 1;
0889     QTest::newRow( "Replace stat 2" ) << "title2" << 3;
0890     QTest::newRow( "Replace stat 3" ) << "title3" << 6;
0891 
0892     QTest::newRow( "Remove stat 1" ) << "title1" << 0;
0893     QTest::newRow( "Remove stat 2" ) << "title2" << 0;
0894     QTest::newRow( "Remove stat 3" ) << "title3" << 0;
0895 }
0896 
0897 void
0898 TestImporterBase::commitAfterSettingPlaycountShouldSaveIt()
0899 {
0900     ProviderPtr provider( getWritableProvider() );
0901     amarokProviderSkipIfNoMysqld( provider );
0902     skipIfNoSupport( provider->writableTrackStatsData(), Meta::valPlaycount );
0903 
0904     QFETCH( QString, title );
0905     QFETCH( int, newPlayCount );
0906 
0907     TrackPtr track = trackForName( provider, title, "testStatisticsNotSet" );
0908     QVERIFY( track );
0909 
0910     const Meta::FieldHash data = saveData( track );
0911     track->setPlayCount( newPlayCount );
0912     track->commit();
0913     provider->commitTracks();
0914 
0915     track = trackForName( provider, title, "testStatisticsNotSet" );
0916     QVERIFY( track );
0917     QCOMPARE( track->playCount(), newPlayCount );
0918     verifyEqualExcept( data, track, Meta::valPlaycount );
0919 }
0920 
0921 void
0922 TestImporterBase::commitAfterSettingLabelsShouldSaveThem_data()
0923 {
0924     QTest::addColumn<QString>( "title" );
0925     QTest::addColumn<QStringList>( "newLabels" );
0926 
0927     QTest::newRow( "Add new label" ) << "title4" << ( QStringList() << "singleTag2" );
0928     QTest::newRow( "Add existing label" ) << "title5" << ( QStringList() << "singleTag" );
0929     QTest::newRow( "Add labels" ) << "title6" << ( QStringList() << "multi" << "labels" );
0930     QTest::newRow( "Add existing labels" ) << "title7"
0931                                            << ( QStringList() << "multiple" << "labels" );
0932     QTest::newRow( "Add case-sensitive labels" ) << "title8"
0933                                                  << ( QStringList() << "cs" << "Cs" );
0934 
0935     QTest::newRow( "Replace all labels" ) << "title1" << ( QStringList() << "a" << "l" );
0936     QTest::newRow( "Replace some labels" ) << "title1"
0937                                            << ( QStringList() << "a" << "tags" );
0938     QTest::newRow( "Add additional labels" ) << "title1"
0939                                       << ( QStringList() << "multiple" << "tags" << "2" );
0940 
0941     QTest::newRow( "Remove labels 1" ) << "title0" << QStringList();
0942     QTest::newRow( "Remove labels 2" ) << "title1" << QStringList();
0943     QTest::newRow( "Remove labels 3" ) << "title2" << QStringList();
0944 }
0945 
0946 void
0947 TestImporterBase::commitAfterSettingLabelsShouldSaveThem()
0948 {
0949     ProviderPtr provider( getWritableProvider() );
0950     amarokProviderSkipIfNoMysqld( provider );
0951     skipIfNoSupport( provider->writableTrackStatsData(), Meta::valLabel );
0952 
0953     QFETCH( QString, title );
0954     QFETCH( QStringList, newLabels );
0955 
0956     TrackPtr track = trackForName( provider, title, "testStatistics" );
0957     QVERIFY( track );
0958 
0959     const Meta::FieldHash data = saveData( track );
0960     track->setLabels( newLabels.toSet() );
0961     track->commit();
0962     provider->commitTracks();
0963 
0964     track = trackForName( provider, title, "testStatistics" );
0965     QVERIFY( track );
0966     QCOMPARE( track->labels(), newLabels.toSet() );
0967     verifyEqualExcept( data, track, Meta::valLabel );
0968 }