1 /* This file is part of Clementine.
2 Copyright 2010, David Sansome <me@davidsansome.com>
3
4 Clementine is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 Clementine is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Clementine. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 #include "gmock/gmock-matchers.h"
20 #include "gtest/gtest.h"
21 #include "test_utils.h"
22
23 #include "core/timeconstants.h"
24 #include "playlistparsers/cueparser.h"
25
26 #include <QUrl>
27
28 class CueParserTest : public ::testing::Test {
29 protected:
CueParserTest()30 CueParserTest()
31 : parser_(nullptr) {
32 }
33
34 // We believe CUE - all songs with proper CUE entries should be valid.
validate_songs(SongList songs)35 bool validate_songs(SongList songs) {
36 foreach(const Song& song, songs) {
37 if(!song.is_valid()) {
38 return false;
39 }
40 }
41
42 return true;
43 }
44
to_nanosec(int minutes,int seconds,int frames)45 qlonglong to_nanosec(int minutes, int seconds, int frames) {
46 return (minutes * 60 * 75 + seconds * 75 + frames) * kNsecPerSec / 75;
47 }
48
49 CueParser parser_;
50 };
51
TEST_F(CueParserTest,ParsesASong)52 TEST_F(CueParserTest, ParsesASong) {
53 QFile file(":testdata/onesong.cue");
54 file.open(QIODevice::ReadOnly);
55
56 SongList song_list = parser_.Load(&file, "CUEPATH", QDir(""));
57
58 // one song
59 ASSERT_EQ(1, song_list.size());
60
61 // with the specified metadata
62 Song first_song = song_list.at(0);
63 ASSERT_EQ("Un soffio caldo", first_song.title());
64 ASSERT_EQ("Zucchero", first_song.artist());
65 ASSERT_EQ("Zucchero himself", first_song.albumartist());
66 ASSERT_EQ("", first_song.album());
67 ASSERT_EQ(to_nanosec(0, 1, 15), first_song.beginning_nanosec());
68 ASSERT_EQ(1, first_song.track());
69 ASSERT_EQ("CUEPATH", first_song.cue_path());
70
71 validate_songs(song_list);
72 }
73
TEST_F(CueParserTest,ParsesTwoSongs)74 TEST_F(CueParserTest, ParsesTwoSongs) {
75 QFile file(":testdata/twosongs.cue");
76 file.open(QIODevice::ReadOnly);
77
78 SongList song_list = parser_.Load(&file, "", QDir(""));
79
80 // two songs
81 ASSERT_EQ(2, song_list.size());
82
83 // with the specified metadata
84 Song first_song = song_list.at(0);
85 Song second_song = song_list.at(1);
86
87 ASSERT_EQ("Un soffio caldo", first_song.title());
88 ASSERT_EQ("Chocabeck", first_song.album());
89 ASSERT_EQ("Zucchero himself", first_song.artist());
90 ASSERT_EQ("Zucchero himself", first_song.albumartist());
91 ASSERT_EQ(to_nanosec(0, 1, 0), first_song.beginning_nanosec());
92 ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
93 ASSERT_EQ(1, first_song.track());
94
95 ASSERT_EQ("Somewon Else's Tears", second_song.title());
96 ASSERT_EQ("Chocabeck", second_song.album());
97 ASSERT_EQ("Zucchero himself", second_song.artist());
98 ASSERT_EQ("Zucchero himself", second_song.albumartist());
99 ASSERT_EQ(to_nanosec(5, 3, 68), second_song.beginning_nanosec());
100 ASSERT_EQ(2, second_song.track());
101
102 validate_songs(song_list);
103 }
104
TEST_F(CueParserTest,SkipsBrokenSongs)105 TEST_F(CueParserTest, SkipsBrokenSongs) {
106 QFile file(":testdata/brokensong.cue");
107 file.open(QIODevice::ReadOnly);
108
109 SongList song_list = parser_.Load(&file, "", QDir(""));
110
111 // two songs (the broken one is not in the list)
112 ASSERT_EQ(2, song_list.size());
113
114 // with the specified metadata
115 Song first_song = song_list.at(0);
116 Song second_song = song_list.at(1);
117
118 ASSERT_EQ("Un soffio caldo", first_song.title());
119 ASSERT_EQ("Chocabeck", first_song.album());
120 ASSERT_EQ("Zucchero himself", first_song.artist());
121 ASSERT_EQ("Zucchero himself", first_song.albumartist());
122 ASSERT_EQ(to_nanosec(0, 1, 0), first_song.beginning_nanosec());
123 // includes the broken song too; this entry will span from it's
124 // INDEX (beginning) to the end of the next correct song
125 ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
126 ASSERT_EQ(1, first_song.track());
127
128 ASSERT_EQ("Somewon Else's Tears", second_song.title());
129 ASSERT_EQ("Chocabeck", second_song.album());
130 ASSERT_EQ("Zucchero himself", second_song.artist());
131 ASSERT_EQ("Zucchero himself", second_song.albumartist());
132 ASSERT_EQ(to_nanosec(5, 0, 0), second_song.beginning_nanosec());
133 ASSERT_EQ(2, second_song.track());
134
135 validate_songs(song_list);
136 }
137
TEST_F(CueParserTest,UsesAllMetadataInformation)138 TEST_F(CueParserTest, UsesAllMetadataInformation) {
139 QFile file(":testdata/fullmetadata.cue");
140 file.open(QIODevice::ReadOnly);
141
142 SongList song_list = parser_.Load(&file, "", QDir(""));
143
144 // two songs
145 ASSERT_EQ(2, song_list.size());
146
147 // with the specified metadata
148 Song first_song = song_list.at(0);
149 Song second_song = song_list.at(1);
150
151 ASSERT_TRUE(first_song.url().toString().endsWith("a_file.mp3"));
152 ASSERT_EQ("Un soffio caldo", first_song.title());
153 ASSERT_EQ("Album", first_song.album());
154 ASSERT_EQ("Zucchero", first_song.artist());
155 ASSERT_EQ("Zucchero himself", first_song.albumartist());
156 ASSERT_EQ("Some guy", first_song.composer());
157 ASSERT_EQ(to_nanosec(0, 1, 0), first_song.beginning_nanosec());
158 ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
159 ASSERT_EQ(1, first_song.track());
160
161 ASSERT_TRUE(second_song.url().toString().endsWith("a_file.mp3"));
162 ASSERT_EQ("Hey you!", second_song.title());
163 ASSERT_EQ("Album", second_song.album());
164 ASSERT_EQ("Zucchero himself", second_song.artist());
165 ASSERT_EQ("Zucchero himself", second_song.albumartist());
166 ASSERT_EQ("Some other guy", second_song.composer());
167 ASSERT_EQ(to_nanosec(0, 2, 0), second_song.beginning_nanosec());
168 ASSERT_EQ(2, second_song.track());
169
170 validate_songs(song_list);
171 }
172
TEST_F(CueParserTest,AcceptsMultipleFileBasedCues)173 TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
174 QFile file(":testdata/manyfiles.cue");
175 file.open(QIODevice::ReadOnly);
176
177 SongList song_list = parser_.Load(&file, "CUEPATH", QDir(""));
178
179 // five songs
180 ASSERT_EQ(5, song_list.size());
181
182 // with the specified metadata
183 Song first_song = song_list.at(0);
184 Song second_song = song_list.at(1);
185 Song third_song = song_list.at(2);
186 Song fourth_song = song_list.at(3);
187 Song fifth_song = song_list.at(4);
188
189 ASSERT_TRUE(first_song.url().toString().endsWith("files/longer_one.mp3"));
190 ASSERT_EQ("A1Song1", first_song.title());
191 ASSERT_EQ("Artist One Album", first_song.album());
192 ASSERT_EQ("Artist One", first_song.artist());
193 ASSERT_EQ("Artist One", first_song.albumartist());
194 ASSERT_EQ(to_nanosec(0, 1, 0), first_song.beginning_nanosec());
195 ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
196 ASSERT_EQ(-1, first_song.track());
197 ASSERT_EQ("CUEPATH", first_song.cue_path());
198
199 ASSERT_TRUE(second_song.url().toString().endsWith("files/longer_one.mp3"));
200 ASSERT_EQ("A1Song2", second_song.title());
201 ASSERT_EQ("Artist One Album", second_song.album());
202 ASSERT_EQ("Artist One", second_song.artist());
203 ASSERT_EQ("Artist One", second_song.albumartist());
204 ASSERT_EQ(to_nanosec(5, 3, 68), second_song.beginning_nanosec());
205 ASSERT_EQ(-1, second_song.track());
206
207 ASSERT_TRUE(third_song.url().toString().endsWith("files/longer_two_p1.mp3"));
208 ASSERT_EQ("A2P1Song1", third_song.title());
209 ASSERT_EQ("Artist Two Album", third_song.album());
210 ASSERT_EQ("Artist X", third_song.artist());
211 ASSERT_EQ("Artist Two", third_song.albumartist());
212 ASSERT_EQ(to_nanosec(0, 0, 12), third_song.beginning_nanosec());
213 ASSERT_EQ(fourth_song.beginning_nanosec() - third_song.beginning_nanosec(), third_song.length_nanosec());
214 ASSERT_EQ(-1, third_song.track());
215 ASSERT_EQ("CUEPATH", third_song.cue_path());
216
217 ASSERT_TRUE(fourth_song.url().toString().endsWith("files/longer_two_p1.mp3"));
218 ASSERT_EQ("A2P1Song2", fourth_song.title());
219 ASSERT_EQ("Artist Two Album", fourth_song.album());
220 ASSERT_EQ("Artist Two", fourth_song.artist());
221 ASSERT_EQ("Artist Two", fourth_song.albumartist());
222 ASSERT_EQ(to_nanosec(4, 0, 13), fourth_song.beginning_nanosec());
223 ASSERT_EQ(-1, fourth_song.track());
224
225 ASSERT_TRUE(fifth_song.url().toString().endsWith("files/longer_two_p2.mp3"));
226 ASSERT_EQ("A2P2Song1", fifth_song.title());
227 ASSERT_EQ("Artist Two Album", fifth_song.album());
228 ASSERT_EQ("Artist Two", fifth_song.artist());
229 ASSERT_EQ("Artist Two", fifth_song.albumartist());
230 ASSERT_EQ(to_nanosec(0, 1, 0), fifth_song.beginning_nanosec());
231 ASSERT_EQ(-1, fifth_song.track());
232 ASSERT_EQ("CUEPATH", fifth_song.cue_path());
233
234 validate_songs(song_list);
235 }
236
TEST_F(CueParserTest,SkipsBrokenSongsInMultipleFileBasedCues)237 TEST_F(CueParserTest, SkipsBrokenSongsInMultipleFileBasedCues) {
238 QFile file(":testdata/manyfilesbroken.cue");
239 file.open(QIODevice::ReadOnly);
240
241 SongList song_list = parser_.Load(&file, "", QDir(""));
242
243 // four songs
244 ASSERT_EQ(4, song_list.size());
245
246 // with the specified metadata
247 Song first_song = song_list.at(0);
248 Song second_song = song_list.at(1);
249 Song third_song = song_list.at(2);
250 Song fourth_song = song_list.at(3);
251
252 // A* - broken song in the middle
253 ASSERT_TRUE(first_song.url().toString().endsWith("file1.mp3"));
254 ASSERT_EQ("Artist One", first_song.artist());
255 ASSERT_EQ("Artist One Album", first_song.album());
256 ASSERT_EQ("A1", first_song.title());
257 ASSERT_EQ(to_nanosec(0, 1, 15), first_song.beginning_nanosec());
258 ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
259 ASSERT_EQ(-1, first_song.track());
260
261 ASSERT_TRUE(second_song.url().toString().endsWith("file1.mp3"));
262 ASSERT_EQ("Artist One", second_song.artist());
263 ASSERT_EQ("Artist One Album", second_song.album());
264 ASSERT_EQ("A3", second_song.title());
265 ASSERT_EQ(to_nanosec(1, 0, 16), second_song.beginning_nanosec());
266 ASSERT_EQ(-1, second_song.track());
267
268 // all B* songs are broken
269
270 // C* - broken song at the end
271 ASSERT_TRUE(third_song.url().toString().endsWith("file3.mp3"));
272 ASSERT_EQ("Artist Three", third_song.artist());
273 ASSERT_EQ("Artist Three Album", third_song.album());
274 ASSERT_EQ("C1", third_song.title());
275 ASSERT_EQ(to_nanosec(0, 1, 0), third_song.beginning_nanosec());
276 ASSERT_EQ(-1, third_song.track());
277
278 // D* - broken song at the beginning
279 ASSERT_TRUE(fourth_song.url().toString().endsWith("file4.mp3"));
280 ASSERT_EQ("Artist Four", fourth_song.artist());
281 ASSERT_EQ("Artist Four Album", fourth_song.album());
282 ASSERT_EQ("D2", fourth_song.title());
283 ASSERT_EQ(to_nanosec(15, 55, 66), fourth_song.beginning_nanosec());
284 ASSERT_EQ(-1, fourth_song.track());
285
286 validate_songs(song_list);
287 }
288
TEST_F(CueParserTest,SkipsDataFiles)289 TEST_F(CueParserTest, SkipsDataFiles) {
290 QFile file(":testdata/withdatafiles.cue");
291 file.open(QIODevice::ReadOnly);
292
293 SongList song_list = parser_.Load(&file, "", QDir(""));
294
295 // two songs
296 ASSERT_EQ(2, song_list.size());
297
298 // with the specified metadata
299 Song first_song = song_list.at(0);
300 Song second_song = song_list.at(1);
301
302 ASSERT_TRUE(first_song.url().toString().endsWith("file1.mp3"));
303 ASSERT_EQ("Artist One", first_song.artist());
304 ASSERT_EQ("Artist One Album", first_song.album());
305 ASSERT_EQ("A1", first_song.title());
306 ASSERT_EQ(to_nanosec(0, 1, 0), first_song.beginning_nanosec());
307 ASSERT_EQ(-1, first_song.track());
308
309 ASSERT_TRUE(second_song.url().toString().endsWith("file4.mp3"));
310 ASSERT_EQ("Artist Four", second_song.artist());
311 ASSERT_EQ("Artist Four Album", second_song.album());
312 ASSERT_EQ("D1", second_song.title());
313 ASSERT_EQ(to_nanosec(1, 1, 0), second_song.beginning_nanosec());
314 ASSERT_EQ(-1, second_song.track());
315
316 validate_songs(song_list);
317 }
318