diff --git a/src/playlist.cpp b/src/playlist.cpp index cea75abbd..c65f52de6 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -523,7 +523,7 @@ Song Playlist::current_item_metadata() const { } void Playlist::UpdateScrobblePoint() { - int length = current_item_metadata().length(); + int length = qMin(current_item_metadata().length(), 240); ScrobblePoint point(length / 2); scrobble_point_ = point; diff --git a/src/song.cpp b/src/song.cpp index 4adaa93ec..344a24197 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -19,6 +19,9 @@ #include #include +#include +using boost::scoped_ptr; + #include "trackslider.h" #include "enginebase.h" #include "albumcoverloader.h" @@ -45,6 +48,8 @@ const char* Song::kUpdateSpec = "ctime = :ctime, filesize = :filesize, sampler = :sampler, " "art_automatic = :art_automatic, art_manual = :art_manual"; +TagLibFileRefFactory Song::kDefaultFactory; + SongData::SongData() : valid_(false), id_(-1), @@ -64,23 +69,34 @@ SongData::SongData() { } +TagLib::FileRef* TagLibFileRefFactory::GetFileRef(const QString& filename) { + return new TagLib::FileRef(QFile::encodeName(filename).constData()); +} + Song::Song() - : d(new SongData) + : d(new SongData), + factory_(&kDefaultFactory) { } Song::Song(const Song &other) - : d(other.d) + : d(other.d), + factory_(&kDefaultFactory) { } +Song::Song(FileRefFactory* factory) + : d(new SongData), + factory_(factory) { +} + void Song::InitFromFile(const QString& filename, int directory_id) { d->filename_ = filename; d->directory_id_ = directory_id; - TagLib::FileRef fileref(QFile::encodeName(filename).constData()); + scoped_ptr fileref(factory_->GetFileRef(filename)); - if( fileref.isNull() ) + if(fileref->isNull()) return; QFileInfo info(filename); @@ -88,7 +104,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) { d->mtime_ = info.lastModified().toTime_t(); d->ctime_ = info.created().toTime_t(); - TagLib::Tag* tag = fileref.tag(); + TagLib::Tag* tag = fileref->tag(); if (tag) { #define strip(x) TStringToQString( x ).trimmed() d->title_ = strip(tag->title()); @@ -105,7 +121,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) { QString disc; QString compilation; - if (TagLib::MPEG::File* file = dynamic_cast(fileref.file())) { + if (TagLib::MPEG::File* file = dynamic_cast(fileref->file())) { if (file->ID3v2Tag()) { if (!file->ID3v2Tag()->frameListMap()["TPOS"].isEmpty()) disc = TStringToQString(file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString()).trimmed(); @@ -123,7 +139,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) { compilation = TStringToQString(file->ID3v2Tag()->frameListMap()["TCMP"].front()->toString()).trimmed(); } } - else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast(fileref.file())) { + else if (TagLib::Ogg::Vorbis::File* file = dynamic_cast(fileref->file())) { if (file->tag()) { if ( !file->tag()->fieldListMap()["COMPOSER"].isEmpty() ) d->composer_ = TStringToQString(file->tag()->fieldListMap()["COMPOSER"].front()).trimmed(); @@ -138,7 +154,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) { compilation = TStringToQString(file->tag()->fieldListMap()["COMPILATION"].front()).trimmed(); } } - else if (TagLib::FLAC::File* file = dynamic_cast(fileref.file())) { + else if (TagLib::FLAC::File* file = dynamic_cast(fileref->file())) { if ( file->xiphComment() ) { if (!file->xiphComment()->fieldListMap()["COMPOSER"].isEmpty()) d->composer_ = TStringToQString( file->xiphComment()->fieldListMap()["COMPOSER"].front() ).trimmed(); @@ -172,10 +188,10 @@ void Song::InitFromFile(const QString& filename, int directory_id) { d->compilation_ = (i == 1); } - if (fileref.audioProperties()) { - d->bitrate_ = fileref.audioProperties()->bitrate(); - d->length_ = fileref.audioProperties()->length(); - d->samplerate_ = fileref.audioProperties()->sampleRate(); + if (fileref->audioProperties()) { + d->bitrate_ = fileref->audioProperties()->bitrate(); + d->length_ = fileref->audioProperties()->length(); + d->samplerate_ = fileref->audioProperties()->sampleRate(); } } diff --git a/src/song.h b/src/song.h index 46bd4ab4a..490c7ff34 100644 --- a/src/song.h +++ b/src/song.h @@ -15,6 +15,10 @@ namespace lastfm { class Track; } +namespace TagLib { + class FileRef; +} + struct SongData : public QSharedData { SongData(); @@ -52,10 +56,22 @@ struct SongData : public QSharedData { QImage image_; }; +class FileRefFactory { + public: + virtual ~FileRefFactory() {} + virtual TagLib::FileRef* GetFileRef(const QString& filename) = 0; +}; + +class TagLibFileRefFactory : public FileRefFactory { + public: + virtual TagLib::FileRef* GetFileRef(const QString& filename); +}; + class Song { public: Song(); Song(const Song& other); + Song(FileRefFactory* factory); static const char* kColumnSpec; static const char* kBindSpec; @@ -152,6 +168,9 @@ class Song { private: QSharedDataPointer d; + FileRefFactory* factory_; + + static TagLibFileRefFactory kDefaultFactory; }; Q_DECLARE_METATYPE(Song); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b3c906df..17ce0c0e2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,7 +30,8 @@ target_link_libraries(gmock gtest) set(TESTUTILS-SOURCES test_utils.cpp - mock_networkaccessmanager.cpp) + mock_networkaccessmanager.cpp + mock_taglib.cpp) set(TESTUTILS-MOC-HEADERS mock_networkaccessmanager.h) diff --git a/tests/mock_taglib.cpp b/tests/mock_taglib.cpp new file mode 100644 index 000000000..d45a1d006 --- /dev/null +++ b/tests/mock_taglib.cpp @@ -0,0 +1,42 @@ +#include "mock_taglib.h" + +#include + +using ::testing::Return; + +MockFile::MockFile(TagLib::Tag* tag, const QString& filename) + : TagLib::File(QFile::encodeName(filename).constData()), + tag_(tag) { +} + +TagLib::Tag* MockFile::tag() const { + return tag_.get(); +} + +TagLib::AudioProperties* MockFile::audioProperties() const { + return NULL; +} + +bool MockFile::save() { + return true; +} + +void MockFileRefFactory::ExpectCall(const QString& filename, + const QString& title, + const QString& artist, + const QString& album) { + MockTag* tag = new MockTag; + EXPECT_CALL(*tag, title()).WillRepeatedly(Return(title.toStdString())); + EXPECT_CALL(*tag, artist()).WillRepeatedly(Return(artist.toStdString())); + EXPECT_CALL(*tag, album()).WillRepeatedly(Return(album.toStdString())); + tags_[filename] = tag; +} + +TagLib::FileRef* MockFileRefFactory::GetFileRef(const QString& filename) { + MockTag* tag = tags_.take(filename); + QTemporaryFile temp_file; + temp_file.open(); + MockFile* file = new MockFile(tag, temp_file.fileName()); + TagLib::FileRef* fileref = new TagLib::FileRef(file); + return fileref; +} diff --git a/tests/mock_taglib.h b/tests/mock_taglib.h new file mode 100644 index 000000000..37b2b7336 --- /dev/null +++ b/tests/mock_taglib.h @@ -0,0 +1,60 @@ +#ifndef MOCK_TAGLIB_H +#define MOCK_TAGLIB_H + +#include "gmock/gmock.h" + +#include +#include +#include + +#include + +#include "song.h" + +class MockTag : public TagLib::Tag { + public: + MOCK_CONST_METHOD0(title, TagLib::String()); + MOCK_CONST_METHOD0(artist, TagLib::String()); + MOCK_CONST_METHOD0(album, TagLib::String()); + MOCK_CONST_METHOD0(comment, TagLib::String()); + MOCK_CONST_METHOD0(genre, TagLib::String()); + MOCK_METHOD1(setTitle, void(const TagLib::String&)); + MOCK_METHOD1(setArtist, void(const TagLib::String&)); + MOCK_METHOD1(setAlbum, void(const TagLib::String&)); + MOCK_METHOD1(setComment, void(const TagLib::String&)); + MOCK_METHOD1(setGenre, void(const TagLib::String&)); + + MOCK_CONST_METHOD0(year, uint()); + MOCK_CONST_METHOD0(track, uint()); + MOCK_METHOD1(setYear, void(uint)); + MOCK_METHOD1(setTrack, void(uint)); +}; + + +class MockFile : public TagLib::File { + public: + MockFile(TagLib::Tag* tag, const QString& filename); + + virtual TagLib::Tag* tag() const; + + virtual TagLib::AudioProperties* audioProperties() const; + + virtual bool save(); + + protected: + boost::scoped_ptr tag_; +}; + +class MockFileRefFactory : public FileRefFactory { + public: + void ExpectCall(const QString& filename, + const QString& title, + const QString& artist, + const QString& album); + protected: + virtual TagLib::FileRef* GetFileRef(const QString& filename); + + QMap tags_; +}; + +#endif // MOCK_TAGLIB_H diff --git a/tests/song_test.cpp b/tests/song_test.cpp index 10a57d140..631e977e9 100644 --- a/tests/song_test.cpp +++ b/tests/song_test.cpp @@ -1,14 +1,22 @@ #include "song.h" #include +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "test_utils.h" +#include "mock_taglib.h" namespace { class SongTest : public ::testing::Test { - + protected: + static void SetUpTestCase() { + // Return something from uninteresting mock functions. + testing::DefaultValue::Set("foobarbaz"); + } + + MockFileRefFactory mock_factory_; }; @@ -27,5 +35,13 @@ TEST_F(SongTest, InitsFromLastFM) { EXPECT_EQ("Bar", song.artist()); } +TEST_F(SongTest, InitsFromFile) { + mock_factory_.ExpectCall("foobar.mp3", "Foo", "Bar", "Baz"); + Song song(&mock_factory_); + song.InitFromFile("foobar.mp3", 42); + EXPECT_EQ("Foo", song.title()); + EXPECT_EQ("Bar", song.artist()); + EXPECT_EQ("Baz", song.album()); +} } // namespace