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 #include "gmock/gmock-matchers.h"
19 #include "gtest/gtest.h"
20 #include "test_utils.h"
21
22 #include "core/timeconstants.h"
23 #include "playlistparsers/m3uparser.h"
24
25 #include <QBuffer>
26 #include <QTemporaryFile>
27
28 using ::testing::HasSubstr;
29
30 class M3UParserTest : public ::testing::Test {
31 protected:
M3UParserTest()32 M3UParserTest()
33 : parser_(nullptr) {
34 }
35
36 M3UParser parser_;
37 };
38
TEST_F(M3UParserTest,ParsesMetadata)39 TEST_F(M3UParserTest, ParsesMetadata) {
40 QString line("#EXTINF:123,Foo artist - Foo track");
41 M3UParser::Metadata metadata;
42 ASSERT_TRUE(parser_.ParseMetadata(line, &metadata));
43 EXPECT_EQ("Foo artist", metadata.artist.toStdString());
44 EXPECT_EQ("Foo track", metadata.title.toStdString());
45 EXPECT_EQ(123 * kNsecPerSec, metadata.length);
46 }
47
TEST_F(M3UParserTest,ParsesTrackLocation)48 TEST_F(M3UParserTest, ParsesTrackLocation) {
49 QTemporaryFile temp;
50 temp.open();
51 taglib_.ExpectCall(temp.fileName(), "foo", "bar", "baz");
52 Song song(&taglib_);
53 QString line(temp.fileName());
54 parser_.LoadSong(line, 0, QDir(), &song);
55 ASSERT_EQ(QUrl::fromLocalFile(temp.fileName()), song.url());
56
57 song.InitFromFile(song.url().toLocalFile(), -1);
58
59 EXPECT_EQ("foo", song.title());
60 EXPECT_EQ("bar", song.artist());
61 EXPECT_EQ("baz", song.album());
62 }
63
TEST_F(M3UParserTest,ParsesTrackLocationRelative)64 TEST_F(M3UParserTest, ParsesTrackLocationRelative) {
65 QTemporaryFile temp;
66 temp.open();
67 QFileInfo info(temp);
68 taglib_.ExpectCall(temp.fileName(), "foo", "bar", "baz");
69 M3UParser parser(nullptr);
70 QString line(info.fileName());
71 Song song(&taglib_);
72 parser.LoadSong(line, 0, info.dir(), &song);
73 ASSERT_EQ(QUrl::fromLocalFile(temp.fileName()), song.url());
74
75 song.InitFromFile(song.url().toLocalFile(), -1);
76
77 EXPECT_EQ("foo", song.title());
78 }
79
TEST_F(M3UParserTest,ParsesTrackLocationHttp)80 TEST_F(M3UParserTest, ParsesTrackLocationHttp) {
81 QString line("http://example.com/foo/bar.mp3");
82 Song song;
83 parser_.LoadSong(line, 0, QDir(), &song);
84 EXPECT_EQ(QUrl("http://example.com/foo/bar.mp3"), song.url());
85 }
86
TEST_F(M3UParserTest,ParsesSongsFromDevice)87 TEST_F(M3UParserTest, ParsesSongsFromDevice) {
88 QByteArray data = "#EXTM3U\n"
89 "#EXTINF:123,Some Artist - Some Title\n"
90 "http://foo.com/bar/somefile.mp3\n";
91 QBuffer buffer(&data);
92 buffer.open(QIODevice::ReadOnly);
93 M3UParser parser(nullptr);
94 SongList songs = parser.Load(&buffer);
95 ASSERT_EQ(1, songs.size());
96 Song s = songs[0];
97 EXPECT_EQ("Some Artist", s.artist());
98 EXPECT_EQ("Some Title", s.title());
99 EXPECT_EQ(123 * kNsecPerSec, s.length_nanosec());
100 EXPECT_EQ(QUrl("http://foo.com/bar/somefile.mp3"), s.url());
101 }
102
TEST_F(M3UParserTest,ParsesNonExtendedM3U)103 TEST_F(M3UParserTest, ParsesNonExtendedM3U) {
104 QByteArray data = "http://foo.com/bar/somefile.mp3\n"
105 "http://baz.com/thing.mp3\n";
106 QBuffer buffer(&data);
107 buffer.open(QIODevice::ReadOnly);
108 M3UParser parser(nullptr);
109 SongList songs = parser.Load(&buffer, "", QDir("somedir"));
110 ASSERT_EQ(2, songs.size());
111 EXPECT_EQ(QUrl("http://foo.com/bar/somefile.mp3"), songs[0].url());
112 EXPECT_EQ(QUrl("http://baz.com/thing.mp3"), songs[1].url());
113 EXPECT_EQ(-1, songs[0].length_nanosec());
114 EXPECT_EQ(-1, songs[1].length_nanosec());
115 EXPECT_TRUE(songs[0].artist().isEmpty());
116 }
117
TEST_F(M3UParserTest,ParsesActualM3U)118 TEST_F(M3UParserTest, ParsesActualM3U) {
119 QFile file(":testdata/test.m3u");
120 file.open(QIODevice::ReadOnly);
121 M3UParser parser(nullptr);
122 SongList songs = parser.Load(&file, "", QDir("somedir"));
123 ASSERT_EQ(239, songs.size());
124 EXPECT_EQ("gravity", songs[0].title());
125 EXPECT_EQ(203 * kNsecPerSec, songs[0].length_nanosec());
126 EXPECT_EQ(QString::fromUtf8("ほっぴンちょっぴン"), songs.back().title());
127 EXPECT_EQ(85 * kNsecPerSec, songs.back().length_nanosec());
128 }
129
TEST_F(M3UParserTest,SavesSong)130 TEST_F(M3UParserTest, SavesSong) {
131 QByteArray data;
132 QBuffer buffer(&data);
133 buffer.open(QIODevice::WriteOnly);
134 Song one;
135 one.set_filetype(Song::Type_Stream);
136 one.set_title("foo");
137 one.set_artist("bar");
138 one.set_length_nanosec(123 * kNsecPerSec);
139 one.set_url(QUrl("http://www.example.com/foo.mp3"));
140 SongList songs;
141 songs << one;
142 M3UParser parser(nullptr);
143 parser.Save(songs, &buffer);
144 EXPECT_THAT(data.constData(), HasSubstr("#EXTM3U"));
145 EXPECT_THAT(data.constData(), HasSubstr("#EXTINF:123,bar - foo"));
146 EXPECT_THAT(data.constData(), HasSubstr("http://www.example.com/foo.mp3"));
147 }
148
TEST_F(M3UParserTest,ParsesUTF8)149 TEST_F(M3UParserTest, ParsesUTF8) {
150 QByteArray data = "#EXTM3U\n"
151 "#EXTINF:123,Разные - исполнители\n"
152 "/foo/Разные/исполнители.mp3\n";
153 QBuffer buffer(&data);
154 buffer.open(QIODevice::ReadOnly);
155 M3UParser parser(nullptr);
156 SongList songs = parser.Load(&buffer);
157 ASSERT_EQ(1, songs.length());
158 EXPECT_EQ(6, songs[0].artist().length());
159 EXPECT_EQ(11, songs[0].title().length());
160 EXPECT_EQ(QString::fromUtf8("Разные"), songs[0].artist());
161 EXPECT_EQ(QString::fromUtf8("исполнители"), songs[0].title());
162 EXPECT_EQ(QUrl::fromLocalFile(QString::fromUtf8("/foo/Разные/исполнители.mp3")),
163 songs[0].url());
164 }
165