1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Strawberry is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include <memory>
23 
24 #include <gtest/gtest.h>
25 
26 #include "test_utils.h"
27 
28 #include "collection/collectionplaylistitem.h"
29 #include "playlist/playlist.h"
30 #include "mock_settingsprovider.h"
31 #include "mock_playlistitem.h"
32 
33 #include <QtDebug>
34 #include <QUndoStack>
35 
36 using ::testing::Return;
37 
38 // clazy:excludeall=non-pod-global-static,returning-void-expression
39 
40 namespace {
41 
42 class PlaylistTest : public ::testing::Test {
43  protected:
PlaylistTest()44   PlaylistTest()
45     : playlist_(nullptr, nullptr, nullptr, 1),
46       sequence_(nullptr, new DummySettingsProvider)
47   {
48   }
49 
SetUp()50   void SetUp() override {
51     playlist_.set_sequence(&sequence_);
52   }
53 
MakeMockItem(const QString & title,const QString & artist=QString (),const QString & album=QString (),int length=123) const54   MockPlaylistItem* MakeMockItem(const QString &title, const QString &artist = QString(), const QString &album = QString(), int length = 123) const {
55     Song metadata;
56     metadata.Init(title, artist, album, length);
57 
58     MockPlaylistItem *ret = new MockPlaylistItem;
59     EXPECT_CALL(*ret, Metadata()).WillRepeatedly(Return(metadata));
60 
61     return ret;
62   }
63 
MakeMockItemP(const QString & title,const QString & artist=QString (),const QString & album=QString (),int length=123) const64   PlaylistItemPtr MakeMockItemP(const QString &title, const QString &artist = QString(), const QString &album = QString(), int length = 123) const {
65     return PlaylistItemPtr(MakeMockItem(title, artist, album, length));
66   }
67 
68   Playlist playlist_;  // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
69   PlaylistSequence sequence_;  // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
70 
71 };
72 
TEST_F(PlaylistTest,Basic)73 TEST_F(PlaylistTest, Basic) {
74   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
75 }
76 
TEST_F(PlaylistTest,InsertItems)77 TEST_F(PlaylistTest, InsertItems) {
78 
79   MockPlaylistItem* item = MakeMockItem("Title", "Artist", "Album", 123);
80   PlaylistItemPtr item_ptr(item);
81 
82   // Insert the item
83   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
84   playlist_.InsertItems(PlaylistItemList() << item_ptr, -1);
85   ASSERT_EQ(1, playlist_.rowCount(QModelIndex()));
86 
87   // Get the metadata
88   EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
89   EXPECT_EQ("Artist", playlist_.data(playlist_.index(0, Playlist::Column_Artist)));
90   EXPECT_EQ("Album", playlist_.data(playlist_.index(0, Playlist::Column_Album)));
91   EXPECT_EQ(123, playlist_.data(playlist_.index(0, Playlist::Column_Length)));
92 
93 }
94 
TEST_F(PlaylistTest,Indexes)95 TEST_F(PlaylistTest, Indexes) {
96 
97   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
98   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
99 
100   // Start "playing" track 1
101   playlist_.set_current_row(0);
102   EXPECT_EQ(0, playlist_.current_row());
103   EXPECT_EQ("One", playlist_.current_item()->Metadata().title());
104   EXPECT_EQ(-1, playlist_.previous_row());
105   EXPECT_EQ(1, playlist_.next_row());
106 
107   // Stop playing
108   EXPECT_EQ(0, playlist_.last_played_row());
109   playlist_.set_current_row(-1);
110   EXPECT_EQ(0, playlist_.last_played_row());
111   EXPECT_EQ(-1, playlist_.current_row());
112 
113   // Play track 2
114   playlist_.set_current_row(1);
115   EXPECT_EQ(1, playlist_.current_row());
116   EXPECT_EQ("Two", playlist_.current_item()->Metadata().title());
117   EXPECT_EQ(0, playlist_.previous_row());
118   EXPECT_EQ(2, playlist_.next_row());
119 
120   // Play track 3
121   playlist_.set_current_row(2);
122   EXPECT_EQ(2, playlist_.current_row());
123   EXPECT_EQ("Three", playlist_.current_item()->Metadata().title());
124   EXPECT_EQ(1, playlist_.previous_row());
125   EXPECT_EQ(-1, playlist_.next_row());
126 
127 }
128 
TEST_F(PlaylistTest,RepeatPlaylist)129 TEST_F(PlaylistTest, RepeatPlaylist) {
130 
131   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
132   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
133 
134   playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Playlist);
135 
136   playlist_.set_current_row(0);
137   EXPECT_EQ(1, playlist_.next_row());
138 
139   playlist_.set_current_row(1);
140   EXPECT_EQ(2, playlist_.next_row());
141 
142   playlist_.set_current_row(2);
143   EXPECT_EQ(0, playlist_.next_row());
144 
145 }
146 
TEST_F(PlaylistTest,RepeatTrack)147 TEST_F(PlaylistTest, RepeatTrack) {
148 
149   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
150   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
151 
152   playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Track);
153 
154   playlist_.set_current_row(0);
155   EXPECT_EQ(0, playlist_.next_row());
156 
157 }
158 
TEST_F(PlaylistTest,RepeatAlbum)159 TEST_F(PlaylistTest, RepeatAlbum) {
160 
161   playlist_.InsertItems(PlaylistItemList()
162       << MakeMockItemP("One", "Album one")
163       << MakeMockItemP("Two", "Album two")
164       << MakeMockItemP("Three", "Album one"));
165   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
166 
167   playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Album);
168 
169   playlist_.set_current_row(0);
170   EXPECT_EQ(2, playlist_.next_row());
171 
172   playlist_.set_current_row(2);
173   EXPECT_EQ(0, playlist_.next_row());
174 
175 }
176 
TEST_F(PlaylistTest,RemoveBeforeCurrent)177 TEST_F(PlaylistTest, RemoveBeforeCurrent) {
178 
179   playlist_.InsertItems(PlaylistItemList()
180       << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
181   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
182 
183   // Remove a row before the currently playing track
184   playlist_.set_current_row(2);
185   EXPECT_EQ(2, playlist_.current_row());
186   playlist_.removeRow(1, QModelIndex());
187   EXPECT_EQ(1, playlist_.current_row());
188   EXPECT_EQ(1, playlist_.last_played_row());
189   EXPECT_EQ(0, playlist_.previous_row());
190   EXPECT_EQ(-1, playlist_.next_row());
191 
192 }
193 
TEST_F(PlaylistTest,RemoveAfterCurrent)194 TEST_F(PlaylistTest, RemoveAfterCurrent) {
195 
196   playlist_.InsertItems(PlaylistItemList()
197       << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
198   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
199 
200   // Remove a row after the currently playing track
201   playlist_.set_current_row(0);
202   EXPECT_EQ(0, playlist_.current_row());
203   playlist_.removeRow(1, QModelIndex());
204   EXPECT_EQ(0, playlist_.current_row());
205   EXPECT_EQ(0, playlist_.last_played_row());
206   EXPECT_EQ(-1, playlist_.previous_row());
207   EXPECT_EQ(1, playlist_.next_row());
208 
209   playlist_.set_current_row(1);
210   EXPECT_EQ(-1, playlist_.next_row());
211 
212 }
213 
TEST_F(PlaylistTest,RemoveCurrent)214 TEST_F(PlaylistTest, RemoveCurrent) {
215 
216   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
217   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
218 
219   // Remove the currently playing track's row
220   playlist_.set_current_row(1);
221   EXPECT_EQ(1, playlist_.current_row());
222   playlist_.removeRow(1, QModelIndex());
223   EXPECT_EQ(-1, playlist_.current_row());
224   EXPECT_EQ(-1, playlist_.last_played_row());
225   EXPECT_EQ(-1, playlist_.previous_row());
226   EXPECT_EQ(0, playlist_.next_row());
227 
228 }
229 
TEST_F(PlaylistTest,InsertBeforeCurrent)230 TEST_F(PlaylistTest, InsertBeforeCurrent) {
231 
232   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
233   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
234 
235   playlist_.set_current_row(1);
236   EXPECT_EQ(1, playlist_.current_row());
237   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Four"), 0);
238   ASSERT_EQ(4, playlist_.rowCount(QModelIndex()));
239 
240   EXPECT_EQ(2, playlist_.current_row());
241   EXPECT_EQ(2, playlist_.last_played_row());
242   EXPECT_EQ(1, playlist_.previous_row());
243   EXPECT_EQ(3, playlist_.next_row());
244 
245   EXPECT_EQ("Four", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
246   EXPECT_EQ("One", playlist_.data(playlist_.index(1, Playlist::Column_Title)));
247 
248 }
249 
TEST_F(PlaylistTest,InsertAfterCurrent)250 TEST_F(PlaylistTest, InsertAfterCurrent) {
251 
252   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
253   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
254 
255   playlist_.set_current_row(1);
256   EXPECT_EQ(1, playlist_.current_row());
257   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Four"), 2);
258   ASSERT_EQ(4, playlist_.rowCount(QModelIndex()));
259 
260   EXPECT_EQ(1, playlist_.current_row());
261   EXPECT_EQ(1, playlist_.last_played_row());
262   EXPECT_EQ(0, playlist_.previous_row());
263   EXPECT_EQ(2, playlist_.next_row());
264 
265   EXPECT_EQ("Two", playlist_.data(playlist_.index(1, Playlist::Column_Title)));
266   EXPECT_EQ("Four", playlist_.data(playlist_.index(2, Playlist::Column_Title)));
267   EXPECT_EQ("Three", playlist_.data(playlist_.index(3, Playlist::Column_Title)));
268 
269 }
270 
TEST_F(PlaylistTest,Clear)271 TEST_F(PlaylistTest, Clear) {
272 
273   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
274   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
275 
276   playlist_.set_current_row(1);
277   EXPECT_EQ(1, playlist_.current_row());
278   playlist_.Clear();
279 
280   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
281   EXPECT_EQ(-1, playlist_.current_row());
282   EXPECT_EQ(-1, playlist_.last_played_row());
283   EXPECT_EQ(-1, playlist_.previous_row());
284   EXPECT_EQ(-1, playlist_.next_row());
285 
286 }
287 
TEST_F(PlaylistTest,UndoAdd)288 TEST_F(PlaylistTest, UndoAdd) {
289 
290   EXPECT_FALSE(playlist_.undo_stack()->canUndo());
291   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
292 
293   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
294   EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
295   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
296   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
297 
298   playlist_.undo_stack()->undo();
299   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
300   EXPECT_FALSE(playlist_.undo_stack()->canUndo());
301   ASSERT_TRUE(playlist_.undo_stack()->canRedo());
302 
303   playlist_.undo_stack()->redo();
304   EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
305   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
306   EXPECT_TRUE(playlist_.undo_stack()->canUndo());
307 
308   EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
309 
310 }
311 
TEST_F(PlaylistTest,UndoMultiAdd)312 TEST_F(PlaylistTest, UndoMultiAdd) {
313 
314   // Add 1 item
315   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One"));
316 
317   // Add 2 items
318   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Two") << MakeMockItemP("Three"));
319 
320   // Undo adding 2 items
321   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
322   EXPECT_EQ("add 2 songs", playlist_.undo_stack()->undoText());
323   playlist_.undo_stack()->undo();
324 
325   // Undo adding 1 item
326   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
327   EXPECT_EQ("add 1 songs", playlist_.undo_stack()->undoText());
328   playlist_.undo_stack()->undo();
329 
330   EXPECT_FALSE(playlist_.undo_stack()->canUndo());
331 
332 }
333 
TEST_F(PlaylistTest,UndoRemove)334 TEST_F(PlaylistTest, UndoRemove) {
335 
336   EXPECT_FALSE(playlist_.undo_stack()->canUndo());
337   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
338 
339   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
340 
341   EXPECT_TRUE(playlist_.undo_stack()->canUndo());
342   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
343 
344   playlist_.removeRow(0);
345 
346   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
347   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
348   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
349 
350   playlist_.undo_stack()->undo();
351   EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
352   ASSERT_TRUE(playlist_.undo_stack()->canRedo());
353 
354   EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
355 
356   playlist_.undo_stack()->redo();
357   EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
358   EXPECT_FALSE(playlist_.undo_stack()->canRedo());
359   EXPECT_TRUE(playlist_.undo_stack()->canUndo());
360 
361 }
362 
TEST_F(PlaylistTest,UndoMultiRemove)363 TEST_F(PlaylistTest, UndoMultiRemove) {
364 
365   // Add 3 items
366   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
367   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
368 
369   // Remove 1 item
370   playlist_.removeRow(1); // Item "Two"
371 
372   // Remove 2 items
373   playlist_.removeRows(0, 2); // "One" and "Three"
374 
375   ASSERT_EQ(0, playlist_.rowCount(QModelIndex()));
376 
377   // Undo removing all 3 items
378   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
379   EXPECT_EQ("remove 3 songs", playlist_.undo_stack()->undoText());
380 
381   playlist_.undo_stack()->undo();
382   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
383 
384 }
385 
TEST_F(PlaylistTest,UndoClear)386 TEST_F(PlaylistTest, UndoClear) {
387 
388   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
389   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
390 
391   playlist_.Clear();
392   ASSERT_EQ(0, playlist_.rowCount(QModelIndex()));
393   ASSERT_TRUE(playlist_.undo_stack()->canUndo());
394   EXPECT_EQ("remove 3 songs", playlist_.undo_stack()->undoText());
395   playlist_.undo_stack()->undo();
396 
397   ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
398 
399 }
400 
TEST_F(PlaylistTest,UndoRemoveCurrent)401 TEST_F(PlaylistTest, UndoRemoveCurrent) {
402 
403   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
404   playlist_.set_current_row(0);
405   EXPECT_EQ(0, playlist_.current_row());
406   EXPECT_EQ(0, playlist_.last_played_row());
407 
408   playlist_.removeRow(0);
409   EXPECT_EQ(-1, playlist_.current_row());
410   EXPECT_EQ(-1, playlist_.last_played_row());
411 
412   playlist_.undo_stack()->undo();
413   EXPECT_EQ(-1, playlist_.current_row());
414   EXPECT_EQ(-1, playlist_.last_played_row());
415 
416 }
417 
TEST_F(PlaylistTest,UndoRemoveOldCurrent)418 TEST_F(PlaylistTest, UndoRemoveOldCurrent) {
419 
420   playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
421   playlist_.set_current_row(0);
422   EXPECT_EQ(0, playlist_.current_row());
423   EXPECT_EQ(0, playlist_.last_played_row());
424 
425   playlist_.removeRow(0);
426   EXPECT_EQ(-1, playlist_.current_row());
427   EXPECT_EQ(-1, playlist_.last_played_row());
428 
429   playlist_.set_current_row(-1);
430 
431   playlist_.undo_stack()->undo();
432   EXPECT_EQ(-1, playlist_.current_row());
433   EXPECT_EQ(-1, playlist_.last_played_row());
434 
435 }
436 
TEST_F(PlaylistTest,ShuffleThenNext)437 TEST_F(PlaylistTest, ShuffleThenNext) {
438 
439   // Add 100 items
440   PlaylistItemList items;
441   items.reserve(100);
442   for (int i=0 ; i<100 ; ++i)
443     items << MakeMockItemP("Item " + QString::number(i));
444   playlist_.InsertItems(items);
445 
446   playlist_.set_current_row(0);
447 
448   // Shuffle until the current index is not at the end
449   forever {
450     playlist_.Shuffle();
451     if (playlist_.current_row() != items.count()-1)
452       break;
453   }
454 
455   int index = playlist_.current_row();
456   EXPECT_EQ("Item 0", playlist_.current_item()->Metadata().title());
457   EXPECT_EQ("Item 0", playlist_.data(playlist_.index(index, Playlist::Column_Title)));
458   EXPECT_EQ(index, playlist_.last_played_row());
459   //EXPECT_EQ(index + 1, playlist_.next_row());
460 
461   // Shuffle until the current index *is* at the end
462   //forever {
463     //playlist_.Shuffle();
464     //if (playlist_.current_row() == items.count()-1)
465       //break;
466   //}
467 
468   index = playlist_.current_row();
469   EXPECT_EQ("Item 0", playlist_.current_item()->Metadata().title());
470   EXPECT_EQ("Item 0", playlist_.data(playlist_.index(index, Playlist::Column_Title)));
471   EXPECT_EQ(index, playlist_.last_played_row());
472   //EXPECT_EQ(-1, playlist_.next_row());
473   //EXPECT_EQ(index-1, playlist_.previous_row());
474 
475 }
476 
TEST_F(PlaylistTest,CollectionIdMapSingle)477 TEST_F(PlaylistTest, CollectionIdMapSingle) {
478 
479   Song song;
480   song.Init("title", "artist", "album", 123);
481   song.set_id(1);
482 
483   PlaylistItemPtr item(std::make_shared<CollectionPlaylistItem>(song));
484   playlist_.InsertItems(PlaylistItemList() << item);
485 
486   EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count());
487   EXPECT_EQ(0, playlist_.collection_items_by_id(0).count());
488   EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
489   ASSERT_EQ(1, playlist_.collection_items_by_id(1).count());
490   EXPECT_EQ(song.title(), playlist_.collection_items_by_id(1)[0]->Metadata().title());  // clazy:exclude=detaching-temporary
491 
492   playlist_.Clear();
493 
494   EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
495 
496 }
497 
TEST_F(PlaylistTest,CollectionIdMapInvalid)498 TEST_F(PlaylistTest, CollectionIdMapInvalid) {
499 
500   Song invalid;
501   invalid.Init("title", "artist", "album", 123);
502   ASSERT_EQ(-1, invalid.id());
503 
504   PlaylistItemPtr item(std::make_shared<CollectionPlaylistItem>(invalid));
505   playlist_.InsertItems(PlaylistItemList() << item);
506 
507   EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count());
508   EXPECT_EQ(0, playlist_.collection_items_by_id(0).count());
509   EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
510   EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
511 
512 }
513 
TEST_F(PlaylistTest,CollectionIdMapMulti)514 TEST_F(PlaylistTest, CollectionIdMapMulti) {
515 
516   Song one;
517   one.Init("title", "artist", "album", 123);
518   one.set_id(1);
519 
520   Song two;
521   two.Init("title 2", "artist 2", "album 2", 123);
522   two.set_id(2);
523 
524   PlaylistItemPtr item_one(std::make_shared<CollectionPlaylistItem>(one));
525   PlaylistItemPtr item_two(std::make_shared<CollectionPlaylistItem>(two));
526   PlaylistItemPtr item_three(std::make_shared<CollectionPlaylistItem>(one));
527   playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three);
528 
529   EXPECT_EQ(2, playlist_.collection_items_by_id(1).count());
530   EXPECT_EQ(1, playlist_.collection_items_by_id(2).count());
531 
532   playlist_.removeRow(1); // item_two
533   EXPECT_EQ(2, playlist_.collection_items_by_id(1).count());
534   EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
535 
536   playlist_.removeRow(1); // item_three
537   EXPECT_EQ(1, playlist_.collection_items_by_id(1).count());
538   EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
539 
540   playlist_.removeRow(0); // item_one
541   EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
542   EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
543 
544 }
545 
546 
547 }  // namespace
548