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