Use nanoseconds in playlist parsers, and fix the tests

This commit is contained in:
David Sansome 2011-02-13 18:35:26 +00:00
parent 507c5e2632
commit 3a1853a681
13 changed files with 58 additions and 55 deletions

View File

@ -317,7 +317,7 @@ qint64 CueParser::IndexToMarker(const QString& index) const {
QStringList splitted = index_regexp.capturedTexts().mid(1, -1);
// TODO: use frames when #1166 is fixed
return splitted.at(0).toLongLong() * 60 + splitted.at(1).toLongLong();
return (splitted.at(0).toLongLong() * 60 + splitted.at(1).toLongLong()) * 1e9;
}
void CueParser::Save(const SongList &songs, QIODevice *device, const QDir &dir) const {

View File

@ -100,7 +100,7 @@ bool M3UParser::ParseMetadata(const QString& line, M3UParser::Metadata* metadata
if (!ok) {
return false;
}
metadata->length = length;
metadata->length = length * 1e9;
QString track_info = info.section(',', 1);
QStringList list = track_info.split('-');
@ -120,7 +120,7 @@ void M3UParser::Save(const SongList &songs, QIODevice *device, const QDir &dir)
continue;
}
QString meta = QString("#EXTINF:%1,%2 - %3\n")
.arg(song.length_nanosec())
.arg(song.length_nanosec() / 1e9)
.arg(song.artist()).arg(song.title());
device->write(meta.toUtf8());
device->write(MakeRelativeTo(song.filename(), dir).toUtf8());

View File

@ -50,7 +50,7 @@ class M3UParser : public ParserBase {
Metadata() : length(-1) {}
QString artist;
QString title;
int length;
qint64 length;
};
bool ParseMetadata(const QString& line, Metadata* metadata) const;

View File

@ -52,7 +52,10 @@ SongList PLSParser::Load(QIODevice *device, const QString& playlist_path, const
} else if (key.startsWith("title")) {
songs[n].set_title(value);
} else if (key.startsWith("length")) {
songs[n].set_length_nanosec(value.toLongLong() * 1e9);
qint64 seconds = value.toLongLong();
if (seconds > 0) {
songs[n].set_length_nanosec(seconds * 1e9);
}
}
}

View File

@ -50,7 +50,7 @@ SongList XSPFParser::Load(QIODevice *device, const QString& playlist_path, const
Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
Song song;
QString title, artist, album;
int length = -1;
qint64 nanosec = -1;
while (!reader->atEnd()) {
QXmlStreamReader::TokenType type = reader->readNext();
switch (type) {
@ -84,9 +84,9 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
} else if (name == "duration") { // in milliseconds.
const QString& duration = reader->readElementText();
bool ok = false;
length = duration.toInt(&ok) / 1000;
nanosec = duration.toInt(&ok) * 1e6;
if (!ok) {
length = -1;
nanosec = -1;
}
} else if (name == "image") {
// TODO: Fetch album covers.
@ -97,7 +97,7 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
}
case QXmlStreamReader::EndElement: {
if (reader->name() == "track") {
song.Init(title, artist, album, length);
song.Init(title, artist, album, nanosec);
return song;
}
}
@ -106,7 +106,7 @@ Song XSPFParser::ParseTrack(QXmlStreamReader* reader) const {
}
}
// At least make an effort if we never find a </track>.
song.Init(title, artist, album, length);
song.Init(title, artist, album, nanosec);
return song;
}

View File

