1 /****************************************************************************************
2 * Copyright (c) 2011 Ralf Engels <ralf-engels@gmx.de> *
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 "TestDynamicModel.h"
18
19 #include "amarokconfig.h"
20 #include "dynamic/Bias.h"
21 #include "dynamic/BiasedPlaylist.h"
22 #include "dynamic/DynamicModel.h"
23
24 #include "core/support/Amarok.h"
25 #include "core/support/Debug.h"
26
27 #include <QByteArray>
28 #include <QDataStream>
29 #include <QMimeData>
30 #include <QSignalSpy>
31 #include <QTemporaryDir>
32
33
34 Q_DECLARE_METATYPE(QModelIndex);
35
36 QTemporaryDir *s_tmpDir = 0; // Memory leak here now, but if it's deleted, we have a segfault
37
38 // We return a special saveLocation.
saveLocation(const QString & directory)39 QString Amarok::saveLocation( const QString &directory )
40 {
41 return s_tmpDir->path() + directory;
42 }
43
QTEST_GUILESS_MAIN(TestDynamicModel)44 QTEST_GUILESS_MAIN( TestDynamicModel )
45
46 TestDynamicModel::TestDynamicModel()
47 {
48 qRegisterMetaType<QModelIndex>();
49 }
50
51 void
init()52 TestDynamicModel::init()
53 {
54 AmarokConfig::instance("amarokrc");
55
56 s_tmpDir = new QTemporaryDir();
57 QVERIFY( s_tmpDir->isValid() );
58 }
59
60 void
cleanup()61 TestDynamicModel::cleanup()
62 {
63 }
64
65 void
testData()66 TestDynamicModel::testData()
67 {
68 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
69
70 // load from the empty directory
71 model->loadPlaylists();
72
73 // now we should have the four default playlists
74 QModelIndex playlistIndex = model->index( 0, 0 );
75 QCOMPARE( model->data( playlistIndex ).toString(), QString("Random") );
76 QCOMPARE( model->data( playlistIndex, Qt::EditRole ).toString(), QString("Random") );
77 QVERIFY( model->data( playlistIndex, Dynamic::DynamicModel::PlaylistRole ).isValid() );
78 QVERIFY( !model->data( playlistIndex, Dynamic::DynamicModel::BiasRole ).isValid() );
79
80 QModelIndex biasIndex = model->index( 0, 0, playlistIndex );
81 QVERIFY( !model->data( biasIndex ).toString().isEmpty() );
82 QVERIFY( !model->data( biasIndex, Dynamic::DynamicModel::PlaylistRole ).isValid() );
83 QVERIFY( model->data( biasIndex, Dynamic::DynamicModel::BiasRole ).isValid() );
84 }
85
86 void
testPlaylistIndex()87 TestDynamicModel::testPlaylistIndex()
88 {
89 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
90
91 // load from the empty directory
92 model->loadPlaylists();
93
94 // now we should have the four default playlists
95 QCOMPARE( model->rowCount(), 4 );
96 QCOMPARE( model->columnCount(), 1 );
97
98 // -- random playlist with one bias
99 QModelIndex playlistIndex = model->index( 0, 0 );
100 QModelIndex biasIndex = model->index( 0, 0, playlistIndex );
101
102 QCOMPARE( model->rowCount( playlistIndex ), 1 );
103 QCOMPARE( model->rowCount( biasIndex ), 0 );
104 QCOMPARE( playlistIndex.parent(), QModelIndex() );
105 QCOMPARE( biasIndex.parent(), playlistIndex );
106
107 // -- albumplay playlist with bias structure
108 playlistIndex = model->index( 2, 0 );
109 biasIndex = model->index( 0, 0, playlistIndex );
110 QModelIndex subBiasIndex = model->index( 1, 0, biasIndex );
111
112 QCOMPARE( model->rowCount( playlistIndex ), 1 );
113 QCOMPARE( model->rowCount( biasIndex ), 2 );
114 QCOMPARE( model->rowCount( subBiasIndex ), 0 );
115 QCOMPARE( playlistIndex.parent(), QModelIndex() );
116 QCOMPARE( biasIndex.parent(), playlistIndex );
117 QCOMPARE( subBiasIndex.parent(), biasIndex );
118
119
120 // and now the non-model index functions:
121 model->setActivePlaylist( 2 );
122 Dynamic::DynamicPlaylist* playlist = model->activePlaylist();
123 playlistIndex = model->index( model->activePlaylistIndex(), 0 );
124 QCOMPARE( model->index( playlist ), playlistIndex );
125
126 Dynamic::BiasPtr bias = qobject_cast<Dynamic::BiasedPlaylist*>(playlist)->bias();
127 biasIndex = model->index( 0, 0, playlistIndex );
128 QCOMPARE( model->index( bias ), biasIndex );
129
130 Dynamic::BiasPtr subBias = qobject_cast<Dynamic::AndBias*>(bias.data())->biases().at(0);
131 subBiasIndex = model->index( 0, 0, biasIndex );
132 QCOMPARE( model->index( subBias ), subBiasIndex );
133 }
134
135 void
testSlots()136 TestDynamicModel::testSlots()
137 {
138 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
139
140 // load from the empty directory
141 model->loadPlaylists();
142
143 QSignalSpy spy1( model, &Dynamic::DynamicModel::rowsAboutToBeRemoved );
144 QSignalSpy spy2( model, &Dynamic::DynamicModel::rowsRemoved );
145 QSignalSpy spy3( model, &Dynamic::DynamicModel::rowsAboutToBeInserted );
146 QSignalSpy spy4( model, &Dynamic::DynamicModel::rowsInserted );
147
148 // -- removeAt with playlist
149 QModelIndex playlistIndex = model->index( 1, 0 );
150 QString oldName = model->data( playlistIndex ).toString();
151
152 model->removeAt( playlistIndex );
153
154 QCOMPARE( spy1.count(), 1 );
155 QCOMPARE( spy3.count(), 0 );
156 QList<QVariant> args1 = spy1.takeFirst();
157 QVERIFY( args1.value(0).canConvert<QModelIndex>() );
158 QCOMPARE( args1.value(0).value<QModelIndex>(), QModelIndex() );
159 QCOMPARE( args1.value(1).toInt(), 1 );
160 QCOMPARE( args1.value(2).toInt(), 1 );
161 QCOMPARE( spy2.count(), 1 );
162 spy2.takeFirst();
163
164 // name should be different
165 playlistIndex = model->index( 1, 0 );
166 QVERIFY( model->data( playlistIndex ).toString() != oldName );
167
168 QCOMPARE( model->rowCount(), 3 );
169
170 // -- removeAt with bias
171 playlistIndex = model->index( 1, 0 );
172 QModelIndex biasIndex = model->index( 0, 0, playlistIndex );
173 QModelIndex subBiasIndex = model->index( 0, 0, biasIndex );
174 QCOMPARE( model->rowCount( biasIndex ), 2 );
175
176 model->removeAt( subBiasIndex );
177
178 QCOMPARE( spy1.count(), 1 );
179 QCOMPARE( spy3.count(), 0 );
180 args1 = spy1.takeFirst();
181 QCOMPARE( args1.count(), 3 );
182 QVERIFY( args1.value(0).canConvert<QModelIndex>() );
183 QCOMPARE( args1.value(0).value<QModelIndex>(), biasIndex );
184 QCOMPARE( args1.value(1).toInt(), 0 );
185 QCOMPARE( args1.value(2).toInt(), 0 );
186 QCOMPARE( spy2.count(), 1 );
187 spy2.takeFirst();
188
189 QCOMPARE( model->rowCount( biasIndex ), 1 );
190 QCOMPARE( model->rowCount(), 3 ); // only the bias was removed
191
192 // -- cloneAt with level 2 bias
193 playlistIndex = model->index( 1, 0 );
194
195 biasIndex = model->index( 0, 0, playlistIndex );
196 subBiasIndex = model->index( 0, 0, biasIndex );
197 QCOMPARE( model->rowCount( biasIndex ), 1 );
198
199 QModelIndex resultIndex = model->cloneAt(subBiasIndex);
200 QCOMPARE( resultIndex.row(), 1 );
201 QCOMPARE( resultIndex.parent(), biasIndex );
202
203 QCOMPARE( spy3.count(), 1 );
204 args1 = spy3.takeFirst();
205 QVERIFY( args1.value(0).canConvert<QModelIndex>() );
206 QCOMPARE( args1.value(0).value<QModelIndex>(), biasIndex );
207 QCOMPARE( args1.value(1).toInt(), 1 );
208 QCOMPARE( args1.value(2).toInt(), 1 );
209 QCOMPARE( spy4.count(), 1 );
210 spy4.takeFirst();
211
212 QCOMPARE( model->rowCount( biasIndex ), 2 );
213 QCOMPARE( model->rowCount(), 3 ); // only the bias was cloned
214
215 // -- newPlaylist
216 QCOMPARE( spy1.count(), 0 );
217 QCOMPARE( spy3.count(), 0 );
218
219 QCOMPARE( model->rowCount(), 3 );
220 resultIndex = model->newPlaylist();
221 QCOMPARE( model->rowCount(), 4 );
222
223 QCOMPARE( resultIndex.row(), 3 );
224 QCOMPARE( resultIndex.parent(), QModelIndex() );
225
226 QCOMPARE( spy1.count(), 0 );
227 QCOMPARE( spy3.count(), 1 );
228 args1 = spy3.takeFirst();
229 QVERIFY( args1.value(0).canConvert<QModelIndex>() );
230 QCOMPARE( args1.value(0).value<QModelIndex>(), QModelIndex() );
231 QCOMPARE( args1.value(1).toInt(), 3 );
232 QCOMPARE( args1.value(2).toInt(), 3 );
233 QCOMPARE( spy4.count(), 1 );
234 spy4.takeFirst();
235
236 // -- cloneAt with playlist
237 playlistIndex = model->index( 1, 0 );
238
239 QCOMPARE( model->rowCount(), 4 );
240 resultIndex = model->cloneAt(playlistIndex);
241 QCOMPARE( model->rowCount(), 5 );
242
243 QCOMPARE( resultIndex.row(), 4 );
244 QCOMPARE( resultIndex.parent(), QModelIndex() );
245 QCOMPARE( model->rowCount( resultIndex ), 1 );
246
247 QCOMPARE( spy3.count(), 1 );
248 args1 = spy3.takeFirst();
249 QVERIFY( args1.value(0).canConvert<QModelIndex>() );
250 QCOMPARE( args1.value(0).value<QModelIndex>(), QModelIndex() );
251 QCOMPARE( args1.value(1).toInt(), 4 );
252 QCOMPARE( args1.value(2).toInt(), 4 );
253 QCOMPARE( spy4.count(), 1 );
254 spy4.takeFirst();
255 }
256
257 QModelIndex
serializeUnserialize(const QModelIndex & index)258 TestDynamicModel::serializeUnserialize( const QModelIndex& index )
259 {
260 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
261
262 QByteArray bytes;
263 QDataStream stream( &bytes, QIODevice::WriteOnly );
264 model->serializeIndex( &stream, index );
265
266 QDataStream stream2( &bytes, QIODevice::ReadOnly );
267 return model->unserializeIndex( &stream2 );
268 }
269
270 void
testSerializeIndex()271 TestDynamicModel::testSerializeIndex()
272 {
273 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
274
275 // load from the empty directory
276 model->loadPlaylists();
277
278 QModelIndex playlistIndex = model->index( 2, 0 );
279 QModelIndex biasIndex = model->index( 0, 0, playlistIndex );
280 QModelIndex subBiasIndex = model->index( 0, 0, biasIndex );
281
282 QCOMPARE( QModelIndex(), serializeUnserialize( QModelIndex() ) );
283 QCOMPARE( biasIndex, serializeUnserialize( biasIndex ) );
284 QCOMPARE( subBiasIndex, serializeUnserialize( subBiasIndex ) );
285 }
286
287 void
testDnD()288 TestDynamicModel::testDnD()
289 {
290 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
291
292 // load from the empty directory
293 model->loadPlaylists();
294
295 // -- copy a playlist
296 QModelIndex playlistIndex = model->index( 2, 0 );
297 QModelIndexList indexes;
298 indexes << playlistIndex;
299 int oldRowCount = model->rowCount();
300 QString oldName = model->data( playlistIndex ).toString();
301 QMimeData* data = model->mimeData( indexes );
302 QVERIFY( model->dropMimeData( data, Qt::CopyAction, 0, 0, QModelIndex() ) );
303
304 QCOMPARE( model->rowCount(), oldRowCount + 1 );
305 playlistIndex = model->index( 0, 0 );
306 QCOMPARE( oldName, model->data( playlistIndex ).toString() );
307 delete data;
308
309 // -- move a playlist (to the end)
310 playlistIndex = model->index( 0, 0 );
311 indexes.clear();
312 indexes << playlistIndex;
313
314 oldRowCount = model->rowCount();
315 oldName = model->data( playlistIndex ).toString();
316 data = model->mimeData( indexes );
317 QVERIFY( model->dropMimeData( data, Qt::MoveAction, oldRowCount, 0, QModelIndex() ) );
318
319 QCOMPARE( model->rowCount(), oldRowCount );
320 playlistIndex = model->index( oldRowCount - 1, 0 );
321 QCOMPARE( oldName, model->data( playlistIndex ).toString() );
322 delete data;
323
324
325 // -- copy a bias
326 // TODO
327 // QModelIndex biasIndex = model->index( 0, 0, playlistIndex );
328 // QModelIndex subBiasIndex = model->index( 0, 0, biasIndex );
329 }
330
331 void
testRemoveActive()332 TestDynamicModel::testRemoveActive()
333 {
334 Dynamic::DynamicModel *model = Dynamic::DynamicModel::instance();
335
336 // load from the empty directory
337 model->loadPlaylists();
338 QCOMPARE( model->rowCount(), 4 );
339
340 // -- try to remove the active playlist
341 model->setActivePlaylist( 2 );
342 QCOMPARE( model->activePlaylistIndex(), 2 );
343 Dynamic::DynamicPlaylist* pl = model->activePlaylist();
344
345 model->removeAt( model->index( pl ) );
346 QCOMPARE( model->rowCount(), 3 );
347 QVERIFY( model->activePlaylist() != pl );
348
349 // -- now remove all playlists remaining three playlists
350 model->removeAt( model->index( model->activePlaylist() ) );
351 model->removeAt( model->index( model->activePlaylist() ) );
352 model->removeAt( model->index( model->activePlaylist() ) );
353
354 QCOMPARE( model->rowCount(), 0 );
355 QCOMPARE( model->activePlaylist(), static_cast<Dynamic::DynamicPlaylist*>(0) );
356 }
357
358