1 /****************************************************************************************
2  * Copyright (c) 2009 Maximilian Kossick <maximilian.kossick@googlemail.com>       *
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 "TestSqlQueryMaker.h"
18 
19 #include "core/support/Debug.h"
20 
21 #include "DatabaseUpdater.h"
22 #include "SqlCollection.h"
23 #include "SqlQueryMaker.h"
24 #include "SqlRegistry.h"
25 #include "core-impl/storage/sql/mysqlestorage/MySqlEmbeddedStorage.h"
26 
27 #include "SqlMountPointManagerMock.h"
28 
29 #include <QSignalSpy>
30 
31 
32 using namespace Collections;
33 
34 QTEST_GUILESS_MAIN( TestSqlQueryMaker )
35 
36 //required for QTest, this is not done in Querymaker.h
Q_DECLARE_METATYPE(Collections::QueryMaker::QueryType)37 Q_DECLARE_METATYPE( Collections::QueryMaker::QueryType )
38 Q_DECLARE_METATYPE( Collections::QueryMaker::NumberComparison )
39 Q_DECLARE_METATYPE( Collections::QueryMaker::ReturnFunction )
40 Q_DECLARE_METATYPE( Collections::QueryMaker::AlbumQueryMode )
41 Q_DECLARE_METATYPE( Collections::QueryMaker::LabelQueryMode )
42 
43 TestSqlQueryMaker::TestSqlQueryMaker()
44 {
45     qRegisterMetaType<Meta::TrackPtr>();
46     qRegisterMetaType<Meta::TrackList>();
47     qRegisterMetaType<Meta::AlbumPtr>();
48     qRegisterMetaType<Meta::AlbumList>();
49     qRegisterMetaType<Meta::ArtistPtr>();
50     qRegisterMetaType<Meta::ArtistList>();
51     qRegisterMetaType<Meta::GenrePtr>();
52     qRegisterMetaType<Meta::GenreList>();
53     qRegisterMetaType<Meta::ComposerPtr>();
54     qRegisterMetaType<Meta::ComposerList>();
55     qRegisterMetaType<Meta::YearPtr>();
56     qRegisterMetaType<Meta::YearList>();
57     qRegisterMetaType<Meta::LabelPtr>();
58     qRegisterMetaType<Meta::LabelList>();
59     qRegisterMetaType<Collections::QueryMaker::QueryType>();
60     qRegisterMetaType<Collections::QueryMaker::NumberComparison>();
61     qRegisterMetaType<Collections::QueryMaker::ReturnFunction>();
62     qRegisterMetaType<Collections::QueryMaker::AlbumQueryMode>();
63     qRegisterMetaType<Collections::QueryMaker::LabelQueryMode>();
64 }
65 
66 void
initTestCase()67 TestSqlQueryMaker::initTestCase()
68 {
69     m_tmpDir = new QTemporaryDir();
70     m_storage = QSharedPointer<MySqlEmbeddedStorage>( new MySqlEmbeddedStorage() );
71     QVERIFY( m_storage->init( m_tmpDir->path() ) );
72     m_collection = new Collections::SqlCollection( m_storage );
73 
74     QMap<int,QString> mountPoints;
75     mountPoints.insert( 1, "/foo" );
76     mountPoints.insert( 2, "/bar" );
77 
78     m_mpm = new SqlMountPointManagerMock( this, m_storage );
79     m_mpm->m_mountPoints = mountPoints;
80 
81     m_collection->setMountPointManager( m_mpm );
82 
83     //setup test data
84     m_storage->query( "INSERT INTO artists(id, name) VALUES (1, 'artist1');" );
85     m_storage->query( "INSERT INTO artists(id, name) VALUES (2, 'artist2');" );
86     m_storage->query( "INSERT INTO artists(id, name) VALUES (3, 'artist3');" );
87 
88     m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(1,'album1',1);" );
89     m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(2,'album2',1);" );
90     m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(3,'album3',2);" );
91     m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(4,'album4',NULL);" );
92     m_storage->query( "INSERT INTO albums(id,name,artist) VALUES(5,'album4',3);" );
93 
94     m_storage->query( "INSERT INTO composers(id, name) VALUES (1, 'composer1');" );
95     m_storage->query( "INSERT INTO composers(id, name) VALUES (2, 'composer2');" );
96     m_storage->query( "INSERT INTO composers(id, name) VALUES (3, 'composer3');" );
97 
98     m_storage->query( "INSERT INTO genres(id, name) VALUES (1, 'genre1');" );
99     m_storage->query( "INSERT INTO genres(id, name) VALUES (2, 'genre2');" );
100     m_storage->query( "INSERT INTO genres(id, name) VALUES (3, 'genre3');" );
101 
102     m_storage->query( "INSERT INTO years(id, name) VALUES (1, '1');" );
103     m_storage->query( "INSERT INTO years(id, name) VALUES (2, '2');" );
104     m_storage->query( "INSERT INTO years(id, name) VALUES (3, '3');" );
105 
106     m_storage->query( "INSERT INTO directories(id, deviceid, dir) VALUES (1, -1, './');" );
107 
108     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (1, -1, './IDoNotExist.mp3', 1, '1');" );
109     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (2, -1, './IDoNotExistAsWell.mp3', 1, '2');" );
110     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (3, -1, './MeNeither.mp3', 1, '3');" );
111     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (4, 2, './NothingHere.mp3', 1, '4');" );
112     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (5, 1, './GuessWhat.mp3', 1, '5');" );
113     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES (6, 2, './LookItsA.flac', 1, '6');" );
114 
115     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
116                       "VALUES(1,1,'track1','comment1',1,1,1,1,1);" );
117     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
118                       "VALUES(2,2,'track2','comment2',1,2,1,1,1);" );
119     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
120                       "VALUES(3,3,'track3','comment3',3,4,1,1,1);" );
121     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
122                       "VALUES(4,4,'track4','comment4',2,3,3,3,3);" );
123     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
124                       "VALUES(5,5,'track5','',3,5,2,2,2);" );
125     m_storage->query( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
126                       "VALUES(6,6,'track6','',1,4,2,2,2);" );
127 
128     m_storage->query( "INSERT INTO statistics(url,createdate,accessdate,score,rating,playcount) "
129                       "VALUES(1,1000,10000, 50.0,2,100);" );
130     m_storage->query( "INSERT INTO statistics(url,createdate,accessdate,score,rating,playcount) "
131                       "VALUES(2,2000,30000, 70.0,9,50);" );
132     m_storage->query( "INSERT INTO statistics(url,createdate,accessdate,score,rating,playcount) "
133                       "VALUES(3,4000,20000, 60.0,4,10);" );
134 
135     m_storage->query( "INSERT INTO labels(id,label) VALUES (1,'labelA'), (2,'labelB'),(3,'test');" );
136     m_storage->query( "INSERT INTO urls_labels(url,label) VALUES (1,1),(1,2),(2,2),(3,3),(4,3),(4,2);" );
137 
138 }
139 
140 void
cleanupTestCase()141 TestSqlQueryMaker::cleanupTestCase()
142 {
143     delete m_collection;
144     //m_storage is deleted by SqlCollection
145     delete m_tmpDir;
146 
147 }
148 
149 void
cleanup()150 TestSqlQueryMaker::cleanup()
151 {
152     m_collection->setMountPointManager( m_mpm );
153 }
154 
155 void
testQueryAlbums()156 TestSqlQueryMaker::testQueryAlbums()
157 {
158     Collections::SqlQueryMaker qm( m_collection );
159     qm.setBlocking( true );
160     qm.setAlbumQueryMode( Collections::QueryMaker::AllAlbums );
161     qm.setQueryType( Collections::QueryMaker::Album );
162     qm.run();
163     QCOMPARE( qm.albums().count(), 5 );
164 }
165 
166 void
testQueryArtists()167 TestSqlQueryMaker::testQueryArtists()
168 {
169     Collections::SqlQueryMaker qm( m_collection );
170     qm.setBlocking( true );
171     qm.setQueryType( Collections::QueryMaker::Artist );
172     qm.run();
173     QCOMPARE( qm.artists().count(), 3 );
174 }
175 
176 void
testQueryComposers()177 TestSqlQueryMaker::testQueryComposers()
178 {
179     Collections::SqlQueryMaker qm( m_collection );
180     qm.setBlocking( true );
181     qm.setQueryType( Collections::QueryMaker::Composer );
182     qm.run();
183     QCOMPARE( qm.composers().count(), 3 );
184 }
185 
186 void
testQueryGenres()187 TestSqlQueryMaker::testQueryGenres()
188 {
189     Collections::SqlQueryMaker qm( m_collection );
190     qm.setBlocking( true );
191     qm.setQueryType( Collections::QueryMaker::Genre );
192     qm.run();
193     QCOMPARE( qm.genres().count(), 3 );
194 }
195 
196 void
testQueryYears()197 TestSqlQueryMaker::testQueryYears()
198 {
199     Collections::SqlQueryMaker qm( m_collection );
200     qm.setBlocking( true );
201     qm.setQueryType( Collections::QueryMaker::Year );
202     qm.run();
203     QCOMPARE( qm.years().count(), 3 );
204 }
205 
206 void
testQueryTracks()207 TestSqlQueryMaker::testQueryTracks()
208 {
209     Collections::SqlQueryMaker qm( m_collection );
210     qm.setBlocking( true );
211     qm.setQueryType( Collections::QueryMaker::Track );
212     qm.run();
213     QCOMPARE( qm.tracks().count(), 6 );
214 }
215 
216 void
testAlbumQueryMode()217 TestSqlQueryMaker::testAlbumQueryMode()
218 {
219     {
220         Collections::SqlQueryMaker qm( m_collection );
221         qm.setBlocking( true );
222         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyCompilations );
223         qm.setQueryType( Collections::QueryMaker::Album );
224         qm.run();
225         QCOMPARE( qm.albums().count(), 1 );
226     }
227 
228     {
229         Collections::SqlQueryMaker qm( m_collection );
230         qm.setBlocking( true );
231         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyNormalAlbums );
232         qm.setQueryType( Collections::QueryMaker::Album );
233         qm.run();
234         QCOMPARE( qm.albums().count(), 4 );
235     }
236 
237     {
238         Collections::SqlQueryMaker qm( m_collection );
239         qm.setBlocking( true );
240         qm.setQueryType( Collections::QueryMaker::Track );
241         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyCompilations );
242         qm.run();
243         QCOMPARE( qm.tracks().count(), 2 );
244     }
245 
246     {
247         Collections::SqlQueryMaker qm( m_collection );
248         qm.setBlocking( true );
249         qm.setQueryType( Collections::QueryMaker::Track );
250         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyNormalAlbums );
251         qm.run();
252         QCOMPARE( qm.tracks().count(), 4 );
253     }
254 
255     {
256         Collections::SqlQueryMaker qm( m_collection );
257         qm.setBlocking( true );
258         qm.setQueryType( Collections::QueryMaker::Artist );
259         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyCompilations );
260         qm.run();
261         QCOMPARE( qm.artists().count() , 2 );
262     }
263 
264     {
265         Collections::SqlQueryMaker qm( m_collection );
266         qm.setBlocking( true );
267         qm.setQueryType( Collections::QueryMaker::Artist );
268         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyNormalAlbums );
269         qm.run();
270         QCOMPARE( qm.artists().count(), 3 );
271     }
272 
273     {
274         Collections::SqlQueryMaker qm( m_collection );
275         qm.setBlocking( true );
276         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyCompilations );
277         qm.setQueryType( Collections::QueryMaker::Genre );
278         qm.run();
279         QCOMPARE( qm.genres().count(), 2 );
280     }
281 
282     {
283         Collections::SqlQueryMaker qm( m_collection );
284         qm.setBlocking( true );
285         qm.setAlbumQueryMode( Collections::QueryMaker::OnlyNormalAlbums );
286         qm.setQueryType( Collections::QueryMaker::Genre );
287         qm.run();
288         QCOMPARE( qm.genres().count(), 3 );
289     }
290 
291 }
292 
293 void
testDeleteQueryMakerWithRunningQuery()294 TestSqlQueryMaker::testDeleteQueryMakerWithRunningQuery()
295 {
296     int iteration = 0;
297     bool queryNotDoneYet = true;
298 
299     //wait one second per query in total, that should be enough for it to complete
300     do
301     {
302         Collections::SqlQueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
303         QSignalSpy spy( qm, &Collections::QueryMaker::queryDone );
304         qm->setQueryType( Collections::QueryMaker::Track );
305         qm->addFilter( Meta::valTitle, QString::number( iteration), false, false );
306         qm->run();
307         //wait 10 msec more per iteration, might have to be tweaked
308         if( iteration > 0 )
309         {
310             QTest::qWait( 10 * iteration );
311         }
312         delete qm;
313         queryNotDoneYet = ( spy.count() == 0 );
314         if( iteration > 50 )
315         {
316             break;
317         }
318         iteration++;
319     } while ( queryNotDoneYet );
320     qDebug() << "Iterations: " << iteration;
321 }
322 
323 void
testAsyncAlbumQuery()324 TestSqlQueryMaker::testAsyncAlbumQuery()
325 {
326     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
327     qm->setQueryType( Collections::QueryMaker::Album );
328     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
329     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newAlbumsReady );
330 
331     qm->run();
332 
333     doneSpy1.wait( 1000 );
334 
335     QCOMPARE( resultSpy1.count(), 1 );
336     QList<QVariant> args1 = resultSpy1.takeFirst();
337     QVERIFY( args1.value(0).canConvert<Meta::AlbumList>() );
338     QCOMPARE( args1.value(0).value<Meta::AlbumList>().count(), 5 );
339     QCOMPARE( doneSpy1.count(), 1);
340     delete qm;
341 
342     qm = new Collections::SqlQueryMaker( m_collection );
343     qm->setQueryType( Collections::QueryMaker::Album );
344     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
345     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newAlbumsReady );
346     qm->addFilter( Meta::valAlbum, "foo" ); //should result in no match
347 
348     qm->run();
349 
350     doneSpy2.wait( 1000 );
351 
352     QCOMPARE( resultSpy2.count(), 1 );
353     QList<QVariant> args2 = resultSpy2.takeFirst();
354     QVERIFY( args2.value(0).canConvert<Meta::AlbumList>() );
355     QCOMPARE( args2.value(0).value<Meta::AlbumList>().count(), 0 );
356     QCOMPARE( doneSpy2.count(), 1);
357 }
358 
359 void
testAsyncArtistQuery()360 TestSqlQueryMaker::testAsyncArtistQuery()
361 {
362     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
363     qm->setQueryType( Collections::QueryMaker::Artist );
364     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
365     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newArtistsReady );
366 
367     qm->run();
368 
369     doneSpy1.wait( 1000 );
370 
371     QCOMPARE( resultSpy1.count(), 1 );
372     QList<QVariant> args1 = resultSpy1.takeFirst();
373     QVERIFY( args1.value(0).canConvert<Meta::ArtistList>() );
374     QCOMPARE( args1.value(0).value<Meta::ArtistList>().count(), 3 );
375     QCOMPARE( doneSpy1.count(), 1);
376     delete qm;
377 
378     qm = new Collections::SqlQueryMaker( m_collection );
379     qm->setQueryType( Collections::QueryMaker::Artist );
380     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
381     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newArtistsReady );
382     qm->addFilter( Meta::valArtist, "foo" ); //should result in no match
383 
384     qm->run();
385 
386     doneSpy2.wait( 1000 );
387 
388     QCOMPARE( resultSpy2.count(), 1 );
389     QList<QVariant> args2 = resultSpy2.takeFirst();
390     QVERIFY( args2.value(0).canConvert<Meta::ArtistList>() );
391     QCOMPARE( args2.value(0).value<Meta::ArtistList>().count(), 0 );
392     QCOMPARE( doneSpy2.count(), 1);
393 }
394 
395 void
testAsyncComposerQuery()396 TestSqlQueryMaker::testAsyncComposerQuery()
397 {
398     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
399     qm->setQueryType( Collections::QueryMaker::Composer );
400     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
401     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newComposersReady );
402 
403     qm->run();
404 
405     doneSpy1.wait( 1000 );
406 
407     QCOMPARE( resultSpy1.count(), 1 );
408     QList<QVariant> args1 = resultSpy1.takeFirst();
409     QVERIFY( args1.value(0).canConvert<Meta::ComposerList>() );
410     QCOMPARE( args1.value(0).value<Meta::ComposerList>().count(), 3 );
411     QCOMPARE( doneSpy1.count(), 1);
412 
413     delete qm;
414 
415     qm = new Collections::SqlQueryMaker( m_collection );
416     qm->setQueryType( Collections::QueryMaker::Composer );
417     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
418     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newComposersReady );
419     qm->addFilter( Meta::valComposer, "foo" ); //should result in no match
420 
421     qm->run();
422 
423     doneSpy2.wait( 1000 );
424 
425     QCOMPARE( resultSpy2.count(), 1 );
426     QList<QVariant> args2 = resultSpy2.takeFirst();
427     QVERIFY( args2.value(0).canConvert<Meta::ComposerList>() );
428     QCOMPARE( args2.value(0).value<Meta::ComposerList>().count(), 0 );
429     QCOMPARE( doneSpy2.count(), 1);
430 }
431 
432 void
testAsyncTrackQuery()433 TestSqlQueryMaker::testAsyncTrackQuery()
434 {
435     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
436     qm->setQueryType( Collections::QueryMaker::Track );
437     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
438     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newTracksReady );
439 
440     qm->run();
441 
442     doneSpy1.wait( 1000 );
443 
444     QCOMPARE( resultSpy1.count(), 1 );
445     QList<QVariant> args1 = resultSpy1.takeFirst();
446     QVERIFY( args1.value(0).canConvert<Meta::TrackList>() );
447     QCOMPARE( args1.value(0).value<Meta::TrackList>().count(), 6 );
448     QCOMPARE( doneSpy1.count(), 1);
449 
450     delete qm;
451 
452     qm = new Collections::SqlQueryMaker( m_collection );
453     qm->setQueryType( Collections::QueryMaker::Track );
454     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
455     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newTracksReady );
456     qm->addFilter( Meta::valTitle, "foo" ); //should result in no match
457 
458     qm->run();
459 
460     doneSpy2.wait( 1000 );
461 
462     QCOMPARE( resultSpy2.count(), 1 );
463     QList<QVariant> args2 = resultSpy2.takeFirst();
464     QVERIFY( args2.value(0).canConvert<Meta::TrackList>() );
465     QCOMPARE( args2.value(0).value<Meta::TrackList>().count(), 0 );
466     QCOMPARE( doneSpy2.count(), 1);
467 }
468 
469 void
testAsyncGenreQuery()470 TestSqlQueryMaker::testAsyncGenreQuery()
471 {
472     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
473     qm->setQueryType( Collections::QueryMaker::Genre );
474     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
475     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newGenresReady );
476 
477     qm->run();
478 
479     doneSpy1.wait( 1000 );
480 
481     QCOMPARE( resultSpy1.count(), 1 );
482     QList<QVariant> args1 = resultSpy1.takeFirst();
483     QVERIFY( args1.value(0).canConvert<Meta::GenreList>() );
484     QCOMPARE( args1.value(0).value<Meta::GenreList>().count(), 3 );
485     QCOMPARE( doneSpy1.count(), 1);
486 
487     delete qm;
488 
489     qm = new Collections::SqlQueryMaker( m_collection );
490     qm->setQueryType( Collections::QueryMaker::Genre );
491     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
492     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newGenresReady );
493     qm->addFilter( Meta::valGenre, "foo" ); //should result in no match
494 
495     qm->run();
496 
497     doneSpy2.wait( 1000 );
498 
499     QCOMPARE( resultSpy2.count(), 1 );
500     QList<QVariant> args2 = resultSpy2.takeFirst();
501     QVERIFY( args2.value(0).canConvert<Meta::GenreList>() );
502     QCOMPARE( args2.value(0).value<Meta::GenreList>().count(), 0 );
503     QCOMPARE( doneSpy2.count(), 1);
504 }
505 
506 void
testAsyncYearQuery()507 TestSqlQueryMaker::testAsyncYearQuery()
508 {
509     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
510     qm->setQueryType( Collections::QueryMaker::Year );
511     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
512     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newYearsReady );
513 
514     qm->run();
515 
516     doneSpy1.wait( 1000 );
517 
518     QCOMPARE( resultSpy1.count(), 1 );
519     QList<QVariant> args1 = resultSpy1.takeFirst();
520     QVERIFY( args1.value(0).canConvert<Meta::YearList>() );
521     QCOMPARE( args1.value(0).value<Meta::YearList>().count(), 3 );
522     QCOMPARE( doneSpy1.count(), 1);
523 
524     delete qm;
525 
526     qm = new Collections::SqlQueryMaker( m_collection );
527     qm->setQueryType( Collections::QueryMaker::Year );
528     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
529     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newYearsReady );
530     qm->addFilter( Meta::valYear, "foo" ); //should result in no match
531 
532     qm->run();
533 
534     doneSpy2.wait( 1000 );
535 
536     QCOMPARE( resultSpy2.count(), 1 );
537     QList<QVariant> args2 = resultSpy2.takeFirst();
538     QVERIFY( args2.value(0).canConvert<Meta::YearList>() );
539     QCOMPARE( args2.value(0).value<Meta::YearList>().count(), 0 );
540     QCOMPARE( doneSpy2.count(), 1);
541 }
542 
543 void
testAsyncCustomQuery()544 TestSqlQueryMaker::testAsyncCustomQuery()
545 {
546     Collections::QueryMaker *qm = new Collections::SqlQueryMaker( m_collection );
547     qm->setQueryType( Collections::QueryMaker::Custom );
548     qm->addReturnFunction( Collections::QueryMaker::Count, Meta::valTitle );
549     QSignalSpy doneSpy1( qm, &Collections::QueryMaker::queryDone );
550     QSignalSpy resultSpy1( qm, &Collections::QueryMaker::newResultReady );
551 
552     qm->run();
553 
554     doneSpy1.wait( 1000 );
555 
556     QCOMPARE( resultSpy1.count(), 1 );
557     QList<QVariant> args1 = resultSpy1.takeFirst();
558     QVERIFY( args1.value(0).canConvert<QStringList>() );
559     QCOMPARE( args1.value(0).value<QStringList>().count(), 1 );
560     QCOMPARE( args1.value(0).value<QStringList>().first(), QString( "6" ) );
561     QCOMPARE( doneSpy1.count(), 1);
562 
563     delete qm;
564 
565     qm = new Collections::SqlQueryMaker( m_collection );
566     qm->setQueryType( Collections::QueryMaker::Custom );
567     qm->addReturnFunction( Collections::QueryMaker::Count, Meta::valTitle );
568     QSignalSpy doneSpy2( qm, &Collections::QueryMaker::queryDone );
569     QSignalSpy resultSpy2( qm, &Collections::QueryMaker::newResultReady );
570     qm->addFilter( Meta::valTitle, "foo" ); //should result in no match
571 
572     qm->run();
573 
574     doneSpy2.wait( 1000 );
575 
576     QCOMPARE( resultSpy2.count(), 1 );
577     QList<QVariant> args2 = resultSpy2.takeFirst();
578     QVERIFY( args2.value(0).canConvert<QStringList>() );
579     QCOMPARE( args2.value(0).value<QStringList>().count(), 1 );
580     QCOMPARE( args2.value(0).value<QStringList>().first(), QString( "0" ) );
581     QCOMPARE( doneSpy2.count(), 1);
582 }
583 
584 void
testFilter_data()585 TestSqlQueryMaker::testFilter_data()
586 {
587     QTest::addColumn<Collections::QueryMaker::QueryType>( "type" );
588     QTest::addColumn<qint64>( "value" );
589     QTest::addColumn<QString>( "filter" );
590     QTest::addColumn<bool>( "matchBeginning" );
591     QTest::addColumn<bool>( "matchEnd" );
592     QTest::addColumn<int>( "count" );
593 
594     QTest::newRow( "track match all titles" ) << Collections::QueryMaker::Track << Meta::valTitle << "track" << false << false << 6;
595     QTest::newRow( "track match all title beginnings" ) << Collections::QueryMaker::Track << Meta::valTitle << "track" << true << false << 6;
596     QTest::newRow( "track match one title beginning" ) << Collections::QueryMaker::Track << Meta::valTitle << "track1" << true << false << 1;
597     QTest::newRow( "track match one title end" ) << Collections::QueryMaker::Track << Meta::valTitle << "rack2" << false << true << 1;
598     QTest::newRow( "track match title on both ends" ) << Collections::QueryMaker::Track << Meta::valTitle << "track3" << true << true << 1;
599     QTest::newRow( "track match artist" ) << Collections::QueryMaker::Track << Meta::valArtist << "artist1" << false << false << 3;
600     QTest::newRow( "artist match artist" ) << Collections::QueryMaker::Artist << Meta::valArtist << "artist1" << true << true << 1;
601     QTest::newRow( "album match artist" ) << Collections::QueryMaker::Album << Meta::valArtist << "artist3" << false << false << 2;
602     QTest::newRow( "track match genre" ) << Collections::QueryMaker::Track << Meta::valGenre << "genre1" << false << false << 3;
603     QTest::newRow( "genre match genre" ) << Collections::QueryMaker::Genre << Meta::valGenre << "genre1" << false << false << 1;
604     QTest::newRow( "track match composer" ) << Collections::QueryMaker::Track << Meta::valComposer << "composer2" << false << false << 2;
605     QTest::newRow( "composer match composer" ) << Collections::QueryMaker::Composer << Meta::valComposer << "composer2" << false << false << 1;
606     QTest::newRow( "track match year" ) << Collections::QueryMaker::Track << Meta::valYear << "2" << true << true << 2;
607     QTest::newRow( "year match year" ) << Collections::QueryMaker::Year << Meta::valYear << "1" << false << false << 1;
608     QTest::newRow( "album match album" ) << Collections::QueryMaker::Album << Meta::valAlbum << "album1" << false << false << 1;
609     QTest::newRow( "track match album" ) << Collections::QueryMaker::Track << Meta::valAlbum << "album1" << false << false << 1;
610     QTest::newRow( "track match albumartit" ) << Collections::QueryMaker::Track << Meta::valAlbumArtist << "artist1" << false << false << 2;
611     QTest::newRow( "album match albumartist" ) << Collections::QueryMaker::Album << Meta::valAlbumArtist << "artist2" << false << false << 1;
612     QTest::newRow( "album match all albumartists" ) << Collections::QueryMaker::Album << Meta::valAlbumArtist << "artist" << true << false << 4;
613     QTest::newRow( "genre match albumartist" ) << Collections::QueryMaker::Genre << Meta::valAlbumArtist << "artist1" << false << false << 1;
614     QTest::newRow( "year match albumartist" ) << Collections::QueryMaker::Year << Meta::valAlbumArtist << "artist1" << false << false << 1;
615     QTest::newRow( "composer match albumartist" ) << Collections::QueryMaker::Composer << Meta::valAlbumArtist << "artist1" << false << false << 1;
616     QTest::newRow( "genre match title" ) << Collections::QueryMaker::Genre << Meta::valTitle << "track1" << false << false << 1;
617     QTest::newRow( "composer match title" ) << Collections::QueryMaker::Composer << Meta::valTitle << "track1" << false << false << 1;
618     QTest::newRow( "year match title" ) << Collections::QueryMaker::Year << Meta::valTitle << "track1" << false << false << 1;
619     QTest::newRow( "album match title" ) << Collections::QueryMaker::Album << Meta::valTitle << "track1" << false << false << 1;
620     QTest::newRow( "artist match title" ) << Collections::QueryMaker::Artist << Meta::valTitle << "track1" << false << false << 1;
621     QTest::newRow( "track match comment" ) << Collections::QueryMaker::Track << Meta::valComment << "comment" << true << false << 4;
622     QTest::newRow( "track match url" ) << Collections::QueryMaker::Track << Meta::valUrl << "Exist" << false << false << 2;
623     QTest::newRow( "album match comment" ) << Collections::QueryMaker::Track << Meta::valComment << "comment1" << true << true << 1;
624 }
625 
626 void
checkResultCount(Collections::SqlQueryMaker * qm,Collections::QueryMaker::QueryType type,int count)627 TestSqlQueryMaker::checkResultCount( Collections::SqlQueryMaker* qm,
628                                      Collections::QueryMaker::QueryType type, int count ) {
629     switch( type ) {
630     case QueryMaker::Track: QCOMPARE( qm->tracks().count(), count ); break;
631     case QueryMaker::Artist: QCOMPARE( qm->artists().count(), count ); break;
632     case QueryMaker::Album: QCOMPARE( qm->albums().count(), count ); break;
633     case QueryMaker::Genre: QCOMPARE( qm->genres().count(), count ); break;
634     case QueryMaker::Composer: QCOMPARE( qm->composers().count(), count ); break;
635     case QueryMaker::Year: QCOMPARE( qm->years().count(), count ); break;
636     case QueryMaker::Label: QCOMPARE( qm->labels().count(), count ); break;
637     default:
638         ; // do nothing
639     }
640 }
641 
642 void
testFilter()643 TestSqlQueryMaker::testFilter()
644 {
645     QFETCH( Collections::QueryMaker::QueryType, type );
646     QFETCH( qint64, value );
647     QFETCH( QString, filter );
648     QFETCH( bool, matchBeginning );
649     QFETCH( bool, matchEnd );
650     QFETCH( int, count );
651 
652     Collections::SqlQueryMaker qm( m_collection );
653     qm.setBlocking( true );
654     qm.setQueryType( type );
655 
656     qm.addFilter( value, filter, matchBeginning, matchEnd );
657 
658     qm.run();
659 
660     checkResultCount( &qm, type, count );
661 }
662 
663 void
testDynamicCollection()664 TestSqlQueryMaker::testDynamicCollection()
665 {
666     //this will not crash as we reset the correct mock in cleanup()
667     SqlMountPointManagerMock mpm( this, m_storage );
668 
669     QMap<int, QString> mountPoints;
670 
671     mpm.m_mountPoints = mountPoints;
672 
673     m_collection->setMountPointManager( &mpm );
674 
675     Collections::SqlQueryMaker trackQm( m_collection );
676     trackQm.setQueryType( Collections::QueryMaker::Track );
677     trackQm.setBlocking( true );
678     trackQm.run();
679     QCOMPARE( trackQm.tracks().count(), 3 );
680 
681     mpm.m_mountPoints.insert( 1, "/foo" );
682 
683     Collections::SqlQueryMaker trackQm2( m_collection );
684     trackQm2.setQueryType( Collections::QueryMaker::Track );
685     trackQm2.setBlocking( true );
686     trackQm2.run();
687     QCOMPARE( trackQm2.tracks().count(), 4 );
688 
689     Collections::SqlQueryMaker artistQm( m_collection );
690     artistQm.setQueryType( Collections::QueryMaker::Artist );
691     artistQm.setBlocking( true );
692     artistQm.run();
693     QCOMPARE( artistQm.artists().count(), 2 );
694 
695     Collections::SqlQueryMaker albumQm( m_collection );
696     albumQm.setQueryType( Collections::QueryMaker::Album );
697     albumQm.setBlocking( true );
698     albumQm.run();
699     QCOMPARE( albumQm.albums().count(), 4 );
700 
701     Collections::SqlQueryMaker genreQm( m_collection );
702     genreQm.setQueryType( Collections::QueryMaker::Genre );
703     genreQm.setBlocking( true );
704     genreQm.run();
705     QCOMPARE( genreQm.genres().count(), 2 );
706 
707     Collections::SqlQueryMaker composerQm( m_collection );
708     composerQm.setQueryType( Collections::QueryMaker::Composer );
709     composerQm.setBlocking( true );
710     composerQm.run();
711     QCOMPARE( composerQm.composers().count(), 2 );
712 
713     Collections::SqlQueryMaker yearQm( m_collection );
714     yearQm.setQueryType( Collections::QueryMaker::Year );
715     yearQm.setBlocking( true );
716     yearQm.run();
717     QCOMPARE( yearQm.years().count(), 2 );
718 
719 }
720 
721 void
testSpecialCharacters_data()722 TestSqlQueryMaker::testSpecialCharacters_data()
723 {
724     QTest::addColumn<QString>( "filter" );
725     QTest::addColumn<bool>( "like" );
726 
727     QTest::newRow( "slash in filter w/o like" ) << "AC/DC" << false;
728     QTest::newRow( "slash in filter w/ like" ) << "AC/DC" << true;
729     QTest::newRow( "backslash in filter w/o like" ) << "AC\\DC" << false;
730     QTest::newRow( "backslash in filter w like" ) << "AC\\DC" << true;
731     QTest::newRow( "quote in filter w/o like" ) << "Foo'Bar" << false;
732     QTest::newRow( "quote in filter w like" ) << "Foo'Bar" << true;
733     QTest::newRow( "% in filter w/o like" ) << "Foo%Bar" << false;
734     QTest::newRow( "% in filter w/ like" ) << "Foo%Bar"  << true;
735     QTest::newRow( "filter ending with % w/o like" ) << "Foo%" << false;
736     QTest::newRow( "filter ending with % w like" ) << "Foo%" << true;
737     QTest::newRow( "filter beginning with % w/o like" ) << "%Foo" << false;
738     QTest::newRow( "filter beginning with % w/o like" ) << "%Foo" << true;
739     QTest::newRow( "\" in filter w/o like" ) << "Foo\"Bar" << false;
740     QTest::newRow( "\" in filter w like" ) << "Foo\"Bar" << true;
741     QTest::newRow( "_ in filter w/o like" ) << "track_" << false;
742     QTest::newRow( "_ in filter w/ like" ) << "track_" << true;
743     QTest::newRow( "filter with two consecutive backslashes w/o like" ) << "Foo\\\\Bar" << false;
744     QTest::newRow( "filter with two consecutive backslashes w like" ) << "Foo\\\\Bar" << true;
745     QTest::newRow( "filter with backslash% w/o like" ) << "FooBar\\%" << false;
746     QTest::newRow( "filter with backslash% w like" ) << "FooBar\\%" << true;
747 }
748 
749 void
testSpecialCharacters()750 TestSqlQueryMaker::testSpecialCharacters()
751 {
752     QFETCH( QString, filter );
753     QFETCH( bool, like );
754 
755     QString insertTrack = QString( "INSERT INTO tracks(id,url,title,comment,artist,album,genre,year,composer) "
756                               "VALUES(999,999,'%1','',1,1,1,1,1);").arg( m_storage->escape( filter ) );
757 
758     //there is a unique index on TRACKS.URL
759     m_storage->query( "INSERT INTO urls(id, deviceid, rpath, directory, uniqueid) VALUES(999, -1, './foobar.mp3', 1, '999');");
760     m_storage->query( insertTrack );
761 
762     QCOMPARE( m_storage->query( "select count(*) from urls where id = 999" ).first(), QString("1") );
763     QCOMPARE( m_storage->query( "select count(*) from tracks where id = 999" ).first(), QString("1") );
764 
765     Collections::SqlQueryMaker qm( m_collection );
766     qm.setBlocking( true );
767     qm.setQueryType( Collections::QueryMaker::Track );
768     qm.addFilter( Meta::valTitle, filter, !like, !like );
769 
770     qm.run();
771 
772     m_storage->query( "DELETE FROM urls WHERE id = 999;" );
773     m_storage->query( "DELETE FROM tracks WHERE id = 999;" );
774 
775     QCOMPARE( qm.tracks().count(), 1 );
776 }
777 
778 void
testNumberFilter_data()779 TestSqlQueryMaker::testNumberFilter_data()
780 {
781     QTest::addColumn<Collections::QueryMaker::QueryType>( "type" );
782     QTest::addColumn<qint64>( "value" );
783     QTest::addColumn<int>( "filter" );
784     QTest::addColumn<Collections::QueryMaker::NumberComparison>( "comparison" );
785     QTest::addColumn<bool>( "exclude" );
786     QTest::addColumn<int>( "count" );
787 
788     QTest::newRow( "include rating greater 4" ) << Collections::QueryMaker::Track << Meta::valRating << 4 << Collections::QueryMaker::GreaterThan << false << 1;
789     QTest::newRow( "exclude rating smaller 4" ) << Collections::QueryMaker::Album << Meta::valRating << 4 << Collections::QueryMaker::LessThan << true << 4;
790     QTest::newRow( "exclude tracks first played later than 2000" ) << Collections::QueryMaker::Track << Meta::valFirstPlayed << 2000 << Collections::QueryMaker::GreaterThan << true << 5;
791     //having never been played does not mean played before 20000
792     QTest::newRow( "include last played before 20000" ) << Collections::QueryMaker::Track << Meta::valLastPlayed << 20000 << Collections::QueryMaker::LessThan << false << 1;
793     QTest::newRow( "playcount equals 100" ) << Collections::QueryMaker::Album << Meta::valPlaycount << 100 << Collections::QueryMaker::Equals << false << 1;
794     //should include unplayed songs
795     QTest::newRow( "playcount != 50" ) << Collections::QueryMaker::Track << Meta::valPlaycount << 50 << Collections::QueryMaker::Equals << true << 5;
796     QTest::newRow( "score greater 60" ) << Collections::QueryMaker::Genre << Meta::valScore << 60 << Collections::QueryMaker::GreaterThan << false << 1;
797 }
798 
799 void
testNumberFilter()800 TestSqlQueryMaker::testNumberFilter()
801 {
802 
803     QFETCH( Collections::QueryMaker::QueryType, type );
804     QFETCH( qint64, value );
805     QFETCH( int, filter );
806     QFETCH( bool, exclude );
807     QFETCH( Collections::QueryMaker::NumberComparison, comparison );
808     QFETCH( int, count );
809 
810     Collections::SqlQueryMaker qm( m_collection );
811     qm.setBlocking( true );
812     qm.setQueryType( type );
813 
814     if( exclude )
815         qm.excludeNumberFilter( value, filter, comparison );
816     else
817         qm.addNumberFilter( value, filter, comparison );
818 
819     qm.run();
820 
821     checkResultCount( &qm, type, count );
822 }
823 
824 void
testReturnFunctions_data()825 TestSqlQueryMaker::testReturnFunctions_data()
826 {
827     QTest::addColumn<Collections::QueryMaker::ReturnFunction>( "function" );
828     QTest::addColumn<qint64>( "value" );
829     QTest::addColumn<QString>( "result" );
830 
831     QTest::newRow( "count tracks" ) << Collections::QueryMaker::Count << Meta::valTitle << QString( "6" );
832     QTest::newRow( "sum of playcount" ) << Collections::QueryMaker::Sum << Meta::valPlaycount << QString( "160" );
833     QTest::newRow( "min score" ) << Collections::QueryMaker::Min << Meta::valScore << QString( "50" );
834     QTest::newRow( "max rating" ) << Collections::QueryMaker::Max << Meta::valRating << QString( "9" );
835 }
836 
837 void
testReturnFunctions()838 TestSqlQueryMaker::testReturnFunctions()
839 {
840     QFETCH( Collections::QueryMaker::ReturnFunction, function );
841     QFETCH( qint64, value );
842     QFETCH( QString, result );
843 
844     Collections::SqlQueryMaker qm( m_collection );
845     qm.setBlocking( true );
846     qm.setQueryType( Collections::QueryMaker::Custom );
847     qm.addReturnFunction( function, value );
848 
849     qm.run();
850 
851     QCOMPARE( qm.customData().first(), result );
852 }
853 
854 void
testLabelMatch()855 TestSqlQueryMaker::testLabelMatch()
856 {
857     Meta::LabelPtr label = m_collection->registry()->getLabel( "labelB" );
858     Collections::SqlQueryMaker qm( m_collection );
859     qm.setBlocking( true );
860     qm.setQueryType( QueryMaker::Track );
861     qm.addMatch( label );
862     qm.run();
863 
864     QCOMPARE( qm.tracks().count(), 3 );
865 }
866 
867 void
testMultipleLabelMatches()868 TestSqlQueryMaker::testMultipleLabelMatches()
869 {
870     Meta::LabelPtr labelB = m_collection->registry()->getLabel( "labelB" );
871     Meta::LabelPtr labelA = m_collection->registry()->getLabel( "labelA" );
872     Collections::SqlQueryMaker qm( m_collection );
873     qm.setBlocking( true );
874     qm.setQueryType( QueryMaker::Track );
875     qm.addMatch( labelB );
876     qm.addMatch( labelA );
877     qm.run();
878 
879     QCOMPARE( qm.tracks().count(), 1 );
880 }
881 
882 void
testQueryTypesWithLabelMatching_data()883 TestSqlQueryMaker::testQueryTypesWithLabelMatching_data()
884 {
885     QTest::addColumn<Collections::QueryMaker::QueryType>( "type" );
886     QTest::addColumn<int>( "result" );
887 
888     QTest::newRow( "query tracks" ) << Collections::QueryMaker::Track << 1;
889     QTest::newRow( "query albums" ) << Collections::QueryMaker::Album << 1;
890     QTest::newRow( "query artists" ) << Collections::QueryMaker::Artist << 1;
891     QTest::newRow( "query genre" ) << Collections::QueryMaker::Genre << 1;
892     QTest::newRow( "query composers" ) << Collections::QueryMaker::Composer << 1;
893     QTest::newRow( "query years" ) << Collections::QueryMaker::Year << 1;
894     QTest::newRow( "query labels" ) << Collections::QueryMaker::Label << 2;
895 }
896 
897 void
testQueryTypesWithLabelMatching()898 TestSqlQueryMaker::testQueryTypesWithLabelMatching()
899 {
900 
901     QFETCH( Collections::QueryMaker::QueryType, type );
902     QFETCH( int, result );
903 
904     Meta::LabelPtr labelB = m_collection->registry()->getLabel( "labelB" );
905     Meta::LabelPtr labelA = m_collection->registry()->getLabel( "labelA" );
906     Collections::SqlQueryMaker qm( m_collection );
907     qm.setBlocking( true );
908     qm.setQueryType( type );
909     qm.addMatch( labelB );
910     qm.addMatch( labelA );
911     qm.run();
912 
913     checkResultCount( &qm, type, result );
914 }
915 
916 void
testFilterOnLabelsAndCombination()917 TestSqlQueryMaker::testFilterOnLabelsAndCombination()
918 {
919     Collections::SqlQueryMaker qm( m_collection );
920     qm.setBlocking( true );
921     qm.setQueryType( Collections::QueryMaker::Track );
922     qm.beginAnd();
923     qm.addFilter( Meta::valLabel, "labelB", true, true );
924     qm.addFilter( Meta::valLabel, "labelA", false, false );
925     qm.endAndOr();
926     qm.run();
927 
928     QCOMPARE( qm.tracks().count(), 1 );
929 }
930 
931 void
testFilterOnLabelsOrCombination()932 TestSqlQueryMaker::testFilterOnLabelsOrCombination()
933 {
934     Collections::SqlQueryMaker qm( m_collection );
935     qm.setBlocking( true );
936     qm.setQueryType( Collections::QueryMaker::Track );
937     qm.beginOr();
938     qm.addFilter( Meta::valLabel, "labelB", true, true );
939     qm.addFilter( Meta::valLabel, "labelA", false, false );
940     qm.endAndOr();
941     qm.run();
942 
943     QCOMPARE( qm.tracks().count(), 3 );
944 }
945 
946 void
testFilterOnLabelsNegationAndCombination()947 TestSqlQueryMaker::testFilterOnLabelsNegationAndCombination()
948 {
949     Collections::SqlQueryMaker qm( m_collection );
950     qm.setBlocking( true );
951     qm.setQueryType( Collections::QueryMaker::Track );
952     qm.beginAnd();
953     qm.excludeFilter( Meta::valLabel, "labelB", true, true );
954     qm.excludeFilter( Meta::valLabel, "labelA", false, false );
955     qm.endAndOr();
956     qm.run();
957 
958     QCOMPARE( qm.tracks().count(), 3 );
959 }
960 
961 void
testFilterOnLabelsNegationOrCombination()962 TestSqlQueryMaker::testFilterOnLabelsNegationOrCombination()
963 {
964     Collections::SqlQueryMaker qm( m_collection );
965     qm.setBlocking( true );
966     qm.setQueryType( Collections::QueryMaker::Track );
967     qm.beginOr();
968     qm.excludeFilter( Meta::valLabel, "labelB", true, true );
969     qm.excludeFilter( Meta::valLabel, "labelA", false, false );
970     qm.endAndOr();
971     qm.run();
972 
973     QCOMPARE( qm.tracks().count(), 5 );
974 }
975 
976 void
testComplexLabelsFilter()977 TestSqlQueryMaker::testComplexLabelsFilter()
978 {
979     Collections::SqlQueryMaker qm( m_collection );
980     qm.setBlocking( true );
981     qm.setQueryType( Collections::QueryMaker::Track );
982     qm.beginOr();
983     qm.addFilter( Meta::valLabel, "test", true, true );
984     qm.beginAnd();
985     qm.addFilter( Meta::valLabel, "labelB", false, false );
986     qm.excludeFilter( Meta::valLabel, "labelA", false, true );
987     qm.endAndOr();
988     qm.endAndOr();
989     qm.run();
990 
991     QCOMPARE( qm.tracks().count(), 3 );
992 }
993 
994 void
testLabelQueryMode_data()995 TestSqlQueryMaker::testLabelQueryMode_data()
996 {
997     QTest::addColumn<Collections::QueryMaker::QueryType>( "type" );
998     QTest::addColumn<Collections::QueryMaker::LabelQueryMode>( "labelMode" );
999     QTest::addColumn<Collections::QueryMaker::AlbumQueryMode>( "albumMode" );
1000     QTest::addColumn<int>( "result" );
1001 
1002     QTest::newRow( "labels with querymode WithoutLabels" ) << QueryMaker::Label << QueryMaker::OnlyWithoutLabels << QueryMaker::AllAlbums << 0;
1003     QTest::newRow( "tracks with labels" ) << QueryMaker::Track << QueryMaker::OnlyWithLabels << QueryMaker::AllAlbums << 4;
1004     QTest::newRow( "Compilations with labels" ) << QueryMaker::Album << QueryMaker::OnlyWithLabels << QueryMaker::OnlyCompilations << 1;
1005     QTest::newRow( "Compilations without labels" ) << QueryMaker::Album << QueryMaker::OnlyWithoutLabels << QueryMaker::OnlyCompilations << 1;
1006 }
1007 
1008 void
testLabelQueryMode()1009 TestSqlQueryMaker::testLabelQueryMode()
1010 {
1011     QFETCH( QueryMaker::QueryType, type );
1012     QFETCH( QueryMaker::LabelQueryMode, labelMode );
1013     QFETCH( QueryMaker::AlbumQueryMode, albumMode );
1014     QFETCH( int, result );
1015 
1016     SqlQueryMaker qm( m_collection );
1017     qm.setBlocking( true );
1018     qm.setQueryType( type );
1019     qm.setAlbumQueryMode( albumMode );
1020     qm.setLabelQueryMode( labelMode );
1021     qm.run();
1022 
1023     checkResultCount( &qm, type, result );
1024 }
1025 
1026