@ -102,7 +102,7 @@ TEST_F(ASXParserTest, SavesSong) {
one.set_filename("http://www.example.com/foo.mp3");
one.set_filetype(Song::Type_Stream);
one.set_title("foo");
one.set_length(123);
one.set_length_nanosec(123 * 1e9);
one.set_artist("bar");
SongList songs;
songs << one;

View File

@ -63,7 +63,7 @@ TEST_F(CueParserTest, ParsesASong) {
ASSERT_EQ("Zucchero", first_song.artist());
ASSERT_EQ("Zucchero himself", first_song.albumartist());
ASSERT_EQ("", first_song.album());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(1, first_song.track());
ASSERT_EQ("CUEPATH", first_song.cue_path());
@ -87,15 +87,15 @@ TEST_F(CueParserTest, ParsesTwoSongs) {
ASSERT_EQ("Chocabeck", first_song.album());
ASSERT_EQ("Zucchero himself", first_song.artist());
ASSERT_EQ("Zucchero himself", first_song.albumartist());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
ASSERT_EQ(1, first_song.track());
ASSERT_EQ("Somewon Else's Tears", second_song.title());
ASSERT_EQ("Chocabeck", second_song.album());
ASSERT_EQ("Zucchero himself", second_song.artist());
ASSERT_EQ("Zucchero himself", second_song.albumartist());
ASSERT_EQ(5 * 60 + 3, second_song.beginning());
ASSERT_EQ((5 * 60 + 3) * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(2, second_song.track());
validate_songs(song_list);
@ -118,17 +118,17 @@ TEST_F(CueParserTest, SkipsBrokenSongs) {
ASSERT_EQ("Chocabeck", first_song.album());
ASSERT_EQ("Zucchero himself", first_song.artist());
ASSERT_EQ("Zucchero himself", first_song.albumartist());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
// includes the broken song too; this entry will span from it's
// INDEX (beginning) to the end of the next correct song
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
ASSERT_EQ(1, first_song.track());
ASSERT_EQ("Somewon Else's Tears", second_song.title());
ASSERT_EQ("Chocabeck", second_song.album());
ASSERT_EQ("Zucchero himself", second_song.artist());
ASSERT_EQ("Zucchero himself", second_song.albumartist());
ASSERT_EQ(5 * 60, second_song.beginning());
ASSERT_EQ((5 * 60) * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(2, second_song.track());
validate_songs(song_list);
@ -153,8 +153,8 @@ TEST_F(CueParserTest, UsesAllMetadataInformation) {
ASSERT_EQ("Zucchero", first_song.artist());
ASSERT_EQ("Zucchero himself", first_song.albumartist());
ASSERT_EQ("Some guy", first_song.composer());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
ASSERT_EQ(1, first_song.track());
ASSERT_TRUE(second_song.filename().endsWith("a_file.mp3"));
@ -163,7 +163,7 @@ TEST_F(CueParserTest, UsesAllMetadataInformation) {
ASSERT_EQ("Zucchero himself", second_song.artist());
ASSERT_EQ("Zucchero himself", second_song.albumartist());
ASSERT_EQ("Some other guy", second_song.composer());
ASSERT_EQ(2, second_song.beginning());
ASSERT_EQ(2 * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(2, second_song.track());
validate_songs(song_list);
@ -190,8 +190,8 @@ TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
ASSERT_EQ("Artist One Album", first_song.album());
ASSERT_EQ("Artist One", first_song.artist());
ASSERT_EQ("Artist One", first_song.albumartist());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
ASSERT_EQ(-1, first_song.track());
ASSERT_EQ("CUEPATH", first_song.cue_path());
@ -200,7 +200,7 @@ TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
ASSERT_EQ("Artist One Album", second_song.album());
ASSERT_EQ("Artist One", second_song.artist());
ASSERT_EQ("Artist One", second_song.albumartist());
ASSERT_EQ((5 * 60 + 3), second_song.beginning());
ASSERT_EQ((5 * 60 + 3) * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(-1, second_song.track());
ASSERT_TRUE(third_song.filename().endsWith("files/longer_two_p1.mp3"));
@ -208,8 +208,8 @@ TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
ASSERT_EQ("Artist Two Album", third_song.album());
ASSERT_EQ("Artist X", third_song.artist());
ASSERT_EQ("Artist Two", third_song.albumartist());
ASSERT_EQ(0, third_song.beginning());
ASSERT_EQ(fourth_song.beginning() - third_song.beginning(), third_song.length());
ASSERT_EQ(0, third_song.beginning_nanosec());
ASSERT_EQ(fourth_song.beginning_nanosec() - third_song.beginning_nanosec(), third_song.length_nanosec());
ASSERT_EQ(-1, third_song.track());
ASSERT_EQ("CUEPATH", third_song.cue_path());
@ -218,7 +218,7 @@ TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
ASSERT_EQ("Artist Two Album", fourth_song.album());
ASSERT_EQ("Artist Two", fourth_song.artist());
ASSERT_EQ("Artist Two", fourth_song.albumartist());
ASSERT_EQ(4 * 60, fourth_song.beginning());
ASSERT_EQ((4 * 60) * 1e9, fourth_song.beginning_nanosec());
ASSERT_EQ(-1, fourth_song.track());
ASSERT_TRUE(fifth_song.filename().endsWith("files/longer_two_p2.mp3"));
@ -226,7 +226,7 @@ TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
ASSERT_EQ("Artist Two Album", fifth_song.album());
ASSERT_EQ("Artist Two", fifth_song.artist());
ASSERT_EQ("Artist Two", fifth_song.albumartist());
ASSERT_EQ(1, fifth_song.beginning());
ASSERT_EQ(1 * 1e9, fifth_song.beginning_nanosec());
ASSERT_EQ(-1, fifth_song.track());
ASSERT_EQ("CUEPATH", fifth_song.cue_path());
@ -253,15 +253,15 @@ TEST_F(CueParserTest, SkipsBrokenSongsInMultipleFileBasedCues) {
ASSERT_EQ("Artist One", first_song.artist());
ASSERT_EQ("Artist One Album", first_song.album());
ASSERT_EQ("A1", first_song.title());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(second_song.beginning_nanosec() - first_song.beginning_nanosec(), first_song.length_nanosec());
ASSERT_EQ(-1, first_song.track());
ASSERT_TRUE(second_song.filename().endsWith("file1.mp3"));
ASSERT_EQ("Artist One", second_song.artist());
ASSERT_EQ("Artist One Album", second_song.album());
ASSERT_EQ("A3", second_song.title());
ASSERT_EQ(60, second_song.beginning());
ASSERT_EQ(60 * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(-1, second_song.track());
// all B* songs are broken
@ -271,7 +271,7 @@ TEST_F(CueParserTest, SkipsBrokenSongsInMultipleFileBasedCues) {
ASSERT_EQ("Artist Three", third_song.artist());
ASSERT_EQ("Artist Three Album", third_song.album());
ASSERT_EQ("C1", third_song.title());
ASSERT_EQ(1, third_song.beginning());
ASSERT_EQ(1 * 1e9, third_song.beginning_nanosec());
ASSERT_EQ(-1, third_song.track());
// D* - broken song at the beginning
@ -279,7 +279,7 @@ TEST_F(CueParserTest, SkipsBrokenSongsInMultipleFileBasedCues) {
ASSERT_EQ("Artist Four", fourth_song.artist());
ASSERT_EQ("Artist Four Album", fourth_song.album());
ASSERT_EQ("D2", fourth_song.title());
ASSERT_EQ(61, fourth_song.beginning());
ASSERT_EQ(61 * 1e9, fourth_song.beginning_nanosec());
ASSERT_EQ(-1, fourth_song.track());
validate_songs(song_list);
@ -302,14 +302,14 @@ TEST_F(CueParserTest, SkipsDataFiles) {
ASSERT_EQ("Artist One", first_song.artist());
ASSERT_EQ("Artist One Album", first_song.album());
ASSERT_EQ("A1", first_song.title());
ASSERT_EQ(1, first_song.beginning());
ASSERT_EQ(1 * 1e9, first_song.beginning_nanosec());
ASSERT_EQ(-1, first_song.track());
ASSERT_TRUE(second_song.filename().endsWith("file4.mp3"));
ASSERT_EQ("Artist Four", second_song.artist());
ASSERT_EQ("Artist Four Album", second_song.album());
ASSERT_EQ("D1", second_song.title());
ASSERT_EQ(61, second_song.beginning());
ASSERT_EQ(61 * 1e9, second_song.beginning_nanosec());
ASSERT_EQ(-1, second_song.track());
validate_songs(song_list);

View File

@ -47,7 +47,7 @@ TEST_F(M3UParserTest, ParsesMetadata) {
ASSERT_TRUE(parser_.ParseMetadata(line, &metadata));
EXPECT_EQ("Foo artist", metadata.artist.toStdString());
EXPECT_EQ("Foo track", metadata.title.toStdString());
EXPECT_EQ(123, metadata.length);
EXPECT_EQ(123 * 1e9, metadata.length);
}
TEST_F(M3UParserTest, ParsesTrackLocation) {
@ -101,7 +101,7 @@ TEST_F(M3UParserTest, ParsesSongsFromDevice) {
Song s = songs[0];
EXPECT_EQ("Some Artist", s.artist());
EXPECT_EQ("Some Title", s.title());
EXPECT_EQ(123, s.length());
EXPECT_EQ(123 * 1e9, s.length_nanosec());
EXPECT_PRED_FORMAT2(::testing::IsSubstring,
"http://foo.com/bar/somefile.mp3", s.filename().toStdString());
}
@ -118,8 +118,8 @@ TEST_F(M3UParserTest, ParsesNonExtendedM3U) {
"http://foo.com/bar/somefile.mp3", songs[0].filename().toStdString());
EXPECT_PRED_FORMAT2(::testing::IsSubstring,
"http://baz.com/thing.mp3", songs[1].filename().toStdString());
EXPECT_EQ(-1, songs[0].length());
EXPECT_EQ(-1, songs[1].length());
EXPECT_EQ(-1, songs[0].length_nanosec());
EXPECT_EQ(-1, songs[1].length_nanosec());
EXPECT_TRUE(songs[0].artist().isEmpty());
}
@ -130,9 +130,9 @@ TEST_F(M3UParserTest, ParsesActualM3U) {
SongList songs = parser.Load(&file, "", QDir("somedir"));
ASSERT_EQ(239, songs.size());
EXPECT_EQ("gravity", songs[0].title());
EXPECT_EQ(203, songs[0].length());
EXPECT_EQ(203 * 1e9, songs[0].length_nanosec());
EXPECT_EQ(QString::fromUtf8("ほっぴンちょっぴン"), songs.back().title());
EXPECT_EQ(85, songs.back().length());
EXPECT_EQ(85 * 1e9, songs.back().length_nanosec());
}
TEST_F(M3UParserTest, SavesSong) {
@ -143,7 +143,7 @@ TEST_F(M3UParserTest, SavesSong) {
one.set_filetype(Song::Type_Stream);
one.set_title("foo");
one.set_artist("bar");
one.set_length(123);
one.set_length_nanosec(123 * 1e9);
one.set_filename("http://www.example.com/foo.mp3");
SongList songs;
songs << one;

View File

@ -52,7 +52,7 @@ class MockLibraryBackend : public LibraryBackendInterface {
MOCK_METHOD1(GetSongById, Song(int));
MOCK_METHOD1(GetSongsByFilename, SongList(const QString&));
MOCK_METHOD2(GetSongByFilename, Song(const QString&, int));
MOCK_METHOD2(GetSongByFilename, Song(const QString&, qint64));
MOCK_METHOD1(AddDirectory, void(const QString&));
MOCK_METHOD1(RemoveDirectory, void(const Directory&));

View File

@ -37,7 +37,7 @@ TEST_F(OrganiseFormatTest, BasicReplace) {
song_.set_composer("composer");
song_.set_disc(789);
song_.set_genre("genre");
song_.set_length(987);
song_.set_length_nanosec(987 * 1e9);
song_.set_samplerate(654);
song_.set_title("title");
song_.set_track(321);

View File

@ -50,7 +50,7 @@ TEST_F(PLSParserTest, ParseOneTrack) {
ASSERT_EQ(1, songs.length());
EXPECT_EQ("/relative/to/filename with spaces.mp3", songs[0].filename());
EXPECT_EQ("Title", songs[0].title());
EXPECT_EQ(123, songs[0].length());
EXPECT_EQ(123 * 1e9, songs[0].length_nanosec());
}
TEST_F(PLSParserTest, ParseSomaFM) {
@ -65,7 +65,7 @@ TEST_F(PLSParserTest, ParseSomaFM) {
EXPECT_EQ("SomaFM: Groove Salad (#1 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[0].title());
EXPECT_EQ("SomaFM: Groove Salad (#2 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[1].title());
EXPECT_EQ("SomaFM: Groove Salad (#3 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[2].title());
EXPECT_EQ(-1, songs[0].length());
EXPECT_EQ(-1, songs[0].length_nanosec());
EXPECT_EQ(Song::Type_Stream, songs[0].filetype());
}
@ -81,7 +81,7 @@ TEST_F(PLSParserTest, ParseSomaFM2) {
EXPECT_EQ("SomaFM: Secret Agent (#1 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[0].title());
EXPECT_EQ("SomaFM: Secret Agent (#2 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[1].title());
EXPECT_EQ("SomaFM: Secret Agent (#3 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[2].title());
EXPECT_EQ(-1, songs[0].length());
EXPECT_EQ(-1, songs[0].length_nanosec());
EXPECT_EQ(Song::Type_Stream, songs[0].filetype());
}
@ -93,7 +93,7 @@ TEST_F(PLSParserTest, SaveAndLoad) {
Song two;
two.set_filename("relative/bar.mp3");
two.set_title("Bar");
two.set_length(123);
two.set_length_nanosec(123 * 1e9);
SongList songs;
songs << one << two;
@ -110,6 +110,6 @@ TEST_F(PLSParserTest, SaveAndLoad) {
EXPECT_EQ("/meep/relative/bar.mp3", songs[1].filename());
EXPECT_EQ(one.title(), songs[0].title());
EXPECT_EQ(two.title(), songs[1].title());
EXPECT_EQ(one.length(), songs[0].length());
EXPECT_EQ(two.length(), songs[1].length());
EXPECT_EQ(one.length_nanosec(), songs[0].length_nanosec());
EXPECT_EQ(two.length_nanosec(), songs[1].length_nanosec());
}

View File

@ -111,7 +111,7 @@ TEST_F(SongLoaderTest, LoadLocalPls) {
// Check the song got loaded
ASSERT_EQ(1, loader_->songs().count());
EXPECT_EQ("Title", loader_->songs()[0].title());
EXPECT_EQ(123, loader_->songs()[0].length());
EXPECT_EQ(123 * 1e9, loader_->songs()[0].length_nanosec());
}
TEST_F(SongLoaderTest, LoadLocalM3U) {

View File

@ -50,7 +50,7 @@ TEST_F(XSPFParserTest, ParsesOneTrackFromXML) {
EXPECT_EQ("Bar", song.artist());
EXPECT_EQ("Baz", song.album());
EXPECT_EQ("http://example.com/foo.mp3", song.filename());
EXPECT_EQ(60, song.length());
EXPECT_EQ(60 * 1e9, song.length_nanosec());
EXPECT_TRUE(song.is_valid());
}
@ -91,7 +91,7 @@ TEST_F(XSPFParserTest, IgnoresInvalidLength) {
XSPFParser parser(NULL);
SongList songs = parser.Load(&buffer);
ASSERT_EQ(1, songs.length());
EXPECT_EQ(-1, songs[0].length());
EXPECT_EQ(-1, songs[0].length_nanosec());
}
TEST_F(XSPFParserTest, SavesSong) {
@ -103,7 +103,7 @@ TEST_F(XSPFParserTest, SavesSong) {
one.set_filename("http://www.example.com/foo.mp3");
one.set_filetype(Song::Type_Stream);
one.set_title("foo");
one.set_length(123);
one.set_length_nanosec(123 * 1e9);
one.set_artist("bar");
SongList songs;
songs << one;
@ -124,7 +124,7 @@ TEST_F(XSPFParserTest, SavesLocalFile) {
one.set_filename("/bar/foo.mp3");
one.set_filetype(Song::Type_Mpeg);
one.set_title("foo");
one.set_length(123);
one.set_length_nanosec(123 * 1e9);
one.set_artist("bar");
SongList songs;
songs << one;